fix: removed unused packages and upgraded to next 14 (#2944)

* fix: upgrading next package and removed unused deps

* chore: unused variable removed

* chore: next image icon fix

* chore: unused component removed

* chore: next image icon fix

* chore: replace use-debounce with lodash debounce

* chore: unused component removed

* resolved: fixed issue with next link component

* fix: updates in next config

* fix: updating types pages

---------

Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>
This commit is contained in:
sriram veeraghanta 2023-11-29 20:32:10 +05:30
parent 804313413b
commit ee30eb0590
137 changed files with 469 additions and 1524 deletions

View file

@ -114,7 +114,9 @@ export const EmailSignUpForm: React.FC<Props> = (props) => {
</div>
<div className="text-right text-xs">
<Link href="/">
<a className="text-custom-text-200 hover:text-custom-primary-100">Already have an account? Sign in.</a>
<span className="text-custom-text-200 hover:text-custom-primary-100">
Already have an account? Sign in.
</span>
</Link>
</div>
<div>

View file

@ -2,8 +2,9 @@
import { BarDatum } from "@nivo/bar";
// components
import { CustomTooltip } from "./custom-tooltip";
import { Tooltip } from "@plane/ui";
// ui
import { BarGraph, Tooltip } from "components/ui";
import { BarGraph } from "components/ui";
// helpers
import { findStringWithMostCharacters } from "helpers/array.helper";
import { generateBarColor, generateDisplayName } from "helpers/analytics.helper";

View file

@ -38,7 +38,7 @@ export const NotAuthorizedView: React.FC<Props> = ({ actionButton, type }) => {
<p>
You have signed in as {user.email}. <br />
<Link href={`/?next=${currentPath}`}>
<a className="font-medium text-custom-text-100">Sign in</a>
<span className="font-medium text-custom-text-100">Sign in</span>
</Link>{" "}
with different account that has access to this page.
</p>
@ -46,7 +46,7 @@ export const NotAuthorizedView: React.FC<Props> = ({ actionButton, type }) => {
<p>
You need to{" "}
<Link href={`/?next=${currentPath}`}>
<a className="font-medium text-custom-text-100">Sign in</a>
<span className="font-medium text-custom-text-100">Sign in</span>
</Link>{" "}
with an account that has access to this page.
</p>

View file

@ -18,14 +18,14 @@ export const NotAWorkspaceMember = () => (
</div>
<div className="flex items-center justify-center gap-2">
<Link href="/invitations">
<a>
<span>
<Button variant="neutral-primary">Check pending invites</Button>
</a>
</span>
</Link>
<Link href="/create-workspace">
<a>
<span>
<Button variant="primary">Create new workspace</Button>
</a>
</span>
</Link>
</div>
</div>

View file

@ -45,12 +45,12 @@ const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({
<>
{link ? (
<Link href={link}>
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm ${linkTruncate ? "truncate" : ""}`}>
<span className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm ${linkTruncate ? "truncate" : ""}`}>
<p className={`${linkTruncate ? "truncate" : ""}${icon ? "flex items-center gap-2" : ""}`}>
{icon ?? null}
{title}
</p>
</a>
</span>
</Link>
) : (
<div className={`px-3 text-sm truncate ${unshrinkTitle ? "flex-shrink-0" : ""}`}>

View file

@ -28,7 +28,7 @@ export const EmptyState: React.FC<Props> = ({
}) => (
<div className={`flex items-center justify-center h-full w-full`}>
<div className="text-center flex flex-col items-center w-full">
<Image src={image} className="w-52 sm:w-60" alt={primaryButton?.text} />
<Image src={image} className="w-52 sm:w-60" alt={primaryButton?.text || "button image"} />
<h6 className="text-xl font-semibold mt-6 sm:mt-8 mb-3">{title}</h6>
{description && <p className="text-custom-text-300 mb-7 sm:mb-8 px-5">{description}</p>}
<div className="flex items-center gap-4">

View file

@ -20,7 +20,6 @@ type Props = {
text: string;
onClick: () => void;
};
secondaryButton?: React.ReactNode;
disabled?: boolean;
};
@ -29,7 +28,6 @@ export const NewEmptyState: React.FC<Props> = ({
description,
image,
primaryButton,
secondaryButton,
disabled = false,
comicBox,
}) => {
@ -48,7 +46,7 @@ export const NewEmptyState: React.FC<Props> = ({
<h3 className="font-semibold text-2xl">{title}</h3>
{description && <p className=" text-lg">{description}</p>}
<div className="relative w-full max-w-6xl">
<Image src={image} className="w-52 sm:w-60" alt={primaryButton?.text} />
<Image src={image} className="w-52 sm:w-60" alt={primaryButton?.text || "button image"} />
</div>
<div className="flex justify-center items-start relative">

View file

@ -317,9 +317,9 @@ export const ActiveCycleDetails: React.FC<IActiveCycleDetails> = observer((props
</div>
<Link href={`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`}>
<a className="bg-custom-primary text-white px-4 rounded-md py-2 text-center text-sm font-medium w-full hover:bg-custom-primary/90">
<span className="bg-custom-primary text-white px-4 rounded-md py-2 text-center text-sm font-medium w-full hover:bg-custom-primary/90">
View Cycle
</a>
</span>
</Link>
</div>
</div>

View file

@ -152,7 +152,7 @@ export const CyclesBoardCard: FC<ICyclesBoardCard> = (props) => {
/>
<Link href={`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`}>
<a className="flex flex-col justify-between p-4 h-44 w-full min-w-[250px] text-sm rounded bg-custom-background-100 border border-custom-border-100 hover:shadow-md">
<span className="flex flex-col justify-between p-4 h-44 w-full min-w-[250px] text-sm rounded bg-custom-background-100 border border-custom-border-100 hover:shadow-md">
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-3 truncate">
<span className="flex-shrink-0">
@ -268,7 +268,7 @@ export const CyclesBoardCard: FC<ICyclesBoardCard> = (props) => {
</div>
</div>
</div>
</a>
</span>
</Link>
</div>
);

View file

@ -153,7 +153,7 @@ export const CyclesListItem: FC<TCyclesListItem> = (props) => {
projectId={projectId}
/>
<Link href={`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`}>
<a className="group flex items-center justify-between gap-5 px-5 py-6 h-16 w-full text-sm bg-custom-background-100 border-b border-custom-border-100 hover:bg-custom-background-90">
<span className="group flex items-center justify-between gap-5 px-5 py-6 h-16 w-full text-sm bg-custom-background-100 border-b border-custom-border-100 hover:bg-custom-background-90">
<div className="flex items-center gap-3 w-full truncate">
<div className="flex items-center gap-4 truncate">
<span className="flex-shrink-0">
@ -262,7 +262,7 @@ export const CyclesListItem: FC<TCyclesListItem> = (props) => {
</CustomMenu.MenuItem>
</CustomMenu>
</div>
</a>
</span>
</Link>
</>
);

View file

@ -24,7 +24,10 @@ interface ICycleDelete {
export const CycleDeleteModal: React.FC<ICycleDelete> = observer((props) => {
const { isOpen, handleClose, cycle, workspaceSlug, projectId } = props;
// store
const { cycle: cycleStore, trackEvent: { postHogEventTracker } } = useMobxStore();
const {
cycle: cycleStore,
trackEvent: { postHogEventTracker },
} = useMobxStore();
// toast
const { setToastAlert } = useToast();
// states
@ -36,26 +39,23 @@ export const CycleDeleteModal: React.FC<ICycleDelete> = observer((props) => {
setLoader(true);
if (cycle?.id)
try {
await cycleStore.removeCycle(workspaceSlug, projectId, cycle?.id).then((res) => {
setToastAlert({
type: "success",
title: "Success!",
message: "Cycle deleted successfully.",
await cycleStore
.removeCycle(workspaceSlug, projectId, cycle?.id)
.then(() => {
setToastAlert({
type: "success",
title: "Success!",
message: "Cycle deleted successfully.",
});
postHogEventTracker("CYCLE_DELETE", {
state: "SUCCESS",
});
})
.catch(() => {
postHogEventTracker("CYCLE_DELETE", {
state: "FAILED",
});
});
postHogEventTracker(
"CYCLE_DELETE",
{
state: "SUCCESS"
}
);
}).catch((error) => {
postHogEventTracker(
"CYCLE_DELETE",
{
state: "FAILED"
}
);
});
if (cycleId || peekCycle) router.push(`/${workspaceSlug}/projects/${projectId}/cycles`);

View file

@ -67,11 +67,11 @@ const IntegrationGuide = () => {
</div>
<div className="flex-shrink-0">
<Link href={`/${workspaceSlug}/settings/exports?provider=${service.provider}`}>
<a>
<span>
<Button variant="primary" className="capitalize">
{service.type}
</Button>
</a>
</span>
</Link>
</div>
</div>

View file

@ -119,7 +119,7 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
<div className="flex items-center gap-1 p-1 rounded bg-custom-background-80">
{GLOBAL_VIEW_LAYOUTS.map((layout) => (
<Link key={layout.key} href={`/${workspaceSlug}/${layout.link}`}>
<a>
<span>
<Tooltip tooltipContent={layout.title}>
<div
className={`w-7 h-[22px] rounded grid place-items-center transition-all hover:bg-custom-background-100 overflow-hidden group ${
@ -133,7 +133,7 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
/>
</div>
</Tooltip>
</a>
</span>
</Link>
))}
</div>

View file

@ -185,7 +185,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
</FiltersDropdown>
{projectId && inboxStore.isInboxEnabled && inboxDetails && (
<Link href={`/${workspaceSlug}/projects/${projectId}/inbox/${inboxStore.getInboxId(projectId)}`}>
<a>
<span>
<Button variant="neutral-primary" size="sm" className="relative">
Inbox
{inboxDetails.pending_issue_count > 0 && (
@ -194,7 +194,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
</span>
)}
</Button>
</a>
</span>
</Link>
)}
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">

View file

@ -1,9 +1,13 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import AudioFileIcon from "public/attachment/audio-icon.png";
export const AudioIcon: React.FC<Props> = ({ width, height }) => (
export type AudioIconProps = {
width?: number;
height?: number;
};
export const AudioIcon: React.FC<AudioIconProps> = ({ width, height }) => (
<Image src={AudioFileIcon} height={height} width={width} alt="AudioFileIcon" />
);

View file

@ -1,10 +1,11 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import CMDIcon from "public/mac-command.svg";
// type
import type { ImageIconPros } from "./types";
export const MacCommandIcon: React.FC<Props> = ({ width = "14", height = "14" }) => (
export const MacCommandIcon: React.FC<ImageIconPros> = ({ width = 14, height = 14 }) => (
<Image src={CMDIcon} height={height} width={width} alt="CMDIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import CssFileIcon from "public/attachment/css-icon.png";
// type
import type { ImageIconPros } from "./types";
export const CssIcon: React.FC<Props> = ({ width, height }) => (
export const CssIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={CssFileIcon} height={height} width={width} alt="CssFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import CSVFileIcon from "public/attachment/csv-icon.png";
// type
import type { ImageIconPros } from "./types";
export const CsvIcon: React.FC<Props> = ({ width, height }) => (
export const CsvIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={CSVFileIcon} height={height} width={width} alt="CSVFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import DefaultFileIcon from "public/attachment/default-icon.png";
// type
import type { ImageIconPros } from "./types";
export const DefaultIcon: React.FC<Props> = ({ width, height }) => (
export const DefaultIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={DefaultFileIcon} height={height} width={width} alt="DefaultFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import DocFileIcon from "public/attachment/doc-icon.png";
// type
import type { ImageIconPros } from "./types";
export const DocIcon: React.FC<Props> = ({ width, height }) => (
export const DocIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={DocFileIcon} height={height} width={width} alt="DocFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import FigmaFileIcon from "public/attachment/figma-icon.png";
// type
import type { ImageIconPros } from "./types";
export const FigmaIcon: React.FC<Props> = ({ width, height }) => (
export const FigmaIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={FigmaFileIcon} height={height} width={width} alt="FigmaFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import HtmlFileIcon from "public/attachment/html-icon.png";
// type
import type { ImageIconPros } from "./types";
export const HtmlIcon: React.FC<Props> = ({ width, height }) => (
export const HtmlIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={HtmlFileIcon} height={height} width={width} alt="HtmlFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import ImgFileIcon from "public/attachment/img-icon.png";
// type
import type { ImageIconPros } from "./types";
export const ImgIcon: React.FC<Props> = ({ width, height }) => (
export const ImgIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={ImgFileIcon} height={height} width={width} alt="ImgFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import JpgFileIcon from "public/attachment/jpg-icon.png";
// type
import type { ImageIconPros } from "./types";
export const JpgIcon: React.FC<Props> = ({ width, height }) => (
export const JpgIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={JpgFileIcon} height={height} width={width} alt="JpgFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import JsFileIcon from "public/attachment/js-icon.png";
// type
import type { ImageIconPros } from "./types";
export const JavaScriptIcon: React.FC<Props> = ({ width, height }) => (
export const JavaScriptIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={JsFileIcon} height={height} width={width} alt="JsFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import PDFFileIcon from "public/attachment/pdf-icon.png";
// type
import type { ImageIconPros } from "./types";
export const PdfIcon: React.FC<Props> = ({ width, height }) => (
export const PdfIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={PDFFileIcon} height={height} width={width} alt="PDFFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import PngFileIcon from "public/attachment/png-icon.png";
// type
import type { ImageIconPros } from "./types";
export const PngIcon: React.FC<Props> = ({ width, height }) => (
export const PngIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={PngFileIcon} height={height} width={width} alt="PngFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import SheetFileIcon from "public/attachment/excel-icon.png";
// type
import type { ImageIconPros } from "./types";
export const SheetIcon: React.FC<Props> = ({ width, height }) => (
export const SheetIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={SheetFileIcon} height={height} width={width} alt="SheetFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import SvgFileIcon from "public/attachment/svg-icon.png";
// type
import type { ImageIconPros } from "./types";
export const SvgIcon: React.FC<Props> = ({ width, height }) => (
export const SvgIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={SvgFileIcon} height={height} width={width} alt="SvgFileIcon" />
);

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import TxtFileIcon from "public/attachment/txt-icon.png";
// type
import type { ImageIconPros } from "./types";
export const TxtIcon: React.FC<Props> = ({ width, height }) => (
export const TxtIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={TxtFileIcon} height={height} width={width} alt="TxtFileIcon" />
);

View file

@ -4,3 +4,8 @@ export type Props = {
height?: string | number;
color?: string;
};
export type ImageIconPros = {
width?: number;
height?: number;
};

View file

@ -1,9 +1,10 @@
import React from "react";
import Image from "next/image";
import type { Props } from "./types";
// image
import VideoFileIcon from "public/attachment/video-icon.png";
// type
import type { ImageIconPros } from "./types";
export const VideoIcon: React.FC<Props> = ({ width, height }) => (
export const VideoIcon: React.FC<ImageIconPros> = ({ width, height }) => (
<Image src={VideoFileIcon} height={height} width={width} alt="VideoFileIcon" />
);

View file

@ -27,7 +27,7 @@ export const InboxIssueCard: React.FC<Props> = (props) => {
return (
<Link href={`/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}?inboxIssueId=${issue.issue_inbox[0].id}`}>
<a>
<span>
<div
id={issue.id}
className={`relative min-h-[5rem] cursor-pointer select-none space-y-3 py-2 px-4 border-b border-custom-border-200 hover:bg-custom-primary/5 ${
@ -91,7 +91,7 @@ export const InboxIssueCard: React.FC<Props> = (props) => {
)}
</div>
</div>
</a>
</span>
</Link>
);
};

View file

@ -1,7 +1,7 @@
import { FC } from "react";
import { Controller, useForm } from "react-hook-form";
// ui
import { Button, Input, ToggleSwitch } from "@plane/ui";
import { Button, Input } from "@plane/ui";
// types
import { IInstance, IInstanceAdmin } from "types/instance";
// hooks

View file

@ -97,16 +97,13 @@ export const InstanceHelpSection: FC = () => {
{helpOptions.map(({ name, Icon, href, onClick }) => {
if (href)
return (
<Link href={href} key={name}>
<a
target="_blank"
className="flex items-center gap-x-2 rounded px-2 py-1 text-xs hover:bg-custom-background-80"
>
<Link href={href} key={name} target="_blank">
<span className="flex items-center gap-x-2 rounded px-2 py-1 text-xs hover:bg-custom-background-80">
<div className="grid place-items-center flex-shrink-0">
<Icon className="text-custom-text-200 h-3.5 w-3.5" size={14} />
</div>
<span className="text-xs">{name}</span>
</a>
</span>
</Link>
);
else

View file

@ -67,12 +67,12 @@ export const InstanceAdminRestriction: FC<InstanceAdminRestrictionProps> = ({ re
</div>
<div className="flex items-center justify-center gap-2">
<Link href={`/${redirectWorkspaceSlug}`}>
<a>
<span>
<Button variant="primary" size="sm">
<LayoutGrid width={16} height={16} />
To the workspace
</Button>
</a>
</span>
</Link>
</div>
</div>

View file

@ -78,9 +78,9 @@ export const InstanceSidebarDropdown = observer(() => {
<Tooltip position="bottom-left" tooltipContent="Exit God Mode">
<div className="flex-shrink-0">
<Link href={`/${redirectWorkspaceSlug}`}>
<a>
<span>
<LogIn className="h-5 w-5 text-custom-text-200 rotate-180" />
</a>
</span>
</Link>
</div>
</Tooltip>
@ -119,10 +119,10 @@ export const InstanceSidebarDropdown = observer(() => {
{PROFILE_LINKS.map((link) => (
<Menu.Item key={link.key} as="button" type="button">
<Link href={link.link}>
<a className="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-custom-sidebar-background-80">
<span className="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-custom-sidebar-background-80">
<link.icon className="h-4 w-4 stroke-[1.5]" />
{link.name}
</a>
</span>
</Link>
</Menu.Item>
))}
@ -142,9 +142,9 @@ export const InstanceSidebarDropdown = observer(() => {
<div className="p-2 pb-0">
<Menu.Item as="button" type="button" className="w-full">
<Link href={`/${redirectWorkspaceSlug}`}>
<a className="flex w-full items-center justify-center rounded px-2 py-1 text-sm font-medium text-custom-primary-100 hover:text-custom-primary-200 bg-custom-primary-100/20 hover:bg-custom-primary-100/30">
<span className="flex w-full items-center justify-center rounded px-2 py-1 text-sm font-medium text-custom-primary-100 hover:text-custom-primary-200 bg-custom-primary-100/20 hover:bg-custom-primary-100/30">
Exit God Mode
</a>
</span>
</Link>
</Menu.Item>
</div>

View file

@ -54,7 +54,7 @@ export const InstanceAdminSidebarMenu = () => {
return (
<Link key={index} href={item.href}>
<a className="block w-full">
<span className="block w-full">
<Tooltip tooltipContent={item.name} position="right" className="ml-2" disabled={!sidebarCollapsed}>
<div
className={`group flex w-full items-center gap-3 rounded-md px-3 py-2 outline-none ${
@ -84,7 +84,7 @@ export const InstanceAdminSidebarMenu = () => {
)}
</div>
</Tooltip>
</a>
</span>
</Link>
);
})}

View file

@ -165,10 +165,10 @@ export const GithubImporterRoot: React.FC<Props> = () => {
<form onSubmit={handleSubmit(createGithubImporterService)}>
<div className="space-y-2 mt-4">
<Link href={`/${workspaceSlug}/settings/imports`}>
<div className="inline-flex cursor-pointer items-center gap-2 text-sm font-medium text-custom-text-200 hover:text-custom-text-100">
<span className="inline-flex cursor-pointer items-center gap-2 text-sm font-medium text-custom-text-200 hover:text-custom-text-100">
<ArrowLeft className="h-3 w-3" />
<div>Cancel import & go back</div>
</div>
</span>
</Link>
<div className="space-y-4 rounded-[10px] border border-custom-border-200 bg-custom-background-100 p-4">

View file

@ -89,9 +89,9 @@ const IntegrationGuide = () => {
</div>
<div className="flex-shrink-0">
<Link href={`/${workspaceSlug}/settings/imports?provider=${service.provider}`}>
<a>
<span>
<Button variant="primary">{service.type}</Button>
</a>
</span>
</Link>
</div>
</div>

View file

@ -16,7 +16,11 @@ export const JiraGetImportDetail: React.FC = observer(() => {
const router = useRouter();
const { workspaceSlug } = router.query;
const { project: projectStore, commandPalette: commandPaletteStore, trackEvent: { setTrackElement } } = useMobxStore();
const {
project: projectStore,
commandPalette: commandPaletteStore,
trackEvent: { setTrackElement },
} = useMobxStore();
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined;
const {
@ -31,10 +35,8 @@ export const JiraGetImportDetail: React.FC = observer(() => {
<h3 className="font-semibold">Jira Personal Access Token</h3>
<p className="text-sm text-custom-text-200">
Get to know your access token by navigating to{" "}
<Link href="https://id.atlassian.com/manage-profile/security/api-tokens">
<a className="text-custom-primary underline" target="_blank" rel="noreferrer">
Atlassian Settings
</a>
<Link href="https://id.atlassian.com/manage-profile/security/api-tokens" target="_blank" rel="noreferrer">
<span className="text-custom-primary underline">Atlassian Settings</span>
</Link>
</p>
</div>
@ -192,7 +194,7 @@ export const JiraGetImportDetail: React.FC = observer(() => {
type="button"
onClick={() => {
setTrackElement("JIRA_IMPORT_DETAIL");
commandPaletteStore.toggleCreateProjectModal(true)
commandPaletteStore.toggleCreateProjectModal(true);
}}
className="flex cursor-pointer select-none items-center space-x-2 truncate rounded px-1 py-1.5 text-custom-text-200"
>

View file

@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import { mutate } from "swr";
import { FormProvider, useForm } from "react-hook-form";
// icons
import { ArrowLeft, Check, List, Settings, Users2 } from "lucide-react";
import { ArrowLeft, Check, List, Settings } from "lucide-react";
// services
import { JiraImporterService } from "services/integrations";
// fetch keys
@ -100,12 +100,12 @@ export const JiraImporterRoot: React.FC<Props> = () => {
return (
<div className="flex h-full flex-col space-y-2 mt-4">
<Link href={`/${workspaceSlug}/settings/imports`}>
<div className="inline-flex cursor-pointer items-center gap-2 text-sm font-medium text-custom-text-200 hover:text-custom-text-100">
<span className="inline-flex cursor-pointer items-center gap-2 text-sm font-medium text-custom-text-200 hover:text-custom-text-100">
<div>
<ArrowLeft className="h-3 w-3" />
</div>
<div>Cancel import & go back</div>
</div>
</span>
</Link>
<div className="flex h-full flex-col space-y-4 rounded-[10px] border border-custom-border-200 bg-custom-background-100 p-4">

View file

@ -105,11 +105,11 @@ export const IssueActivitySection: React.FC<Props> = ({
<span className="text-gray font-medium">{activityItem.actor_detail.first_name} Bot</span>
) : (
<Link href={`/${workspaceSlug}/profile/${activityItem.actor_detail.id}`}>
<a className="text-gray font-medium">
<span className="text-gray font-medium">
{activityItem.actor_detail.is_bot
? activityItem.actor_detail.first_name
: activityItem.actor_detail.display_name}
</a>
</span>
</Link>
)}{" "}
{message}{" "}

View file

@ -59,8 +59,8 @@ export const IssueAttachments = () => {
key={file.id}
className="flex h-[60px] items-center justify-between gap-1 rounded-md border-[2px] border-custom-border-200 bg-custom-background-100 px-4 py-2 text-sm"
>
<Link href={file.asset}>
<a target="_blank">
<Link href={file.asset} target="_blank">
<span>
<div className="flex items-center gap-3">
<div className="h-7 w-7">{getFileIcon(getFileExtension(file.asset))}</div>
<div className="flex flex-col gap-1">
@ -85,7 +85,7 @@ export const IssueAttachments = () => {
</div>
</div>
</div>
</a>
</span>
</Link>
<button

View file

@ -2,7 +2,7 @@ import { ChangeEvent, FC, useCallback, useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
// hooks
import useReloadConfirmations from "hooks/use-reload-confirmation";
import { useDebouncedCallback } from "use-debounce";
import debounce from "lodash/debounce";
// components
import { TextArea } from "@plane/ui";
import { RichTextEditor } from "@plane/rich-text-editor";
@ -93,7 +93,7 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = (props) => {
});
}, [issue, reset]);
const debouncedFormSave = useDebouncedCallback(async () => {
const debouncedFormSave = debounce(async () => {
handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted"));
}, 1500);

View file

@ -7,12 +7,8 @@ import { EmptyState } from "components/common";
// assets
import emptyIssue from "public/empty-state/issue.svg";
import { EProjectStore } from "store/command-palette.store";
import { useRouter } from "next/router";
export const ProjectViewEmptyState: React.FC = observer(() => {
const router = useRouter();
const { viewId } = router.query as { viewId: string };
const {
commandPalette: commandPaletteStore,
trackEvent: { setTrackElement },

View file

@ -3,11 +3,10 @@ import { PlusIcon } from "lucide-react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { EmptyState } from "components/common";
import { NewEmptyState } from "components/common/new-empty-state";
// assets
import emptyIssue from "public/empty-state/empty_issues.webp";
import { EProjectStore } from "store/command-palette.store";
import { NewEmptyState } from "components/common/new-empty-state";
export const ProjectEmptyState: React.FC = observer(() => {
const {

View file

@ -1,4 +1,3 @@
import { useEffect } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";

View file

@ -2,7 +2,7 @@ import React, { useState } from "react";
import { observer } from "mobx-react-lite";
// components
import { FilterHeader, FilterOption } from "components/issues";
import { FilterOption } from "components/issues";
// types
import { IIssueDisplayFilterOptions, TIssueExtraOptions } from "types";
// constants

View file

@ -10,7 +10,6 @@ import { KanbanIssueBlocksList, KanBanQuickAddIssueForm } from "components/issue
import { IIssueDisplayProperties, IIssue, IState } from "types";
// constants
import { getValueFromObject } from "constants/issue";
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
import { EIssueActions } from "../types";
import { IIssueResponse, IGroupedIssues, ISubGroupedIssues, TUnGroupedIssues } from "store/issues/types";
import { EProjectStore } from "store/command-palette.store";

View file

@ -1,8 +1,5 @@
import React, { FC } from "react";
import { useRouter } from "next/router";
// services
import { ModuleService } from "services/module.service";
import { IssueService } from "services/issue";
// components
import { CustomMenu } from "@plane/ui";
import { CreateUpdateIssueModal } from "components/issues/modal";

View file

@ -1,6 +1,5 @@
import { FC } from "react";
import { observer } from "mobx-react-lite";
import { AlertCircle, SignalHigh, SignalMedium, SignalLow, Ban } from "lucide-react";
// components
import { HeaderGroupByCard } from "./group-by-card";
import { HeaderSubGroupByCard } from "./sub-group-by-card";

View file

@ -81,7 +81,7 @@ export const KanBanQuickAddIssueForm: React.FC<IKanBanQuickAddIssueForm> = obser
handleSubmit,
setFocus,
register,
formState: { errors, isSubmitting },
formState: { isSubmitting },
} = useForm<IIssue>({ defaultValues });
useEffect(() => {

View file

@ -4,7 +4,7 @@ import { ListGroupByHeaderRoot } from "./headers/group-by-root";
import { IssueBlocksList, ListQuickAddIssueForm } from "components/issues";
// types
import { IIssue, IIssueDisplayProperties, IIssueLabel, IProject, IState, IUserLite } from "types";
import { IIssueResponse, IGroupedIssues, TUnGroupedIssues, ViewFlags } from "store/issues/types";
import { IIssueResponse, IGroupedIssues, TUnGroupedIssues } from "store/issues/types";
import { EIssueActions } from "../types";
// constants
import { getValueFromObject } from "constants/issue";

View file

@ -10,7 +10,6 @@ import { Avatar, AvatarGroup, Tooltip } from "@plane/ui";
import { Placement } from "@popperjs/core";
export interface IIssuePropertyAssignee {
view?: "profile" | "workspace" | "project";
projectId: string | null;
value: string[] | string;
onChange: (data: string[]) => void;
@ -26,7 +25,6 @@ export interface IIssuePropertyAssignee {
export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer((props) => {
const {
view,
projectId,
value,
onChange,

View file

@ -12,7 +12,6 @@ import { Placement } from "@popperjs/core";
import { RootStore } from "store/root";
export interface IIssuePropertyLabels {
view?: "profile" | "workspace" | "project";
projectId: string | null;
value: string[];
onChange: (data: string[]) => void;
@ -28,7 +27,6 @@ export interface IIssuePropertyLabels {
export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((props) => {
const {
view,
projectId,
value,
onChange,

View file

@ -15,7 +15,6 @@ import { Placement } from "@popperjs/core";
import { RootStore } from "store/root";
export interface IIssuePropertyState {
view?: "profile" | "workspace" | "project";
projectId: string | null;
value: any | string | null;
onChange: (state: IState) => void;
@ -29,7 +28,6 @@ export interface IIssuePropertyState {
export const IssuePropertyState: React.FC<IIssuePropertyState> = observer((props) => {
const {
view,
projectId,
value,
onChange,

View file

@ -93,11 +93,11 @@ export const IssueActivityCard: FC<IssueActivityCard> = (props) => {
<span className="text-gray font-medium">{activityItem.actor_detail.first_name} Bot</span>
) : (
<Link href={`/${workspaceSlug}/profile/${activityItem.actor_detail.id}`}>
<a className="text-gray font-medium">
<span className="text-gray font-medium">
{activityItem.actor_detail.is_bot
? activityItem.actor_detail.first_name
: activityItem.actor_detail.display_name}
</a>
</span>
</Link>
)}{" "}
{message}{" "}

View file

@ -6,7 +6,7 @@ import { RichTextEditor } from "@plane/rich-text-editor";
import { TextArea } from "@plane/ui";
import { IssueReaction } from "./reactions";
// hooks
import { useDebouncedCallback } from "use-debounce";
import debounce from "lodash/debounce";
import useReloadConfirmations from "hooks/use-reload-confirmation";
import useEditorSuggestions from "hooks/use-editor-suggestions";
// types
@ -74,7 +74,7 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) =
}
}, [issueTitleCurrentValue, localTitleValue]);
const debouncedFormSave = useDebouncedCallback(async () => {
const debouncedFormSave = debounce(async () => {
handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted"));
}, 1500);

View file

@ -280,7 +280,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
await issueDraftService
.createDraftIssue(workspaceSlug as string, activeProject ?? "", payload)
.then((res) => {
.then(() => {
setToastAlert({
type: "success",
title: "Success!",

View file

@ -139,7 +139,7 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
)}
<DeleteModuleModal data={module} isOpen={deleteModal} onClose={() => setDeleteModal(false)} />
<Link href={`/${workspaceSlug}/projects/${module.project}/modules/${module.id}`}>
<a className="flex flex-col justify-between p-4 h-44 w-full min-w-[250px] text-sm rounded bg-custom-background-100 border border-custom-border-100 hover:shadow-md">
<span className="flex flex-col justify-between p-4 h-44 w-full min-w-[250px] text-sm rounded bg-custom-background-100 border border-custom-border-100 hover:shadow-md">
<div>
<div className="flex items-center justify-between gap-2">
<Tooltip tooltipContent={module.name} position="top">
@ -249,7 +249,7 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
</div>
</div>
</div>
</a>
</span>
</Link>
</>
);

View file

@ -128,7 +128,7 @@ export const ModuleListItem: React.FC<Props> = observer((props) => {
)}
<DeleteModuleModal data={module} isOpen={deleteModal} onClose={() => setDeleteModal(false)} />
<Link href={`/${workspaceSlug}/projects/${module.project}/modules/${module.id}`}>
<a className="group flex items-center justify-between gap-5 px-5 py-6 h-16 w-full text-sm bg-custom-background-100 border-b border-custom-border-100 hover:bg-custom-background-90">
<span className="group flex items-center justify-between gap-5 px-5 py-6 h-16 w-full text-sm bg-custom-background-100 border-b border-custom-border-100 hover:bg-custom-background-90">
<div className="flex items-center gap-3 w-full truncate">
<div className="flex items-center gap-4 truncate">
<span className="flex-shrink-0">
@ -225,7 +225,7 @@ export const ModuleListItem: React.FC<Props> = observer((props) => {
</CustomMenu.MenuItem>
</CustomMenu>
</div>
</a>
</span>
</Link>
</>
);

View file

@ -7,7 +7,6 @@ import { useMobxStore } from "lib/mobx/store-provider";
import useLocalStorage from "hooks/use-local-storage";
// components
import { ModuleCardItem, ModuleListItem, ModulePeekOverview, ModulesListGanttChartView } from "components/modules";
import { EmptyState } from "components/common";
// ui
import { Loader } from "@plane/ui";
// assets

View file

@ -32,14 +32,12 @@ export const Invitations: React.FC<Props> = (props) => {
const {
workspace: workspaceStore,
user: { currentUser, updateCurrentUser },
trackEvent: { postHogEventTracker }
trackEvent: { postHogEventTracker },
} = useMobxStore();
const {
data: invitations,
mutate: mutateInvitations,
isLoading,
} = useSWR(USER_WORKSPACE_INVITATIONS, () => workspaceService.userWorkspaceInvitations());
const { data: invitations, mutate: mutateInvitations } = useSWR(USER_WORKSPACE_INVITATIONS, () =>
workspaceService.userWorkspaceInvitations()
);
const handleInvitation = (workspace_invitation: IWorkspaceMemberInvitation, action: "accepted" | "withdraw") => {
if (action === "accepted") {
@ -74,7 +72,8 @@ export const Invitations: React.FC<Props> = (props) => {
.catch((error) => {
console.log(error);
postHogEventTracker("WORKSPACE_USER_INVITE_ACCEPT", { state: "FAILED" });
}).finally(() => setIsJoiningWorkspaces(false));
})
.finally(() => setIsJoiningWorkspaces(false));
};
return invitations && invitations.length > 0 ? (
@ -89,10 +88,11 @@ export const Invitations: React.FC<Props> = (props) => {
return (
<div
key={invitation.id}
className={`flex cursor-pointer items-center gap-2 border p-3.5 rounded ${isSelected
? "border-custom-primary-100"
: "border-onboarding-border-200 hover:bg-onboarding-background-300/30"
}`}
className={`flex cursor-pointer items-center gap-2 border p-3.5 rounded ${
isSelected
? "border-custom-primary-100"
: "border-onboarding-border-200 hover:bg-onboarding-background-300/30"
}`}
onClick={() => handleInvitation(invitation, isSelected ? "withdraw" : "accepted")}
>
<div className="flex-shrink-0">

View file

@ -20,7 +20,7 @@ export const JoinWorkspaces: React.FC<Props> = ({ stepChange, setTryDiffAccount
control,
setValue,
watch,
formState: { errors, isSubmitting, isValid },
formState: { errors, isSubmitting },
} = useForm<IWorkspace>({
defaultValues: {
name: "",

View file

@ -1,5 +1,4 @@
import { useState } from "react";
import Image from "next/image";
import { useRouter } from "next/router";
import useSWR from "swr";
import { observer } from "mobx-react-lite";
@ -9,9 +8,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
import { TourRoot } from "components/onboarding";
import { UserGreetingsView } from "components/user";
import { CompletedIssuesGraph, IssuesList, IssuesPieChart, IssuesStats } from "components/workspace";
import { Button } from "@plane/ui";
// images
import emptyDashboard from "public/empty-state/dashboard.svg";
import { NewEmptyState } from "components/common/new-empty-state";
import emptyProject from "public/empty-state/dashboard_empty_project.webp";

View file

@ -157,7 +157,7 @@ export const PagesListItem: FC<IPagesListItem> = observer((props) => {
<DeletePageModal isOpen={deletePageModal} onClose={() => setDeletePageModal(false)} data={page} />
<li>
<Link href={`/${workspaceSlug}/projects/${projectId}/pages/${page.id}`}>
<a>
<span>
<div className="relative rounded p-4 text-custom-text-200 hover:bg-custom-background-80">
<div className="flex items-center justify-between">
<div className="flex overflow-hidden items-center gap-2">
@ -295,7 +295,7 @@ export const PagesListItem: FC<IPagesListItem> = observer((props) => {
</div>
</div>
</div>
</a>
</span>
</Link>
</li>
</>

View file

@ -50,7 +50,7 @@ export const ProfileNavbar: React.FC<Props> = (props) => {
<div className="flex items-center overflow-x-scroll">
{tabsList.map((tab) => (
<Link key={tab.route} href={`/${workspaceSlug}/profile/${userId}/${tab.route}`}>
<a
<span
className={`border-b-2 p-4 text-sm font-medium outline-none whitespace-nowrap ${
router.pathname === tab.selected
? "border-custom-primary-100 text-custom-primary-100"
@ -58,7 +58,7 @@ export const ProfileNavbar: React.FC<Props> = (props) => {
}`}
>
{tab.label}
</a>
</span>
</Link>
))}
</div>

View file

@ -43,7 +43,7 @@ export const ProfileStats: React.FC<Props> = ({ userProfile }) => {
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{overviewCards.map((card) => (
<Link key={card.route} href={`/${workspaceSlug}/profile/${userId}/${card.route}`}>
<a className="flex items-center gap-3 p-4 rounded border border-custom-border-100 whitespace-nowrap">
<span className="flex items-center gap-3 p-4 rounded border border-custom-border-100 whitespace-nowrap">
<div className="h-11 w-11 bg-custom-background-90 rounded grid place-items-center">
<card.icon className="h-5 w-5" />
</div>
@ -51,7 +51,7 @@ export const ProfileStats: React.FC<Props> = ({ userProfile }) => {
<p className="text-custom-text-400 text-sm">{card.title}</p>
<p className="text-xl font-semibold">{card.value}</p>
</div>
</a>
</span>
</Link>
))}
</div>

View file

@ -68,9 +68,9 @@ export const ProfileSidebar = () => {
{user?.id === userId && (
<div className="absolute top-3.5 right-3.5 h-5 w-5 bg-white rounded grid place-items-center">
<Link href="/profile">
<a className="grid place-items-center text-black">
<span className="grid place-items-center text-black">
<Pencil className="h-3 w-3" />
</a>
</span>
</Link>
</div>
)}

View file

@ -4,12 +4,10 @@ import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { ProjectCard } from "components/project";
import { EmptyState } from "components/project/empty-state";
import { Loader } from "@plane/ui";
// images
import emptyProject from "public/empty-state/empty_project.webp";
// icons
import { Plus } from "lucide-react";
import { NewEmptyState } from "components/common/new-empty-state";
export interface IProjectCardList {

View file

@ -28,7 +28,7 @@ export const EmptyState: React.FC<Props> = ({
}) => (
<div className="flex items-center lg:p-20 md:px-10 px-5 justify-center h-full w-full">
<div className="relative h-full w-full max-w-6xl">
<Image src={image} className="w-52 sm:w-60" alt={primaryButton?.text} layout="fill" />
<Image src={image} className="w-52 sm:w-60" alt={primaryButton?.text ?? ""} layout="fill" />
</div>
<div className="absolute pt-[30vh] md:pt-[35vh] lg:pt-[45vh] text-center flex flex-col items-center w-full">
<h6 className="text-xl font-semibold mt-6">{title}</h6>

View file

@ -76,27 +76,27 @@ export const ProjectMemberListItem: React.FC<Props> = observer((props) => {
<div className="flex items-center gap-x-4 gap-y-2">
{memberDetails.avatar && memberDetails.avatar !== "" ? (
<Link href={`/${workspaceSlug}/profile/${memberDetails.id}`}>
<a className="relative flex h-10 w-10 items-center justify-center rounded p-4 capitalize text-white">
<span className="relative flex h-10 w-10 items-center justify-center rounded p-4 capitalize text-white">
<img
src={memberDetails.avatar}
alt={memberDetails.display_name || memberDetails.email}
className="absolute top-0 left-0 h-full w-full object-cover rounded"
/>
</a>
</span>
</Link>
) : (
<Link href={`/${workspaceSlug}/profile/${memberDetails.id}`}>
<a className="relative flex h-10 w-10 items-center justify-center rounded p-4 capitalize bg-gray-700 text-white">
<span className="relative flex h-10 w-10 items-center justify-center rounded p-4 capitalize bg-gray-700 text-white">
{(memberDetails.display_name ?? memberDetails.email ?? "?")[0]}
</a>
</span>
</Link>
)}
<div>
<Link href={`/${workspaceSlug}/profile/${memberDetails.id}`}>
<a className="text-sm font-medium">
<span className="text-sm font-medium">
{memberDetails.first_name} {memberDetails.last_name}
</a>
</span>
</Link>
<div className="flex items-center">
<p className="text-xs text-custom-text-300">{memberDetails.display_name}</p>

View file

@ -12,8 +12,6 @@ import { Avatar, Button, CustomSelect, CustomSearchSelect } from "@plane/ui";
import { ProjectMemberService } from "services/project";
// hooks
import useToast from "hooks/use-toast";
// helpers
import { trackEvent } from "helpers/event-tracker.helper";
// types
import { IProjectMember, TUserProjectRole } from "types";
// constants
@ -58,7 +56,7 @@ export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
const {
user: { currentProjectRole },
workspaceMember: { workspaceMembers },
trackEvent: { postHogEventTracker }
trackEvent: { postHogEventTracker },
} = useMobxStore();
const {
@ -94,22 +92,16 @@ export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
type: "success",
message: "Member added successfully",
});
postHogEventTracker(
'PROJECT_MEMBER_INVITE',
{
...res,
state: "SUCCESS"
}
);
postHogEventTracker("PROJECT_MEMBER_INVITE", {
...res,
state: "SUCCESS",
});
})
.catch((error) => {
console.log(error);
postHogEventTracker(
'PROJECT_MEMBER_INVITE',
{
state: "FAILED",
}
);
postHogEventTracker("PROJECT_MEMBER_INVITE", {
state: "FAILED",
});
})
.finally(() => {
reset(defaultValues);

View file

@ -75,7 +75,11 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { project, provided, snapshot, handleCopyText, shortContextMenu = false } = props;
// store
const { project: projectStore, theme: themeStore, trackEvent: { setTrackElement } } = useMobxStore();
const {
project: projectStore,
theme: themeStore,
trackEvent: { setTrackElement },
} = useMobxStore();
// router
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
@ -308,7 +312,7 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
return (
<Link key={item.name} href={item.href}>
<a className="block w-full">
<span className="block w-full">
<Tooltip
tooltipContent={`${project?.name}: ${item.name}`}
position="right"
@ -326,7 +330,7 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
{!isCollapsed && item.name}
</div>
</Tooltip>
</a>
</span>
</Link>
);
})}

View file

@ -18,7 +18,6 @@ import type { IState } from "types";
import { STATES_LIST } from "constants/fetch-keys";
// constants
import { GROUP_CHOICES } from "constants/project";
import { stat } from "fs";
type Props = {
data: IState | null;
@ -44,7 +43,10 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
const { workspaceSlug, projectId } = router.query;
// store
const { projectState: projectStateStore, trackEvent: { postHogEventTracker, setTrackElement } } = useMobxStore();
const {
projectState: projectStateStore,
trackEvent: { postHogEventTracker, setTrackElement },
} = useMobxStore();
// hooks
const { setToastAlert } = useToast();
@ -95,13 +97,10 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
title: "Success!",
message: "State created successfully.",
});
postHogEventTracker(
'STATE_CREATE',
{
...res,
state: "SUCCESS"
}
);
postHogEventTracker("STATE_CREATE", {
...res,
state: "SUCCESS",
});
})
.catch((error) => {
if (error.status === 400)
@ -116,12 +115,9 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
title: "Error!",
message: "State could not be created. Please try again.",
});
postHogEventTracker(
'STATE_CREATE',
{
state: "FAILED"
}
);
postHogEventTracker("STATE_CREATE", {
state: "FAILED",
});
});
};
@ -133,13 +129,10 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
.then((res) => {
mutate(STATES_LIST(projectId.toString()));
handleClose();
postHogEventTracker(
'STATE_UPDATE',
{
...res,
state: "SUCCESS",
}
);
postHogEventTracker("STATE_UPDATE", {
...res,
state: "SUCCESS",
});
setToastAlert({
type: "success",
title: "Success!",
@ -159,12 +152,9 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
title: "Error!",
message: "State could not be updated. Please try again.",
});
postHogEventTracker(
'STATE_UPDATE',
{
state: "FAILED",
}
);
postHogEventTracker("STATE_UPDATE", {
state: "FAILED",
});
});
};
@ -187,8 +177,9 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
{({ open }) => (
<>
<Popover.Button
className={`group inline-flex items-center text-base font-medium focus:outline-none ${open ? "text-custom-text-100" : "text-custom-text-200"
}`}
className={`group inline-flex items-center text-base font-medium focus:outline-none ${
open ? "text-custom-text-100" : "text-custom-text-200"
}`}
>
{watch("color") && watch("color") !== "" && (
<span
@ -292,10 +283,14 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
<Button variant="neutral-primary" onClick={handleClose}>
Cancel
</Button>
<Button variant="primary" type="submit" loading={isSubmitting} onClick={() => {
setTrackElement("PROJECT_SETTINGS_STATE_PAGE");
}
}>
<Button
variant="primary"
type="submit"
loading={isSubmitting}
onClick={() => {
setTrackElement("PROJECT_SETTINGS_STATE_PAGE");
}}
>
{isSubmitting ? (data ? "Updating..." : "Creating...") : data ? "Update" : "Create"}
</Button>
</form>

View file

@ -28,7 +28,10 @@ export const DeleteStateModal: React.FC<Props> = observer((props) => {
const { workspaceSlug } = router.query;
// store
const { projectState: projectStateStore, trackEvent: { postHogEventTracker } } = useMobxStore();
const {
projectState: projectStateStore,
trackEvent: { postHogEventTracker },
} = useMobxStore();
// states
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
@ -47,13 +50,10 @@ export const DeleteStateModal: React.FC<Props> = observer((props) => {
await projectStateStore
.deleteState(workspaceSlug.toString(), data.project, data.id)
.then((res) => {
postHogEventTracker(
'STATE_DELETE',
{
state: "SUCCESS"
}
);
.then(() => {
postHogEventTracker("STATE_DELETE", {
state: "SUCCESS",
});
handleClose();
})
.catch((err) => {
@ -70,12 +70,9 @@ export const DeleteStateModal: React.FC<Props> = observer((props) => {
title: "Error!",
message: "State could not be deleted. Please try again.",
});
postHogEventTracker(
'STATE_DELETE',
{
state: "FAILED"
}
)
postHogEventTracker("STATE_DELETE", {
state: "FAILED",
});
})
.finally(() => {
setIsDeleteLoading(false);

View file

@ -1,39 +0,0 @@
import React, { useEffect, useState } from "react";
export const CircularProgress = ({ progress }: { progress: number }) => {
const [circumference, setCircumference] = useState(0);
useEffect(() => {
const radius = 40;
const calcCircumference = 2 * Math.PI * radius;
setCircumference(calcCircumference);
}, []);
const progressAngle = (progress / 100) * 360 >= 360 ? 359.9 : (progress / 100) * 360;
const progressX = 50 + Math.cos((progressAngle - 90) * (Math.PI / 180)) * 40;
const progressY = 50 + Math.sin((progressAngle - 90) * (Math.PI / 180)) * 40;
return (
<div className="relative h-5 w-5">
<svg className="absolute top-0 left-0" viewBox="0 0 100 100">
<circle
className="stroke-current"
cx="50"
cy="50"
r="40"
strokeWidth="12"
fill="none"
strokeDasharray={`${circumference} ${circumference}`}
/>
<path
className="fill-current"
d={`M50 10
A40 40 0 ${progress > 50 ? 1 : 0} 1 ${progressX} ${progressY}
L50 50 Z`}
strokeWidth="12"
strokeLinecap="round"
/>
</svg>
</div>
);
};

View file

@ -1,123 +0,0 @@
import React, { useEffect, useRef } from "react";
import Link from "next/link";
// hooks
import useOutsideClickDetector from "hooks/use-outside-click-detector";
type Props = {
clickEvent: React.MouseEvent | null;
children: React.ReactNode;
title?: string | JSX.Element;
isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
};
const ContextMenu = ({ clickEvent, children, title, isOpen, setIsOpen }: Props) => {
const contextMenuRef = useRef<HTMLDivElement>(null);
// Close the context menu when clicked outside
useOutsideClickDetector(contextMenuRef, () => {
if (isOpen) setIsOpen(false);
});
useEffect(() => {
const hideContextMenu = () => {
if (isOpen) setIsOpen(false);
};
const escapeKeyEvent = (e: KeyboardEvent) => {
if (e.key === "Escape") hideContextMenu();
};
window.addEventListener("click", hideContextMenu);
window.addEventListener("keydown", escapeKeyEvent);
return () => {
window.removeEventListener("click", hideContextMenu);
window.removeEventListener("keydown", escapeKeyEvent);
};
}, [isOpen, setIsOpen]);
useEffect(() => {
const contextMenu = contextMenuRef.current;
if (contextMenu && isOpen) {
const contextMenuWidth = contextMenu.clientWidth;
const contextMenuHeight = contextMenu.clientHeight;
const clickX = clickEvent?.pageX || 0;
const clickY = clickEvent?.pageY || 0;
let top = clickY;
// check if there's enough space at the bottom, otherwise show at the top
if (clickY + contextMenuHeight > window.innerHeight) top = clickY - contextMenuHeight;
// check if there's enough space on the right, otherwise show on the left
let left = clickX;
if (clickX + contextMenuWidth > window.innerWidth) left = clickX - contextMenuWidth;
contextMenu.style.top = `${top}px`;
contextMenu.style.left = `${left}px`;
}
}, [clickEvent, isOpen]);
return (
<div
className={`fixed z-50 top-0 left-0 h-full w-full ${
isOpen ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
}`}
>
<div
ref={contextMenuRef}
className={`fixed z-50 flex min-w-[8rem] flex-col items-stretch gap-1 rounded-md border border-custom-border-200 bg-custom-background-90 p-2 text-xs shadow-lg`}
>
{title && (
<h4 className="border-b border-custom-border-200 px-1 py-1 pb-2 text-[0.8rem] font-medium">{title}</h4>
)}
{children}
</div>
</div>
);
};
type MenuItemProps = {
children: JSX.Element | string;
renderAs?: "button" | "a";
href?: string;
onClick?: () => void;
className?: string;
Icon?: any;
};
const MenuItem: React.FC<MenuItemProps> = ({ children, renderAs, href = "", onClick, className = "", Icon }) => (
<>
{renderAs === "a" ? (
<Link href={href}>
<a
className={`${className} flex w-full items-center gap-2 rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80`}
>
<>
{Icon && <Icon />}
{children}
</>
</a>
</Link>
) : (
<button
type="button"
className={`${className} flex w-full items-center gap-2 rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80`}
onClick={onClick}
>
<>
{Icon && <Icon height={12} width={12} />}
{children}
</>
</button>
)}
</>
);
ContextMenu.Item = MenuItem;
export { ContextMenu };

View file

@ -1,162 +0,0 @@
import React, { useState } from "react";
import Link from "next/link";
// react-poppper
import { usePopper } from "react-popper";
// headless ui
import { Menu } from "@headlessui/react";
// ui
import { DropdownProps } from "components/ui";
// icons
import { ChevronDown, MoreHorizontal } from "lucide-react";
export type CustomMenuProps = DropdownProps & {
children: React.ReactNode;
ellipsis?: boolean;
noBorder?: boolean;
verticalEllipsis?: boolean;
menuButtonOnClick?: (...args: any) => void;
};
const CustomMenu = ({
buttonClassName = "",
customButtonClassName = "",
placement,
children,
className = "",
customButton,
disabled = false,
ellipsis = false,
label,
maxHeight = "md",
noBorder = false,
noChevron = false,
optionsClassName = "",
verticalEllipsis = false,
width = "auto",
menuButtonOnClick,
}: CustomMenuProps) => {
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: placement ?? "bottom-start",
});
return (
<Menu as="div" className={`relative w-min text-left ${className}`}>
{({ open }) => (
<>
{customButton ? (
<Menu.Button as={React.Fragment}>
<button
ref={setReferenceElement}
type="button"
onClick={menuButtonOnClick}
className={customButtonClassName}
>
{customButton}
</button>
</Menu.Button>
) : (
<>
{ellipsis || verticalEllipsis ? (
<Menu.Button as={React.Fragment}>
<button
ref={setReferenceElement}
type="button"
onClick={menuButtonOnClick}
disabled={disabled}
className={`relative grid place-items-center rounded p-1 text-custom-text-200 hover:text-custom-text-100 outline-none ${
disabled ? "cursor-not-allowed" : "cursor-pointer hover:bg-custom-background-80"
} ${buttonClassName}`}
>
<MoreHorizontal className={`h-3.5 w-3.5 ${verticalEllipsis ? "rotate-90" : ""}`} />
</button>
</Menu.Button>
) : (
<Menu.Button as={React.Fragment}>
<button
ref={setReferenceElement}
type="button"
className={`flex items-center justify-between gap-1 rounded-md px-2.5 py-1 text-xs whitespace-nowrap duration-300 ${
open ? "bg-custom-background-90 text-custom-text-100" : "text-custom-text-200"
} ${noBorder ? "" : "border border-custom-border-300 shadow-sm focus:outline-none"} ${
disabled
? "cursor-not-allowed text-custom-text-200"
: "cursor-pointer hover:bg-custom-background-80"
} ${buttonClassName}`}
>
{label}
{!noChevron && <ChevronDown className="h-3.5 w-3.5" />}
</button>
</Menu.Button>
)}
</>
)}
<Menu.Items>
<div
className={`z-10 overflow-y-scroll whitespace-nowrap rounded-md border border-custom-border-300 p-1 text-xs shadow-custom-shadow-rg focus:outline-none bg-custom-background-90 my-1 ${
maxHeight === "lg"
? "max-h-60"
: maxHeight === "md"
? "max-h-48"
: maxHeight === "rg"
? "max-h-36"
: maxHeight === "sm"
? "max-h-28"
: ""
} ${width === "auto" ? "min-w-[8rem] whitespace-nowrap" : width} ${optionsClassName}`}
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
>
<div className="py-1">{children}</div>
</div>
</Menu.Items>
</>
)}
</Menu>
);
};
type MenuItemProps = {
children: React.ReactNode;
renderAs?: "button" | "a";
href?: string;
onClick?: (args?: any) => void;
className?: string;
};
const MenuItem: React.FC<MenuItemProps> = ({ children, renderAs, href, onClick, className = "" }) => (
<Menu.Item as="div">
{({ active, close }) =>
renderAs === "a" ? (
<Link href={href ?? ""}>
<a
className={`inline-block w-full select-none truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80 ${
active ? "bg-custom-background-80" : ""
} ${className}`}
onClick={close}
>
{children}
</a>
</Link>
) : (
<button
type="button"
className={`w-full select-none truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80 ${
active ? "bg-custom-background-80" : ""
} ${className}`}
onClick={onClick}
>
{children}
</button>
)
}
</Menu.Item>
);
CustomMenu.MenuItem = MenuItem;
export { CustomMenu };

View file

@ -1,188 +0,0 @@
import React, { useState } from "react";
// react-popper
import { usePopper } from "react-popper";
// headless ui
import { Combobox } from "@headlessui/react";
// icons
import { Check, ChevronDown, Search } from "lucide-react";
// types
import { DropdownProps } from "./types";
export type CustomSearchSelectProps = DropdownProps & {
footerOption?: JSX.Element;
onChange: any;
options:
| {
value: any;
query: string;
content: React.ReactNode;
}[]
| undefined;
} & (
| { multiple?: false; value: any } // if multiple is false, value can be anything
| {
multiple?: true;
value: any[] | null; // if multiple is true, value should be an array
}
);
export const CustomSearchSelect = ({
customButtonClassName = "",
buttonClassName = "",
className = "",
customButton,
placement,
disabled = false,
footerOption,
input = false,
label,
maxHeight = "md",
multiple = false,
noChevron = false,
onChange,
options,
onOpen,
optionsClassName = "",
value,
width = "auto",
}: CustomSearchSelectProps) => {
const [query, setQuery] = useState("");
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: placement ?? "bottom-start",
});
const filteredOptions =
query === "" ? options : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase()));
const props: any = {
value,
onChange,
disabled,
};
if (multiple) props.multiple = true;
return (
<Combobox as="div" className={`relative flex-shrink-0 text-left ${className}`} {...props}>
{({ open }: { open: boolean }) => {
if (open && onOpen) onOpen();
return (
<>
{customButton ? (
<Combobox.Button as={React.Fragment}>
<button
ref={setReferenceElement}
type="button"
className={`flex items-center justify-between gap-1 w-full text-xs ${
disabled
? "cursor-not-allowed text-custom-text-200"
: "cursor-pointer hover:bg-custom-background-80"
} ${customButtonClassName}`}
>
{customButton}
</button>
</Combobox.Button>
) : (
<Combobox.Button as={React.Fragment}>
<button
ref={setReferenceElement}
type="button"
className={`flex items-center justify-between gap-1 w-full rounded-md border border-custom-border-300 shadow-sm duration-300 focus:outline-none ${
input ? "px-3 py-2 text-sm" : "px-2.5 py-1 text-xs"
} ${
disabled
? "cursor-not-allowed text-custom-text-200"
: "cursor-pointer hover:bg-custom-background-80"
} ${buttonClassName}`}
>
{label}
{!noChevron && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
</button>
</Combobox.Button>
)}
<Combobox.Options as={React.Fragment}>
<div
className={`z-10 min-w-[10rem] border border-custom-border-300 p-2 rounded-md bg-custom-background-90 text-xs shadow-custom-shadow-rg focus:outline-none my-1 ${
width === "auto" ? "min-w-[8rem] whitespace-nowrap" : width
} ${optionsClassName}`}
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
>
<div className="flex w-full items-center justify-start rounded-sm border-[0.6px] border-custom-border-200 bg-custom-background-90 px-2">
<Search className="h-3 w-3 text-custom-text-200" />
<Combobox.Input
className="w-full bg-transparent py-1 px-2 text-xs text-custom-text-200 placeholder:text-custom-text-400 focus:outline-none"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Type to search..."
displayValue={(assigned: any) => assigned?.name}
/>
</div>
<div
className={`mt-2 space-y-1 ${
maxHeight === "lg"
? "max-h-60"
: maxHeight === "md"
? "max-h-48"
: maxHeight === "rg"
? "max-h-36"
: maxHeight === "sm"
? "max-h-28"
: ""
} overflow-y-scroll`}
>
{filteredOptions ? (
filteredOptions.length > 0 ? (
filteredOptions.map((option) => (
<Combobox.Option
key={option.value}
value={option.value}
className={({ active, selected }) =>
`flex items-center justify-between gap-2 cursor-pointer select-none truncate rounded px-1 py-1.5 ${
active || selected ? "bg-custom-background-80" : ""
} ${selected ? "text-custom-text-100" : "text-custom-text-200"}`
}
>
{({ active, selected }) => (
<>
{option.content}
{multiple ? (
<div
className={`flex items-center justify-center rounded border border-custom-border-400 p-0.5 ${
active || selected ? "opacity-100" : "opacity-0"
}`}
>
<Check className={`h-3 w-3 ${selected ? "opacity-100" : "opacity-0"}`} />
</div>
) : (
<Check className={`h-3 w-3 ${selected ? "opacity-100" : "opacity-0"}`} />
)}
</>
)}
</Combobox.Option>
))
) : (
<span className="flex items-center gap-2 p-1">
<p className="text-left text-custom-text-200 ">No matching results</p>
</span>
)
) : (
<p className="text-center text-custom-text-200">Loading...</p>
)}
</div>
{footerOption}
</div>
</Combobox.Options>
</>
);
}}
</Combobox>
);
};

View file

@ -1,130 +0,0 @@
import React, { useState } from "react";
// react-popper
import { usePopper } from "react-popper";
// headless ui
import { Listbox } from "@headlessui/react";
// icons
import { Check, ChevronDown } from "lucide-react";
// types
import { DropdownProps } from "./types";
export type CustomSelectProps = DropdownProps & {
children: React.ReactNode;
value: any;
onChange: any;
};
const CustomSelect = ({
customButtonClassName = "",
buttonClassName = "",
placement,
children,
className = "",
customButton,
disabled = false,
input = false,
label,
maxHeight = "md",
noChevron = false,
onChange,
optionsClassName = "",
value,
width = "auto",
}: CustomSelectProps) => {
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: placement ?? "bottom-start",
});
return (
<Listbox
as="div"
value={value}
onChange={onChange}
className={`relative flex-shrink-0 text-left ${className}`}
disabled={disabled}
>
<>
{customButton ? (
<Listbox.Button as={React.Fragment}>
<button
ref={setReferenceElement}
type="button"
className={`flex items-center justify-between gap-1 w-full text-xs ${
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
} ${customButtonClassName}`}
>
{customButton}
</button>
</Listbox.Button>
) : (
<Listbox.Button as={React.Fragment}>
<button
ref={setReferenceElement}
type="button"
className={`flex items-center justify-between gap-1 w-full rounded-md border border-custom-border-300 shadow-sm duration-300 focus:outline-none ${
input ? "px-3 py-2 text-sm" : "px-2.5 py-1 text-xs"
} ${
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
} ${buttonClassName}`}
>
{label}
{!noChevron && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
</button>
</Listbox.Button>
)}
</>
<Listbox.Options>
<div
className={`z-10 border border-custom-border-300 overflow-y-auto rounded-md bg-custom-background-90 text-xs shadow-custom-shadow-rg focus:outline-none my-1 ${
maxHeight === "lg"
? "max-h-60"
: maxHeight === "md"
? "max-h-48"
: maxHeight === "rg"
? "max-h-36"
: maxHeight === "sm"
? "max-h-28"
: ""
} ${width === "auto" ? "min-w-[8rem] whitespace-nowrap" : width} ${optionsClassName}`}
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
>
<div className="space-y-1 p-2">{children}</div>
</div>
</Listbox.Options>
</Listbox>
);
};
type OptionProps = {
children: React.ReactNode;
value: any;
className?: string;
};
const Option: React.FC<OptionProps> = ({ children, value, className }) => (
<Listbox.Option
value={value}
className={({ active, selected }) =>
`cursor-pointer select-none truncate rounded px-1 py-1.5 ${active || selected ? "bg-custom-background-80" : ""} ${
selected ? "text-custom-text-100" : "text-custom-text-200"
} ${className}`
}
>
{({ selected }) => (
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2">{children}</div>
{selected && <Check className="h-4 w-4 flex-shrink-0" />}
</div>
)}
</Listbox.Option>
);
CustomSelect.Option = Option;
export { CustomSelect };

View file

@ -1,5 +0,0 @@
export * from "./context-menu";
export * from "./custom-menu";
export * from "./custom-search-select";
export * from "./custom-select";
export * from "./types.d";

View file

@ -1,18 +0,0 @@
import { Placement } from "@popperjs/core";
export type DropdownProps = {
customButtonClassName?: string;
buttonClassName?: string;
customButtonClassName?: string;
className?: string;
customButton?: JSX.Element;
disabled?: boolean;
input?: boolean;
label?: string | JSX.Element;
maxHeight?: "sm" | "rg" | "md" | "lg";
noChevron?: boolean;
onOpen?: () => void;
optionsClassName?: string;
width?: "auto" | string;
placement?: Placement;
};

View file

@ -30,10 +30,10 @@ const EmptySpace: React.FC<EmptySpaceProps> = ({ title, description, children, I
{link ? (
<div className="mt-6 flex">
<Link href={link.href}>
<a className="text-sm font-medium text-custom-primary hover:text-custom-primary">
<span className="text-sm font-medium text-custom-primary hover:text-custom-primary">
{link.text}
<span aria-hidden="true"> &rarr;</span>
</a>
</span>
</Link>
</div>
) : null}

View file

@ -1,10 +0,0 @@
import React from "react";
type Props = {
iconName: string;
className?: string;
};
export const Icon: React.FC<Props> = ({ iconName, className = "" }) => (
<span className={`material-symbols-rounded text-sm leading-5 font-light ${className}`}>{iconName}</span>
);

View file

@ -1,23 +1,12 @@
export * from "./dropdowns";
export * from "./graphs";
export * from "./input";
export * from "./text-area";
export * from "./date";
export * from "./datepicker";
export * from "./empty-space";
export * from "./icon";
export * from "./labels-list";
export * from "./linear-progress-indicator";
export * from "./loader";
export * from "./multi-level-dropdown";
export * from "./multi-level-select";
export * from "./progress-bar";
export * from "./spinner";
export * from "./tooltip";
export * from "./toggle-switch";
export * from "./markdown-to-component";
export * from "./product-updates-modal";
export * from "./integration-and-import-export-banner";
export * from "./range-datepicker";
export * from "./circular-progress";
export * from "./profile-empty-state";

View file

@ -1,52 +0,0 @@
import * as React from "react";
// types
import { Props } from "./types";
export const Input: React.FC<Props> = ({
label,
value,
name,
register,
validations,
error,
mode = "primary",
onChange,
className = "",
type,
id,
size = "rg",
fullWidth = true,
...rest
}) => (
<>
{label && (
<label htmlFor={id} className="text-custom-text-200 mb-2">
{label}
</label>
)}
<input
type={type}
id={id}
value={value}
{...(register && register(name ?? "", validations))}
onChange={(e) => {
register && register(name ?? "").onChange(e);
onChange && onChange(e);
}}
className={`block rounded-md bg-transparent text-sm focus:outline-none placeholder-custom-text-400 ${
mode === "primary"
? "rounded-md border border-custom-border-200"
: mode === "transparent"
? "rounded border-none bg-transparent ring-0 transition-all focus:ring-1 focus:ring-custom-primary"
: mode === "trueTransparent"
? "rounded border-none bg-transparent ring-0"
: ""
} ${error ? "border-red-500" : ""} ${error && mode === "primary" ? "bg-red-500/20" : ""} ${
fullWidth ? "w-full" : ""
} ${size === "rg" ? "px-3 py-2" : size === "lg" ? "p-3" : ""} ${className}`}
{...rest}
/>
{error?.message && <div className="text-sm text-red-500">{error.message}</div>}
</>
);

View file

@ -1,15 +0,0 @@
import * as React from "react";
import type { UseFormRegister, RegisterOptions } from "react-hook-form";
export interface Props extends React.ComponentPropsWithoutRef<"input"> {
label?: string;
name?: string;
value?: string | number | readonly string[];
mode?: "primary" | "transparent" | "trueTransparent" | "secondary" | "disabled";
register?: UseFormRegister<any>;
validations?: RegisterOptions;
error?: any;
className?: string;
size?: "rg" | "lg";
fullWidth?: boolean;
}

View file

@ -1,39 +0,0 @@
import React from "react";
import { Tooltip } from "@plane/ui";
type Props = {
data: any;
noTooltip?: boolean;
};
export const LinearProgressIndicator: React.FC<Props> = ({ data, noTooltip = false }) => {
const total = data.reduce((acc: any, cur: any) => acc + cur.value, 0);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let progress = 0;
const bars = data.map((item: any) => {
const width = `${(item.value / total) * 100}%`;
const style = {
width,
backgroundColor: item.color,
};
progress += item.value;
if (noTooltip) return <div style={style} />;
else
return (
<Tooltip key={item.id} tooltipContent={`${item.name} ${Math.round(item.value)}%`}>
<div style={style} />
</Tooltip>
);
});
return (
<div className="flex h-1 w-full items-center justify-between gap-1">
{total === 0 ? (
<div className="flex h-full w-full gap-1 bg-neutral-500">{bars}</div>
) : (
<div className="flex h-full w-full gap-1">{bars}</div>
)}
</div>
);
};

View file

@ -1,25 +0,0 @@
import React from "react";
type Props = {
children: React.ReactNode;
className?: string;
};
const Loader = ({ children, className = "" }: Props) => (
<div className={`${className} animate-pulse`} role="status">
{children}
</div>
);
type ItemProps = {
height?: string;
width?: string;
};
const Item: React.FC<ItemProps> = ({ height = "auto", width = "auto" }) => (
<div className="rounded-md bg-custom-background-80" style={{ height: height, width: width }} />
);
Loader.Item = Item;
export { Loader };

View file

@ -1,68 +0,0 @@
import React from "react";
type Props = {
maxValue?: number;
value?: number;
radius?: number;
strokeWidth?: number;
activeStrokeColor?: string;
inactiveStrokeColor?: string;
};
export const ProgressBar: React.FC<Props> = ({
maxValue = 0,
value = 0,
radius = 8,
strokeWidth = 2,
activeStrokeColor = "#3e98c7",
inactiveStrokeColor = "#ddd",
}) => {
// PIE Calc Fn
const generatePie = (value: any) => {
const x = radius - Math.cos((2 * Math.PI) / (100 / value)) * radius;
const y = radius + Math.sin((2 * Math.PI) / (100 / value)) * radius;
const long = value <= 50 ? 0 : 1;
const d = `M${radius} ${radius} L${radius} ${0} A${radius} ${radius} 0 ${long} 1 ${y} ${x} Z`;
return d;
};
// ---- PIE Area Calc --------
const calculatePieValue = (numberOfBars: any) => {
const angle = 360 / numberOfBars;
const pieValue = Math.floor(angle / 4);
return pieValue < 1 ? 1 : Math.floor(angle / 4);
};
// ---- PIE Render Fn --------
const renderPie = (i: any) => {
const DIRECTION = -1;
// Rotation Calc
const primaryRotationAngle = (maxValue - 1) * (360 / maxValue);
const rotationAngle = -1 * DIRECTION * primaryRotationAngle + i * DIRECTION * primaryRotationAngle;
const rotationTransformation = `rotate(${rotationAngle}, ${radius}, ${radius})`;
const pieValue = calculatePieValue(maxValue);
const dValue = generatePie(pieValue);
const fillColor = value > 0 && i <= value ? activeStrokeColor : inactiveStrokeColor;
return (
<path
style={{ opacity: i === 0 ? 0 : 1 }}
key={i}
d={dValue}
fill={fillColor}
transform={rotationTransformation}
/>
);
};
// combining the Pies
const renderOuterCircle = () => [...Array(maxValue + 1)].map((e, i) => renderPie(i));
return (
<svg width={radius * 2} height={radius * 2}>
{renderOuterCircle()}
<circle r={radius - strokeWidth} cx={radius} cy={radius} className="progress-bar" />
</svg>
);
};

View file

@ -1,23 +0,0 @@
import * as React from "react";
export const Spinner: React.FC = () => (
<div role="status">
<svg
aria-hidden="true"
className="mr-2 h-8 w-8 animate-spin fill-blue-600 text-custom-text-200"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span className="sr-only">Loading...</span>
</div>
);

View file

@ -1,83 +0,0 @@
import React, { useState, useRef, useEffect } from "react";
// types
import { Props } from "./types";
// Updates the height of a <textarea> when the value changes.
const useAutoSizeTextArea = (textAreaRef: HTMLTextAreaElement | null, value: any) => {
useEffect(() => {
if (textAreaRef) {
// We need to reset the height momentarily to get the correct scrollHeight for the textarea
textAreaRef.style.height = "0px";
const scrollHeight = textAreaRef.scrollHeight;
// We then set the height directly, outside of the render loop
// Trying to set this with state or a ref will product an incorrect value.
textAreaRef.style.height = scrollHeight + "px";
}
}, [textAreaRef, value]);
};
export const TextArea: React.FC<Props> = ({
id,
label,
className = "",
value,
placeholder,
name,
register,
mode = "primary",
rows,
cols,
disabled,
error,
validations,
noPadding = false,
onChange,
...rest
}) => {
const [textareaValue, setTextareaValue] = useState(value ?? "");
const textAreaRef = useRef<any>(null);
useAutoSizeTextArea(textAreaRef.current, textareaValue);
return (
<>
{label && (
<label htmlFor={id} className="mb-2 text-custom-text-200">
{label}
</label>
)}
<textarea
id={id}
placeholder={placeholder}
value={value}
rows={rows}
cols={cols}
disabled={disabled}
{...(register && register(name, validations))}
ref={(e) => {
textAreaRef.current = e;
if (register) register(name).ref(e);
}}
onChange={(e) => {
register && register(name).onChange(e);
onChange && onChange(e);
setTextareaValue(e.target.value);
}}
className={`no-scrollbar w-full bg-transparent placeholder-custom-text-400 ${
noPadding ? "" : "px-3 py-2"
} outline-none ${
mode === "primary"
? "rounded-md border border-custom-border-200"
: mode === "transparent"
? "rounded border-none bg-transparent ring-0 transition-all focus:ring-1 focus:ring-theme"
: ""
} ${error ? "border-red-500" : ""} ${error && mode === "primary" ? "bg-red-100" : ""} ${className}`}
{...rest}
/>
{error?.message && <div className="text-sm text-red-500">{error.message}</div>}
</>
);
};

View file

@ -1,13 +0,0 @@
import React from "react";
import type { UseFormRegister, RegisterOptions, FieldError } from "react-hook-form";
export interface Props extends React.ComponentPropsWithoutRef<"textarea"> {
label?: string;
value?: string | number | readonly string[];
name: string;
register?: UseFormRegister<any>;
mode?: "primary" | "transparent" | "secondary" | "disabled";
validations?: RegisterOptions;
error?: FieldError | Merge<FieldError, FieldErrorsImpl<any>>;
noPadding?: boolean;
}

View file

@ -1,39 +0,0 @@
import { Switch } from "@headlessui/react";
type Props = {
value: boolean;
onChange: (value: boolean) => void;
label?: string;
size?: "sm" | "md" | "lg";
disabled?: boolean;
className?: string;
};
export const ToggleSwitch: React.FC<Props> = (props) => {
const { value, onChange, label, size = "sm", disabled, className } = props;
return (
<Switch
checked={value}
disabled={disabled}
onChange={onChange}
className={`relative flex-shrink-0 inline-flex ${
size === "sm" ? "h-4 w-6" : size === "md" ? "h-5 w-8" : "h-6 w-10"
} flex-shrink-0 cursor-pointer rounded-full border border-custom-border-200 transition-colors duration-200 ease-in-out focus:outline-none ${
value ? "bg-custom-primary-100" : "bg-gray-700"
} ${className || ""} ${disabled ? "cursor-not-allowed" : ""}`}
>
<span className="sr-only">{label}</span>
<span
aria-hidden="true"
className={`self-center inline-block ${
size === "sm" ? "h-2 w-2" : size === "md" ? "h-3 w-3" : "h-4 w-4"
} transform rounded-full shadow ring-0 transition duration-200 ease-in-out ${
value
? (size === "sm" ? "translate-x-3" : size === "md" ? "translate-x-4" : "translate-x-5") + " bg-white"
: "translate-x-0.5 bg-custom-background-90"
} ${disabled ? "cursor-not-allowed" : ""}`}
/>
</Switch>
);
};

View file

@ -1,68 +0,0 @@
import React from "react";
import { useTheme } from "next-themes";
import { Tooltip2 } from "@blueprintjs/popover2";
type Props = {
tooltipHeading?: string;
tooltipContent: string | React.ReactNode;
position?:
| "top"
| "right"
| "bottom"
| "left"
| "auto"
| "auto-end"
| "auto-start"
| "bottom-left"
| "bottom-right"
| "left-bottom"
| "left-top"
| "right-bottom"
| "right-top"
| "top-left"
| "top-right";
children: JSX.Element;
disabled?: boolean;
className?: string;
openDelay?: number;
closeDelay?: number;
};
export const Tooltip: React.FC<Props> = ({
tooltipHeading,
tooltipContent,
position = "top",
children,
disabled = false,
className = "",
openDelay = 200,
closeDelay,
}) => {
const { theme } = useTheme();
return (
<Tooltip2
disabled={disabled}
hoverOpenDelay={openDelay}
hoverCloseDelay={closeDelay}
content={
<div
className={`relative z-50 max-w-xs gap-1 rounded-md p-2 text-xs shadow-md ${
theme === "custom" ? "bg-custom-background-100 text-custom-text-200" : "bg-black text-gray-400"
} break-words overflow-hidden ${className}`}
>
{tooltipHeading && (
<h5 className={`font-medium ${theme === "custom" ? "text-custom-text-100" : "text-white"}`}>
{tooltipHeading}
</h5>
)}
{tooltipContent}
</div>
}
position={position}
renderTarget={({ ref: eleReference, ...tooltipProps }) =>
React.cloneElement(children, { ref: eleReference, ...tooltipProps, ...children.props })
}
/>
);
};

View file

@ -57,7 +57,7 @@ export const ProjectViewListItem: React.FC<Props> = observer((props) => {
<DeleteProjectViewModal data={view} isOpen={deleteViewModal} onClose={() => setDeleteViewModal(false)} />
<div className="group hover:bg-custom-background-90 border-b border-custom-border-200">
<Link href={`/${workspaceSlug}/projects/${projectId}/views/${view.id}`}>
<a className="flex items-center justify-between relative rounded p-4 w-full">
<span className="flex items-center justify-between relative rounded p-4 w-full">
<div className="flex items-center justify-between w-full">
<div className="flex items-center gap-4 overflow-hidden">
<div className="grid place-items-center flex-shrink-0 h-10 w-10 rounded bg-custom-background-90 group-hover:bg-custom-background-100">
@ -128,7 +128,7 @@ export const ProjectViewListItem: React.FC<Props> = observer((props) => {
</div>
</div>
</div>
</a>
</span>
</Link>
</div>
</>

View file

@ -31,10 +31,10 @@ export const WebhooksListItem: FC<IWebhookListItem> = (props) => {
return (
<div className="border-b border-custom-border-200">
<Link href={`/${workspaceSlug}/settings/webhooks/${webhook?.id}`}>
<a className="flex items-center justify-between gap-4 px-3.5 py-[18px]">
<span className="flex items-center justify-between gap-4 px-3.5 py-[18px]">
<h5 className="text-base font-medium truncate">{webhook.url}</h5>
<ToggleSwitch value={webhook.is_active} onChange={handleToggle} />
</a>
</span>
</Link>
</div>
);

View file

@ -14,8 +14,6 @@ import { Button, CustomSelect, Input } from "@plane/ui";
import { IWorkspace } from "types";
// constants
import { ORGANIZATION_SIZE, RESTRICTED_URLS } from "constants/workspace";
// events
import { trackEvent } from "helpers/event-tracker.helper";
type Props = {
onSubmit?: (res: IWorkspace) => Promise<void>;

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