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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,4 @@
// hoc/withDockItems.tsx
"use client";
import React from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
@ -13,7 +11,7 @@ type WithDockItemsProps = {
};
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 { isProjectsPath, isNotificationsPath } = useWorkspacePaths();

View file

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

View file

@ -69,7 +69,7 @@ export const PaidPlanUpgradeModal = observer(function PaidPlanUpgradeModal(props
verticalFeatureList
extraFeatures={
<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
</a>
</p>
@ -87,7 +87,11 @@ export const PaidPlanUpgradeModal = observer(function PaidPlanUpgradeModal(props
verticalFeatureList
extraFeatures={
<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
</a>
</p>
@ -105,7 +109,11 @@ export const PaidPlanUpgradeModal = observer(function PaidPlanUpgradeModal(props
verticalFeatureList
extraFeatures={
<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
</a>
</p>

View file

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

View file

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

View file

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

View file

@ -17,10 +17,10 @@ export const getTimelineStore = (
return timelineStore.modulesTimeLineStore as IBaseTimelineStore;
}
if (timelineType === GANTT_TIMELINE_TYPE.PROJECT) {
return timelineStore.projectTimeLineStore as IBaseTimelineStore;
return timelineStore.projectTimeLineStore;
}
if (timelineType === GANTT_TIMELINE_TYPE.GROUPED) {
return timelineStore.groupedTimeLineStore as IBaseTimelineStore;
return timelineStore.groupedTimeLineStore;
}
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">
<p className="text-xs text-custom-text-400">
{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"}
</p>
<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">
{token.is_active
? 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"
: `Expired ${calculateTimeAgo(token.expired_at)}`}
</p>

View file

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

View file

@ -65,7 +65,7 @@ export const CommentsWrapper = observer(function CommentsWrapper(props: TComment
<CommentCard
key={comment.id}
workspaceSlug={workspaceSlug}
comment={comment as TIssueComment}
comment={comment}
activityOperations={activityOperations}
disabled={!isEditingAllowed}
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 { observer } from "mobx-react";
import { Globe2, Link, Lock, Pencil, Trash2 } from "lucide-react";
@ -31,46 +30,48 @@ export const CommentQuickActions = observer(function CommentQuickActions(props:
// translation
const { t } = useTranslation();
const MENU_ITEMS = useMemo<TContextMenuItem[]>(
() => [
{
key: "edit",
action: setEditMode,
title: t("common.actions.edit"),
icon: Pencil,
shouldRender: canEdit,
},
{
key: "copy_link",
action: () => activityOperations.copyCommentLink(comment.id),
title: t("common.actions.copy_link"),
icon: Link,
shouldRender: showCopyLinkOption,
},
{
key: "access_specifier",
action: () =>
activityOperations.updateComment(comment.id, {
access:
comment.access === EIssueCommentAccessSpecifier.INTERNAL
? EIssueCommentAccessSpecifier.EXTERNAL
: EIssueCommentAccessSpecifier.INTERNAL,
}),
title:
comment.access === EIssueCommentAccessSpecifier.INTERNAL
? t("issue.comments.switch.public")
: t("issue.comments.switch.private"),
icon: comment.access === EIssueCommentAccessSpecifier.INTERNAL ? Globe2 : Lock,
shouldRender: showAccessSpecifier,
},
{
key: "delete",
action: () => activityOperations.removeComment(comment.id),
title: t("common.actions.delete"),
icon: Trash2,
shouldRender: canDelete,
},
],
const MENU_ITEMS = useMemo(
function MENU_ITEMS(): TContextMenuItem[] {
return [
{
key: "edit",
action: setEditMode,
title: t("common.actions.edit"),
icon: Pencil,
shouldRender: canEdit,
},
{
key: "copy_link",
action: () => activityOperations.copyCommentLink(comment.id),
title: t("common.actions.copy_link"),
icon: Link,
shouldRender: showCopyLinkOption,
},
{
key: "access_specifier",
action: () =>
activityOperations.updateComment(comment.id, {
access:
comment.access === EIssueCommentAccessSpecifier.INTERNAL
? EIssueCommentAccessSpecifier.EXTERNAL
: EIssueCommentAccessSpecifier.INTERNAL,
}),
title:
comment.access === EIssueCommentAccessSpecifier.INTERNAL
? t("issue.comments.switch.public")
: t("issue.comments.switch.private"),
icon: comment.access === EIssueCommentAccessSpecifier.INTERNAL ? Globe2 : Lock,
shouldRender: showAccessSpecifier,
},
{
key: "delete",
action: () => activityOperations.removeComment(comment.id),
title: t("common.actions.delete"),
icon: Trash2,
shouldRender: 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 { observer } from "mobx-react";
import Link from "next/link";
@ -19,7 +18,7 @@ const IconWrapper = React.memo(function IconWrapper({ icon }: { icon: React.Reac
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>;
});
@ -30,7 +29,7 @@ const BreadcrumbContent = React.memo(function BreadcrumbContent({
label,
}: {
icon?: React.ReactNode;
label?: ReactNode;
label?: React.ReactNode;
}) {
if (!icon && !label) return null;
@ -58,10 +57,10 @@ export const BreadcrumbLink = observer(function BreadcrumbLink(props: Props) {
const { isMobile } = usePlatformOS();
const itemWrapperProps = useMemo(
() => ({
(): Omit<React.ComponentProps<typeof ItemWrapper>, "children"> => ({
label: label?.toString(),
disableTooltip: isMobile || disableTooltip,
type: (href && href !== "" ? "link" : "text") as "link" | "text",
type: href && href !== "" ? "link" : "text",
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];
await removeBulkIssues(workspaceSlug as string, projectId as string, data.delete_issue_ids)
await removeBulkIssues(workspaceSlug, projectId, data.delete_issue_ids)
.then(() => {
setToast({
type: TOAST_TYPE.SUCCESS,

View file

@ -1,5 +1,3 @@
"use client";
import React, { useState } from "react";
import { observer } from "mobx-react";
import { Controller, useForm } from "react-hook-form";
@ -29,7 +27,7 @@ const defaultValues: TUniqueCodeValuesForm = { email: "", code: "" };
// service initialization
const authService = new AuthService();
export const ChangeEmailModal: React.FC<Props> = observer((props) => {
export const ChangeEmailModal = observer(function ChangeEmailModal(props: Props) {
const { isOpen, onClose } = props;
// states
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) => {
try {
const res = await cycleService.cycleDateCheck(workspaceSlug as string, projectId as string, payload);
const res = await cycleService.cycleDateCheck(workspaceSlug, projectId, payload);
return res.status;
} catch (err) {
return false;

View file

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

View file

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

View file

@ -79,7 +79,7 @@ export const WorkItemStateDropdownBase = observer(function WorkItemStateDropdown
const { t } = useTranslation();
const statesList = stateIds.map((stateId) => getStateById(stateId)).filter((state) => !!state);
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
const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: placement ?? "bottom-start",

View file

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

View file

@ -87,7 +87,7 @@ export const EstimatePointUpdate = observer(function EstimatePointUpdate(props:
const currentEstimatePointValues = estimatePoints
.map((point) => (point?.key != estimatePoint?.key ? point?.value : undefined))
.filter((value) => value != undefined) as string[];
.filter((value) => value != undefined);
const isRepeated =
(estimateType && isEstimatePointValuesRepeated(currentEstimatePointValues, estimateType, estimateInputValue)) ||
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"}
target="_blank"
className="text-custom-primary-100/80 hover:text-custom-primary-100"
rel="noreferrer"
>
here.
</a>

View file

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

View file

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

View file

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

View file

@ -35,15 +35,13 @@ export const PrevExports = observer(function PrevExports(props: Props) {
const columns = useExportColumns();
const { data: exporterServices } = useSWR(
workspaceSlug && cursor ? EXPORT_SERVICES_LIST(workspaceSlug as string, cursor, `${per_page}`) : null,
workspaceSlug && cursor
? () => integrationService.getExportsServicesList(workspaceSlug as string, cursor, per_page)
: null
workspaceSlug && cursor ? EXPORT_SERVICES_LIST(workspaceSlug, cursor, `${per_page}`) : null,
workspaceSlug && cursor ? () => integrationService.getExportsServicesList(workspaceSlug, cursor, per_page) : null
);
const handleRefresh = () => {
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(() => {

View file

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

View file

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

View file

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

View file

@ -15,6 +15,7 @@ export function ProductUpdatesFooter() {
href="https://go.plane.so/p-docs"
target="_blank"
className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none"
rel="noreferrer"
>
{t("docs")}
</a>
@ -26,6 +27,7 @@ export function ProductUpdatesFooter() {
href="https://go.plane.so/p-changelog"
target="_blank"
className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none"
rel="noreferrer"
>
{t("full_changelog")}
</a>
@ -36,6 +38,7 @@ export function ProductUpdatesFooter() {
href="mailto:support@plane.so"
target="_blank"
className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none"
rel="noreferrer"
>
{t("support")}
</a>
@ -46,6 +49,7 @@ export function ProductUpdatesFooter() {
href="https://go.plane.so/p-discord"
target="_blank"
className="text-sm text-custom-text-200 hover:text-custom-text-100 hover:underline underline-offset-1 outline-none"
rel="noreferrer"
>
Discord
</a>
@ -57,6 +61,7 @@ export function ProductUpdatesFooter() {
getButtonStyling("accent-primary", "sm"),
"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" />
{t("powered_by_plane_pages")}

View file

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

View file

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

View file

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

View file

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

View file

@ -30,10 +30,10 @@ export function GithubRepoDetails({ selectedRepo, handleStepChange, setUsers, se
const { workspaceSlug } = useParams();
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
? () =>
githubIntegrationService.getGithubRepoInfo(workspaceSlug as string, {
githubIntegrationService.getGithubRepoInfo(workspaceSlug, {
owner: selectedRepo.owner.login,
repo: selectedRepo.name,
})

View file

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

View file

@ -54,8 +54,8 @@ const IntegrationGuide = observer(function IntegrationGuide() {
const { t } = useTranslation();
const { data: importerServices } = useSWR(
workspaceSlug ? IMPORTER_SERVICES_LIST(workspaceSlug as string) : null,
workspaceSlug ? () => integrationService.getImporterServicesList(workspaceSlug as string) : null
workspaceSlug ? IMPORTER_SERVICES_LIST(workspaceSlug) : null,
workspaceSlug ? () => integrationService.getImporterServicesList(workspaceSlug) : null
);
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"
onClick={() => {
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" : ""}`} />{" "}

View file

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

View file

@ -38,16 +38,10 @@ export const SelectChannel = observer(function SelectChannel({ integration }: Pr
});
const { data: projectIntegration } = useSWR(
workspaceSlug && projectId && integration.id
? SLACK_CHANNEL_INFO(workspaceSlug as string, projectId as string)
: null,
workspaceSlug && projectId && integration.id ? SLACK_CHANNEL_INFO(workspaceSlug, projectId) : null,
() =>
workspaceSlug && projectId && integration.id
? appInstallationService.getSlackChannelDetail(
workspaceSlug as string,
projectId as string,
integration.id as string
)
? appInstallationService.getSlackChannelDetail(workspaceSlug, projectId, integration.id)
: null
);
@ -74,7 +68,7 @@ export const SelectChannel = observer(function SelectChannel({ integration }: Pr
setSlackChannel(null);
});
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));
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -17,12 +17,7 @@ import type { IProjectViewIssuesFilter } from "@/store/issue/project-views";
// helpers
interface Props {
issuesFilterStore:
| IProjectIssuesFilter
| IModuleIssuesFilter
| ICycleIssuesFilter
| IProjectViewIssuesFilter
| IProjectEpicsFilter;
issuesFilterStore: IProjectIssuesFilter | IModuleIssuesFilter | ICycleIssuesFilter | IProjectViewIssuesFilter;
}
export const CalendarMonthsDropdown = observer(function CalendarMonthsDropdown(props: 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";
interface ICalendarHeader {
issuesFilterStore:
| IProjectIssuesFilter
| IModuleIssuesFilter
| ICycleIssuesFilter
| IProjectViewIssuesFilter
| IProjectEpicsFilter;
issuesFilterStore: IProjectIssuesFilter | IModuleIssuesFilter | ICycleIssuesFilter | IProjectViewIssuesFilter;
updateFilters?: (
projectId: string,
filterType: TSupportedFilterTypeForUpdate,

View file

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

View file

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

View file

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

View file

@ -37,7 +37,7 @@ export const FilterDisplayProperties = observer(function FilterDisplayProperties
// states
const [previewEnabled, setPreviewEnabled] = React.useState(true);
// 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
// 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
? ((groupedIssueIds as TSubGroupedIssues)?.[subList.id]?.[sub_group_id] ?? [])
: ((groupedIssueIds as TGroupedIssues)?.[subList.id] ?? []);
const issueLength = issueIds?.length as number;
const issueLength = issueIds?.length;
const groupHeight = issueLength * approximateCardHeight;
return (

View file

@ -268,7 +268,7 @@ export const KanbanGroup = observer(function KanbanGroup(props: IKanbanGroup) {
const canDragIssuesInCurrentGrouping =
!!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 (
<div

View file

@ -160,7 +160,7 @@ const getCycleColumns = (): IGroupByColumn[] | undefined => {
cycles.push({
id: cycle.id,
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 },
isDropDisabled,
dropErrorMessage: isDropDisabled ? "Work item cannot be moved to completed cycles" : undefined,
@ -486,11 +486,8 @@ const handleSortOrder = (
return currentIssueState;
};
export const getIssueBlockId = (
issueId: string | undefined,
groupId: string | undefined,
subGroupId?: string | undefined
) => `issue_${issueId}_${groupId}_${subGroupId}`;
export const getIssueBlockId = (issueId: string | undefined, groupId: string | undefined, subGroupId?: string) =>
`issue_${issueId}_${groupId}_${subGroupId}`;
/**
* returns empty Array if groupId is None

View file

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

View file

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

View file

@ -63,7 +63,7 @@ export const RelationIssueListItem = observer(function RelationIssueListItem(pro
// derived values
const issue = getIssueById(relationIssueId);
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 projectId = issue?.project_id;

View file

@ -150,7 +150,7 @@ export const LabelDndHOC = observer(function LabelDndHOC(props: Props) {
if (instruction === "reorder-below") dropAtEndOfList = true;
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,
"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
</a>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -24,13 +24,7 @@ type Props = {
* 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
*/
export const TabNavigationOverflowMenu: React.FC<Props> = ({
overflowItems,
isActive,
tabPreferences,
onToggleDefault,
onShow,
}) => {
export function TabNavigationOverflowMenu({ overflowItems, isActive, tabPreferences, onToggleDefault, onShow }: Props) {
const { t } = useTranslation();
return (
@ -97,4 +91,4 @@ export const TabNavigationOverflowMenu: React.FC<Props> = ({
})}
</Menu>
);
};
}

View file

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

View file

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

View file

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

View file

@ -87,108 +87,111 @@ export const PageActions = observer(function PageActions(props: Props) {
canCurrentUserMovePage,
} = page;
// menu items
const MENU_ITEMS = useMemo(() => {
const menuItems: (TContextMenuItem & { key: TPageActions })[] = [
{
key: "toggle-lock",
action: () => {
captureClick({
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.LOCK_BUTTON,
});
pageOperations.toggleLock();
const MENU_ITEMS = useMemo(
function MENU_ITEMS() {
const menuItems: (TContextMenuItem & { key: TPageActions })[] = [
{
key: "toggle-lock",
action: () => {
captureClick({
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.LOCK_BUTTON,
});
pageOperations.toggleLock();
},
title: is_locked ? "Unlock" : "Lock",
icon: is_locked ? LockKeyholeOpen : LockKeyhole,
shouldRender: canCurrentUserLockPage,
},
title: is_locked ? "Unlock" : "Lock",
icon: is_locked ? LockKeyholeOpen : LockKeyhole,
shouldRender: canCurrentUserLockPage,
},
{
key: "toggle-access",
action: () => {
captureClick({
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.ACCESS_TOGGLE,
});
pageOperations.toggleAccess();
{
key: "toggle-access",
action: () => {
captureClick({
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.ACCESS_TOGGLE,
});
pageOperations.toggleAccess();
},
title: access === EPageAccess.PUBLIC ? "Make private" : "Make public",
icon: access === EPageAccess.PUBLIC ? Lock : Globe2,
shouldRender: canCurrentUserChangeAccess && !archived_at,
},
title: access === EPageAccess.PUBLIC ? "Make private" : "Make public",
icon: access === EPageAccess.PUBLIC ? Lock : Globe2,
shouldRender: canCurrentUserChangeAccess && !archived_at,
},
{
key: "open-in-new-tab",
action: pageOperations.openInNewTab,
title: "Open in new tab",
icon: ExternalLink,
shouldRender: true,
},
{
key: "copy-link",
action: pageOperations.copyLink,
title: "Copy link",
icon: Link,
shouldRender: true,
},
{
key: "make-a-copy",
action: () => {
captureClick({
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.DUPLICATE_BUTTON,
});
pageOperations.duplicate();
{
key: "open-in-new-tab",
action: pageOperations.openInNewTab,
title: "Open in new tab",
icon: ExternalLink,
shouldRender: true,
},
title: "Make a copy",
icon: Copy,
shouldRender: canCurrentUserDuplicatePage,
},
{
key: "archive-restore",
action: () => {
captureClick({
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.ARCHIVE_BUTTON,
});
pageOperations.toggleArchive();
{
key: "copy-link",
action: pageOperations.copyLink,
title: "Copy link",
icon: Link,
shouldRender: true,
},
title: archived_at ? "Restore" : "Archive",
icon: archived_at ? ArchiveRestoreIcon : ArchiveIcon,
shouldRender: canCurrentUserArchivePage,
},
{
key: "delete",
action: () => {
captureClick({
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.CONTEXT_MENU,
});
setDeletePageModal(true);
{
key: "make-a-copy",
action: () => {
captureClick({
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.DUPLICATE_BUTTON,
});
pageOperations.duplicate();
},
title: "Make a copy",
icon: Copy,
shouldRender: canCurrentUserDuplicatePage,
},
title: "Delete",
icon: Trash2,
shouldRender: canCurrentUserDeletePage && !!archived_at,
},
{
key: "move",
action: () => setMovePageModal(true),
title: "Move",
icon: FileOutput,
shouldRender: canCurrentUserMovePage && isMovePageEnabled,
},
];
if (extraOptions) {
menuItems.push(...extraOptions);
}
return menuItems;
}, [
extraOptions,
is_locked,
canCurrentUserLockPage,
access,
canCurrentUserChangeAccess,
archived_at,
canCurrentUserDuplicatePage,
canCurrentUserArchivePage,
canCurrentUserDeletePage,
canCurrentUserMovePage,
isMovePageEnabled,
pageOperations,
]);
{
key: "archive-restore",
action: () => {
captureClick({
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.ARCHIVE_BUTTON,
});
pageOperations.toggleArchive();
},
title: archived_at ? "Restore" : "Archive",
icon: archived_at ? ArchiveRestoreIcon : ArchiveIcon,
shouldRender: canCurrentUserArchivePage,
},
{
key: "delete",
action: () => {
captureClick({
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.CONTEXT_MENU,
});
setDeletePageModal(true);
},
title: "Delete",
icon: Trash2,
shouldRender: canCurrentUserDeletePage && !!archived_at,
},
{
key: "move",
action: () => setMovePageModal(true),
title: "Move",
icon: FileOutput,
shouldRender: canCurrentUserMovePage && isMovePageEnabled,
},
];
if (extraOptions) {
menuItems.push(...extraOptions);
}
return menuItems;
},
[
extraOptions,
is_locked,
canCurrentUserLockPage,
access,
canCurrentUserChangeAccess,
archived_at,
canCurrentUserDuplicatePage,
canCurrentUserArchivePage,
canCurrentUserDeletePage,
canCurrentUserMovePage,
isMovePageEnabled,
pageOperations,
]
);
// arrange options
const arrangedOptions = useMemo<(TContextMenuItem & { key: TPageActions })[]>(
() =>

View file

@ -4,7 +4,6 @@ import { ArrowUpToLine, Clipboard, History } from "lucide-react";
// plane imports
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { ToggleSwitch } from "@plane/ui";
import type { TContextMenuItem } from "@plane/ui";
import { copyTextToClipboard } from "@plane/utils";
// hooks
import { useAppRouter } from "@/hooks/use-app-router";
@ -17,7 +16,6 @@ import type { EPageStoreType } from "@/plane-web/hooks/store";
import type { TPageInstance } from "@/store/pages/base-page";
// local imports
import { PageActions } from "../../dropdowns";
import type { TPageActions } from "../../dropdowns";
import { ExportPageModal } from "../../modals/export-page-modal";
import { PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM } from "../../navigation-pane";
@ -43,70 +41,72 @@ export const PageOptionsDropdown = observer(function PageOptionsDropdown(props:
// query params
const { updateQueryParams } = useQueryParams();
// menu items list
const EXTRA_MENU_OPTIONS = useMemo<(TContextMenuItem & { key: TPageActions })[]>(
() => [
{
key: "full-screen",
action: () => handleFullWidth(!isFullWidth),
customContent: (
<>
Full width
<ToggleSwitch value={isFullWidth} onChange={() => {}} />
</>
),
className: "flex items-center justify-between gap-2",
},
{
key: "sticky-toolbar",
action: () => handleStickyToolbar(!isStickyToolbarEnabled),
customContent: (
<>
Sticky toolbar
<ToggleSwitch value={isStickyToolbarEnabled} onChange={() => {}} />
</>
),
className: "flex items-center justify-between gap-2",
shouldRender: isContentEditable,
},
{
key: "copy-markdown",
action: () => {
if (!editorRef) return;
copyTextToClipboard(editorRef.getMarkDown()).then(() =>
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
message: "Markdown copied to clipboard.",
})
);
const EXTRA_MENU_OPTIONS = useMemo(
function EXTRA_MENU_OPTIONS(): React.ComponentProps<typeof PageActions>["extraOptions"] {
return [
{
key: "full-screen",
action: () => handleFullWidth(!isFullWidth),
customContent: (
<>
Full width
<ToggleSwitch value={isFullWidth} onChange={() => {}} />
</>
),
className: "flex items-center justify-between gap-2",
},
title: "Copy markdown",
icon: Clipboard,
shouldRender: true,
},
{
key: "version-history",
action: () => {
// update query param to show info tab in navigation pane
const updatedRoute = updateQueryParams({
paramsToAdd: {
[PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM]: "info" satisfies TPageNavigationPaneTab,
},
});
router.push(updatedRoute);
{
key: "sticky-toolbar",
action: () => handleStickyToolbar(!isStickyToolbarEnabled),
customContent: (
<>
Sticky toolbar
<ToggleSwitch value={isStickyToolbarEnabled} onChange={() => {}} />
</>
),
className: "flex items-center justify-between gap-2",
shouldRender: isContentEditable,
},
title: "Version history",
icon: History,
shouldRender: true,
},
{
key: "export",
action: () => setIsExportModalOpen(true),
title: "Export",
icon: ArrowUpToLine,
shouldRender: true,
},
],
{
key: "copy-markdown",
action: () => {
if (!editorRef) return;
copyTextToClipboard(editorRef.getMarkDown()).then(() =>
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
message: "Markdown copied to clipboard.",
})
);
},
title: "Copy markdown",
icon: Clipboard,
shouldRender: true,
},
{
key: "version-history",
action: () => {
// update query param to show info tab in navigation pane
const updatedRoute = updateQueryParams({
paramsToAdd: {
[PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM]: "info" satisfies TPageNavigationPaneTab,
},
});
router.push(updatedRoute);
},
title: "Version history",
icon: History,
shouldRender: true,
},
{
key: "export",
action: () => setIsExportModalOpen(true),
title: "Export",
icon: ArrowUpToLine,
shouldRender: true,
},
];
},
[
handleFullWidth,
isFullWidth,

View file

@ -21,10 +21,7 @@ type Props = {
export const ProfileIssuesPage = observer(function ProfileIssuesPage(props: Props) {
const { type } = props;
const { workspaceSlug, userId } = useParams() as {
workspaceSlug: string;
userId: string;
};
const { workspaceSlug, userId } = useParams();
// store hooks
const {
issues: { setViewId },

View file

@ -47,7 +47,7 @@ export const StateCreate = observer(function StateCreate(props: TStateCreate) {
handleClose();
return { status: "success" };
} catch (error) {
const errorStatus = error as unknown as { status: number; data: { error: string } };
const errorStatus = error as { status: number; data: { error: string } };
if (shouldTrackEvents)
captureError({
eventName: STATE_TRACKER_EVENTS.create,

View file

@ -47,7 +47,7 @@ export const StateUpdate = observer(function StateUpdate(props: TStateUpdate) {
handleClose();
return { status: "success" };
} catch (error) {
const errorStatus = error as unknown as { status: number };
const errorStatus = error as { status: number };
if (errorStatus?.status === 400) {
setToast({
type: TOAST_TYPE.ERROR,

View file

@ -48,7 +48,7 @@ export const StateDelete = observer(function StateDelete(props: TStateDelete) {
setIsDelete(false);
} catch (error) {
const errorStatus = error as unknown as { status: number; data: { error: string } };
const errorStatus = error as { status: number; data: { error: string } };
if (shouldTrackEvents) {
captureError({
eventName: STATE_TRACKER_EVENTS.delete,

View file

@ -96,10 +96,10 @@ export const StateItem = observer(function StateItem(props: TStateItem) {
const destinationData = self.data as TDraggableData;
if (sourceData && destinationData && sourceData.id) {
const destinationGroupKey = destinationData.groupKey as TStateGroups;
const destinationGroupKey = destinationData.groupKey;
const edge = extractClosestEdge(destinationData) || undefined;
const payload: Partial<IState> = {
id: sourceData.id as string,
id: sourceData.id,
group: destinationGroupKey,
sequence: getCurrentStateSequence(groupedStates[destinationGroupKey], destinationData, edge),
};

View file

@ -34,12 +34,10 @@ const projectService = new ProjectService();
export function IntegrationCard({ integration }: Props) {
const { workspaceSlug, projectId } = useParams();
const { data: syncedGithubRepository } = useSWR(
projectId ? PROJECT_GITHUB_REPOSITORY(projectId as string) : null,
() =>
workspaceSlug && projectId && integration
? projectService.getProjectGithubRepository(workspaceSlug as string, projectId as string, integration.id)
: null
const { data: syncedGithubRepository } = useSWR(projectId ? PROJECT_GITHUB_REPOSITORY(projectId) : null, () =>
workspaceSlug && projectId && integration
? projectService.getProjectGithubRepository(workspaceSlug, projectId, integration.id)
: null
);
const handleChange = (repo: any) => {
@ -53,14 +51,14 @@ export function IntegrationCard({ integration }: Props) {
} = repo;
projectService
.syncGithubRepository(workspaceSlug as string, projectId as string, integration.id, {
.syncGithubRepository(workspaceSlug, projectId, integration.id, {
name,
owner: login,
repository_id: id,
url: html_url,
})
.then(() => {
mutate(PROJECT_GITHUB_REPOSITORY(projectId as string));
mutate(PROJECT_GITHUB_REPOSITORY(projectId));
setToast({
type: TOAST_TYPE.SUCCESS,

View file

@ -44,7 +44,7 @@ export const WebhookSecretKey = observer(function WebhookSecretKey(props: Props)
.then(() =>
setToast({
type: TOAST_TYPE.SUCCESS,
title: `${t("success")!}`,
title: `${t("success")}`,
message: t("workspace_settings.settings.webhooks.toasts.secret_key_copied.message"),
})
)
@ -66,7 +66,7 @@ export const WebhookSecretKey = observer(function WebhookSecretKey(props: Props)
.then(() => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: `${t("success")!}`,
title: `${t("success")}`,
message: "New key regenerated successfully.",
});

View file

@ -15,7 +15,7 @@ import { DateDropdown } from "@/components/dropdowns/date";
type TNotificationSnoozeModal = {
isOpen: boolean;
onClose: () => void;
onSubmit: (dateTime?: Date | undefined) => Promise<void>;
onSubmit: (dateTime?: Date) => Promise<void>;
};
type FormValues = {

View file

@ -6,7 +6,7 @@ import type { IFavorite, TLogoProps } from "@plane/types";
// plane web constants
import { FAVORITE_ITEM_ICONS, FAVORITE_ITEM_LINKS } from "@/plane-web/constants/sidebar-favorites";
export const getFavoriteItemIcon = (type: string, logo?: TLogoProps | undefined) => {
export const getFavoriteItemIcon = (type: string, logo?: TLogoProps) => {
const Icon = FAVORITE_ITEM_ICONS[type] || PageIcon;
return (

View file

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

View file

@ -51,7 +51,7 @@ export const useRealtimePageEvents = ({
(userId: string | undefined) => {
if (!userId) return "";
try {
const userDetails = getUserDetails(userId as string);
const userDetails = getUserDetails(userId);
return userDetails?.display_name ? ` by ${userDetails.display_name}` : "";
} catch {
return "";
@ -61,110 +61,112 @@ export const useRealtimePageEvents = ({
);
const ACTION_HANDLERS = useMemo(
() => ({
archived: ({ pageIds, data }: { pageIds: string[]; data: EventToPayloadMap["archived"] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.archive({ archived_at: data.archived_at, shouldSync: false });
});
},
unarchived: ({ pageIds }: { pageIds: string[] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.restore({ shouldSync: false });
});
},
locked: ({ pageIds }: { pageIds: string[] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.lock({ shouldSync: false, recursive: false });
});
},
unlocked: ({ pageIds }: { pageIds: string[] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.unlock({ shouldSync: false, recursive: false });
});
},
"made-public": ({ pageIds }: { pageIds: string[] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.makePublic({ shouldSync: false });
});
},
"made-private": ({ pageIds }: { pageIds: string[] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.makePrivate({ shouldSync: false });
});
},
deleted: ({ pageIds, data }: { pageIds: string[]; data: EventToPayloadMap["deleted"] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) {
removePage({ pageId, shouldSync: false });
if (page.id === pageId && data?.user_id !== currentUser?.id) {
setToast({
type: TOAST_TYPE.ERROR,
title: "Page deleted",
message: `Page deleted${getUserDisplayText(data.user_id)}`,
});
router.push(handlers.getRedirectionLink());
} else if (page.id === pageId) {
router.push(handlers.getRedirectionLink());
}
}
});
},
property_updated: ({ pageIds, data }: { pageIds: string[]; data: EventToPayloadMap["property_updated"] }) => {
pageIds.forEach((pageId) => {
const pageInstance = getPageById(pageId);
const { name: updatedName, ...rest } = data;
if (updatedName != null) pageInstance?.updateTitle(updatedName);
pageInstance?.mutateProperties(rest);
});
},
error: ({ pageIds, data }: { pageIds: string[]; data: EventToPayloadMap["error"] }) => {
const errorType = data.error_type;
const errorMessage = data.error_message || "An error occurred";
const errorCode = data.error_code;
if (page.id && pageIds.includes(page.id)) {
// Show toast notification
setToast({
type: TOAST_TYPE.ERROR,
title: errorType === "fetch" ? "Failed to load page" : "Failed to save page",
message: errorMessage,
function ACTION_HANDLERS() {
return {
archived: ({ pageIds, data }: { pageIds: string[]; data: EventToPayloadMap["archived"] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.archive({ archived_at: data.archived_at, shouldSync: false });
});
},
// Handle specific error codes
const pageInstance = getPageById(page.id);
if (pageInstance) {
if (errorCode === "page_locked") {
// Lock the page if not already locked
if (!pageInstance.is_locked) {
pageInstance.mutateProperties({ is_locked: true });
unarchived: ({ pageIds }: { pageIds: string[] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.restore({ shouldSync: false });
});
},
locked: ({ pageIds }: { pageIds: string[] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.lock({ shouldSync: false, recursive: false });
});
},
unlocked: ({ pageIds }: { pageIds: string[] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.unlock({ shouldSync: false, recursive: false });
});
},
"made-public": ({ pageIds }: { pageIds: string[] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.makePublic({ shouldSync: false });
});
},
"made-private": ({ pageIds }: { pageIds: string[] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) pageItem.makePrivate({ shouldSync: false });
});
},
deleted: ({ pageIds, data }: { pageIds: string[]; data: EventToPayloadMap["deleted"] }) => {
pageIds.forEach((pageId) => {
const pageItem = getPageById(pageId);
if (pageItem) {
removePage({ pageId, shouldSync: false });
if (page.id === pageId && data?.user_id !== currentUser?.id) {
setToast({
type: TOAST_TYPE.ERROR,
title: "Page deleted",
message: `Page deleted${getUserDisplayText(data.user_id)}`,
});
router.push(handlers.getRedirectionLink());
} else if (page.id === pageId) {
router.push(handlers.getRedirectionLink());
}
} else if (errorCode === "page_archived") {
// Mark page as archived if not already
if (!pageInstance.archived_at) {
pageInstance.mutateProperties({ archived_at: new Date().toISOString() });
}
});
},
property_updated: ({ pageIds, data }: { pageIds: string[]; data: EventToPayloadMap["property_updated"] }) => {
pageIds.forEach((pageId) => {
const pageInstance = getPageById(pageId);
const { name: updatedName, ...rest } = data;
if (updatedName != null) pageInstance?.updateTitle(updatedName);
pageInstance?.mutateProperties(rest);
});
},
error: ({ pageIds, data }: { pageIds: string[]; data: EventToPayloadMap["error"] }) => {
const errorType = data.error_type;
const errorMessage = data.error_message || "An error occurred";
const errorCode = data.error_code;
if (page.id && pageIds.includes(page.id)) {
// Show toast notification
setToast({
type: TOAST_TYPE.ERROR,
title: errorType === "fetch" ? "Failed to load page" : "Failed to save page",
message: errorMessage,
});
// Handle specific error codes
const pageInstance = getPageById(page.id);
if (pageInstance) {
if (errorCode === "page_locked") {
// Lock the page if not already locked
if (!pageInstance.is_locked) {
pageInstance.mutateProperties({ is_locked: true });
}
} else if (errorCode === "page_archived") {
// Mark page as archived if not already
if (!pageInstance.archived_at) {
pageInstance.mutateProperties({ archived_at: new Date().toISOString() });
}
}
}
}
}
},
},
...customRealtimeEventHandlers,
}),
...customRealtimeEventHandlers,
};
},
[getPageById, removePage, page, currentUser, getUserDisplayText, router, handlers, customRealtimeEventHandlers]
);

View file

@ -1,5 +1,3 @@
"use client";
import { createContext, useContext } from "react";
import type { IAppRailVisibilityContext } from "./types";

View file

@ -1,5 +1,3 @@
"use client";
import React, { useCallback, useMemo } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
@ -16,7 +14,10 @@ interface AppRailVisibilityProviderProps {
* AppRailVisibilityProvider - manages app rail visibility state
* Base provider that accepts isEnabled as a prop
*/
export const AppRailVisibilityProvider = observer(({ children, isEnabled = false }: AppRailVisibilityProviderProps) => {
export const AppRailVisibilityProvider = observer(function AppRailVisibilityProvider({
children,
isEnabled = false,
}: AppRailVisibilityProviderProps) {
const { workspaceSlug } = useParams();
// User preference from localStorage

View file

@ -174,7 +174,7 @@ export class GlobalViewStore implements IGlobalViewStore {
);
this.rootStore.issue.workspaceIssues.fetchIssuesWithExistingPagination(workspaceSlug, viewId, "mutation");
}
return currentView as IWorkspaceView;
return currentView;
} catch {
Object.keys(data).forEach((key) => {
const currentKey = key as keyof IWorkspaceView;

View file

@ -64,7 +64,7 @@ export interface IProjectInboxStore {
workspaceSlug: string,
projectId: string,
loadingType?: TLoader,
tab?: TInboxIssueCurrentTab | undefined
tab?: TInboxIssueCurrentTab
) => Promise<void>;
fetchInboxPaginationIssues: (workspaceSlug: string, projectId: string) => Promise<void>;
fetchInboxIssueById: (workspaceSlug: string, projectId: string, inboxIssueId: string) => Promise<TInboxIssue>;

View file

@ -202,7 +202,7 @@ export class CycleIssuesFilter extends IssueFilterHelperStore implements ICycleI
if (isEmpty(this.filters) || isEmpty(this.filters[cycleId])) return;
const _filters = {
richFilters: this.filters[cycleId].richFilters as TWorkItemFilterExpression,
richFilters: this.filters[cycleId].richFilters,
displayFilters: this.filters[cycleId].displayFilters as IIssueDisplayFilterOptions,
displayProperties: this.filters[cycleId].displayProperties as IIssueDisplayProperties,
kanbanFilters: this.filters[cycleId].kanbanFilters as TIssueKanbanFilters,

View file

@ -131,7 +131,7 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues {
* @param projectId
* @param id is the cycle Id
*/
fetchParentStats = (workspaceSlug: string, projectId?: string | undefined, id?: string | undefined) => {
fetchParentStats = (workspaceSlug: string, projectId?: string, id?: string) => {
const cycleId = id ?? this.cycleId;
if (projectId && cycleId) {
@ -150,7 +150,7 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues {
}
};
updateParentStats = (prevIssueState?: TIssue, nextIssueState?: TIssue, id?: string | undefined) => {
updateParentStats = (prevIssueState?: TIssue, nextIssueState?: TIssue, id?: string) => {
try {
const distributionUpdates = getDistributionPathsPostUpdate(
prevIssueState,
@ -305,12 +305,7 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues {
}
) => {
// call API call to transfer issues
const response = await this.cycleService.transferIssues(
workspaceSlug as string,
projectId as string,
cycleId as string,
payload
);
const response = await this.cycleService.transferIssues(workspaceSlug, projectId, cycleId, payload);
// call fetch issues
if (this.paginationOptions) {
await this.fetchIssues(workspaceSlug, projectId, "mutation", this.paginationOptions, cycleId);

View file

@ -249,12 +249,12 @@ export const getFilteredWorkItems = (workItems: TIssue[], filters: IIssueFilterO
activeFilters.every(([filterKey, filterValues]) => {
// Handle date filters separately
if (filterKey === "start_date" || filterKey === "target_date") {
return checkIssueDateFilter(workItem, filterKey as "start_date" | "target_date", filterValues as string[]);
return checkIssueDateFilter(workItem, filterKey, filterValues as string[]);
}
// Handle regular filters
const issueKey = FILTER_TO_ISSUE_MAP[filterKey as keyof IIssueFilterOptions];
if (!issueKey) return true; // Skip if no mapping exists
const issueValue = workItem[issueKey as keyof TIssue];
const issueValue = workItem[issueKey];
// Handle array-based properties vs single value properties
if (Array.isArray(issueValue)) {
return filterValues!.some((filterValue: any) => issueValue.includes(filterValue));
@ -338,7 +338,7 @@ export const getGroupedWorkItemIds = (
// Convert to Record type
const groupedWorkItemsRecord: Record<string, string[]> = {};
Object.entries(groupedWorkItems).forEach(([key, items]) => {
groupedWorkItemsRecord[key] = getOrderedWorkItems(items as TIssue[], orderByKey);
groupedWorkItemsRecord[key] = getOrderedWorkItems(items, orderByKey);
});
return groupedWorkItemsRecord;

View file

@ -307,15 +307,15 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
const allIssues = groupedIssueIds[ALL_ISSUES] ?? [];
if (!this.groupBy && !this.subGroupBy && allIssues && Array.isArray(allIssues)) {
return allIssues as string[];
return allIssues;
}
if (this.groupBy && groupId && groupedIssueIds?.[groupId] && Array.isArray(groupedIssueIds[groupId])) {
return (groupedIssueIds[groupId] ?? []) as string[];
return groupedIssueIds[groupId] ?? [];
}
if (this.groupBy && this.subGroupBy && groupId && subGroupId) {
return ((groupedIssueIds as TSubGroupedIssues)[groupId]?.[subGroupId] ?? []) as string[];
return (groupedIssueIds as TSubGroupedIssues)[groupId]?.[subGroupId] ?? [];
}
return undefined;
@ -1405,7 +1405,7 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
// if groupedIssueIds is an array, update the `groupedIssueIds` store at the issuePath
if (groupedIssueIds && Array.isArray(groupedIssueIds)) {
update(this, ["groupedIssueIds", ...issuePath], (issueIds: string[] = []) =>
this.issuesSortWithOrderBy(uniq(concat(issueIds, groupedIssueIds as string[])), this.orderBy)
this.issuesSortWithOrderBy(uniq(concat(issueIds, groupedIssueIds)), this.orderBy)
);
// return true to indicate the store has been updated
return true;
@ -1617,7 +1617,7 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
getArrayStringArray = (
issueObject: Partial<TIssue> | undefined,
value: string | string[] | undefined | null,
groupByKey?: TIssueGroupByOptions | undefined
groupByKey?: TIssueGroupByOptions
): string[] => {
// if issue object is undefined return empty array
if (!issueObject) return [];

View file

@ -207,7 +207,7 @@ export abstract class IssueDetail implements IIssueDetail {
this.issue = new IssueStore(this, serviceType);
this.reaction = new IssueReactionStore(this, serviceType);
this.attachment = new IssueAttachmentStore(rootStore, serviceType);
this.activity = new IssueActivityStore(rootStore.rootStore as RootStore, serviceType);
this.activity = new IssueActivityStore(rootStore.rootStore, serviceType);
this.comment = new IssueCommentStore(this, serviceType);
this.commentReaction = new IssueCommentReactionStore(this);
this.subIssues = new IssueSubIssuesStore(this, serviceType);

View file

@ -207,7 +207,7 @@ export class ModuleIssuesFilter extends IssueFilterHelperStore implements IModul
if (isEmpty(this.filters) || isEmpty(this.filters[moduleId])) return;
const _filters = {
richFilters: this.filters[moduleId].richFilters as TWorkItemFilterExpression,
richFilters: this.filters[moduleId].richFilters,
displayFilters: this.filters[moduleId].displayFilters as IIssueDisplayFilterOptions,
displayProperties: this.filters[moduleId].displayProperties as IIssueDisplayProperties,
kanbanFilters: this.filters[moduleId].kanbanFilters as TIssueKanbanFilters,

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