diff --git a/packages/tailwind-config-custom/tailwind.config.js b/packages/tailwind-config-custom/tailwind.config.js
index 061168c4f78..4e727ecc1f5 100644
--- a/packages/tailwind-config-custom/tailwind.config.js
+++ b/packages/tailwind-config-custom/tailwind.config.js
@@ -7,7 +7,7 @@ module.exports = {
"./constants/**/*.{js,ts,jsx,tsx}",
"./layouts/**/*.tsx",
"./pages/**/*.tsx",
- "./ui/**/*.tsx",
+ "../packages/ui/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
diff --git a/packages/ui/dist/index.d.ts b/packages/ui/dist/index.d.ts
index 48321708f93..e3b79002451 100644
--- a/packages/ui/dist/index.d.ts
+++ b/packages/ui/dist/index.d.ts
@@ -1,32 +1,39 @@
import * as React from 'react';
-import { FC } from 'react';
+import React__default, { FC } from 'react';
-declare const Button: () => JSX.Element;
+declare type TButtonVariant = "primary" | "accent-primary" | "outline-primary" | "neutral-primary" | "link-primary" | "danger" | "accent-danger" | "outline-danger" | "link-danger" | "tertiary-danger";
-interface InputProps {
- type: string;
- id: string;
- value: string;
- name: string;
- onChange: () => void;
+interface ButtonProps extends React.ButtonHTMLAttributes {
+ variant?: TButtonVariant;
+ size?: "sm" | "md" | "lg";
className?: string;
- mode?: "primary" | "transparent" | "true-transparent";
+ loading?: boolean;
+ disabled?: boolean;
+ appendIcon?: any;
+ prependIcon?: any;
+ children: React.ReactNode;
+}
+declare const Button: React.ForwardRefExoticComponent>;
+
+interface IToggleSwitchProps {
+ value: boolean;
+ onChange: (value: boolean) => void;
+ label?: string;
size?: "sm" | "md" | "lg";
- hasError?: boolean;
- placeholder?: string;
disabled?: boolean;
+ className?: string;
+}
+declare const ToggleSwitch: React.FC;
+
+interface InputProps extends React.InputHTMLAttributes {
+ mode?: "primary" | "transparent" | "true-transparent";
+ inputSize?: "sm" | "md";
+ hasError?: boolean;
+ className?: string;
}
declare const Input: React.ForwardRefExoticComponent>;
-interface TextAreaProps {
- id: string;
- name: string;
- placeholder?: string;
- value?: string;
- rows?: number;
- cols?: number;
- disabled?: boolean;
- onChange: () => void;
+interface TextAreaProps extends React.TextareaHTMLAttributes {
mode?: "primary" | "transparent";
hasError?: boolean;
className?: string;
@@ -38,6 +45,30 @@ interface IRadialProgressBar {
}
declare const RadialProgressBar: FC;
+declare type Props$1 = {
+ maxValue?: number;
+ value?: number;
+ radius?: number;
+ strokeWidth?: number;
+ activeStrokeColor?: string;
+ inactiveStrokeColor?: string;
+};
+declare const ProgressBar: React__default.FC;
+
declare const Spinner: React.FC;
-export { Button, Input, InputProps, RadialProgressBar, Spinner, TextArea, TextAreaProps };
+declare type Props = {
+ children: React__default.ReactNode;
+ className?: string;
+};
+declare const Loader: {
+ ({ children, className }: Props): JSX.Element;
+ Item: React__default.FC;
+ displayName: string;
+};
+declare type ItemProps = {
+ height?: string;
+ width?: string;
+};
+
+export { Button, ButtonProps, Input, InputProps, Loader, ProgressBar, RadialProgressBar, Spinner, TextArea, TextAreaProps, ToggleSwitch };
diff --git a/packages/ui/dist/index.js b/packages/ui/dist/index.js
index 72851d0e7ed..7ac83b1aece 100644
--- a/packages/ui/dist/index.js
+++ b/packages/ui/dist/index.js
@@ -28,52 +28,184 @@ var src_exports = {};
__export(src_exports, {
Button: () => Button,
Input: () => Input,
+ Loader: () => Loader,
+ ProgressBar: () => ProgressBar,
RadialProgressBar: () => RadialProgressBar,
Spinner: () => Spinner,
- TextArea: () => TextArea
+ TextArea: () => TextArea,
+ ToggleSwitch: () => ToggleSwitch
});
module.exports = __toCommonJS(src_exports);
-// src/buttons/index.tsx
+// src/button/button.tsx
var React = __toESM(require("react"));
-var Button = () => {
- return /* @__PURE__ */ React.createElement("button", null, "button");
+
+// src/button/helper.tsx
+var buttonStyling = {
+ primary: {
+ default: `text-white bg-custom-primary-100`,
+ hover: `hover:bg-custom-primary-200`,
+ pressed: `focus:text-custom-brand-40 focus:bg-custom-primary-200`,
+ disabled: `cursor-not-allowed !bg-custom-primary-60 hover:bg-custom-primary-60`
+ },
+ "accent-primary": {
+ default: `bg-custom-primary-10 text-custom-primary-100`,
+ hover: `hover:bg-custom-primary-20 hover:text-custom-primary-200`,
+ pressed: `focus:bg-custom-primary-20`,
+ disabled: `cursor-not-allowed !text-custom-primary-60`
+ },
+ "outline-primary": {
+ default: `text-custom-primary-100 bg-custom-background-100 border border-custom-primary-100`,
+ hover: `hover:border-custom-primary-80 hover:bg-custom-primary-10`,
+ pressed: `focus:text-custom-primary-80 focus:bg-custom-primary-10 focus:border-custom-primary-80`,
+ disabled: `cursor-not-allowed !text-custom-primary-60 !border-custom-primary-60 `
+ },
+ "neutral-primary": {
+ default: `text-custom-text-200 bg-custom-background-100 border border-custom-border-200`,
+ hover: `hover:bg-custom-background-90`,
+ pressed: `focus:text-custom-text-300 focus:bg-custom-background-90`,
+ disabled: `cursor-not-allowed !text-custom-text-400`
+ },
+ "link-primary": {
+ default: `text-custom-primary-100 bg-custom-background-100`,
+ hover: `hover:text-custom-primary-200`,
+ pressed: `focus:text-custom-primary-80 `,
+ disabled: `cursor-not-allowed !text-custom-primary-60`
+ },
+ danger: {
+ default: `text-white bg-red-500`,
+ hover: ` hover:bg-red-600`,
+ pressed: `focus:text-red-200 focus:bg-red-600`,
+ disabled: `cursor-not-allowed !bg-red-300`
+ },
+ "accent-danger": {
+ default: `text-red-500 bg-red-50`,
+ hover: `hover:text-red-600 hover:bg-red-100`,
+ pressed: `focus:text-red-500 focus:bg-red-100`,
+ disabled: `cursor-not-allowed !text-red-300`
+ },
+ "outline-danger": {
+ default: `text-red-500 bg-custom-background-100 border border-red-500`,
+ hover: `hover:text-red-400 hover:border-red-400`,
+ pressed: `focus:text-red-400 focus:border-red-400`,
+ disabled: `cursor-not-allowed !text-red-300 !border-red-300`
+ },
+ "link-danger": {
+ default: `text-red-500 bg-custom-background-100`,
+ hover: `hover:text-red-400`,
+ pressed: `focus:text-red-400`,
+ disabled: `cursor-not-allowed !text-red-300`
+ },
+ "tertiary-danger": {
+ default: `text-red-500 bg-custom-background-100 border border-red-200`,
+ hover: `hover:bg-red-50 hover:border-red-300`,
+ pressed: `focus:text-red-400`,
+ disabled: `cursor-not-allowed !text-red-300`
+ }
+};
+var getButtonStyling = (variant, size, disabled = false) => {
+ let _variant = ``;
+ const currentVariant = buttonStyling[variant];
+ _variant = `${currentVariant.default} ${disabled ? currentVariant.disabled : currentVariant.hover} ${currentVariant.pressed}`;
+ let _size = ``;
+ if (size === "sm")
+ _size = "px-3 py-1.5 font-medium text-xs rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline" /* sm */;
+ if (size === "md")
+ _size = "px-4 py-1.5 font-medium text-sm rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline" /* md */;
+ if (size === "lg")
+ _size = "px-5 py-2 font-medium text-base rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline" /* lg */;
+ return `${_variant} ${_size}`;
+};
+var getIconStyling = (size) => {
+ let icon = ``;
+ if (size === "sm")
+ icon = "h-3 w-3 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0" /* sm */;
+ if (size === "md")
+ icon = "h-3.5 w-3.5 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0" /* md */;
+ if (size === "lg")
+ icon = "h-4 w-4 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0" /* lg */;
+ return icon;
};
-// src/form-fields/input.tsx
+// src/button/button.tsx
+var Button = React.forwardRef(
+ (props, ref) => {
+ const {
+ variant = "primary",
+ size = "md",
+ className = "",
+ type = "button",
+ loading = false,
+ disabled = false,
+ prependIcon = null,
+ appendIcon = null,
+ children,
+ ...rest
+ } = props;
+ const buttonStyle = getButtonStyling(variant, size, disabled || loading);
+ const buttonIconStyle = getIconStyling(size);
+ return /* @__PURE__ */ React.createElement("button", {
+ ref,
+ type,
+ className: `${buttonStyle} ${className}`,
+ disabled: disabled || loading,
+ ...rest
+ }, prependIcon && /* @__PURE__ */ React.createElement("div", {
+ className: buttonIconStyle
+ }, React.cloneElement(prependIcon, { "stroke-width": 2 })), children, appendIcon && /* @__PURE__ */ React.createElement("div", {
+ className: buttonIconStyle
+ }, React.cloneElement(appendIcon, { "stroke-width": 2 })));
+ }
+);
+Button.displayName = "plane-ui-button";
+
+// src/button/toggle-switch.tsx
var React2 = __toESM(require("react"));
-var Input = React2.forwardRef((props, ref) => {
+var import_react = require("@headlessui/react");
+var ToggleSwitch = (props) => {
+ const { value, onChange, label, size = "sm", disabled, className } = props;
+ return /* @__PURE__ */ React2.createElement(import_react.Switch, {
+ checked: value,
+ disabled,
+ 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" : ""}`
+ }, /* @__PURE__ */ React2.createElement("span", {
+ className: "sr-only"
+ }, label), /* @__PURE__ */ React2.createElement("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" : ""}`
+ }));
+};
+ToggleSwitch.displayName = "plane-ui-toggle-switch";
+
+// src/form-fields/input.tsx
+var React3 = __toESM(require("react"));
+var Input = React3.forwardRef((props, ref) => {
const {
id,
type,
- value,
name,
- onChange,
- className = "",
mode = "primary",
- size = "md",
+ inputSize = "sm",
hasError = false,
- placeholder = "",
- disabled = false
+ className = "",
+ ...rest
} = props;
- return /* @__PURE__ */ React2.createElement("input", {
+ return /* @__PURE__ */ React3.createElement("input", {
id,
ref,
type,
- value,
name,
- onChange,
- placeholder,
- disabled,
- 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 === "true-transparent" ? "rounded border-none bg-transparent ring-0" : ""} ${hasError ? "border-red-500" : ""} ${hasError && mode === "primary" ? "bg-red-500/20" : ""} ${size === "sm" ? "px-3 py-2" : size === "lg" ? "p-3" : ""} ${className}`
+ 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 === "true-transparent" ? "rounded border-none bg-transparent ring-0" : ""} ${hasError ? "border-red-500" : ""} ${hasError && mode === "primary" ? "bg-red-500/20" : ""} ${inputSize === "sm" ? "px-3 py-2" : inputSize === "md" ? "p-3" : ""} ${className}`,
+ ...rest
});
});
Input.displayName = "form-input-field";
// src/form-fields/textarea.tsx
-var React3 = __toESM(require("react"));
+var React4 = __toESM(require("react"));
var useAutoSizeTextArea = (textAreaRef, value) => {
- React3.useEffect(() => {
+ React4.useEffect(() => {
if (textAreaRef) {
textAreaRef.style.height = "0px";
const scrollHeight = textAreaRef.scrollHeight;
@@ -81,55 +213,51 @@ var useAutoSizeTextArea = (textAreaRef, value) => {
}
}, [textAreaRef, value]);
};
-var TextArea = React3.forwardRef(
+var TextArea = React4.forwardRef(
(props, ref) => {
const {
id,
name,
- placeholder = "",
value = "",
rows = 1,
cols = 1,
- disabled,
- onChange,
mode = "primary",
hasError = false,
- className = ""
+ className = "",
+ ...rest
} = props;
- const textAreaRef = React3.useRef(ref);
+ const textAreaRef = React4.useRef(ref);
ref && useAutoSizeTextArea(textAreaRef == null ? void 0 : textAreaRef.current, value);
- return /* @__PURE__ */ React3.createElement("textarea", {
+ return /* @__PURE__ */ React4.createElement("textarea", {
id,
name,
ref: textAreaRef,
- placeholder,
value,
rows,
cols,
- disabled,
- onChange,
- className: `no-scrollbar w-full bg-transparent placeholder-custom-text-400 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" : ""} ${hasError ? "border-red-500" : ""} ${hasError && mode === "primary" ? "bg-red-100" : ""} ${className}`
+ className: `no-scrollbar w-full bg-transparent placeholder-custom-text-400 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" : ""} ${hasError ? "border-red-500" : ""} ${hasError && mode === "primary" ? "bg-red-100" : ""} ${className}`,
+ ...rest
});
}
);
// src/progress/radial-progress.tsx
-var import_react = __toESM(require("react"));
+var import_react2 = __toESM(require("react"));
var RadialProgressBar = (props) => {
const { progress } = props;
- const [circumference, setCircumference] = (0, import_react.useState)(0);
- (0, import_react.useEffect)(() => {
+ const [circumference, setCircumference] = (0, import_react2.useState)(0);
+ (0, import_react2.useEffect)(() => {
const radius = 40;
const circumference2 = 2 * Math.PI * radius;
setCircumference(circumference2);
}, []);
const progressOffset = (100 - progress) / 100 * circumference;
- return /* @__PURE__ */ import_react.default.createElement("div", {
+ return /* @__PURE__ */ import_react2.default.createElement("div", {
className: "relative h-4 w-4"
- }, /* @__PURE__ */ import_react.default.createElement("svg", {
+ }, /* @__PURE__ */ import_react2.default.createElement("svg", {
className: "absolute top-0 left-0",
viewBox: "0 0 100 100"
- }, /* @__PURE__ */ import_react.default.createElement("circle", {
+ }, /* @__PURE__ */ import_react2.default.createElement("circle", {
className: "stroke-current opacity-10",
cx: "50",
cy: "50",
@@ -137,7 +265,7 @@ var RadialProgressBar = (props) => {
strokeWidth: "12",
fill: "none",
strokeDasharray: `${circumference} ${circumference}`
- }), /* @__PURE__ */ import_react.default.createElement("circle", {
+ }), /* @__PURE__ */ import_react2.default.createElement("circle", {
className: `stroke-current`,
cx: "50",
cy: "50",
@@ -150,30 +278,96 @@ var RadialProgressBar = (props) => {
})));
};
+// src/progress/progress-bar.tsx
+var import_react3 = __toESM(require("react"));
+var ProgressBar = ({
+ maxValue = 0,
+ value = 0,
+ radius = 8,
+ strokeWidth = 2,
+ activeStrokeColor = "#3e98c7",
+ inactiveStrokeColor = "#ddd"
+}) => {
+ const generatePie = (value2) => {
+ const x = radius - Math.cos(2 * Math.PI / (100 / value2)) * radius;
+ const y = radius + Math.sin(2 * Math.PI / (100 / value2)) * radius;
+ const long = value2 <= 50 ? 0 : 1;
+ const d = `M${radius} ${radius} L${radius} ${0} A${radius} ${radius} 0 ${long} 1 ${y} ${x} Z`;
+ return d;
+ };
+ const calculatePieValue = (numberOfBars) => {
+ const angle = 360 / numberOfBars;
+ const pieValue = Math.floor(angle / 4);
+ return pieValue < 1 ? 1 : Math.floor(angle / 4);
+ };
+ const renderPie = (i) => {
+ const DIRECTION = -1;
+ 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 /* @__PURE__ */ import_react3.default.createElement("path", {
+ style: { opacity: i === 0 ? 0 : 1 },
+ key: i,
+ d: dValue,
+ fill: fillColor,
+ transform: rotationTransformation
+ });
+ };
+ const renderOuterCircle = () => [...Array(maxValue + 1)].map((e, i) => renderPie(i));
+ return /* @__PURE__ */ import_react3.default.createElement("svg", {
+ width: radius * 2,
+ height: radius * 2
+ }, renderOuterCircle(), /* @__PURE__ */ import_react3.default.createElement("circle", {
+ r: radius - strokeWidth,
+ cx: radius,
+ cy: radius,
+ className: "progress-bar"
+ }));
+};
+
// src/spinners/circular-spinner.tsx
-var React5 = __toESM(require("react"));
-var Spinner = () => /* @__PURE__ */ React5.createElement("div", {
+var React7 = __toESM(require("react"));
+var Spinner = () => /* @__PURE__ */ React7.createElement("div", {
role: "status"
-}, /* @__PURE__ */ React5.createElement("svg", {
+}, /* @__PURE__ */ React7.createElement("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"
-}, /* @__PURE__ */ React5.createElement("path", {
+}, /* @__PURE__ */ React7.createElement("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"
-}), /* @__PURE__ */ React5.createElement("path", {
+}), /* @__PURE__ */ React7.createElement("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"
-})), /* @__PURE__ */ React5.createElement("span", {
+})), /* @__PURE__ */ React7.createElement("span", {
className: "sr-only"
}, "Loading..."));
+
+// src/loader.tsx
+var import_react4 = __toESM(require("react"));
+var Loader = ({ children, className = "" }) => /* @__PURE__ */ import_react4.default.createElement("div", {
+ className: `${className} animate-pulse`,
+ role: "status"
+}, children);
+var Item = ({ height = "auto", width = "auto" }) => /* @__PURE__ */ import_react4.default.createElement("div", {
+ className: "rounded-md bg-custom-background-80",
+ style: { height, width }
+});
+Loader.Item = Item;
+Loader.displayName = "plane-ui-loader";
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Button,
Input,
+ Loader,
+ ProgressBar,
RadialProgressBar,
Spinner,
- TextArea
+ TextArea,
+ ToggleSwitch
});
diff --git a/packages/ui/dist/index.mjs b/packages/ui/dist/index.mjs
index 97590dbcf94..d9112b83216 100644
--- a/packages/ui/dist/index.mjs
+++ b/packages/ui/dist/index.mjs
@@ -1,43 +1,172 @@
-// src/buttons/index.tsx
+// src/button/button.tsx
import * as React from "react";
-var Button = () => {
- return /* @__PURE__ */ React.createElement("button", null, "button");
+
+// src/button/helper.tsx
+var buttonStyling = {
+ primary: {
+ default: `text-white bg-custom-primary-100`,
+ hover: `hover:bg-custom-primary-200`,
+ pressed: `focus:text-custom-brand-40 focus:bg-custom-primary-200`,
+ disabled: `cursor-not-allowed !bg-custom-primary-60 hover:bg-custom-primary-60`
+ },
+ "accent-primary": {
+ default: `bg-custom-primary-10 text-custom-primary-100`,
+ hover: `hover:bg-custom-primary-20 hover:text-custom-primary-200`,
+ pressed: `focus:bg-custom-primary-20`,
+ disabled: `cursor-not-allowed !text-custom-primary-60`
+ },
+ "outline-primary": {
+ default: `text-custom-primary-100 bg-custom-background-100 border border-custom-primary-100`,
+ hover: `hover:border-custom-primary-80 hover:bg-custom-primary-10`,
+ pressed: `focus:text-custom-primary-80 focus:bg-custom-primary-10 focus:border-custom-primary-80`,
+ disabled: `cursor-not-allowed !text-custom-primary-60 !border-custom-primary-60 `
+ },
+ "neutral-primary": {
+ default: `text-custom-text-200 bg-custom-background-100 border border-custom-border-200`,
+ hover: `hover:bg-custom-background-90`,
+ pressed: `focus:text-custom-text-300 focus:bg-custom-background-90`,
+ disabled: `cursor-not-allowed !text-custom-text-400`
+ },
+ "link-primary": {
+ default: `text-custom-primary-100 bg-custom-background-100`,
+ hover: `hover:text-custom-primary-200`,
+ pressed: `focus:text-custom-primary-80 `,
+ disabled: `cursor-not-allowed !text-custom-primary-60`
+ },
+ danger: {
+ default: `text-white bg-red-500`,
+ hover: ` hover:bg-red-600`,
+ pressed: `focus:text-red-200 focus:bg-red-600`,
+ disabled: `cursor-not-allowed !bg-red-300`
+ },
+ "accent-danger": {
+ default: `text-red-500 bg-red-50`,
+ hover: `hover:text-red-600 hover:bg-red-100`,
+ pressed: `focus:text-red-500 focus:bg-red-100`,
+ disabled: `cursor-not-allowed !text-red-300`
+ },
+ "outline-danger": {
+ default: `text-red-500 bg-custom-background-100 border border-red-500`,
+ hover: `hover:text-red-400 hover:border-red-400`,
+ pressed: `focus:text-red-400 focus:border-red-400`,
+ disabled: `cursor-not-allowed !text-red-300 !border-red-300`
+ },
+ "link-danger": {
+ default: `text-red-500 bg-custom-background-100`,
+ hover: `hover:text-red-400`,
+ pressed: `focus:text-red-400`,
+ disabled: `cursor-not-allowed !text-red-300`
+ },
+ "tertiary-danger": {
+ default: `text-red-500 bg-custom-background-100 border border-red-200`,
+ hover: `hover:bg-red-50 hover:border-red-300`,
+ pressed: `focus:text-red-400`,
+ disabled: `cursor-not-allowed !text-red-300`
+ }
+};
+var getButtonStyling = (variant, size, disabled = false) => {
+ let _variant = ``;
+ const currentVariant = buttonStyling[variant];
+ _variant = `${currentVariant.default} ${disabled ? currentVariant.disabled : currentVariant.hover} ${currentVariant.pressed}`;
+ let _size = ``;
+ if (size === "sm")
+ _size = "px-3 py-1.5 font-medium text-xs rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline" /* sm */;
+ if (size === "md")
+ _size = "px-4 py-1.5 font-medium text-sm rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline" /* md */;
+ if (size === "lg")
+ _size = "px-5 py-2 font-medium text-base rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline" /* lg */;
+ return `${_variant} ${_size}`;
+};
+var getIconStyling = (size) => {
+ let icon = ``;
+ if (size === "sm")
+ icon = "h-3 w-3 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0" /* sm */;
+ if (size === "md")
+ icon = "h-3.5 w-3.5 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0" /* md */;
+ if (size === "lg")
+ icon = "h-4 w-4 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0" /* lg */;
+ return icon;
};
-// src/form-fields/input.tsx
+// src/button/button.tsx
+var Button = React.forwardRef(
+ (props, ref) => {
+ const {
+ variant = "primary",
+ size = "md",
+ className = "",
+ type = "button",
+ loading = false,
+ disabled = false,
+ prependIcon = null,
+ appendIcon = null,
+ children,
+ ...rest
+ } = props;
+ const buttonStyle = getButtonStyling(variant, size, disabled || loading);
+ const buttonIconStyle = getIconStyling(size);
+ return /* @__PURE__ */ React.createElement("button", {
+ ref,
+ type,
+ className: `${buttonStyle} ${className}`,
+ disabled: disabled || loading,
+ ...rest
+ }, prependIcon && /* @__PURE__ */ React.createElement("div", {
+ className: buttonIconStyle
+ }, React.cloneElement(prependIcon, { "stroke-width": 2 })), children, appendIcon && /* @__PURE__ */ React.createElement("div", {
+ className: buttonIconStyle
+ }, React.cloneElement(appendIcon, { "stroke-width": 2 })));
+ }
+);
+Button.displayName = "plane-ui-button";
+
+// src/button/toggle-switch.tsx
import * as React2 from "react";
-var Input = React2.forwardRef((props, ref) => {
+import { Switch } from "@headlessui/react";
+var ToggleSwitch = (props) => {
+ const { value, onChange, label, size = "sm", disabled, className } = props;
+ return /* @__PURE__ */ React2.createElement(Switch, {
+ checked: value,
+ disabled,
+ 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" : ""}`
+ }, /* @__PURE__ */ React2.createElement("span", {
+ className: "sr-only"
+ }, label), /* @__PURE__ */ React2.createElement("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" : ""}`
+ }));
+};
+ToggleSwitch.displayName = "plane-ui-toggle-switch";
+
+// src/form-fields/input.tsx
+import * as React3 from "react";
+var Input = React3.forwardRef((props, ref) => {
const {
id,
type,
- value,
name,
- onChange,
- className = "",
mode = "primary",
- size = "md",
+ inputSize = "sm",
hasError = false,
- placeholder = "",
- disabled = false
+ className = "",
+ ...rest
} = props;
- return /* @__PURE__ */ React2.createElement("input", {
+ return /* @__PURE__ */ React3.createElement("input", {
id,
ref,
type,
- value,
name,
- onChange,
- placeholder,
- disabled,
- 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 === "true-transparent" ? "rounded border-none bg-transparent ring-0" : ""} ${hasError ? "border-red-500" : ""} ${hasError && mode === "primary" ? "bg-red-500/20" : ""} ${size === "sm" ? "px-3 py-2" : size === "lg" ? "p-3" : ""} ${className}`
+ 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 === "true-transparent" ? "rounded border-none bg-transparent ring-0" : ""} ${hasError ? "border-red-500" : ""} ${hasError && mode === "primary" ? "bg-red-500/20" : ""} ${inputSize === "sm" ? "px-3 py-2" : inputSize === "md" ? "p-3" : ""} ${className}`,
+ ...rest
});
});
Input.displayName = "form-input-field";
// src/form-fields/textarea.tsx
-import * as React3 from "react";
+import * as React4 from "react";
var useAutoSizeTextArea = (textAreaRef, value) => {
- React3.useEffect(() => {
+ React4.useEffect(() => {
if (textAreaRef) {
textAreaRef.style.height = "0px";
const scrollHeight = textAreaRef.scrollHeight;
@@ -45,40 +174,36 @@ var useAutoSizeTextArea = (textAreaRef, value) => {
}
}, [textAreaRef, value]);
};
-var TextArea = React3.forwardRef(
+var TextArea = React4.forwardRef(
(props, ref) => {
const {
id,
name,
- placeholder = "",
value = "",
rows = 1,
cols = 1,
- disabled,
- onChange,
mode = "primary",
hasError = false,
- className = ""
+ className = "",
+ ...rest
} = props;
- const textAreaRef = React3.useRef(ref);
+ const textAreaRef = React4.useRef(ref);
ref && useAutoSizeTextArea(textAreaRef == null ? void 0 : textAreaRef.current, value);
- return /* @__PURE__ */ React3.createElement("textarea", {
+ return /* @__PURE__ */ React4.createElement("textarea", {
id,
name,
ref: textAreaRef,
- placeholder,
value,
rows,
cols,
- disabled,
- onChange,
- className: `no-scrollbar w-full bg-transparent placeholder-custom-text-400 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" : ""} ${hasError ? "border-red-500" : ""} ${hasError && mode === "primary" ? "bg-red-100" : ""} ${className}`
+ className: `no-scrollbar w-full bg-transparent placeholder-custom-text-400 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" : ""} ${hasError ? "border-red-500" : ""} ${hasError && mode === "primary" ? "bg-red-100" : ""} ${className}`,
+ ...rest
});
}
);
// src/progress/radial-progress.tsx
-import React4, { useState, useEffect as useEffect2 } from "react";
+import React5, { useState, useEffect as useEffect2 } from "react";
var RadialProgressBar = (props) => {
const { progress } = props;
const [circumference, setCircumference] = useState(0);
@@ -88,12 +213,12 @@ var RadialProgressBar = (props) => {
setCircumference(circumference2);
}, []);
const progressOffset = (100 - progress) / 100 * circumference;
- return /* @__PURE__ */ React4.createElement("div", {
+ return /* @__PURE__ */ React5.createElement("div", {
className: "relative h-4 w-4"
- }, /* @__PURE__ */ React4.createElement("svg", {
+ }, /* @__PURE__ */ React5.createElement("svg", {
className: "absolute top-0 left-0",
viewBox: "0 0 100 100"
- }, /* @__PURE__ */ React4.createElement("circle", {
+ }, /* @__PURE__ */ React5.createElement("circle", {
className: "stroke-current opacity-10",
cx: "50",
cy: "50",
@@ -101,7 +226,7 @@ var RadialProgressBar = (props) => {
strokeWidth: "12",
fill: "none",
strokeDasharray: `${circumference} ${circumference}`
- }), /* @__PURE__ */ React4.createElement("circle", {
+ }), /* @__PURE__ */ React5.createElement("circle", {
className: `stroke-current`,
cx: "50",
cy: "50",
@@ -114,29 +239,95 @@ var RadialProgressBar = (props) => {
})));
};
+// src/progress/progress-bar.tsx
+import React6 from "react";
+var ProgressBar = ({
+ maxValue = 0,
+ value = 0,
+ radius = 8,
+ strokeWidth = 2,
+ activeStrokeColor = "#3e98c7",
+ inactiveStrokeColor = "#ddd"
+}) => {
+ const generatePie = (value2) => {
+ const x = radius - Math.cos(2 * Math.PI / (100 / value2)) * radius;
+ const y = radius + Math.sin(2 * Math.PI / (100 / value2)) * radius;
+ const long = value2 <= 50 ? 0 : 1;
+ const d = `M${radius} ${radius} L${radius} ${0} A${radius} ${radius} 0 ${long} 1 ${y} ${x} Z`;
+ return d;
+ };
+ const calculatePieValue = (numberOfBars) => {
+ const angle = 360 / numberOfBars;
+ const pieValue = Math.floor(angle / 4);
+ return pieValue < 1 ? 1 : Math.floor(angle / 4);
+ };
+ const renderPie = (i) => {
+ const DIRECTION = -1;
+ 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 /* @__PURE__ */ React6.createElement("path", {
+ style: { opacity: i === 0 ? 0 : 1 },
+ key: i,
+ d: dValue,
+ fill: fillColor,
+ transform: rotationTransformation
+ });
+ };
+ const renderOuterCircle = () => [...Array(maxValue + 1)].map((e, i) => renderPie(i));
+ return /* @__PURE__ */ React6.createElement("svg", {
+ width: radius * 2,
+ height: radius * 2
+ }, renderOuterCircle(), /* @__PURE__ */ React6.createElement("circle", {
+ r: radius - strokeWidth,
+ cx: radius,
+ cy: radius,
+ className: "progress-bar"
+ }));
+};
+
// src/spinners/circular-spinner.tsx
-import * as React5 from "react";
-var Spinner = () => /* @__PURE__ */ React5.createElement("div", {
+import * as React7 from "react";
+var Spinner = () => /* @__PURE__ */ React7.createElement("div", {
role: "status"
-}, /* @__PURE__ */ React5.createElement("svg", {
+}, /* @__PURE__ */ React7.createElement("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"
-}, /* @__PURE__ */ React5.createElement("path", {
+}, /* @__PURE__ */ React7.createElement("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"
-}), /* @__PURE__ */ React5.createElement("path", {
+}), /* @__PURE__ */ React7.createElement("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"
-})), /* @__PURE__ */ React5.createElement("span", {
+})), /* @__PURE__ */ React7.createElement("span", {
className: "sr-only"
}, "Loading..."));
+
+// src/loader.tsx
+import React8 from "react";
+var Loader = ({ children, className = "" }) => /* @__PURE__ */ React8.createElement("div", {
+ className: `${className} animate-pulse`,
+ role: "status"
+}, children);
+var Item = ({ height = "auto", width = "auto" }) => /* @__PURE__ */ React8.createElement("div", {
+ className: "rounded-md bg-custom-background-80",
+ style: { height, width }
+});
+Loader.Item = Item;
+Loader.displayName = "plane-ui-loader";
export {
Button,
Input,
+ Loader,
+ ProgressBar,
RadialProgressBar,
Spinner,
- TextArea
+ TextArea,
+ ToggleSwitch
};
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 1f95e468b3f..9385a26c705 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -29,5 +29,9 @@
},
"publishConfig": {
"access": "public"
+ },
+ "dependencies": {
+ "@headlessui/react": "^1.7.17",
+ "clsx": "^2.0.0"
}
}
diff --git a/packages/ui/src/button/button.tsx b/packages/ui/src/button/button.tsx
new file mode 100644
index 00000000000..a11ce9e8bf1
--- /dev/null
+++ b/packages/ui/src/button/button.tsx
@@ -0,0 +1,61 @@
+import * as React from "react";
+
+import { getIconStyling, getButtonStyling, TButtonVariant } from "./helper";
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes {
+ variant?: TButtonVariant;
+ size?: "sm" | "md" | "lg";
+ className?: string;
+ loading?: boolean;
+ disabled?: boolean;
+ appendIcon?: any;
+ prependIcon?: any;
+ children: React.ReactNode;
+}
+
+const Button = React.forwardRef(
+ (props, ref) => {
+ const {
+ variant = "primary",
+ size = "md",
+ className = "",
+ type = "button",
+ loading = false,
+ disabled = false,
+ prependIcon = null,
+ appendIcon = null,
+ children,
+ ...rest
+ } = props;
+
+ const buttonStyle = getButtonStyling(variant, size, disabled || loading);
+ const buttonIconStyle = getIconStyling(size);
+
+ return (
+
+ {prependIcon && (
+
+ {React.cloneElement(prependIcon, { "stroke-width": 2 })}
+
+ )}
+ {children}
+ {appendIcon && (
+
+ {React.cloneElement(appendIcon, { "stroke-width": 2 })}
+
+ )}
+
+ );
+ }
+);
+
+Button.displayName = "plane-ui-button";
+
+export { Button };
diff --git a/packages/ui/src/button/helper.tsx b/packages/ui/src/button/helper.tsx
new file mode 100644
index 00000000000..1eaee51340c
--- /dev/null
+++ b/packages/ui/src/button/helper.tsx
@@ -0,0 +1,125 @@
+export type TButtonVariant =
+ | "primary"
+ | "accent-primary"
+ | "outline-primary"
+ | "neutral-primary"
+ | "link-primary"
+ | "danger"
+ | "accent-danger"
+ | "outline-danger"
+ | "link-danger"
+ | "tertiary-danger";
+
+export type TButtonSizes = "sm" | "md" | "lg";
+
+export interface IButtonStyling {
+ [key: string]: {
+ default: string;
+ hover: string;
+ pressed: string;
+ disabled: string;
+ };
+}
+
+enum buttonSizeStyling {
+ sm = `px-3 py-1.5 font-medium text-xs rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline`,
+ md = `px-4 py-1.5 font-medium text-sm rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline`,
+ lg = `px-5 py-2 font-medium text-base rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center inline`,
+}
+
+enum buttonIconStyling {
+ sm = "h-3 w-3 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0",
+ md = "h-3.5 w-3.5 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0",
+ lg = "h-4 w-4 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0",
+}
+
+export const buttonStyling: IButtonStyling = {
+ primary: {
+ default: `text-white bg-custom-primary-100`,
+ hover: `hover:bg-custom-primary-200`,
+ pressed: `focus:text-custom-brand-40 focus:bg-custom-primary-200`,
+ disabled: `cursor-not-allowed !bg-custom-primary-60 hover:bg-custom-primary-60`,
+ },
+ "accent-primary": {
+ default: `bg-custom-primary-10 text-custom-primary-100`,
+ hover: `hover:bg-custom-primary-20 hover:text-custom-primary-200`,
+ pressed: `focus:bg-custom-primary-20`,
+ disabled: `cursor-not-allowed !text-custom-primary-60`,
+ },
+ "outline-primary": {
+ default: `text-custom-primary-100 bg-custom-background-100 border border-custom-primary-100`,
+ hover: `hover:border-custom-primary-80 hover:bg-custom-primary-10`,
+ pressed: `focus:text-custom-primary-80 focus:bg-custom-primary-10 focus:border-custom-primary-80`,
+ disabled: `cursor-not-allowed !text-custom-primary-60 !border-custom-primary-60 `,
+ },
+ "neutral-primary": {
+ default: `text-custom-text-200 bg-custom-background-100 border border-custom-border-200`,
+ hover: `hover:bg-custom-background-90`,
+ pressed: `focus:text-custom-text-300 focus:bg-custom-background-90`,
+ disabled: `cursor-not-allowed !text-custom-text-400`,
+ },
+ "link-primary": {
+ default: `text-custom-primary-100 bg-custom-background-100`,
+ hover: `hover:text-custom-primary-200`,
+ pressed: `focus:text-custom-primary-80 `,
+ disabled: `cursor-not-allowed !text-custom-primary-60`,
+ },
+
+ danger: {
+ default: `text-white bg-red-500`,
+ hover: ` hover:bg-red-600`,
+ pressed: `focus:text-red-200 focus:bg-red-600`,
+ disabled: `cursor-not-allowed !bg-red-300`,
+ },
+ "accent-danger": {
+ default: `text-red-500 bg-red-50`,
+ hover: `hover:text-red-600 hover:bg-red-100`,
+ pressed: `focus:text-red-500 focus:bg-red-100`,
+ disabled: `cursor-not-allowed !text-red-300`,
+ },
+ "outline-danger": {
+ default: `text-red-500 bg-custom-background-100 border border-red-500`,
+ hover: `hover:text-red-400 hover:border-red-400`,
+ pressed: `focus:text-red-400 focus:border-red-400`,
+ disabled: `cursor-not-allowed !text-red-300 !border-red-300`,
+ },
+ "link-danger": {
+ default: `text-red-500 bg-custom-background-100`,
+ hover: `hover:text-red-400`,
+ pressed: `focus:text-red-400`,
+ disabled: `cursor-not-allowed !text-red-300`,
+ },
+ "tertiary-danger": {
+ default: `text-red-500 bg-custom-background-100 border border-red-200`,
+ hover: `hover:bg-red-50 hover:border-red-300`,
+ pressed: `focus:text-red-400`,
+ disabled: `cursor-not-allowed !text-red-300`,
+ },
+};
+
+export const getButtonStyling = (
+ variant: TButtonVariant,
+ size: TButtonSizes,
+ disabled: boolean = false
+): string => {
+ let _variant: string = ``;
+ const currentVariant = buttonStyling[variant];
+
+ _variant = `${currentVariant.default} ${
+ disabled ? currentVariant.disabled : currentVariant.hover
+ } ${currentVariant.pressed}`;
+
+ let _size: string = ``;
+ if (size === "sm") _size = buttonSizeStyling["sm"];
+ if (size === "md") _size = buttonSizeStyling["md"];
+ if (size === "lg") _size = buttonSizeStyling["lg"];
+ return `${_variant} ${_size}`;
+};
+
+export const getIconStyling = (size: TButtonSizes): string => {
+ let icon: string = ``;
+ if (size === "sm") icon = buttonIconStyling["sm"];
+ if (size === "md") icon = buttonIconStyling["md"];
+ if (size === "lg") icon = buttonIconStyling["lg"];
+ return icon;
+};
diff --git a/packages/ui/src/button/index.tsx b/packages/ui/src/button/index.tsx
new file mode 100644
index 00000000000..f1a2d03d4bd
--- /dev/null
+++ b/packages/ui/src/button/index.tsx
@@ -0,0 +1,2 @@
+export * from "./button";
+export * from "./toggle-switch";
diff --git a/packages/ui/src/button/toggle-switch.tsx b/packages/ui/src/button/toggle-switch.tsx
new file mode 100644
index 00000000000..9888dd205f9
--- /dev/null
+++ b/packages/ui/src/button/toggle-switch.tsx
@@ -0,0 +1,49 @@
+import * as React from "react";
+
+import { Switch } from "@headlessui/react";
+
+interface IToggleSwitchProps {
+ value: boolean;
+ onChange: (value: boolean) => void;
+ label?: string;
+ size?: "sm" | "md" | "lg";
+ disabled?: boolean;
+ className?: string;
+}
+
+const ToggleSwitch: React.FC = (props) => {
+ const { value, onChange, label, size = "sm", disabled, className } = props;
+
+ return (
+
+ {label}
+
+
+ );
+};
+
+ToggleSwitch.displayName = "plane-ui-toggle-switch";
+
+export { ToggleSwitch };
diff --git a/packages/ui/src/buttons/index.tsx b/packages/ui/src/buttons/index.tsx
deleted file mode 100644
index de1b0da3186..00000000000
--- a/packages/ui/src/buttons/index.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import * as React from "react";
-
-export const Button = () => {
- return button ;
-};
diff --git a/packages/ui/src/form-fields/input.tsx b/packages/ui/src/form-fields/input.tsx
index 7c93898482f..648b78aa73b 100644
--- a/packages/ui/src/form-fields/input.tsx
+++ b/packages/ui/src/form-fields/input.tsx
@@ -1,32 +1,23 @@
import * as React from "react";
-export interface InputProps {
- type: string;
- id: string;
- value: string;
- name: string;
- onChange: () => void;
- className?: string;
+export interface InputProps
+ extends React.InputHTMLAttributes {
mode?: "primary" | "transparent" | "true-transparent";
- size?: "sm" | "md" | "lg";
+ inputSize?: "sm" | "md";
hasError?: boolean;
- placeholder?: string;
- disabled?: boolean;
+ className?: string;
}
const Input = React.forwardRef((props, ref) => {
const {
id,
type,
- value,
name,
- onChange,
- className = "",
mode = "primary",
- size = "md",
+ inputSize = "sm",
hasError = false,
- placeholder = "",
- disabled = false,
+ className = "",
+ ...rest
} = props;
return (
@@ -34,11 +25,7 @@ const Input = React.forwardRef((props, ref) => {
id={id}
ref={ref}
type={type}
- value={value}
name={name}
- onChange={onChange}
- placeholder={placeholder}
- disabled={disabled}
className={`block rounded-md bg-transparent text-sm focus:outline-none placeholder-custom-text-400 ${
mode === "primary"
? "rounded-md border border-custom-border-200"
@@ -50,8 +37,9 @@ const Input = React.forwardRef((props, ref) => {
} ${hasError ? "border-red-500" : ""} ${
hasError && mode === "primary" ? "bg-red-500/20" : ""
} ${
- size === "sm" ? "px-3 py-2" : size === "lg" ? "p-3" : ""
+ inputSize === "sm" ? "px-3 py-2" : inputSize === "md" ? "p-3" : ""
} ${className}`}
+ {...rest}
/>
);
});
diff --git a/packages/ui/src/form-fields/textarea.tsx b/packages/ui/src/form-fields/textarea.tsx
index e9b748230d2..93a850059f8 100644
--- a/packages/ui/src/form-fields/textarea.tsx
+++ b/packages/ui/src/form-fields/textarea.tsx
@@ -1,14 +1,7 @@
import * as React from "react";
-export interface TextAreaProps {
- id: string;
- name: string;
- placeholder?: string;
- value?: string;
- rows?: number;
- cols?: number;
- disabled?: boolean;
- onChange: () => void;
+export interface TextAreaProps
+ extends React.TextareaHTMLAttributes {
mode?: "primary" | "transparent";
hasError?: boolean;
className?: string;
@@ -37,15 +30,13 @@ const TextArea = React.forwardRef(
const {
id,
name,
- placeholder = "",
value = "",
rows = 1,
cols = 1,
- disabled,
- onChange,
mode = "primary",
hasError = false,
className = "",
+ ...rest
} = props;
const textAreaRef = React.useRef(ref);
@@ -57,12 +48,9 @@ const TextArea = React.forwardRef(
id={id}
name={name}
ref={textAreaRef}
- placeholder={placeholder}
value={value}
rows={rows}
cols={cols}
- disabled={disabled}
- onChange={onChange}
className={`no-scrollbar w-full bg-transparent placeholder-custom-text-400 px-3 py-2 outline-none ${
mode === "primary"
? "rounded-md border border-custom-border-200"
@@ -72,6 +60,7 @@ const TextArea = React.forwardRef(
} ${hasError ? "border-red-500" : ""} ${
hasError && mode === "primary" ? "bg-red-100" : ""
} ${className}`}
+ {...rest}
/>
);
}
diff --git a/packages/ui/src/index.tsx b/packages/ui/src/index.tsx
index 1e80ad867a3..36eb08ef419 100644
--- a/packages/ui/src/index.tsx
+++ b/packages/ui/src/index.tsx
@@ -1,4 +1,5 @@
-export * from "./buttons";
+export * from "./button";
export * from "./form-fields";
export * from "./progress";
export * from "./spinners";
+export * from "./loader";
diff --git a/packages/ui/src/loader.tsx b/packages/ui/src/loader.tsx
new file mode 100644
index 00000000000..cd12bc22f57
--- /dev/null
+++ b/packages/ui/src/loader.tsx
@@ -0,0 +1,30 @@
+import React from "react";
+
+type Props = {
+ children: React.ReactNode;
+ className?: string;
+};
+
+const Loader = ({ children, className = "" }: Props) => (
+
+ {children}
+
+);
+
+type ItemProps = {
+ height?: string;
+ width?: string;
+};
+
+const Item: React.FC = ({ height = "auto", width = "auto" }) => (
+
+);
+
+Loader.Item = Item;
+
+Loader.displayName = "plane-ui-loader";
+
+export { Loader };
diff --git a/packages/ui/src/progress/index.tsx b/packages/ui/src/progress/index.tsx
index caee5259d3a..288a0c1fc46 100644
--- a/packages/ui/src/progress/index.tsx
+++ b/packages/ui/src/progress/index.tsx
@@ -1 +1,2 @@
export * from "./radial-progress";
+export * from "./progress-bar";
diff --git a/packages/ui/src/progress/progress-bar.tsx b/packages/ui/src/progress/progress-bar.tsx
new file mode 100644
index 00000000000..d241e3d5e50
--- /dev/null
+++ b/packages/ui/src/progress/progress-bar.tsx
@@ -0,0 +1,77 @@
+import React from "react";
+
+type Props = {
+ maxValue?: number;
+ value?: number;
+ radius?: number;
+ strokeWidth?: number;
+ activeStrokeColor?: string;
+ inactiveStrokeColor?: string;
+};
+
+export const ProgressBar: React.FC = ({
+ 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 (
+
+ );
+ };
+
+ // combining the Pies
+ const renderOuterCircle = () =>
+ [...Array(maxValue + 1)].map((e, i) => renderPie(i));
+
+ return (
+
+ {renderOuterCircle()}
+
+
+ );
+};
diff --git a/space/components/accounts/email-reset-password-form.tsx b/space/components/accounts/email-reset-password-form.tsx
index c850b305cec..ee71890ecd3 100644
--- a/space/components/accounts/email-reset-password-form.tsx
+++ b/space/components/accounts/email-reset-password-form.tsx
@@ -7,7 +7,8 @@ import userService from "services/user.service";
// hooks
// import useToast from "hooks/use-toast";
// ui
-import { Input, PrimaryButton, SecondaryButton } from "components/ui";
+import { Input } from "components/ui";
+import { Button } from "@plane/ui";
// types
type Props = {
setIsResettingPassword: React.Dispatch>;
@@ -77,12 +78,12 @@ export const EmailResetPasswordForm: React.FC = ({ setIsResettingPassword
{errors.email && {errors.email.message}
}
-
setIsResettingPassword(false)}>
+ setIsResettingPassword(false)}>
Go Back
-
-
+
+
{isSubmitting ? "Sending link..." : "Send reset link"}
-
+
);
diff --git a/web/components/account/email-code-form.tsx b/web/components/account/email-code-form.tsx
index 1e68cbb294a..1a4b1208d89 100644
--- a/web/components/account/email-code-form.tsx
+++ b/web/components/account/email-code-form.tsx
@@ -1,8 +1,7 @@
import React, { useEffect, useState } from "react";
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// ui
-import { CheckCircleIcon } from "@heroicons/react/20/solid";
-import { Input, PrimaryButton, SecondaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// services
import authenticationService from "services/authentication.service";
import useToast from "hooks/use-toast";
@@ -29,6 +28,7 @@ export const EmailCodeForm = ({ handleSignIn }: any) => {
const {
register,
handleSubmit,
+ control,
setError,
setValue,
getValues,
@@ -44,8 +44,7 @@ export const EmailCodeForm = ({ handleSignIn }: any) => {
reValidateMode: "onChange",
});
- const isResendDisabled =
- resendCodeTimer > 0 || isCodeResending || isSubmitting || errorResendingCode;
+ const isResendDisabled = resendCodeTimer > 0 || isCodeResending || isSubmitting || errorResendingCode;
const onSubmit = async ({ email }: EmailCodeFormValues) => {
setErrorResendingCode(false);
@@ -122,44 +121,58 @@ export const EmailCodeForm = ({ handleSignIn }: any) => {
)}
>
diff --git a/web/components/account/email-signup-form.tsx b/web/components/account/email-signup-form.tsx
index 0a219741fb1..76c7e523be3 100644
--- a/web/components/account/email-signup-form.tsx
+++ b/web/components/account/email-signup-form.tsx
@@ -1,8 +1,8 @@
import React from "react";
import Link from "next/link";
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// ui
-import { Input, PrimaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// types
type EmailPasswordFormValues = {
email: string;
@@ -21,6 +21,7 @@ export const EmailSignUpForm: React.FC = (props) => {
const {
register,
handleSubmit,
+ control,
watch,
formState: { errors, isSubmitting, isValid, isDirty },
} = useForm({
@@ -36,49 +37,60 @@ export const EmailSignUpForm: React.FC = (props) => {
return (
<>
-
>
diff --git a/web/components/analytics/custom-analytics/create-update-analytics-modal.tsx b/web/components/analytics/custom-analytics/create-update-analytics-modal.tsx
index 66917ed7c80..508f5722ec0 100644
--- a/web/components/analytics/custom-analytics/create-update-analytics-modal.tsx
+++ b/web/components/analytics/custom-analytics/create-update-analytics-modal.tsx
@@ -3,7 +3,7 @@ import React from "react";
import { useRouter } from "next/router";
// react-hook-form
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
@@ -11,7 +11,7 @@ import analyticsService from "services/analytics.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
+import { Button, Input, TextArea } from "@plane/ui";
// types
import { IAnalyticsParams, ISaveAnalyticsFormData } from "types";
@@ -39,9 +39,9 @@ export const CreateUpdateAnalyticsModal: React.FC = ({ isOpen, handleClos
const { setToastAlert } = useToast();
const {
- register,
formState: { errors, isSubmitting },
handleSubmit,
+ control,
reset,
} = useForm({
defaultValues,
@@ -114,41 +114,54 @@ export const CreateUpdateAnalyticsModal: React.FC = ({ isOpen, handleClos
diff --git a/web/components/analytics/custom-analytics/custom-analytics.tsx b/web/components/analytics/custom-analytics/custom-analytics.tsx
index 3152596c8e0..9d84573ae8e 100644
--- a/web/components/analytics/custom-analytics/custom-analytics.tsx
+++ b/web/components/analytics/custom-analytics/custom-analytics.tsx
@@ -6,7 +6,7 @@ import useProjects from "hooks/use-projects";
// components
import { AnalyticsGraph, AnalyticsSelectBar, AnalyticsSidebar, AnalyticsTable } from "components/analytics";
// ui
-import { Loader, PrimaryButton } from "components/ui";
+import { Button, Loader } from "@plane/ui";
// helpers
import { convertResponseToBarGraphData } from "helpers/analytics.helper";
// types
@@ -100,7 +100,8 @@ export const CustomAnalytics: React.FC = ({ fullScreen, user }) => {
There was some error in fetching the data.
-
{
if (!workspaceSlug) return;
@@ -108,7 +109,7 @@ export const CustomAnalytics: React.FC = ({ fullScreen, user }) => {
}}
>
Refresh
-
+
diff --git a/web/components/analytics/custom-analytics/sidebar.tsx b/web/components/analytics/custom-analytics/sidebar.tsx
index 787fa79bde9..e39f726cd62 100644
--- a/web/components/analytics/custom-analytics/sidebar.tsx
+++ b/web/components/analytics/custom-analytics/sidebar.tsx
@@ -12,7 +12,7 @@ import trackEventServices from "services/track_event.service";
import useProjects from "hooks/use-projects";
import useToast from "hooks/use-toast";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { ArrowDownTrayIcon, ArrowPathIcon, CalendarDaysIcon, UserGroupIcon } from "@heroicons/react/24/outline";
import { ContrastIcon, LayerDiagonalIcon } from "components/icons";
@@ -328,24 +328,19 @@ export const AnalyticsSidebar: React.FC = ({ analytics, params, fullScree
) : null}
-
}
onClick={() => {
if (!workspaceSlug) return;
-
mutate(ANALYTICS(workspaceSlug.toString(), params));
}}
>
-
-
-
-
-
+ Refresh
+
+
} onClick={exportAnalytics}>
+ Export as CSV
+
);
diff --git a/web/components/analytics/scope-and-demand/scope-and-demand.tsx b/web/components/analytics/scope-and-demand/scope-and-demand.tsx
index dc7e6551589..aef15880f9d 100644
--- a/web/components/analytics/scope-and-demand/scope-and-demand.tsx
+++ b/web/components/analytics/scope-and-demand/scope-and-demand.tsx
@@ -5,14 +5,9 @@ import useSWR from "swr";
// services
import analyticsService from "services/analytics.service";
// components
-import {
- AnalyticsDemand,
- AnalyticsLeaderboard,
- AnalyticsScope,
- AnalyticsYearWiseIssues,
-} from "components/analytics";
+import { AnalyticsDemand, AnalyticsLeaderboard, AnalyticsScope, AnalyticsYearWiseIssues } from "components/analytics";
// ui
-import { Loader, PrimaryButton } from "components/ui";
+import { Button, Loader } from "@plane/ui";
// fetch-keys
import { DEFAULT_ANALYTICS } from "constants/fetch-keys";
@@ -40,9 +35,7 @@ export const ScopeAndDemand: React.FC = ({ fullScreen = true }) => {
mutate: mutateDefaultAnalytics,
} = useSWR(
workspaceSlug ? DEFAULT_ANALYTICS(workspaceSlug.toString(), params) : null,
- workspaceSlug
- ? () => analyticsService.getDefaultAnalytics(workspaceSlug.toString(), params)
- : null
+ workspaceSlug ? () => analyticsService.getDefaultAnalytics(workspaceSlug.toString(), params) : null
);
return (
@@ -97,7 +90,9 @@ export const ScopeAndDemand: React.FC = ({ fullScreen = true }) => {
There was some error in fetching the data.
-
mutateDefaultAnalytics()}>Refresh
+
mutateDefaultAnalytics()}>
+ Refresh
+
diff --git a/web/components/auth-screens/project/join-project.tsx b/web/components/auth-screens/project/join-project.tsx
index 73b824b639d..7e2c8cebd5a 100644
--- a/web/components/auth-screens/project/join-project.tsx
+++ b/web/components/auth-screens/project/join-project.tsx
@@ -8,7 +8,7 @@ import { mutate } from "swr";
// services
import projectService from "services/project.service";
// ui
-import { PrimaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { AssignmentClipboardIcon } from "components/icons";
// images
@@ -45,25 +45,22 @@ export const JoinProject: React.FC = () => {
-
- You are not a member of this project
-
+ You are not a member of this project
- You are not a member of this project, but you can join this project by clicking the button
- below.
+ You are not a member of this project, but you can join this project by clicking the button below.
-
}
loading={isJoiningProject}
onClick={handleJoin}
>
-
{isJoiningProject ? "Joining..." : "Click to join"}
-
+
);
diff --git a/web/components/auth-screens/workspace/not-a-member.tsx b/web/components/auth-screens/workspace/not-a-member.tsx
index ee63b58831f..6737115a0f7 100644
--- a/web/components/auth-screens/workspace/not-a-member.tsx
+++ b/web/components/auth-screens/workspace/not-a-member.tsx
@@ -3,7 +3,7 @@ import Link from "next/link";
// layouts
import DefaultLayout from "layouts/default-layout";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
export const NotAWorkspaceMember = () => (
@@ -12,19 +12,19 @@ export const NotAWorkspaceMember = () => (
Not Authorized!
- You{"'"}re not a member of this workspace. Please contact the workspace admin to get an
- invitation or check your pending invitations.
+ You{"'"}re not a member of this workspace. Please contact the workspace admin to get an invitation or check
+ your pending invitations.
diff --git a/web/components/automation/auto-archive-automation.tsx b/web/components/automation/auto-archive-automation.tsx
index d0c9a1be6bf..563381e695e 100644
--- a/web/components/automation/auto-archive-automation.tsx
+++ b/web/components/automation/auto-archive-automation.tsx
@@ -1,7 +1,8 @@
import React, { useState } from "react";
// component
-import { CustomSelect, ToggleSwitch } from "components/ui";
+import { CustomSelect } from "components/ui";
+import { ToggleSwitch } from "@plane/ui";
import { SelectMonthModal } from "components/automation";
// icon
import { ArchiveRestore } from "lucide-react";
@@ -16,11 +17,7 @@ type Props = {
disabled?: boolean;
};
-export const AutoArchiveAutomation: React.FC = ({
- projectDetails,
- handleChange,
- disabled = false,
-}) => {
+export const AutoArchiveAutomation: React.FC = ({ projectDetails, handleChange, disabled = false }) => {
const [monthModal, setmonthModal] = useState(false);
const initialValues: Partial = { archive_in: 1 };
@@ -49,9 +46,7 @@ export const AutoArchiveAutomation: React.FC = ({
- projectDetails?.archive_in === 0
- ? handleChange({ archive_in: 1 })
- : handleChange({ archive_in: 0 })
+ projectDetails?.archive_in === 0 ? handleChange({ archive_in: 1 }) : handleChange({ archive_in: 0 })
}
size="sm"
disabled={disabled}
@@ -61,15 +56,11 @@ export const AutoArchiveAutomation: React.FC = ({
{projectDetails?.archive_in !== 0 && (
-
- Auto-archive issues that are closed for
-
+
Auto-archive issues that are closed for
{
handleChange({ archive_in: val });
}}
diff --git a/web/components/automation/auto-close-automation.tsx b/web/components/automation/auto-close-automation.tsx
index 664967d0faf..30beed9da50 100644
--- a/web/components/automation/auto-close-automation.tsx
+++ b/web/components/automation/auto-close-automation.tsx
@@ -5,8 +5,9 @@ import useSWR from "swr";
import { useRouter } from "next/router";
// component
-import { CustomSearchSelect, CustomSelect, Icon, ToggleSwitch } from "components/ui";
+import { CustomSearchSelect, CustomSelect, Icon } from "components/ui";
import { SelectMonthModal } from "components/automation";
+import { ToggleSwitch } from "@plane/ui";
// icons
import { Squares2X2Icon } from "@heroicons/react/24/outline";
import { StateGroupIcon } from "components/icons";
@@ -27,11 +28,7 @@ type Props = {
disabled?: boolean;
};
-export const AutoCloseAutomation: React.FC = ({
- projectDetails,
- handleChange,
- disabled = false,
-}) => {
+export const AutoCloseAutomation: React.FC = ({ projectDetails, handleChange, disabled = false }) => {
const [monthModal, setmonthModal] = useState(false);
const router = useRouter();
diff --git a/web/components/automation/select-month-modal.tsx b/web/components/automation/select-month-modal.tsx
index 18239d62b4f..0fc42361a44 100644
--- a/web/components/automation/select-month-modal.tsx
+++ b/web/components/automation/select-month-modal.tsx
@@ -3,11 +3,11 @@ import React from "react";
import { useRouter } from "next/router";
// react-hook-form
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// ui
-import { Input, PrimaryButton, SecondaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// types
import type { IProject } from "types";
@@ -20,13 +20,7 @@ type Props = {
handleChange: (formData: Partial) => Promise;
};
-export const SelectMonthModal: React.FC = ({
- type,
- initialValues,
- isOpen,
- handleClose,
- handleChange,
-}) => {
+export const SelectMonthModal: React.FC = ({ type, initialValues, isOpen, handleClose, handleChange }) => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
@@ -34,6 +28,7 @@ export const SelectMonthModal: React.FC = ({
register,
formState: { errors, isSubmitting },
handleSubmit,
+ control,
reset,
} = useForm({
defaultValues: initialValues,
@@ -50,27 +45,6 @@ export const SelectMonthModal: React.FC = ({
onClose();
};
- const inputSection = (name: string) => (
-
-
- Months
-
- );
-
return (
@@ -100,30 +74,72 @@ export const SelectMonthModal: React.FC = ({
-
+
Customise Time Range
-
Cancel
-
+
+ Cancel
+
+
{isSubmitting ? "Submitting..." : "Submit"}
-
+
diff --git a/web/components/command-palette/command-k.tsx b/web/components/command-palette/command-k.tsx
index d51d269cd09..04c42f8cf68 100644
--- a/web/components/command-palette/command-k.tsx
+++ b/web/components/command-palette/command-k.tsx
@@ -26,7 +26,8 @@ import {
commandGroups,
} from "components/command-palette";
// ui
-import { Icon, Loader, ToggleSwitch, Tooltip } from "components/ui";
+import { Icon, Tooltip } from "components/ui";
+import { Loader, ToggleSwitch } from "@plane/ui";
// icons
import { DiscordIcon, GithubIcon, SettingIcon } from "components/icons";
import { InboxIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
diff --git a/web/components/command-palette/issue/change-issue-state.tsx b/web/components/command-palette/issue/change-issue-state.tsx
index 3cc16c2365b..50e396da31d 100644
--- a/web/components/command-palette/issue/change-issue-state.tsx
+++ b/web/components/command-palette/issue/change-issue-state.tsx
@@ -10,7 +10,7 @@ import { Command } from "cmdk";
import issuesService from "services/issue.service";
import stateService from "services/project_state.service";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
// icons
import { CheckIcon, StateGroupIcon } from "components/icons";
// helpers
diff --git a/web/components/command-palette/shortcuts-modal.tsx b/web/components/command-palette/shortcuts-modal.tsx
index 82f9b398c2f..44f3d54429e 100644
--- a/web/components/command-palette/shortcuts-modal.tsx
+++ b/web/components/command-palette/shortcuts-modal.tsx
@@ -6,7 +6,7 @@ import { XMarkIcon } from "@heroicons/react/20/solid";
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { CommandIcon } from "components/icons";
// ui
-import { Input } from "components/ui";
+import { Input } from "@plane/ui";
type Props = {
isOpen: boolean;
@@ -48,9 +48,7 @@ const allShortcuts = shortcuts.map((i) => i.shortcuts).flat(1);
export const ShortcutsModal: React.FC = ({ isOpen, setIsOpen }) => {
const [query, setQuery] = useState("");
const filteredShortcuts = allShortcuts.filter((shortcut) =>
- shortcut.description.toLowerCase().includes(query.trim().toLowerCase()) || query === ""
- ? true
- : false
+ shortcut.description.toLowerCase().includes(query.trim().toLowerCase()) || query === "" ? true : false
);
useEffect(() => {
@@ -105,12 +103,13 @@ export const ShortcutsModal: React.FC = ({ isOpen, setIsOpen }) => {
setQuery(e.target.value)}
+ placeholder="Search for shortcuts"
+ className="w-full border-none bg-transparent py-1 px-2 text-xs text-custom-text-200 focus:outline-none"
/>
@@ -121,9 +120,7 @@ export const ShortcutsModal: React.FC = ({ isOpen, setIsOpen }) => {
-
- {shortcut.description}
-
+
{shortcut.description}
{shortcut.keys.split(",").map((key, index) => (
diff --git a/web/components/common/product-updates-modal.tsx b/web/components/common/product-updates-modal.tsx
index 4f5bad7b3f1..2c88419ddd7 100644
--- a/web/components/common/product-updates-modal.tsx
+++ b/web/components/common/product-updates-modal.tsx
@@ -7,7 +7,8 @@ import { Dialog, Transition } from "@headlessui/react";
// services
import workspaceService from "services/workspace.service";
// components
-import { Loader, MarkdownRenderer } from "components/ui";
+import { MarkdownRenderer } from "components/ui";
+import { Loader } from "@plane/ui";
// icons
import { XMarkIcon } from "@heroicons/react/20/solid";
// helpers
@@ -48,10 +49,7 @@ export const ProductUpdatesModal: React.FC = ({ isOpen, setIsOpen }) => {
>
-
+
Product Updates
setIsOpen(false)}>
diff --git a/web/components/core/filters/date-filter-modal.tsx b/web/components/core/filters/date-filter-modal.tsx
index 4a1ec0e8b98..a94dd809ee1 100644
--- a/web/components/core/filters/date-filter-modal.tsx
+++ b/web/components/core/filters/date-filter-modal.tsx
@@ -6,7 +6,7 @@ import { Dialog, Transition } from "@headlessui/react";
// components
import { DateFilterSelect } from "./date-filter-select";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { XMarkIcon } from "@heroicons/react/20/solid";
// helpers
@@ -127,12 +127,12 @@ export const DateFilterModal: React.FC = ({ title, handleClose, isOpen, o
)}
-
+
Cancel
-
-
+
+
Apply
-
+
diff --git a/web/components/core/filters/issues-view-filter.tsx b/web/components/core/filters/issues-view-filter.tsx
index 79fa9c98439..a190ebfda33 100644
--- a/web/components/core/filters/issues-view-filter.tsx
+++ b/web/components/core/filters/issues-view-filter.tsx
@@ -11,7 +11,8 @@ import useEstimateOption from "hooks/use-estimate-option";
// components
import { SelectFilters } from "components/views";
// ui
-import { CustomMenu, ToggleSwitch, Tooltip } from "components/ui";
+import { CustomMenu, Tooltip } from "components/ui";
+import { ToggleSwitch } from "@plane/ui";
// icons
import { ChevronDownIcon } from "@heroicons/react/24/outline";
import {
diff --git a/web/components/core/image-picker-popover.tsx b/web/components/core/image-picker-popover.tsx
index cfe18cd97d9..7ab0ec6bfbc 100644
--- a/web/components/core/image-picker-popover.tsx
+++ b/web/components/core/image-picker-popover.tsx
@@ -5,13 +5,15 @@ import useSWR from "swr";
import { useDropzone } from "react-dropzone";
import { Tab, Transition, Popover } from "@headlessui/react";
+import { Control, Controller } from "react-hook-form";
+
// services
import fileService from "services/file.service";
// hooks
import useWorkspaceDetails from "hooks/use-workspace-details";
import useOutsideClickDetector from "hooks/use-outside-click-detector";
// components
-import { Input, PrimaryButton, SecondaryButton, Loader } from "components/ui";
+import { Button, Input, Loader } from "@plane/ui";
const tabOptions = [
{
@@ -31,16 +33,12 @@ const tabOptions = [
type Props = {
label: string | React.ReactNode;
value: string | null;
+ control: Control;
onChange: (data: string) => void;
disabled?: boolean;
};
-export const ImagePickerPopover: React.FC = ({
- label,
- value,
- onChange,
- disabled = false,
-}) => {
+export const ImagePickerPopover: React.FC = ({ label, value, control, onChange, disabled = false }) => {
const ref = useRef(null);
const router = useRouter();
@@ -64,14 +62,10 @@ export const ImagePickerPopover: React.FC = ({
}
);
- const { data: projectCoverImages } = useSWR(
- `PROJECT_COVER_IMAGES`,
- () => fileService.getProjectCoverImages(),
- {
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- }
- );
+ const { data: projectCoverImages } = useSWR(`PROJECT_COVER_IMAGES`, () => fileService.getProjectCoverImages(), {
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ });
const imagePickerRef = useRef(null);
@@ -154,8 +148,7 @@ export const ImagePickerPopover: React.FC = ({
{tabOptions.map((tab) => {
if (!unsplashImages && unsplashError && tab.key === "unsplash") return null;
- if (projectCoverImages && projectCoverImages.length === 0 && tab.key === "images")
- return null;
+ if (projectCoverImages && projectCoverImages.length === 0 && tab.key === "images") return null;
return (
= ({
{(unsplashImages || !unsplashError) && (
{unsplashImages ? (
unsplashImages.length > 0 ? (
@@ -208,9 +209,7 @@ export const ImagePickerPopover: React.FC = ({
))}
) : (
-
- No images found.
-
+ No images found.
)
) : (
@@ -249,9 +248,7 @@ export const ImagePickerPopover: React.FC = ({
))}
) : (
-
- No images found.
-
+
No images found.
)
) : (
@@ -297,9 +294,7 @@ export const ImagePickerPopover: React.FC = ({
) : (
- {isDragActive
- ? "Drop image here to upload"
- : "Drag & drop image here"}
+ {isDragActive ? "Drop image here to upload" : "Drag & drop image here"}
)}
@@ -320,23 +315,24 @@ export const ImagePickerPopover: React.FC = ({
-
{
setIsOpen(false);
setImage(null);
}}
>
Cancel
-
-
+
{isImageUploading ? "Uploading..." : "Upload & Save"}
-
+
diff --git a/web/components/core/modals/bulk-delete-issues-modal.tsx b/web/components/core/modals/bulk-delete-issues-modal.tsx
index 964b47d48af..7ecbb3a13b0 100644
--- a/web/components/core/modals/bulk-delete-issues-modal.tsx
+++ b/web/components/core/modals/bulk-delete-issues-modal.tsx
@@ -14,7 +14,7 @@ import issuesServices from "services/issue.service";
import useToast from "hooks/use-toast";
import useIssuesView from "hooks/use-issues-view";
// ui
-import { DangerButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { LayerDiagonalIcon } from "components/icons";
@@ -240,10 +240,12 @@ export const BulkDeleteIssuesModal: React.FC
= ({ isOpen, setIsOpen, user
{filteredIssues.length > 0 && (
- Cancel
-
+
+ Cancel
+
+
{isSubmitting ? "Deleting..." : "Delete selected issues"}
-
+
)}
diff --git a/web/components/core/modals/existing-issues-list-modal.tsx b/web/components/core/modals/existing-issues-list-modal.tsx
index ed3902a4a64..ea66eaa54f6 100644
--- a/web/components/core/modals/existing-issues-list-modal.tsx
+++ b/web/components/core/modals/existing-issues-list-modal.tsx
@@ -13,7 +13,8 @@ import useToast from "hooks/use-toast";
import useIssuesView from "hooks/use-issues-view";
import useDebounce from "hooks/use-debounce";
// ui
-import { Loader, PrimaryButton, SecondaryButton, ToggleSwitch, Tooltip } from "components/ui";
+import { Button, Loader, ToggleSwitch } from "@plane/ui";
+import { Tooltip } from "components/ui";
// icons
import { LaunchOutlined } from "@mui/icons-material";
import { MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/24/outline";
@@ -117,12 +118,7 @@ export const ExistingIssuesListModal: React.FC = ({
return (
<>
- setSearchTerm("")}
- appear
- >
+ setSearchTerm("")} appear>
= ({
- setSelectedIssues((prevData) =>
- prevData.filter((i) => i.id !== issue.id)
- )
- }
+ onClick={() => setSelectedIssues((prevData) => prevData.filter((i) => i.id !== issue.id))}
>
@@ -232,21 +224,15 @@ export const ExistingIssuesListModal: React.FC = ({
)}
- {!isSearching &&
- issues.length === 0 &&
- searchTerm !== "" &&
- debouncedSearchTerm !== "" && (
-
-
-
- No issues found. Create a new issue with{" "}
-
- C
-
- .
-
-
- )}
+ {!isSearching && issues.length === 0 && searchTerm !== "" && debouncedSearchTerm !== "" && (
+
+
+
+ No issues found. Create a new issue with{" "}
+ C .
+
+
+ )}
{isSearching ? (
@@ -256,9 +242,7 @@ export const ExistingIssuesListModal: React.FC = ({
) : (
- 0 ? "p-2" : ""}`}
- >
+ 0 ? "p-2" : ""}`}>
{issues.map((issue) => {
const selected = selectedIssues.some((i) => i.id === issue.id);
@@ -309,10 +293,12 @@ export const ExistingIssuesListModal: React.FC = ({
{selectedIssues.length > 0 && (
-
Cancel
-
+
+ Cancel
+
+
{isSubmitting ? "Adding..." : "Add selected issues"}
-
+
)}
diff --git a/web/components/core/modals/gpt-assistant-modal.tsx b/web/components/core/modals/gpt-assistant-modal.tsx
index fd2de641ff6..c48c72796db 100644
--- a/web/components/core/modals/gpt-assistant-modal.tsx
+++ b/web/components/core/modals/gpt-assistant-modal.tsx
@@ -1,7 +1,7 @@
import React, { useEffect, useState, forwardRef, useRef } from "react";
import { useRouter } from "next/router";
// react-hook-form
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// services
import aiService from "services/ai.service";
import trackEventServices from "services/track_event.service";
@@ -9,8 +9,8 @@ import trackEventServices from "services/track_event.service";
import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// ui
-import { Input, PrimaryButton, SecondaryButton } from "components/ui";
import { TipTapEditor } from "components/tiptap";
+import { Button, Input } from "@plane/ui";
// types
import { IIssue, IPageBlock } from "types";
@@ -56,6 +56,7 @@ export const GptAssistantModal: React.FC = ({
const {
handleSubmit,
+ control,
register,
reset,
setFocus,
@@ -167,18 +168,28 @@ export const GptAssistantModal: React.FC = ({
No response could be generated. This may be due to insufficient content or task information. Please try again.
)}
-
(
+
+ )}
/>
{response !== "" && (
-
{
onResponse(response);
onClose();
@@ -187,13 +198,15 @@ export const GptAssistantModal: React.FC = ({
}}
>
Use this response
-
+
)}
-
Close
-
+
+ Close
+
+
{isSubmitting ? "Generating response..." : response === "" ? "Generate response" : "Generate again"}
-
+
diff --git a/web/components/core/modals/image-upload-modal.tsx b/web/components/core/modals/image-upload-modal.tsx
index df4f21e12b7..eb299af3cff 100644
--- a/web/components/core/modals/image-upload-modal.tsx
+++ b/web/components/core/modals/image-upload-modal.tsx
@@ -11,7 +11,7 @@ import fileServices from "services/file.service";
// hooks
import useWorkspaceDetails from "hooks/use-workspace-details";
// ui
-import { DangerButton, PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { UserCircleIcon } from "components/icons";
@@ -127,10 +127,7 @@ export const ImageUploadModal: React.FC = ({
>
-
+
Upload Image
@@ -161,9 +158,7 @@ export const ImageUploadModal: React.FC
= ({
- {isDragActive
- ? "Drop image here to upload"
- : "Drag & drop image here"}
+ {isDragActive ? "Drop image here to upload" : "Drag & drop image here"}
)}
@@ -185,19 +180,17 @@ export const ImageUploadModal: React.FC = ({
-
+
{isRemoving ? "Removing..." : "Remove"}
-
+
-
Cancel
-
+
+ Cancel
+
+
{isImageUploading ? "Uploading..." : "Upload & Save"}
-
+
diff --git a/web/components/core/modals/link-modal.tsx b/web/components/core/modals/link-modal.tsx
index bed74fca0d7..2e8531bd678 100644
--- a/web/components/core/modals/link-modal.tsx
+++ b/web/components/core/modals/link-modal.tsx
@@ -1,11 +1,11 @@
import React, { useEffect } from "react";
// react-hook-form
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// ui
-import { Input, PrimaryButton, SecondaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// types
import type { IIssueLink, linkDetails, ModuleLink } from "types";
@@ -23,18 +23,12 @@ const defaultValues: IIssueLink | ModuleLink = {
url: "",
};
-export const LinkModal: React.FC = ({
- isOpen,
- handleClose,
- createIssueLink,
- updateIssueLink,
- status,
- data,
-}) => {
+export const LinkModal: React.FC = ({ isOpen, handleClose, createIssueLink, updateIssueLink, status, data }) => {
const {
register,
formState: { errors, isSubmitting },
handleSubmit,
+ control,
reset,
} = useForm({
defaultValues,
@@ -99,46 +93,65 @@ export const LinkModal: React.FC = ({
-
+
{status ? "Update Link" : "Add Link"}
-
Cancel
-
+
+ Cancel
+
+
{status
? isSubmitting
? "Updating Link..."
@@ -146,7 +159,7 @@ export const LinkModal: React.FC = ({
: isSubmitting
? "Adding Link..."
: "Add Link"}
-
+
diff --git a/web/components/core/sidebar/single-progress-stats.tsx b/web/components/core/sidebar/single-progress-stats.tsx
index 1498c9badb9..3ff214b5713 100644
--- a/web/components/core/sidebar/single-progress-stats.tsx
+++ b/web/components/core/sidebar/single-progress-stats.tsx
@@ -1,6 +1,6 @@
import React from "react";
-import { ProgressBar } from "components/ui";
+import { ProgressBar } from "@plane/ui";
type TSingleProgressStatsProps = {
title: any;
@@ -30,10 +30,7 @@ export const SingleProgressStats: React.FC = ({
- {isNaN(Math.floor((completed / total) * 100))
- ? "0"
- : Math.floor((completed / total) * 100)}
- %
+ {isNaN(Math.floor((completed / total) * 100)) ? "0" : Math.floor((completed / total) * 100)}%
of {total}
diff --git a/web/components/core/theme/color-picker-input.tsx b/web/components/core/theme/color-picker-input.tsx
index 73d71e46bd2..a34aa05cbdf 100644
--- a/web/components/core/theme/color-picker-input.tsx
+++ b/web/components/core/theme/color-picker-input.tsx
@@ -2,6 +2,8 @@ import React from "react";
// react-form
import {
+ Control,
+ Controller,
FieldError,
FieldErrorsImpl,
Merge,
@@ -13,7 +15,7 @@ import {
import { ColorResult, SketchPicker } from "react-color";
// component
import { Popover, Transition } from "@headlessui/react";
-import { Input } from "components/ui";
+import { Input } from "@plane/ui";
// icons
import { ColorPickerIcon } from "components/icons";
// types
@@ -24,6 +26,7 @@ type Props = {
position?: "left" | "right";
watch: UseFormWatch;
setValue: UseFormSetValue;
+ control: Control;
error: FieldError | Merge> | undefined;
register: UseFormRegister;
};
@@ -34,6 +37,7 @@ export const ColorPickerInput: React.FC = ({
watch,
setValue,
error,
+ control,
register,
}) => {
const handleColorChange = (newColor: ColorResult) => {
@@ -60,22 +64,28 @@ export const ColorPickerInput: React.FC = ({
return (
-
(
+
+ )}
/>
@@ -95,11 +105,7 @@ export const ColorPickerInput: React.FC = ({
}}
/>
) : (
-
+
)}
diff --git a/web/components/core/theme/custom-theme-selector.tsx b/web/components/core/theme/custom-theme-selector.tsx
index 27817c82aa1..b94232c8165 100644
--- a/web/components/core/theme/custom-theme-selector.tsx
+++ b/web/components/core/theme/custom-theme-selector.tsx
@@ -5,8 +5,8 @@ import { useTheme } from "next-themes";
import { useForm } from "react-hook-form";
// ui
-import { PrimaryButton } from "components/ui";
import { ColorPickerInput } from "components/core";
+import { Button } from "@plane/ui";
// types
import { ICustomTheme } from "types";
// mobx react lite
@@ -38,6 +38,7 @@ export const CustomThemeSelector: React.FC = observer(({ preLoadedData })
register,
formState: { errors, isSubmitting },
handleSubmit,
+ control,
watch,
setValue,
reset,
@@ -78,12 +79,11 @@ export const CustomThemeSelector: React.FC = observer(({ preLoadedData })
-
- Background color
-
+ Background color
= observer(({ preLoadedData })
Text color
= observer(({ preLoadedData })
-
- Primary(Theme) color
-
+ Primary(Theme) color
= observer(({ preLoadedData })
-
- Sidebar background color
-
+ Sidebar background color
= observer(({ preLoadedData })
-
- Sidebar text color
-
+ Sidebar text color
= observer(({ preLoadedData })
-
+
{isSubmitting ? "Creating Theme..." : "Set Theme"}
-
+
);
diff --git a/web/components/core/views/calendar-view/calendar-header.tsx b/web/components/core/views/calendar-view/calendar-header.tsx
index fd69ed44315..931bd3b49a8 100644
--- a/web/components/core/views/calendar-view/calendar-header.tsx
+++ b/web/components/core/views/calendar-view/calendar-header.tsx
@@ -3,17 +3,12 @@ import React from "react";
// headless ui
import { Popover, Transition } from "@headlessui/react";
// ui
-import { CustomMenu, ToggleSwitch } from "components/ui";
+import { CustomMenu } from "components/ui";
+import { ToggleSwitch } from "@plane/ui";
// icons
import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/24/outline";
// helpers
-import {
- formatDate,
- isSameMonth,
- isSameYear,
- updateDateWithMonth,
- updateDateWithYear,
-} from "helpers/calendar.helper";
+import { formatDate, isSameMonth, isSameYear, updateDateWithMonth, updateDateWithYear } from "helpers/calendar.helper";
// constants
import { MONTHS_LIST, YEARS_LIST } from "constants/calendar";
@@ -24,12 +19,7 @@ type Props = {
setShowWeekEnds: React.Dispatch
>;
};
-export const CalendarHeader: React.FC = ({
- currentDate,
- setCurrentDate,
- showWeekEnds,
- setShowWeekEnds,
-}) => (
+export const CalendarHeader: React.FC = ({ currentDate, setCurrentDate, showWeekEnds, setShowWeekEnds }) => (
@@ -37,8 +27,7 @@ export const CalendarHeader: React.FC = ({
<>
- {formatDate(currentDate, "Month")} {" "}
- {formatDate(currentDate, "yyyy")}
+ {formatDate(currentDate, "Month")} {formatDate(currentDate, "yyyy")}
@@ -69,13 +58,9 @@ export const CalendarHeader: React.FC = ({
{MONTHS_LIST.map((month) => (
- setCurrentDate(updateDateWithMonth(`${month.value}`, currentDate))
- }
+ onClick={() => setCurrentDate(updateDateWithMonth(`${month.value}`, currentDate))}
className={`px-2 py-2 text-xs text-custom-text-200 hover:font-medium hover:text-custom-text-100 ${
- isSameMonth(`${month.value}`, currentDate)
- ? "font-medium text-custom-text-100"
- : ""
+ isSameMonth(`${month.value}`, currentDate) ? "font-medium text-custom-text-100" : ""
}`}
>
{month.label}
@@ -93,11 +78,8 @@ export const CalendarHeader: React.FC = ({
className="cursor-pointer"
onClick={() => {
const previousMonthYear =
- currentDate.getMonth() === 0
- ? currentDate.getFullYear() - 1
- : currentDate.getFullYear();
- const previousMonthMonth =
- currentDate.getMonth() === 0 ? 11 : currentDate.getMonth() - 1;
+ currentDate.getMonth() === 0 ? currentDate.getFullYear() - 1 : currentDate.getFullYear();
+ const previousMonthMonth = currentDate.getMonth() === 0 ? 11 : currentDate.getMonth() - 1;
const previousMonthFirstDate = new Date(previousMonthYear, previousMonthMonth, 1);
@@ -110,9 +92,7 @@ export const CalendarHeader: React.FC = ({
className="cursor-pointer"
onClick={() => {
const nextMonthYear =
- currentDate.getMonth() === 11
- ? currentDate.getFullYear() + 1
- : currentDate.getFullYear();
+ currentDate.getMonth() === 11 ? currentDate.getFullYear() + 1 : currentDate.getFullYear();
const nextMonthMonth = (currentDate.getMonth() + 1) % 12;
const nextMonthFirstDate = new Date(nextMonthYear, nextMonthMonth, 1);
diff --git a/web/components/core/views/calendar-view/calendar.tsx b/web/components/core/views/calendar-view/calendar.tsx
index 553c7b723f0..6ded660bd61 100644
--- a/web/components/core/views/calendar-view/calendar.tsx
+++ b/web/components/core/views/calendar-view/calendar.tsx
@@ -8,7 +8,7 @@ import issuesService from "services/issue.service";
import { SingleCalendarDate, CalendarHeader } from "components/core";
import { IssuePeekOverview } from "components/issues";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
// helpers
import { renderDateFormat } from "helpers/date-time.helper";
import { startOfWeek, lastDayOfWeek, eachDayOfInterval, weekDayInterval, formatDate } from "helpers/calendar.helper";
diff --git a/web/components/core/views/issues-view.tsx b/web/components/core/views/issues-view.tsx
index 6d28913285c..ff3754cc05b 100644
--- a/web/components/core/views/issues-view.tsx
+++ b/web/components/core/views/issues-view.tsx
@@ -27,7 +27,7 @@ import {
} from "components/issues";
import { CreateUpdateViewModal } from "components/views";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
// helpers
@@ -498,7 +498,9 @@ export const IssuesView: React.FC = ({ openIssuesListModal, disableUserAc
})
}
/>
- }
onClick={() => {
if (viewId) {
setFilters({}, true);
@@ -512,11 +514,9 @@ export const IssuesView: React.FC = ({ openIssuesListModal, disableUserAc
query: filters,
});
}}
- className="flex items-center gap-2 text-sm"
>
- {!viewId && }
{viewId ? "Update" : "Save"} view
-
+
{
}
>
@@ -556,10 +556,9 @@ export const IssuesView: React.FC = ({ openIssuesListModal, disableUserAc
: undefined,
secondaryButton:
cycleId || moduleId ? (
- {})}>
-
+ } onClick={openIssuesListModal ?? (() => {})}>
Add an existing issue
-
+
) : null,
}}
handleOnDragEnd={handleOnDragEnd}
diff --git a/web/components/core/views/spreadsheet-view/spreadsheet-view.tsx b/web/components/core/views/spreadsheet-view/spreadsheet-view.tsx
index 152ede98d05..258026a4b71 100644
--- a/web/components/core/views/spreadsheet-view/spreadsheet-view.tsx
+++ b/web/components/core/views/spreadsheet-view/spreadsheet-view.tsx
@@ -18,8 +18,9 @@ import {
SpreadsheetStateColumn,
SpreadsheetUpdatedOnColumn,
} from "components/core";
-import { CustomMenu, Icon, Spinner } from "components/ui";
+import { CustomMenu, Icon } from "components/ui";
import { IssuePeekOverview } from "components/issues";
+import { Spinner } from "@plane/ui";
// types
import { IIssue, IIssueDisplayFilterOptions, IIssueDisplayProperties, TIssueOrderByOptions } from "types";
// icon
diff --git a/web/components/cycles/active-cycle-details.tsx b/web/components/cycles/active-cycle-details.tsx
index 7816f0edba1..76391984682 100644
--- a/web/components/cycles/active-cycle-details.tsx
+++ b/web/components/cycles/active-cycle-details.tsx
@@ -10,9 +10,10 @@ import cyclesService from "services/cycles.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { LinearProgressIndicator, Loader, Tooltip } from "components/ui";
+import { LinearProgressIndicator, Tooltip } from "components/ui";
import { AssigneesList } from "components/ui/avatar";
import { SingleProgressStats } from "components/core";
+import { Loader } from "@plane/ui";
// components
import ProgressChart from "components/core/sidebar/progress-chart";
import { ActiveCycleProgressStats } from "components/cycles";
@@ -34,11 +35,7 @@ import { StarIcon } from "@heroicons/react/24/outline";
// components
import { ViewIssueLabel } from "components/issues";
// helpers
-import {
- getDateRangeStatus,
- renderShortDateWithYearFormat,
- findHowManyDaysLeft,
-} from "helpers/date-time.helper";
+import { getDateRangeStatus, renderShortDateWithYearFormat, findHowManyDaysLeft } from "helpers/date-time.helper";
import { truncateText } from "helpers/string.helper";
// types
import { ICycle, IIssue } from "types";
@@ -82,24 +79,18 @@ export const ActiveCycleDetails: React.FC = () => {
const { data: currentCycle } = useSWR(
workspaceSlug && projectId ? CURRENT_CYCLE_LIST(projectId as string) : null,
workspaceSlug && projectId
- ? () =>
- cyclesService.getCyclesWithParams(workspaceSlug as string, projectId as string, "current")
+ ? () => cyclesService.getCyclesWithParams(workspaceSlug as string, projectId as string, "current")
: null
);
const cycle = currentCycle ? currentCycle[0] : null;
const { data: issues } = useSWR(
- workspaceSlug && projectId && cycle?.id
- ? CYCLE_ISSUES_WITH_PARAMS(cycle?.id, { priority: "urgent,high" })
- : null,
+ workspaceSlug && projectId && cycle?.id ? CYCLE_ISSUES_WITH_PARAMS(cycle?.id, { priority: "urgent,high" }) : null,
workspaceSlug && projectId && cycle?.id
? () =>
- cyclesService.getCycleIssuesWithParams(
- workspaceSlug as string,
- projectId as string,
- cycle.id,
- { priority: "urgent,high" }
- )
+ cyclesService.getCycleIssuesWithParams(workspaceSlug as string, projectId as string, cycle.id, {
+ priority: "urgent,high",
+ })
: null
) as { data: IIssue[] | undefined };
@@ -115,20 +106,8 @@ export const ActiveCycleDetails: React.FC = () => {
-
-
+
+
{
false
);
- cyclesService
- .removeCycleFromFavorites(workspaceSlug as string, projectId as string, cycle.id)
- .catch(() => {
- setToastAlert({
- type: "error",
- title: "Error!",
- message: "Couldn't remove the cycle from favorites. Please try again.",
- });
+ cyclesService.removeCycleFromFavorites(workspaceSlug as string, projectId as string, cycle.id).catch(() => {
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Couldn't remove the cycle from favorites. Please try again.",
});
+ });
};
const progressIndicatorData = stateGroups.map((group, index) => ({
id: index,
name: group.title,
- value:
- cycle.total_issues > 0
- ? ((cycle[group.key as keyof ICycle] as number) / cycle.total_issues) * 100
- : 0,
+ value: cycle.total_issues > 0 ? ((cycle[group.key as keyof ICycle] as number) / cycle.total_issues) * 100 : 0,
color: group.color,
}));
@@ -270,9 +244,7 @@ export const ActiveCycleDetails: React.FC = () => {
/>
-
- {truncateText(cycle.name, 70)}
-
+ {truncateText(cycle.name, 70)}
@@ -304,9 +276,7 @@ export const ActiveCycleDetails: React.FC = () => {
{cycle.total_issues - cycle.completed_issues > 0 && (
@@ -443,9 +413,7 @@ export const ActiveCycleDetails: React.FC = () => {
issues.map((issue) => (
- router.push(`/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`)
- }
+ onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`)}
className="flex flex-wrap cursor-pointer rounded-md items-center justify-between gap-2 border border-custom-border-200 bg-custom-background-90 px-3 py-1.5"
>
@@ -459,14 +427,8 @@ export const ActiveCycleDetails: React.FC = () => {
-
-
- {truncateText(issue.name, 30)}
-
+
+ {truncateText(issue.name, 30)}
@@ -481,15 +443,9 @@ export const ActiveCycleDetails: React.FC = () => {
- {issue.assignees &&
- issue.assignees.length > 0 &&
- Array.isArray(issue.assignees) ? (
+ {issue.assignees && issue.assignees.length > 0 && Array.isArray(issue.assignees) ? (
) : (
""
@@ -522,17 +478,14 @@ export const ActiveCycleDetails: React.FC = () => {
width:
issues &&
`${
- (issues.filter((issue) => issue?.state_detail?.group === "completed")
- ?.length /
- issues.length) *
+ (issues.filter((issue) => issue?.state_detail?.group === "completed")?.length / issues.length) *
100 ?? 0
}%`,
}}
/>
- {issues?.filter((issue) => issue?.state_detail?.group === "completed")?.length} of{" "}
- {issues?.length}
+ {issues?.filter((issue) => issue?.state_detail?.group === "completed")?.length} of {issues?.length}
)}
@@ -553,10 +506,7 @@ export const ActiveCycleDetails: React.FC = () => {
-
- Pending Issues -{" "}
- {cycle.total_issues - (cycle.completed_issues + cycle.cancelled_issues)}
-
+
Pending Issues - {cycle.total_issues - (cycle.completed_issues + cycle.cancelled_issues)}
diff --git a/web/components/cycles/cycles-list.tsx b/web/components/cycles/cycles-list.tsx
index 923bdc20ab7..ec8a40837ec 100644
--- a/web/components/cycles/cycles-list.tsx
+++ b/web/components/cycles/cycles-list.tsx
@@ -1,6 +1,6 @@
import { FC } from "react";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
// types
import { ICycle } from "types";
import { CyclesListItem } from "./cycles-list-item";
diff --git a/web/components/cycles/cycles-view-legacy.tsx b/web/components/cycles/cycles-view-legacy.tsx
index 5d025e4fdce..da858bf52db 100644
--- a/web/components/cycles/cycles-view-legacy.tsx
+++ b/web/components/cycles/cycles-view-legacy.tsx
@@ -16,7 +16,7 @@ import {
SingleCycleList,
} from "components/cycles";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
// helpers
import { getDateRangeStatus } from "helpers/date-time.helper";
// types
diff --git a/web/components/cycles/cycles-view.tsx b/web/components/cycles/cycles-view.tsx
index 42e0a427213..2404c27da35 100644
--- a/web/components/cycles/cycles-view.tsx
+++ b/web/components/cycles/cycles-view.tsx
@@ -5,7 +5,7 @@ import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { CyclesBoard, CyclesList } from "components/cycles";
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
export interface ICyclesView {
filter: "all" | "current" | "upcoming" | "draft" | "completed" | "incomplete";
diff --git a/web/components/cycles/delete-cycle-modal.tsx b/web/components/cycles/delete-cycle-modal.tsx
index 35b8e118e66..c2e5085b2cb 100644
--- a/web/components/cycles/delete-cycle-modal.tsx
+++ b/web/components/cycles/delete-cycle-modal.tsx
@@ -10,7 +10,7 @@ import cycleService from "services/cycles.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { DangerButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types
@@ -32,12 +32,7 @@ import {
} from "constants/fetch-keys";
import { getDateRangeStatus } from "helpers/date-time.helper";
-export const DeleteCycleModal: React.FC
= ({
- isOpen,
- setIsOpen,
- data,
- user,
-}) => {
+export const DeleteCycleModal: React.FC = ({ isOpen, setIsOpen, data, user }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter();
@@ -144,36 +139,29 @@ export const DeleteCycleModal: React.FC = ({
-
+
-
+
Delete Cycle
Are you sure you want to delete cycle-{" "}
-
- {data?.name}
-
- ? All of the data related to the cycle will be permanently removed. This
- action cannot be undone.
+ {data?.name} ? All of the
+ data related to the cycle will be permanently removed. This action cannot be undone.
- Cancel
-
+
+ Cancel
+
+
{isDeleteLoading ? "Deleting..." : "Delete"}
-
+
diff --git a/web/components/cycles/form.tsx b/web/components/cycles/form.tsx
index acf5dbf5f63..c4188ea00a3 100644
--- a/web/components/cycles/form.tsx
+++ b/web/components/cycles/form.tsx
@@ -1,7 +1,7 @@
import { Controller, useForm } from "react-hook-form";
// ui
-import { Input, TextArea } from "@plane/ui";
-import { DateSelect, PrimaryButton, SecondaryButton } from "components/ui";
+import { Button, Input, TextArea } from "@plane/ui";
+import { DateSelect } from "components/ui";
// types
import { ICycle } from "types";
@@ -114,8 +114,10 @@ export const CycleForm: React.FC = (props) => {
-
Cancel
-
+
+ Cancel
+
+
{data
? isSubmitting
? "Updating Cycle..."
@@ -123,7 +125,7 @@ export const CycleForm: React.FC = (props) => {
: isSubmitting
? "Creating Cycle..."
: "Create Cycle"}
-
+
);
diff --git a/web/components/cycles/sidebar.tsx b/web/components/cycles/sidebar.tsx
index e2ca98d3f86..aa52aa27fa3 100644
--- a/web/components/cycles/sidebar.tsx
+++ b/web/components/cycles/sidebar.tsx
@@ -17,7 +17,8 @@ import { SidebarProgressStats } from "components/core";
import ProgressChart from "components/core/sidebar/progress-chart";
import { DeleteCycleModal } from "components/cycles";
// ui
-import { CustomMenu, CustomRangeDatePicker, Loader, ProgressBar } from "components/ui";
+import { CustomMenu, CustomRangeDatePicker } from "components/ui";
+import { Loader, ProgressBar } from "@plane/ui";
// icons
import {
CalendarDaysIcon,
diff --git a/web/components/cycles/transfer-issues.tsx b/web/components/cycles/transfer-issues.tsx
index a49c7665f83..a604bc7e697 100644
--- a/web/components/cycles/transfer-issues.tsx
+++ b/web/components/cycles/transfer-issues.tsx
@@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// component
-import { PrimaryButton, Tooltip } from "components/ui";
+import { Button } from "@plane/ui";
// icon
import { ExclamationIcon, TransferIcon } from "components/icons";
// services
@@ -24,12 +24,7 @@ export const TransferIssues: React.FC
= ({ handleClick }) => {
const { data: cycleDetails } = useSWR(
cycleId ? CYCLE_DETAILS(cycleId as string) : null,
workspaceSlug && projectId && cycleId
- ? () =>
- cycleServices.getCycleDetails(
- workspaceSlug as string,
- projectId as string,
- cycleId as string
- )
+ ? () => cycleServices.getCycleDetails(workspaceSlug as string, projectId as string, cycleId as string)
: null
);
@@ -45,10 +40,9 @@ export const TransferIssues: React.FC = ({ handleClick }) => {
{transferableIssuesCount > 0 && (
-
-
- Transfer Issues
-
+
} onClick={handleClick}>
+ Transfer Issues
+
)}
diff --git a/web/components/estimates/create-update-estimate-modal.tsx b/web/components/estimates/create-update-estimate-modal.tsx
index 1242742d43a..5cf9140d761 100644
--- a/web/components/estimates/create-update-estimate-modal.tsx
+++ b/web/components/estimates/create-update-estimate-modal.tsx
@@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import { mutate } from "swr";
// react-hook-form
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
@@ -13,7 +13,7 @@ import estimatesService from "services/project_estimates.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
+import { Button, Input, TextArea } from "@plane/ui";
// helpers
import { checkDuplicates } from "helpers/array.helper";
// types
@@ -52,9 +52,9 @@ const defaultValues: Partial = {
export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data, isOpen, user }) => {
const {
- register,
- formState: { isSubmitting },
+ formState: { errors, isSubmitting },
handleSubmit,
+ control,
reset,
} = useForm({
defaultValues,
@@ -253,23 +253,39 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data,
{data ? "Update" : "Create"} Estimate
- (
+
+ )}
/>
- (
+
+ )}
/>
@@ -277,14 +293,22 @@ export const CreateUpdateEstimateModal: React.FC
= ({ handleClose, data,
1
- (
+
+ )}
/>
@@ -293,14 +317,22 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data,
2
- (
+
+ )}
/>
@@ -309,14 +341,22 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data,
3
- (
+
+ )}
/>
@@ -325,14 +365,22 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data,
4
- (
+
+ )}
/>
@@ -341,14 +389,22 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data,
5
- (
+
+ )}
/>
@@ -357,14 +413,22 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data,
6
- (
+
+ )}
/>
@@ -372,8 +436,10 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data,
-
Cancel
-
+
+ Cancel
+
+
{data
? isSubmitting
? "Updating Estimate..."
@@ -381,7 +447,7 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data,
: isSubmitting
? "Creating Estimate..."
: "Create Estimate"}
-
+
diff --git a/web/components/estimates/delete-estimate-modal.tsx b/web/components/estimates/delete-estimate-modal.tsx
index b4c08b4214e..ce5eb9db5e3 100644
--- a/web/components/estimates/delete-estimate-modal.tsx
+++ b/web/components/estimates/delete-estimate-modal.tsx
@@ -8,7 +8,7 @@ import { IEstimate } from "types";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
-import { SecondaryButton, DangerButton } from "components/ui";
+import { Button } from "@plane/ui";
type Props = {
isOpen: boolean;
@@ -17,12 +17,7 @@ type Props = {
handleDelete: () => void;
};
-export const DeleteEstimateModal: React.FC = ({
- isOpen,
- handleClose,
- data,
- handleDelete,
-}) => {
+export const DeleteEstimateModal: React.FC = ({ isOpen, handleClose, data, handleDelete }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
useEffect(() => {
@@ -64,10 +59,7 @@ export const DeleteEstimateModal: React.FC = ({
-
+
Delete Estimate
@@ -76,16 +68,17 @@ export const DeleteEstimateModal: React.FC = ({
Are you sure you want to delete estimate-{" "}
-
- {data.name}
-
- {""}? All of the data related to the estiamte will be permanently removed.
- This action cannot be undone.
+ {data.name}
+ {""}? All of the data related to the estiamte will be permanently removed. This action cannot be
+ undone.
-
Cancel
-
+ Cancel
+
+ {
setIsDeleteLoading(true);
handleDelete();
@@ -93,7 +86,7 @@ export const DeleteEstimateModal: React.FC = ({
loading={isDeleteLoading}
>
{isDeleteLoading ? "Deleting..." : "Delete Estimate"}
-
+
diff --git a/web/components/estimates/single-estimate.tsx b/web/components/estimates/single-estimate.tsx
index 43edfcb2c7e..31831078009 100644
--- a/web/components/estimates/single-estimate.tsx
+++ b/web/components/estimates/single-estimate.tsx
@@ -10,7 +10,8 @@ import useProjectDetails from "hooks/use-project-details";
// components
import { DeleteEstimateModal } from "components/estimates";
// ui
-import { CustomMenu, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
+import { CustomMenu } from "components/ui";
//icons
import { PencilIcon, TrashIcon } from "@heroicons/react/24/outline";
// helpers
@@ -25,12 +26,7 @@ type Props = {
handleEstimateDelete: (estimateId: string) => void;
};
-export const SingleEstimate: React.FC
= ({
- user,
- estimate,
- editEstimate,
- handleEstimateDelete,
-}) => {
+export const SingleEstimate: React.FC = ({ user, estimate, editEstimate, handleEstimateDelete }) => {
const [isDeleteEstimateModalOpen, setIsDeleteEstimateModalOpen] = useState(false);
const router = useRouter();
@@ -53,15 +49,13 @@ export const SingleEstimate: React.FC = ({
return { ...prevData, estimate: estimate.id };
}, false);
- await projectService
- .updateProject(workspaceSlug as string, projectId as string, payload, user)
- .catch(() => {
- setToastAlert({
- type: "error",
- title: "Error!",
- message: "Estimate points could not be used. Please try again.",
- });
+ await projectService.updateProject(workspaceSlug as string, projectId as string, payload, user).catch(() => {
+ setToastAlert({
+ type: "error",
+ title: "Error!",
+ message: "Estimate points could not be used. Please try again.",
});
+ });
};
return (
@@ -72,9 +66,7 @@ export const SingleEstimate: React.FC = ({
{estimate.name}
{projectDetails?.estimate && projectDetails?.estimate === estimate.id && (
-
- In use
-
+ In use
)}
@@ -83,12 +75,9 @@ export const SingleEstimate: React.FC = ({
{projectDetails?.estimate !== estimate.id && estimate.points.length > 0 && (
-
+
Use
-
+
)}
= ({ isOpen, handleClose, user, provider,
Export the data into separate files
-
Cancel
-
+
+ Cancel
+
+
{exportLoading ? "Exporting..." : "Export"}
-
+
diff --git a/web/components/exporter/guide.tsx b/web/components/exporter/guide.tsx
index 553c7c19b9c..5df8b1d9327 100644
--- a/web/components/exporter/guide.tsx
+++ b/web/components/exporter/guide.tsx
@@ -13,7 +13,8 @@ import IntegrationService from "services/integration.service";
// components
import { Exporter, SingleExport } from "components/exporter";
// ui
-import { Icon, Loader, PrimaryButton } from "components/ui";
+import { Button, Loader } from "@plane/ui";
+import { Icon } from "components/ui";
// icons
import { ArrowPathIcon } from "@heroicons/react/24/outline";
// fetch-keys
@@ -65,9 +66,7 @@ const IntegrationGuide = () => {
diff --git a/web/components/exporter/single-export.tsx b/web/components/exporter/single-export.tsx
index 772119f25a3..2eea9887579 100644
--- a/web/components/exporter/single-export.tsx
+++ b/web/components/exporter/single-export.tsx
@@ -1,6 +1,6 @@
import React from "react";
// ui
-import { PrimaryButton } from "components/ui"; // icons
+import { Button } from "@plane/ui";
// helpers
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
// types
@@ -29,13 +29,7 @@ export const SingleExport: React.FC = ({ service, refreshing }) => {
Export to{" "}
- {provider === "csv"
- ? "CSV"
- : provider === "xlsx"
- ? "Excel"
- : provider === "json"
- ? "JSON"
- : ""}
+ {provider === "csv" ? "CSV" : provider === "xlsx" ? "Excel" : provider === "json" ? "JSON" : ""}
{" "}
= ({ service, refreshing }) => {
{service.status == "completed" && (
)}
diff --git a/web/components/gantt-chart/sidebar.tsx b/web/components/gantt-chart/sidebar.tsx
index 2aec274d9e2..85a5031cf52 100644
--- a/web/components/gantt-chart/sidebar.tsx
+++ b/web/components/gantt-chart/sidebar.tsx
@@ -5,7 +5,7 @@ import StrictModeDroppable from "components/dnd/StrictModeDroppable";
// hooks
import { useChart } from "./hooks";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
// icons
import { EllipsisVerticalIcon } from "@heroicons/react/24/outline";
// helpers
@@ -55,8 +55,7 @@ export const GanttSidebar: React.FC = (props) => {
// update the sort order to the lowest if dropped at the top
if (destination.index === 0) updatedSortOrder = blocks[0].sort_order - 1000;
// update the sort order to the highest if dropped at the bottom
- else if (destination.index === blocks.length - 1)
- updatedSortOrder = blocks[blocks.length - 1].sort_order + 1000;
+ else if (destination.index === blocks.length - 1) updatedSortOrder = blocks[blocks.length - 1].sort_order + 1000;
// update the sort order to the average of the two adjacent blocks if dropped in between
else {
const destinationSortingOrder = blocks[destination.index].sort_order;
@@ -95,11 +94,7 @@ export const GanttSidebar: React.FC = (props) => {
<>
{blocks ? (
blocks.map((block, index) => {
- const duration = findTotalDaysInRange(
- block.start_date ?? "",
- block.target_date ?? "",
- true
- );
+ const duration = findTotalDaysInRange(block.start_date ?? "", block.target_date ?? "", true);
return (
= (props) => {
>
{(provided, snapshot) => (
updateActiveBlock(block)}
onMouseLeave={() => updateActiveBlock(null)}
ref={provided.innerRef}
diff --git a/web/components/headers/global-issues.tsx b/web/components/headers/global-issues.tsx
index 2e4aa588a61..45601ef8a7c 100644
--- a/web/components/headers/global-issues.tsx
+++ b/web/components/headers/global-issues.tsx
@@ -10,7 +10,8 @@ import { useMobxStore } from "lib/mobx/store-provider";
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection } from "components/issues";
import { CreateUpdateWorkspaceViewModal } from "components/workspace";
// ui
-import { PrimaryButton, Tooltip } from "components/ui";
+import { Tooltip } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { List, PlusIcon, Sheet } from "lucide-react";
// types
@@ -145,10 +146,9 @@ export const GlobalIssuesHeader: React.FC
= observer((props) => {
>
)}
- setCreateViewModal(true)}>
-
+ } onClick={() => setCreateViewModal(true)}>
New View
-
+
>
);
diff --git a/web/components/inbox/accept-issue-modal.tsx b/web/components/inbox/accept-issue-modal.tsx
index be557536ba7..bca83a3ec9e 100644
--- a/web/components/inbox/accept-issue-modal.tsx
+++ b/web/components/inbox/accept-issue-modal.tsx
@@ -5,7 +5,7 @@ import { Dialog, Transition } from "@headlessui/react";
// icons
import { CheckCircleIcon } from "@heroicons/react/24/outline";
// ui
-import { SecondaryButton, PrimaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
import type { IInboxIssue } from "types";
@@ -76,10 +76,12 @@ export const AcceptIssueModal: React.FC = ({ isOpen, handleClose, data, o
-
Cancel
-
+
+ Cancel
+
+
{isAccepting ? "Accepting..." : "Accept Issue"}
-
+
diff --git a/web/components/inbox/decline-issue-modal.tsx b/web/components/inbox/decline-issue-modal.tsx
index b3168915a56..48786da556b 100644
--- a/web/components/inbox/decline-issue-modal.tsx
+++ b/web/components/inbox/decline-issue-modal.tsx
@@ -5,7 +5,7 @@ import { Dialog, Transition } from "@headlessui/react";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
-import { SecondaryButton, DangerButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
import type { IInboxIssue } from "types";
@@ -60,10 +60,7 @@ export const DeclineIssueModal: React.FC
= ({ isOpen, handleClose, data,
-
+
Decline Issue
@@ -79,10 +76,12 @@ export const DeclineIssueModal: React.FC = ({ isOpen, handleClose, data,
- Cancel
-
+
+ Cancel
+
+
{isDeclining ? "Declining..." : "Decline Issue"}
-
+
diff --git a/web/components/inbox/delete-issue-modal.tsx b/web/components/inbox/delete-issue-modal.tsx
index a000571133c..fc4f7fd0faf 100644
--- a/web/components/inbox/delete-issue-modal.tsx
+++ b/web/components/inbox/delete-issue-modal.tsx
@@ -15,7 +15,7 @@ import useUser from "hooks/use-user";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
-import { SecondaryButton, DangerButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
import type { IInboxIssue } from "types";
// fetch-keys
@@ -115,10 +115,7 @@ export const DeleteIssueModal: React.FC
= ({ isOpen, handleClose, data })
-
+
Delete Issue
@@ -130,15 +127,16 @@ export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data })
{data?.project_detail?.identifier}-{data?.sequence_id}
- {""}? The issue will only be deleted from the inbox and this action cannot be
- undone.
+ {""}? The issue will only be deleted from the inbox and this action cannot be undone.
- Cancel
-
+
+ Cancel
+
+
{isDeleting ? "Deleting..." : "Delete Issue"}
-
+
diff --git a/web/components/inbox/inbox-action-headers.tsx b/web/components/inbox/inbox-action-headers.tsx
index 86bc15d01aa..ea397a35a89 100644
--- a/web/components/inbox/inbox-action-headers.tsx
+++ b/web/components/inbox/inbox-action-headers.tsx
@@ -25,7 +25,7 @@ import {
SelectDuplicateInboxIssueModal,
} from "components/inbox";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { InboxIcon, StackedLayersHorizontalIcon } from "components/icons";
import {
@@ -74,9 +74,7 @@ export const InboxActionHeader = () => {
mutateInboxIssues(
(prevData: any) =>
(prevData ?? []).map((i: any) =>
- i.bridge_id === inboxIssueId
- ? { ...i, issue_inbox: [{ ...i.issue_inbox[0], ...data }] }
- : i
+ i.bridge_id === inboxIssueId ? { ...i, issue_inbox: [{ ...i.issue_inbox[0], ...data }] } : i
),
false
);
@@ -104,8 +102,7 @@ export const InboxActionHeader = () => {
};
const issue = inboxIssues?.find((issue) => issue.bridge_id === inboxIssueId);
- const currentIssueIndex =
- inboxIssues?.findIndex((issue) => issue.bridge_id === inboxIssueId) ?? 0;
+ const currentIssueIndex = inboxIssues?.findIndex((issue) => issue.bridge_id === inboxIssueId) ?? 0;
useEffect(() => {
if (!issue?.issue_inbox[0].snoozed_till) return;
@@ -126,10 +123,7 @@ export const InboxActionHeader = () => {
setSelectDuplicateIssue(false)}
- value={
- inboxIssues?.find((inboxIssue) => inboxIssue.bridge_id === inboxIssueId)?.issue_inbox[0]
- .duplicate_to
- }
+ value={inboxIssues?.find((inboxIssue) => inboxIssue.bridge_id === inboxIssueId)?.issue_inbox[0].duplicate_to}
onSubmit={(dupIssueId: string) => {
markInboxStatus({
status: 2,
@@ -202,10 +196,13 @@ export const InboxActionHeader = () => {
-
-
- Snooze
-
+ }
+ size="sm"
+ >
+ Snooze
+
{({ close }) => (
@@ -220,8 +217,8 @@ export const InboxActionHeader = () => {
minDate={tomorrow}
inline
/>
- {
close();
markInboxStatus({
@@ -231,7 +228,7 @@ export const InboxActionHeader = () => {
}}
>
Snooze
-
+
)}
@@ -240,50 +237,50 @@ export const InboxActionHeader = () => {
)}
{isAllowed && issueStatus === -2 && (
- }
onClick={() => setSelectDuplicateIssue(true)}
>
-
- Mark as duplicate
-
+ Mark as duplicate
+
)}
{isAllowed && (issueStatus === 0 || issueStatus === -2) && (
- }
onClick={() => setAcceptIssueModal(true)}
>
-
- Accept
-
+ Accept
+
)}
{isAllowed && issueStatus === -2 && (
- }
onClick={() => setDeclineIssueModal(true)}
>
-
- Decline
-
+ Decline
+
)}
{(isAllowed || user?.id === issue?.created_by) && (
- }
onClick={() => setDeleteIssueModal(true)}
>
-
- Delete
-
+ Delete
+
)}
diff --git a/web/components/inbox/inbox-main-content.tsx b/web/components/inbox/inbox-main-content.tsx
index 6c096072963..5b0fb1da70a 100644
--- a/web/components/inbox/inbox-main-content.tsx
+++ b/web/components/inbox/inbox-main-content.tsx
@@ -17,7 +17,7 @@ import useUserAuth from "hooks/use-user-auth";
import { IssueDescriptionForm, IssueDetailsSidebar, IssueReaction } from "components/issues";
import { InboxIssueActivity } from "components/inbox";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
// icons
import {
ArrowTopRightOnSquareIcon,
@@ -117,16 +117,7 @@ export const InboxMainContent: React.FC = () => {
mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id));
});
},
- [
- workspaceSlug,
- inboxIssueId,
- projectId,
- mutateIssueDetails,
- inboxId,
- user,
- issueDetails,
- params,
- ]
+ [workspaceSlug, inboxIssueId, projectId, mutateIssueDetails, inboxId, user, issueDetails, params]
);
const onKeyDown = useCallback(
@@ -178,8 +169,7 @@ export const InboxMainContent: React.FC = () => {
reset({
...issueDetails,
- assignees_list:
- issueDetails.assignees_list ?? (issueDetails.assignee_details ?? []).map((user) => user.id),
+ assignees_list: issueDetails.assignees_list ?? (issueDetails.assignee_details ?? []).map((user) => user.id),
labels_list: issueDetails.labels_list ?? issueDetails.labels,
});
}, [issueDetails, reset, inboxIssueId]);
@@ -194,13 +184,11 @@ export const InboxMainContent: React.FC = () => {
{inboxIssues && inboxIssues.length > 0 ? (
- {inboxIssues?.length} issues found. Select an issue from the sidebar to view its
- details.
+ {inboxIssues?.length} issues found. Select an issue from the sidebar to view its details.
) : (
- No issues found. Use{" "}
- C shortcut
+ No issues found. Use C shortcut
to create a new issue
)}
@@ -247,18 +235,12 @@ export const InboxMainContent: React.FC = () => {
{new Date(issueDetails.issue_inbox[0].snoozed_till ?? "") < new Date() ? (
This issue was snoozed till{" "}
- {renderShortDateWithYearFormat(
- issueDetails.issue_inbox[0].snoozed_till ?? ""
- )}
- .
+ {renderShortDateWithYearFormat(issueDetails.issue_inbox[0].snoozed_till ?? "")}.
) : (
This issue has been snoozed till{" "}
- {renderShortDateWithYearFormat(
- issueDetails.issue_inbox[0].snoozed_till ?? ""
- )}
- .
+ {renderShortDateWithYearFormat(issueDetails.issue_inbox[0].snoozed_till ?? "")}.
)}
>
@@ -293,17 +275,11 @@ export const InboxMainContent: React.FC = () => {
description_html: issueDetails.description_html,
}}
handleFormSubmit={submitChanges}
- isAllowed={
- memberRole.isMember || memberRole.isOwner || user?.id === issueDetails.created_by
- }
+ isAllowed={memberRole.isMember || memberRole.isOwner || user?.id === issueDetails.created_by}
/>
-
+
diff --git a/web/components/inbox/issues-list-sidebar.tsx b/web/components/inbox/issues-list-sidebar.tsx
index 5f0fd116a2e..31fb3e7e6f5 100644
--- a/web/components/inbox/issues-list-sidebar.tsx
+++ b/web/components/inbox/issues-list-sidebar.tsx
@@ -5,7 +5,7 @@ import useInboxView from "hooks/use-inbox-view";
// components
import { InboxIssueCard, InboxFiltersList } from "components/inbox";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
export const IssuesListSidebar = () => {
const router = useRouter();
@@ -20,17 +20,12 @@ export const IssuesListSidebar = () => {
inboxIssues.length > 0 ? (
{inboxIssues.map((issue) => (
-
+
))}
) : (
- {filtersLength > 0 &&
- "No issues found for the selected filters. Try changing the filters."}
+ {filtersLength > 0 && "No issues found for the selected filters. Try changing the filters."}
)
) : (
diff --git a/web/components/inbox/select-duplicate.tsx b/web/components/inbox/select-duplicate.tsx
index 8dbb58faa24..6bf68341247 100644
--- a/web/components/inbox/select-duplicate.tsx
+++ b/web/components/inbox/select-duplicate.tsx
@@ -13,7 +13,7 @@ import useToast from "hooks/use-toast";
// services
import issuesServices from "services/issue.service";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { LayerDiagonalIcon } from "components/icons";
@@ -170,8 +170,12 @@ export const SelectDuplicateInboxIssueModal: React.FC = (props) => {
{filteredIssues.length > 0 && (
-
Cancel
-
Mark as original
+
+ Cancel
+
+
+ Mark as original
+
)}
diff --git a/web/components/integration/delete-import-modal.tsx b/web/components/integration/delete-import-modal.tsx
index 23b95664410..b4de8b3871c 100644
--- a/web/components/integration/delete-import-modal.tsx
+++ b/web/components/integration/delete-import-modal.tsx
@@ -11,7 +11,7 @@ import IntegrationService from "services/integration.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { DangerButton, Input, SecondaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types
@@ -110,21 +110,30 @@ export const DeleteImportModal: React.FC = ({ isOpen, handleClose, data,
To confirm, type delete import below:
{
if (e.target.value === "delete import") setConfirmDeleteImport(true);
else setConfirmDeleteImport(false);
}}
placeholder="Enter 'delete import'"
+ className="mt-2 w-full"
/>
- Cancel
-
+
+ Cancel
+
+
{deleteLoading ? "Deleting..." : "Delete Project"}
-
+
diff --git a/web/components/integration/github/auth.tsx b/web/components/integration/github/auth.tsx
index b530b4a24b8..c94bfacd572 100644
--- a/web/components/integration/github/auth.tsx
+++ b/web/components/integration/github/auth.tsx
@@ -1,7 +1,7 @@
// hooks
import useIntegrationPopup from "hooks/use-integration-popup";
// ui
-import { PrimaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
import { IWorkspaceIntegration } from "types";
@@ -16,11 +16,13 @@ export const GithubAuth: React.FC
= ({ workspaceIntegration, provider })
return (
{workspaceIntegration && workspaceIntegration?.id ? (
-
Successfully Connected
+
+ Successfully Connected
+
) : (
-
+
{isConnecting ? "Connecting..." : "Connect"}
-
+
)}
);
diff --git a/web/components/integration/github/import-configure.tsx b/web/components/integration/github/import-configure.tsx
index ca5a55a77d3..f804d32dddb 100644
--- a/web/components/integration/github/import-configure.tsx
+++ b/web/components/integration/github/import-configure.tsx
@@ -1,7 +1,6 @@
// components
+import { Button } from "@plane/ui";
import { GithubAuth, TIntegrationSteps } from "components/integration";
-// ui
-import { PrimaryButton } from "components/ui";
// types
import { IAppIntegration, IWorkspaceIntegration } from "types";
@@ -20,9 +19,7 @@ export const GithubImportConfigure: React.FC = ({
}) => {
// current integration from all the integrations available
const integration =
- appIntegrations &&
- appIntegrations.length > 0 &&
- appIntegrations.find((i) => i.provider === provider);
+ appIntegrations && appIntegrations.length > 0 && appIntegrations.find((i) => i.provider === provider);
// current integration from workspace integrations
const workspaceIntegration =
@@ -44,12 +41,13 @@ export const GithubImportConfigure: React.FC = ({
-
handleStepChange("import-data")}
disabled={workspaceIntegration && workspaceIntegration?.id ? false : true}
>
Next
-
+
);
diff --git a/web/components/integration/github/import-confirm.tsx b/web/components/integration/github/import-confirm.tsx
index 8a7383062ef..65f3e82b2e6 100644
--- a/web/components/integration/github/import-confirm.tsx
+++ b/web/components/integration/github/import-confirm.tsx
@@ -3,7 +3,7 @@ import { FC } from "react";
// react-hook-form
import { UseFormWatch } from "react-hook-form";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
import { TFormValues, TIntegrationSteps } from "components/integration";
@@ -15,13 +15,16 @@ type Props = {
export const GithubImportConfirm: FC = ({ handleStepChange, watch }) => (
- You are about to import issues from {watch("github").full_name}. Click on {'"'}Confirm &
- Import{'" '}
+ You are about to import issues from {watch("github").full_name}. Click on {'"'}Confirm & Import{'" '}
to complete the process.
-
handleStepChange("import-users")}>Back
-
Confirm & Import
+
handleStepChange("import-users")}>
+ Back
+
+
+ Confirm & Import
+
);
diff --git a/web/components/integration/github/import-data.tsx b/web/components/integration/github/import-data.tsx
index eeae3f28de1..32f76527765 100644
--- a/web/components/integration/github/import-data.tsx
+++ b/web/components/integration/github/import-data.tsx
@@ -7,7 +7,8 @@ import useProjects from "hooks/use-projects";
// components
import { SelectRepository, TFormValues, TIntegrationSteps } from "components/integration";
// ui
-import { CustomSearchSelect, PrimaryButton, SecondaryButton, ToggleSwitch } from "components/ui";
+import { Button, ToggleSwitch } from "@plane/ui";
+import { CustomSearchSelect } from "components/ui";
// helpers
import { truncateText } from "helpers/string.helper";
// types
@@ -51,11 +52,7 @@ export const GithubImportData: FC = ({ handleStepChange, integration, con
integration={integration}
value={value ? value.id : null}
label={
- value ? (
- `${value.full_name}`
- ) : (
- Select Repository
- )
+ value ? `${value.full_name}` : Select Repository
}
onChange={onChange}
characterLimit={50}
@@ -68,9 +65,7 @@ export const GithubImportData: FC = ({ handleStepChange, integration, con
Select Project
-
- Select the project to import the issues to.
-
+
Select the project to import the issues to.
{projects && (
@@ -99,9 +94,7 @@ export const GithubImportData: FC
= ({ handleStepChange, integration, con
Sync Issues
-
- Set whether you want to sync the issues or not.
-
+
Set whether you want to sync the issues or not.
= ({ handleStepChange, integration, con
-
handleStepChange("import-configure")}>Back
-
handleStepChange("import-configure")}>
+ Back
+
+ handleStepChange("repo-details")}
disabled={!watch("github") || !watch("project")}
>
Next
-
+
);
diff --git a/web/components/integration/github/import-users.tsx b/web/components/integration/github/import-users.tsx
index e4caf349b96..ad06544387c 100644
--- a/web/components/integration/github/import-users.tsx
+++ b/web/components/integration/github/import-users.tsx
@@ -3,14 +3,9 @@ import { FC } from "react";
// react-hook-form
import { UseFormWatch } from "react-hook-form";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
-import {
- IUserDetails,
- SingleUserSelect,
- TFormValues,
- TIntegrationSteps,
-} from "components/integration";
+import { IUserDetails, SingleUserSelect, TFormValues, TIntegrationSteps } from "components/integration";
type Props = {
handleStepChange: (value: TIntegrationSteps) => void;
@@ -28,9 +23,7 @@ export const GithubImportUsers: FC
= ({ handleStepChange, users, setUsers
Name
Import as...
-
- {users.filter((u) => u.import !== false).length} users selected
-
+
{users.filter((u) => u.import !== false).length} users selected
{watch("collaborators").map((collaborator, index) => (
@@ -45,10 +38,12 @@ export const GithubImportUsers: FC
= ({ handleStepChange, users, setUsers
-
handleStepChange("repo-details")}>Back
-
handleStepChange("import-confirm")} disabled={isInvalid}>
+ handleStepChange("repo-details")}>
+ Back
+
+ handleStepChange("import-confirm")} disabled={isInvalid}>
Next
-
+
);
diff --git a/web/components/integration/github/repo-details.tsx b/web/components/integration/github/repo-details.tsx
index b53ae2f01ec..1e78f924151 100644
--- a/web/components/integration/github/repo-details.tsx
+++ b/web/components/integration/github/repo-details.tsx
@@ -9,7 +9,7 @@ import { UseFormSetValue } from "react-hook-form";
// services
import GithubIntegrationService from "services/github.service";
// ui
-import { Loader, PrimaryButton, SecondaryButton } from "components/ui";
+import { Button, Loader } from "@plane/ui";
// types
import { IUserDetails, TFormValues, TIntegrationSteps } from "components/integration";
// fetch-keys
@@ -85,13 +85,16 @@ export const GithubRepoDetails: FC = ({ selectedRepo, handleStepChange, s
)}
-
handleStepChange("import-data")}>Back
-
handleStepChange("import-data")}>
+ Back
+
+ handleStepChange("import-users")}
disabled={!repoInfo || repoInfo.issue_count === 0}
>
Next
-
+
);
diff --git a/web/components/integration/github/single-user-select.tsx b/web/components/integration/github/single-user-select.tsx
index 13671ac8930..b66b135c3c0 100644
--- a/web/components/integration/github/single-user-select.tsx
+++ b/web/components/integration/github/single-user-select.tsx
@@ -5,7 +5,8 @@ import useSWR from "swr";
// services
import workspaceService from "services/workspace.service";
// ui
-import { Avatar, CustomSearchSelect, CustomSelect, Input } from "components/ui";
+import { Avatar, CustomSearchSelect, CustomSelect } from "components/ui";
+import { Input } from "@plane/ui";
// types
import { IGithubRepoCollaborator } from "types";
import { IUserDetails } from "./root";
@@ -69,11 +70,7 @@ export const SingleUserSelect: React.FC = ({ collaborator, index, users,
- {importOptions.find((o) => o.key === users[index].import)?.label}
-
- }
+ label={{importOptions.find((o) => o.key === users[index].import)?.label}
}
onChange={(val: any) => {
const newUsers = [...users];
newUsers[index].import = val;
@@ -92,6 +89,7 @@ export const SingleUserSelect: React.FC = ({ collaborator, index, users,
{users[index].import === "invite" && (
= ({ collaborator, index, users,
setUsers(newUsers);
}}
placeholder="Enter email of the user"
- className="py-1 text-xs"
+ className="py-1 text-xs w-full"
/>
)}
{users[index].import === "map" && members && (
diff --git a/web/components/integration/guide.tsx b/web/components/integration/guide.tsx
index 3d8e5d39a91..6ed5d03f36a 100644
--- a/web/components/integration/guide.tsx
+++ b/web/components/integration/guide.tsx
@@ -13,7 +13,7 @@ import IntegrationService from "services/integration.service";
// components
import { DeleteImportModal, GithubImporterRoot, JiraImporterRoot, SingleImport } from "components/integration";
// ui
-import { Loader, PrimaryButton } from "components/ui";
+import { Button, Loader } from "@plane/ui";
// icons
import { ArrowPathIcon } from "@heroicons/react/24/outline";
// types
@@ -90,9 +90,7 @@ const IntegrationGuide = () => {
diff --git a/web/components/integration/jira/give-details.tsx b/web/components/integration/jira/give-details.tsx
index 3fc5d9641c5..d549114dfb5 100644
--- a/web/components/integration/jira/give-details.tsx
+++ b/web/components/integration/jira/give-details.tsx
@@ -13,8 +13,10 @@ import { PlusIcon } from "@heroicons/react/20/solid";
import useProjects from "hooks/use-projects";
// components
-import { Input, CustomSelect } from "components/ui";
+import { CustomSelect } from "components/ui";
+import { Input } from "@plane/ui";
+// types
import { IJiraImporterForm } from "types";
export const JiraGetImportDetail: React.FC = () => {
@@ -42,15 +44,24 @@ export const JiraGetImportDetail: React.FC = () => {
- (
+
+ )}
/>
@@ -61,15 +72,25 @@ export const JiraGetImportDetail: React.FC = () => {
If XXX-123 is your issue, then enter XXX
- (
+
+ )}
/>
@@ -77,21 +98,28 @@ export const JiraGetImportDetail: React.FC = () => {
@@ -102,16 +130,25 @@ export const JiraGetImportDetail: React.FC = () => {
Enter your companies cloud host name
- (
+
+ )}
/>
@@ -119,9 +156,7 @@ export const JiraGetImportDetail: React.FC = () => {
Import to project
-
- Select which project you want to import to.
-
+
Select which project you want to import to.
{
const { data: members } = useSWR(
workspaceSlug ? WORKSPACE_MEMBERS_WITH_EMAIL(workspaceSlug?.toString() ?? "") : null,
- workspaceSlug
- ? () => workspaceService.workspaceMembersWithEmail(workspaceSlug?.toString() ?? "")
- : null
+ workspaceSlug ? () => workspaceService.workspaceMembersWithEmail(workspaceSlug?.toString() ?? "") : null
);
const options = members?.map((member) => ({
@@ -59,17 +58,13 @@ export const JiraImportUsers: FC = () => {
Users
-
- Update, invite or choose not to invite assignee
-
+
Update, invite or choose not to invite assignee
(
-
- )}
+ render={({ field: { value, onChange } }) => }
/>
@@ -97,11 +92,7 @@ export const JiraImportUsers: FC = () => {
value={value}
onChange={onChange}
width="w-full"
- label={
-
- {Boolean(value) ? value : ("Ignore" as any)}
-
- }
+ label={{Boolean(value) ? value : ("Ignore" as any)} }
>
Invite by email
Map to existing
@@ -112,15 +103,24 @@ export const JiraImportUsers: FC = () => {
{watch(`data.users.${index}.import`) === "invite" && (
-
(
+
+ )}
/>
)}
{watch(`data.users.${index}.import`) === "map" && (
diff --git a/web/components/integration/jira/jira-project-detail.tsx b/web/components/integration/jira/jira-project-detail.tsx
index edd35231fbb..e9609dfec1b 100644
--- a/web/components/integration/jira/jira-project-detail.tsx
+++ b/web/components/integration/jira/jira-project-detail.tsx
@@ -18,7 +18,7 @@ import { JIRA_IMPORTER_DETAIL } from "constants/fetch-keys";
import { IJiraImporterForm, IJiraMetadata } from "types";
// components
-import { Spinner, ToggleSwitch } from "components/ui";
+import { ToggleSwitch, Spinner } from "@plane/ui";
import type { IJiraIntegrationData, TJiraIntegrationSteps } from ".";
diff --git a/web/components/integration/jira/root.tsx b/web/components/integration/jira/root.tsx
index 2a4b572ec17..b1b5fa746fe 100644
--- a/web/components/integration/jira/root.tsx
+++ b/web/components/integration/jira/root.tsx
@@ -22,7 +22,7 @@ import jiraImporterService from "services/jira.service";
import { IMPORTER_SERVICES_LIST } from "constants/fetch-keys";
// components
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
import {
JiraGetImportDetail,
JiraProjectDetail,
@@ -178,7 +178,8 @@ export const JiraImporterRoot: React.FC
= ({ user }) => {
{currentStep?.state !== "import-configure" && (
-
{
const currentElementIndex = integrationWorkflowData.findIndex(
(i) => i?.key === currentStep?.state
@@ -189,9 +190,10 @@ export const JiraImporterRoot: React.FC = ({ user }) => {
}}
>
Back
-
+
)}
-
{
const currentElementIndex = integrationWorkflowData.findIndex((i) => i?.key === currentStep?.state);
@@ -206,7 +208,7 @@ export const JiraImporterRoot: React.FC = ({ user }) => {
}}
>
{currentStep?.state === "import-confirmation" ? "Confirm & Import" : "Next"}
-
+
diff --git a/web/components/integration/single-integration-card.tsx b/web/components/integration/single-integration-card.tsx
index 8dbc60bf58d..081de73788e 100644
--- a/web/components/integration/single-integration-card.tsx
+++ b/web/components/integration/single-integration-card.tsx
@@ -11,7 +11,7 @@ import IntegrationService from "services/integration.service";
import useToast from "hooks/use-toast";
import useIntegrationPopup from "hooks/use-integration-popup";
// ui
-import { DangerButton, Loader, PrimaryButton } from "components/ui";
+import { Button, Loader } from "@plane/ui";
// icons
import GithubLogo from "public/services/github.png";
import SlackLogo from "public/services/slack.png";
@@ -113,13 +113,13 @@ export const SingleIntegrationCard: React.FC = ({ integration }) => {
{workspaceIntegrations ? (
isInstalled ? (
-
+
{deletingIntegration ? "Uninstalling..." : "Uninstall"}
-
+
) : (
-
+
{isInstalling ? "Installing..." : "Install"}
-
+
)
) : (
diff --git a/web/components/integration/slack/select-channel.tsx b/web/components/integration/slack/select-channel.tsx
index 728b582f146..6455011d44e 100644
--- a/web/components/integration/slack/select-channel.tsx
+++ b/web/components/integration/slack/select-channel.tsx
@@ -6,7 +6,7 @@ import useSWR, { mutate } from "swr";
// services
import appinstallationsService from "services/app_installation.service";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
// hooks
import useToast from "hooks/use-toast";
import useIntegrationPopup from "hooks/use-integration-popup";
diff --git a/web/components/issues/activity.tsx b/web/components/issues/activity.tsx
index e6f54f51246..5e5f5b4df99 100644
--- a/web/components/issues/activity.tsx
+++ b/web/components/issues/activity.tsx
@@ -7,7 +7,8 @@ import { useRouter } from "next/router";
import { ActivityIcon, ActivityMessage } from "components/core";
import { CommentCard } from "components/issues/comment";
// ui
-import { Icon, Loader, Tooltip } from "components/ui";
+import { Icon, Tooltip } from "components/ui";
+import { Loader } from "@plane/ui";
// helpers
import { render24HourFormatTime, renderLongDateFormat, timeAgo } from "helpers/date-time.helper";
// types
@@ -52,11 +53,7 @@ export const IssueActivitySection: React.FC = ({
{activity.map((activityItem, index) => {
// determines what type of action is performed
- const message = activityItem.field ? (
-
- ) : (
- "created the issue."
- );
+ const message = activityItem.field ? : "created the issue.";
if ("field" in activityItem && activityItem.field !== "updated_by") {
return (
@@ -79,8 +76,7 @@ export const IssueActivitySection: React.FC = ({
) : (
)
- ) : activityItem.actor_detail.avatar &&
- activityItem.actor_detail.avatar !== "" ? (
+ ) : activityItem.actor_detail.avatar && activityItem.actor_detail.avatar !== "" ? (
= ({
diff --git a/web/components/issues/attachment/delete-attachment-modal.tsx b/web/components/issues/attachment/delete-attachment-modal.tsx
index 62dc3cffe13..3dead2d39a6 100644
--- a/web/components/issues/attachment/delete-attachment-modal.tsx
+++ b/web/components/issues/attachment/delete-attachment-modal.tsx
@@ -11,7 +11,7 @@ import issuesService from "services/issue.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { SecondaryButton, DangerButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// helper
@@ -106,15 +106,18 @@ export const DeleteAttachmentModal: React.FC
= ({ isOpen, setIsOpen, data
- Cancel
-
+ Cancel
+
+ {
handleDeletion(data.id);
handleClose();
}}
>
Delete
-
+
diff --git a/web/components/issues/comment/add-comment.tsx b/web/components/issues/comment/add-comment.tsx
index 33d7f2289c7..64198784d9c 100644
--- a/web/components/issues/comment/add-comment.tsx
+++ b/web/components/issues/comment/add-comment.tsx
@@ -5,7 +5,8 @@ import { useForm, Controller } from "react-hook-form";
// components
import { TipTapEditor } from "components/tiptap";
// ui
-import { Icon, SecondaryButton, Tooltip } from "components/ui";
+import { Icon, Tooltip } from "components/ui";
+import { Button } from "@plane/ui";
// types
import type { IIssueComment } from "types";
@@ -33,11 +34,7 @@ const commentAccess = [
},
];
-export const AddComment: React.FC = ({
- disabled = false,
- onSubmit,
- showAccessSpecifier = false,
-}) => {
+export const AddComment: React.FC = ({ disabled = false, onSubmit, showAccessSpecifier = false }) => {
const editorRef = React.useRef(null);
const router = useRouter();
@@ -83,9 +80,7 @@ export const AddComment: React.FC = ({
@@ -112,9 +107,9 @@ export const AddComment: React.FC = ({
/>
-
+
{isSubmitting ? "Adding..." : "Comment"}
-
+
diff --git a/web/components/issues/confirm-issue-discard.tsx b/web/components/issues/confirm-issue-discard.tsx
index f8feab73d65..98b4eaf4806 100644
--- a/web/components/issues/confirm-issue-discard.tsx
+++ b/web/components/issues/confirm-issue-discard.tsx
@@ -3,7 +3,7 @@ import React, { useState } from "react";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// ui
-import { SecondaryButton, PrimaryButton } from "components/ui";
+import { Button } from "@plane/ui";
type Props = {
isOpen: boolean;
@@ -58,29 +58,28 @@ export const ConfirmIssueDiscard: React.FC = (props) => {
-
+
Draft Issue
-
- Would you like to save this issue in drafts?
-
+
Would you like to save this issue in drafts?
- Discard
+
+ Discard
+
-
Cancel
-
+
+ Cancel
+
+
{isLoading ? "Saving..." : "Save Draft"}
-
+
diff --git a/web/components/issues/delete-draft-issue-modal.tsx b/web/components/issues/delete-draft-issue-modal.tsx
index e7f748975ef..1b54f2c0972 100644
--- a/web/components/issues/delete-draft-issue-modal.tsx
+++ b/web/components/issues/delete-draft-issue-modal.tsx
@@ -16,7 +16,7 @@ import useToast from "hooks/use-toast";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
-import { SecondaryButton, DangerButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
import type { IIssue } from "types";
// fetch-keys
@@ -129,10 +129,12 @@ export const DeleteDraftIssueModal: React.FC = (props) => {
- Cancel
-
+
+ Cancel
+
+
{isDeleteLoading ? "Deleting..." : "Delete Issue"}
-
+
diff --git a/web/components/issues/delete-issue-modal.tsx b/web/components/issues/delete-issue-modal.tsx
index 2f23f3f6378..0dcf08f5ee2 100644
--- a/web/components/issues/delete-issue-modal.tsx
+++ b/web/components/issues/delete-issue-modal.tsx
@@ -14,7 +14,7 @@ import useToast from "hooks/use-toast";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
-import { SecondaryButton, DangerButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
import type { IIssue, ICurrentUserResponse, ISubIssueResponse } from "types";
// fetch-keys
@@ -182,10 +182,12 @@ export const DeleteIssueModal: React.FC = ({
- Cancel
-
+
+ Cancel
+
+
{isDeleteLoading ? "Deleting..." : "Delete Issue"}
-
+
diff --git a/web/components/issues/description-form.tsx b/web/components/issues/description-form.tsx
index 54ea0a9760d..cacfc7a6db6 100644
--- a/web/components/issues/description-form.tsx
+++ b/web/components/issues/description-form.tsx
@@ -6,7 +6,7 @@ import { Controller, useForm } from "react-hook-form";
import useReloadConfirmations from "hooks/use-reload-confirmation";
import { useDebouncedCallback } from "use-debounce";
// components
-import { TextArea } from "components/ui";
+import { TextArea } from "@plane/ui";
import { TipTapEditor } from "components/tiptap";
// types
import { IIssue } from "types";
@@ -26,12 +26,7 @@ export interface IssueDetailsProps {
isAllowed: boolean;
}
-export const IssueDescriptionForm: FC = ({
- issue,
- handleFormSubmit,
- workspaceSlug,
- isAllowed,
-}) => {
+export const IssueDescriptionForm: FC = ({ issue, handleFormSubmit, workspaceSlug, isAllowed }) => {
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
const [characterLimit, setCharacterLimit] = useState(false);
@@ -93,32 +88,36 @@ export const IssueDescriptionForm: FC = ({
{isAllowed ? (
-
setCharacterLimit(true)}
- onChange={(e) => {
- setCharacterLimit(false);
- setIsSubmitting("submitting");
- debouncedTitleSave();
- }}
- required={true}
- className="min-h-10 block w-full resize-none overflow-hidden rounded border-none bg-transparent px-3 py-2 text-xl outline-none ring-0 focus:ring-1 focus:ring-custom-primary"
- role="textbox"
- disabled={!isAllowed}
+ control={control}
+ render={({ field: { value, onChange } }) => (
+ setCharacterLimit(true)}
+ onChange={(e) => {
+ setCharacterLimit(false);
+ setIsSubmitting("submitting");
+ debouncedTitleSave();
+ onChange(e.target.value);
+ }}
+ required={true}
+ className="min-h-10 block w-full resize-none overflow-hidden rounded border-none bg-transparent px-3 py-2 text-xl outline-none ring-0 focus:ring-1 focus:ring-custom-primary"
+ hasError={Boolean(errors?.description)}
+ role="textbox"
+ disabled={!isAllowed}
+ />
+ )}
/>
) : (
{issue.name}
)}
{characterLimit && isAllowed && (
-
255 ? "text-red-500" : ""
- }`}
- >
+ 255 ? "text-red-500" : ""}`}>
{watch("name").length}
/255
@@ -136,9 +135,7 @@ export const IssueDescriptionForm: FC = ({
return (
"
: value
}
@@ -146,17 +143,13 @@ export const IssueDescriptionForm: FC = ({
debouncedUpdatesEnabled={true}
setShouldShowAlert={setShowAlert}
setIsSubmitting={setIsSubmitting}
- customClassName={
- isAllowed ? "min-h-[150px] shadow-sm" : "!p-0 !pt-2 text-custom-text-200"
- }
+ customClassName={isAllowed ? "min-h-[150px] shadow-sm" : "!p-0 !pt-2 text-custom-text-200"}
noBorder={!isAllowed}
onChange={(description: Object, description_html: string) => {
setShowAlert(true);
setIsSubmitting("submitting");
onChange(description_html);
- handleSubmit(handleDescriptionFormSubmit)().finally(() =>
- setIsSubmitting("submitted")
- );
+ handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted"));
}}
editable={isAllowed}
/>
diff --git a/web/components/issues/draft-issue-form.tsx b/web/components/issues/draft-issue-form.tsx
index bf6d511e3da..7b16117ccbc 100644
--- a/web/components/issues/draft-issue-form.tsx
+++ b/web/components/issues/draft-issue-form.tsx
@@ -24,7 +24,8 @@ import {
import { CreateStateModal } from "components/states";
import { CreateLabelModal } from "components/labels";
// ui
-import { CustomMenu, Input, PrimaryButton, SecondaryButton, ToggleSwitch } from "components/ui";
+import { CustomMenu } from "components/ui";
+import { Button, Input, ToggleSwitch } from "@plane/ui";
import { TipTapEditor } from "components/tiptap";
// icons
import { SparklesIcon, XMarkIcon } from "@heroicons/react/24/outline";
@@ -356,21 +357,29 @@ export const DraftIssueForm: FC = (props) => {
-
Discard
-
+ Discard
+
+
handleCreateUpdateIssue(formData, data?.id ? "updateDraft" : "createDraft")
)}
>
{isSubmitting ? "Saving..." : "Save Draft"}
-
-
+
handleCreateUpdateIssue(formData, data ? "convertToNewIssue" : "createNewIssue")
)}
>
{isSubmitting ? "Saving..." : "Add Issue"}
-
+
diff --git a/web/components/issues/form.tsx b/web/components/issues/form.tsx
index dd382d43fae..3931ba58c3a 100644
--- a/web/components/issues/form.tsx
+++ b/web/components/issues/form.tsx
@@ -23,7 +23,8 @@ import {
import { CreateStateModal } from "components/states";
import { CreateLabelModal } from "components/labels";
// ui
-import { CustomMenu, Input, PrimaryButton, SecondaryButton, ToggleSwitch } from "components/ui";
+import { CustomMenu } from "components/ui";
+import { Button, Input, ToggleSwitch } from "@plane/ui";
import { TipTapEditor } from "components/tiptap";
// icons
import { SparklesIcon, XMarkIcon } from "@heroicons/react/24/outline";
@@ -321,21 +322,29 @@ export const IssueForm: FC = (props) => {
-
{
handleDiscardClose();
}}
>
Discard
-
-
+
+
{status
? isSubmitting
? "Updating Issue..."
@@ -564,7 +574,7 @@ export const IssueForm: FC = (props) => {
: isSubmitting
? "Adding Issue..."
: "Add Issue"}
-
+
diff --git a/web/components/issues/issue-layouts/calendar/calendar.tsx b/web/components/issues/issue-layouts/calendar/calendar.tsx
index df359e97cf1..778feb57f52 100644
--- a/web/components/issues/issue-layouts/calendar/calendar.tsx
+++ b/web/components/issues/issue-layouts/calendar/calendar.tsx
@@ -5,7 +5,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
// components
import { CalendarHeader, CalendarWeekDays, CalendarWeekHeader } from "components/issues";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
// types
import { ICalendarWeek } from "./types";
import { IIssueGroupedStructure } from "store/issue";
diff --git a/web/components/issues/issue-layouts/calendar/dropdowns/options-dropdown.tsx b/web/components/issues/issue-layouts/calendar/dropdowns/options-dropdown.tsx
index fe14e32f63c..c02be508411 100644
--- a/web/components/issues/issue-layouts/calendar/dropdowns/options-dropdown.tsx
+++ b/web/components/issues/issue-layouts/calendar/dropdowns/options-dropdown.tsx
@@ -6,7 +6,7 @@ import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// ui
-import { ToggleSwitch } from "components/ui";
+import { ToggleSwitch } from "@plane/ui";
// icons
import { Check, ChevronUp } from "lucide-react";
// types
diff --git a/web/components/issues/issue-layouts/filters/applied-filters/global-views-root.tsx b/web/components/issues/issue-layouts/filters/applied-filters/global-views-root.tsx
index 9c5ba1db108..283fac906ce 100644
--- a/web/components/issues/issue-layouts/filters/applied-filters/global-views-root.tsx
+++ b/web/components/issues/issue-layouts/filters/applied-filters/global-views-root.tsx
@@ -7,7 +7,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
// components
import { AppliedFiltersList } from "components/issues";
// ui
-import { PrimaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// helpers
import { areFiltersDifferent } from "helpers/filter.helper";
// types
@@ -93,9 +93,9 @@ export const GlobalViewsAppliedFiltersRoot = observer(() => {
projects={workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined}
/>
{storedFilters && viewDetails && areFiltersDifferent(storedFilters, viewDetails.query_data.filters ?? {}) && (
-
+
Update view
-
+
)}
);
diff --git a/web/components/issues/issue-layouts/filters/header/filters/assignee.tsx b/web/components/issues/issue-layouts/filters/header/filters/assignee.tsx
index 9e41784f8ca..eace4bec53e 100644
--- a/web/components/issues/issue-layouts/filters/header/filters/assignee.tsx
+++ b/web/components/issues/issue-layouts/filters/header/filters/assignee.tsx
@@ -3,7 +3,8 @@ import React, { useState } from "react";
// components
import { FilterHeader, FilterOption } from "components/issues";
// ui
-import { Avatar, Loader } from "components/ui";
+import { Avatar } from "components/ui";
+import { Loader } from "@plane/ui";
// types
import { IUserLite } from "types";
diff --git a/web/components/issues/issue-layouts/filters/header/filters/created-by.tsx b/web/components/issues/issue-layouts/filters/header/filters/created-by.tsx
index 9be5bd05c1d..5d8978ffd29 100644
--- a/web/components/issues/issue-layouts/filters/header/filters/created-by.tsx
+++ b/web/components/issues/issue-layouts/filters/header/filters/created-by.tsx
@@ -3,7 +3,8 @@ import React, { useState } from "react";
// components
import { FilterHeader, FilterOption } from "components/issues";
// ui
-import { Avatar, Loader } from "components/ui";
+import { Avatar } from "components/ui";
+import { Loader } from "@plane/ui";
// types
import { IUserLite } from "types";
diff --git a/web/components/issues/issue-layouts/filters/header/filters/labels.tsx b/web/components/issues/issue-layouts/filters/header/filters/labels.tsx
index a4140507633..37f6846f944 100644
--- a/web/components/issues/issue-layouts/filters/header/filters/labels.tsx
+++ b/web/components/issues/issue-layouts/filters/header/filters/labels.tsx
@@ -3,7 +3,7 @@ import React, { useState } from "react";
// components
import { FilterHeader, FilterOption } from "components/issues";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
// types
import { IIssueLabels } from "types";
diff --git a/web/components/issues/issue-layouts/filters/header/filters/project.tsx b/web/components/issues/issue-layouts/filters/header/filters/project.tsx
index 93163dd9142..de02e969282 100644
--- a/web/components/issues/issue-layouts/filters/header/filters/project.tsx
+++ b/web/components/issues/issue-layouts/filters/header/filters/project.tsx
@@ -3,7 +3,7 @@ import React, { useState } from "react";
// components
import { FilterHeader, FilterOption } from "components/issues";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
// helpers
import { renderEmoji } from "helpers/emoji.helper";
// types
diff --git a/web/components/issues/issue-layouts/filters/header/filters/state.tsx b/web/components/issues/issue-layouts/filters/header/filters/state.tsx
index ae719758af9..6f3472c8e13 100644
--- a/web/components/issues/issue-layouts/filters/header/filters/state.tsx
+++ b/web/components/issues/issue-layouts/filters/header/filters/state.tsx
@@ -3,7 +3,7 @@ import React, { useState } from "react";
// components
import { FilterHeader, FilterOption } from "components/issues";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
// icons
import { StateGroupIcon } from "components/icons";
// helpers
diff --git a/web/components/issues/issue-layouts/spreadsheet/module-root.tsx b/web/components/issues/issue-layouts/spreadsheet/module-root.tsx
index bf02efafe99..8a3c9871c8e 100644
--- a/web/components/issues/issue-layouts/spreadsheet/module-root.tsx
+++ b/web/components/issues/issue-layouts/spreadsheet/module-root.tsx
@@ -11,7 +11,8 @@ import useProjectDetails from "hooks/use-project-details";
import { SpreadsheetColumns, SpreadsheetIssues } from "components/core";
import { IssuePeekOverview } from "components/issues";
// ui
-import { CustomMenu, Spinner } from "components/ui";
+import { CustomMenu } from "components/ui";
+import { Spinner } from "@plane/ui";
// icon
import { PlusIcon } from "@heroicons/react/24/outline";
// types
diff --git a/web/components/issues/issue-layouts/spreadsheet/root.tsx b/web/components/issues/issue-layouts/spreadsheet/root.tsx
index 4ceb15fc60f..0c2373dd8df 100644
--- a/web/components/issues/issue-layouts/spreadsheet/root.tsx
+++ b/web/components/issues/issue-layouts/spreadsheet/root.tsx
@@ -11,7 +11,8 @@ import useProjectDetails from "hooks/use-project-details";
import { SpreadsheetColumns, SpreadsheetIssues } from "components/core";
import { IssuePeekOverview } from "components/issues";
// ui
-import { CustomMenu, Spinner } from "components/ui";
+import { CustomMenu } from "components/ui";
+import { Spinner } from "@plane/ui";
// icon
import { PlusIcon } from "@heroicons/react/24/outline";
// types
diff --git a/web/components/issues/parent-issues-list-modal.tsx b/web/components/issues/parent-issues-list-modal.tsx
index a29fa6521c4..8c74439a6f0 100644
--- a/web/components/issues/parent-issues-list-modal.tsx
+++ b/web/components/issues/parent-issues-list-modal.tsx
@@ -11,7 +11,8 @@ import useDebounce from "hooks/use-debounce";
// components
import { LayerDiagonalIcon } from "components/icons";
// ui
-import { Loader, ToggleSwitch, Tooltip } from "components/ui";
+import { Tooltip } from "components/ui";
+import { Loader, ToggleSwitch } from "@plane/ui";
// icons
import { LaunchOutlined } from "@mui/icons-material";
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
@@ -69,12 +70,7 @@ export const ParentIssuesListModal: React.FC = ({
return (
<>
- setSearchTerm("")}
- appear
- >
+ setSearchTerm("")} appear>
= ({
)}
- {!isSearching &&
- issues.length === 0 &&
- searchTerm !== "" &&
- debouncedSearchTerm !== "" && (
-
-
-
- No issues found. Create a new issue with{" "}
-
- C
-
- .
-
-
- )}
+ {!isSearching && issues.length === 0 && searchTerm !== "" && debouncedSearchTerm !== "" && (
+
+
+
+ No issues found. Create a new issue with{" "}
+ C .
+
+
+ )}
{isSearching ? (
diff --git a/web/components/issues/peek-overview/full-screen-peek-view.tsx b/web/components/issues/peek-overview/full-screen-peek-view.tsx
index 9c04e0b6ae5..47d0d1e7d53 100644
--- a/web/components/issues/peek-overview/full-screen-peek-view.tsx
+++ b/web/components/issues/peek-overview/full-screen-peek-view.tsx
@@ -7,7 +7,7 @@ import {
TPeekOverviewModes,
} from "components/issues";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
// types
import { IIssue } from "types";
@@ -59,11 +59,7 @@ export const FullScreenPeekView: React.FC = ({
{/* issue activity/comments */}
) : (
diff --git a/web/components/issues/peek-overview/side-peek-view.tsx b/web/components/issues/peek-overview/side-peek-view.tsx
index 1bdeed4791f..cb3e8316b4a 100644
--- a/web/components/issues/peek-overview/side-peek-view.tsx
+++ b/web/components/issues/peek-overview/side-peek-view.tsx
@@ -7,7 +7,7 @@ import {
TPeekOverviewModes,
} from "components/issues";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
// types
import { IIssue } from "types";
@@ -69,13 +69,7 @@ export const SidePeekView: React.FC = ({
{/* issue activity/comments */}
- {issue && (
-
- )}
+ {issue &&
}
) : (
diff --git a/web/components/issues/sidebar-select/cycle.tsx b/web/components/issues/sidebar-select/cycle.tsx
index 3080c1af221..5e567256165 100644
--- a/web/components/issues/sidebar-select/cycle.tsx
+++ b/web/components/issues/sidebar-select/cycle.tsx
@@ -8,7 +8,8 @@ import useSWR, { mutate } from "swr";
import issuesService from "services/issue.service";
import cyclesService from "services/cycles.service";
// ui
-import { Spinner, CustomSelect, Tooltip } from "components/ui";
+import { CustomSelect, Tooltip } from "components/ui";
+import { Spinner } from "@plane/ui";
// helper
import { truncateText } from "helpers/string.helper";
// types
diff --git a/web/components/issues/sidebar-select/label.tsx b/web/components/issues/sidebar-select/label.tsx
index 2052a0d56ee..4e373a1c097 100644
--- a/web/components/issues/sidebar-select/label.tsx
+++ b/web/components/issues/sidebar-select/label.tsx
@@ -15,7 +15,7 @@ import issuesService from "services/issue.service";
// hooks
import useUser from "hooks/use-user";
// ui
-import { Input, Spinner } from "components/ui";
+import { Input, Spinner } from "@plane/ui";
// icons
import { PlusIcon, RectangleGroupIcon, TagIcon, XMarkIcon } from "@heroicons/react/24/outline";
// types
@@ -53,10 +53,10 @@ export const SidebarLabelSelect: React.FC = ({
const {
register,
handleSubmit,
- formState: { isSubmitting },
+ formState: { errors, isSubmitting },
reset,
watch,
- control: labelControl,
+ control,
setFocus,
} = useForm>({
defaultValues,
@@ -281,7 +281,7 @@ export const SidebarLabelSelect: React.FC = ({
(
onChange(value.hex)} />
)}
@@ -292,15 +292,25 @@ export const SidebarLabelSelect: React.FC = ({
)}
- (
+
+ )}
/>
= ({
- issueDetail,
- handleModuleChange,
- disabled = false,
-}) => {
+export const SidebarModuleSelect: React.FC = ({ issueDetail, handleModuleChange, disabled = false }) => {
const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query;
const { data: modules } = useSWR(
workspaceSlug && projectId ? MODULE_LIST(projectId as string) : null,
- workspaceSlug && projectId
- ? () => modulesService.getModules(workspaceSlug as string, projectId as string)
- : null
+ workspaceSlug && projectId ? () => modulesService.getModules(workspaceSlug as string, projectId as string) : null
);
const removeIssueFromModule = (bridgeId: string, moduleId: string) => {
@@ -59,9 +54,7 @@ export const SidebarModuleSelect: React.FC = ({
m.id === issueModule?.module)?.name ?? "No module"
- }`}
+ tooltipContent={`${modules?.find((m) => m.id === issueModule?.module)?.name ?? "No module"}`}
>
= ({
disabled ? "cursor-not-allowed" : ""
}`}
>
-
+
{modules?.find((m) => m.id === issueModule?.module)?.name ?? "No module"}
diff --git a/web/components/issues/sidebar-select/state.tsx b/web/components/issues/sidebar-select/state.tsx
index 7c7970b5a8e..90ac18f64c2 100644
--- a/web/components/issues/sidebar-select/state.tsx
+++ b/web/components/issues/sidebar-select/state.tsx
@@ -7,7 +7,8 @@ import useSWR from "swr";
// services
import stateService from "services/project_state.service";
// ui
-import { Spinner, CustomSelect } from "components/ui";
+import { CustomSelect } from "components/ui";
+import { Spinner } from "@plane/ui";
// icons
import { StateGroupIcon } from "components/icons";
// helpers
diff --git a/web/components/labels/create-label-modal.tsx b/web/components/labels/create-label-modal.tsx
index f4123633f55..158eefb9499 100644
--- a/web/components/labels/create-label-modal.tsx
+++ b/web/components/labels/create-label-modal.tsx
@@ -13,7 +13,7 @@ import { Dialog, Popover, Transition } from "@headlessui/react";
// services
import issuesService from "services/issue.service";
// ui
-import { Input, PrimaryButton, SecondaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// icons
import { ChevronDownIcon } from "@heroicons/react/24/outline";
// types
@@ -163,27 +163,36 @@ export const CreateLabelModal: React.FC = ({ isOpen, projectId, handleClo
)}
- (
+
+ )}
/>
-
Cancel
-
+
+ Cancel
+
+
{isSubmitting ? "Creating Label..." : "Create Label"}
-
+
diff --git a/web/components/labels/create-update-label-inline.tsx b/web/components/labels/create-update-label-inline.tsx
index 0f5dcbeff9d..de87a1341a6 100644
--- a/web/components/labels/create-update-label-inline.tsx
+++ b/web/components/labels/create-update-label-inline.tsx
@@ -15,7 +15,7 @@ import { Popover, Transition } from "@headlessui/react";
// services
import issuesService from "services/issue.service";
// ui
-import { Input, PrimaryButton, SecondaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// types
import { IIssueLabels } from "types";
// fetch-keys
@@ -164,27 +164,38 @@ export const CreateUpdateLabelInline = forwardRef(functio
- (
+
+ )}
/>
- handleClose()}>Cancel
+ handleClose()}>
+ Cancel
+
{isUpdating ? (
-
+
{isSubmitting ? "Updating" : "Update"}
-
+
) : (
-
+
{isSubmitting ? "Adding" : "Add"}
-
+
)}
);
diff --git a/web/components/labels/delete-label-modal.tsx b/web/components/labels/delete-label-modal.tsx
index 452fcd79806..99362741ffd 100644
--- a/web/components/labels/delete-label-modal.tsx
+++ b/web/components/labels/delete-label-modal.tsx
@@ -13,7 +13,7 @@ import issuesService from "services/issue.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { DangerButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
import type { ICurrentUserResponse, IIssueLabels } from "types";
// fetch-keys
@@ -112,10 +112,12 @@ export const DeleteLabelModal: React.FC = ({ isOpen, onClose, data, user
- Cancel
-
+
+ Cancel
+
+
{isDeleteLoading ? "Deleting..." : "Delete"}
-
+
diff --git a/web/components/modules/delete-module-modal.tsx b/web/components/modules/delete-module-modal.tsx
index 9faede08f14..06bf44a4b72 100644
--- a/web/components/modules/delete-module-modal.tsx
+++ b/web/components/modules/delete-module-modal.tsx
@@ -11,7 +11,7 @@ import modulesService from "services/modules.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { SecondaryButton, DangerButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types
@@ -44,11 +44,7 @@ export const DeleteModuleModal: React.FC = ({ isOpen, setIsOpen, data, us
if (!workspaceSlug || !projectId || !data) return;
- mutate(
- MODULE_LIST(projectId as string),
- (prevData) => prevData?.filter((m) => m.id !== data.id),
- false
- );
+ mutate(MODULE_LIST(projectId as string), (prevData) => prevData?.filter((m) => m.id !== data.id), false);
await modulesService
.deleteModule(workspaceSlug as string, projectId as string, data.id, user)
@@ -96,36 +92,29 @@ export const DeleteModuleModal: React.FC = ({ isOpen, setIsOpen, data, us
-
+
-
+
Delete Module
Are you sure you want to delete module-{" "}
-
- {data?.name}
-
- ? All of the data related to the module will be permanently removed. This
- action cannot be undone.
+ {data?.name} ? All of the
+ data related to the module will be permanently removed. This action cannot be undone.
- Cancel
-
+
+ Cancel
+
+
{isDeleteLoading ? "Deleting..." : "Delete"}
-
+
diff --git a/web/components/modules/form.tsx b/web/components/modules/form.tsx
index 2715ba26621..fa52e227ff4 100644
--- a/web/components/modules/form.tsx
+++ b/web/components/modules/form.tsx
@@ -5,7 +5,8 @@ import { Controller, useForm } from "react-hook-form";
// components
import { ModuleLeadSelect, ModuleMembersSelect, ModuleStatusSelect } from "components/modules";
// ui
-import { DateSelect, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
+import { DateSelect } from "components/ui";
+import { Button, Input, TextArea } from "@plane/ui";
// types
import { IModule } from "types";
@@ -63,37 +64,49 @@ export const ModuleForm: React.FC = ({ handleFormSubmit, handleClose, sta
return (
-
- {status ? "Update" : "Create"} Module
-
+
{status ? "Update" : "Create"} Module
-
Cancel
-
+
+ Cancel
+
+
{status
? isSubmitting
? "Updating Module..."
@@ -153,7 +164,7 @@ export const ModuleForm: React.FC = ({ handleFormSubmit, handleClose, sta
: isSubmitting
? "Creating Module..."
: "Create Module"}
-
+
);
diff --git a/web/components/modules/sidebar.tsx b/web/components/modules/sidebar.tsx
index e815d19506f..f53d48998e8 100644
--- a/web/components/modules/sidebar.tsx
+++ b/web/components/modules/sidebar.tsx
@@ -29,7 +29,8 @@ import useToast from "hooks/use-toast";
import { LinkModal, LinksList, SidebarProgressStats } from "components/core";
import { DeleteModuleModal, SidebarLeadSelect, SidebarMembersSelect } from "components/modules";
import ProgressChart from "components/core/sidebar/progress-chart";
-import { CustomMenu, CustomSelect, Loader, ProgressBar } from "components/ui";
+import { CustomMenu, CustomSelect } from "components/ui";
+import { Loader, ProgressBar } from "@plane/ui";
// icon
import { ExclamationIcon } from "components/icons";
import { LinkIcon } from "@heroicons/react/20/solid";
@@ -169,8 +170,7 @@ export const ModuleDetailsSidebar: React.FC = ({ module, isOpen, moduleIs
};
const handleCopyText = () => {
- const originURL =
- typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
+ const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(`${workspaceSlug}/projects/${projectId}/modules/${module?.id}`)
.then(() => {
@@ -198,9 +198,7 @@ export const ModuleDetailsSidebar: React.FC = ({ module, isOpen, moduleIs
const isStartValid = new Date(`${module?.start_date}`) <= new Date();
const isEndValid = new Date(`${module?.target_date}`) >= new Date(`${module?.start_date}`);
- const progressPercentage = module
- ? Math.round((module.completed_issues / module.total_issues) * 100)
- : null;
+ const progressPercentage = module ? Math.round((module.completed_issues / module.total_issues) * 100) : null;
const handleEditLink = (link: linkDetails) => {
setSelectedLinkToUpdate(link);
@@ -220,12 +218,7 @@ export const ModuleDetailsSidebar: React.FC = ({ module, isOpen, moduleIs
createIssueLink={handleCreateLink}
updateIssueLink={handleUpdateLink}
/>
-
+
= ({ module, isOpen, moduleIs
}`}
>
-
- {renderShortDateWithYearFormat(
- new Date(`${module.start_date}`),
- "Start date"
- )}
-
+
{renderShortDateWithYearFormat(new Date(`${module.start_date}`), "Start date")}
= ({ module, isOpen, moduleIs
>
{
submitChanges({
start_date: renderDateFormat(date),
@@ -324,12 +308,7 @@ export const ModuleDetailsSidebar: React.FC = ({ module, isOpen, moduleIs
>
-
- {renderShortDateWithYearFormat(
- new Date(`${module?.target_date}`),
- "End date"
- )}
-
+ {renderShortDateWithYearFormat(new Date(`${module?.target_date}`), "End date")}
= ({ module, isOpen, moduleIs
>
{
submitChanges({
target_date: renderDateFormat(date),
@@ -372,9 +347,7 @@ export const ModuleDetailsSidebar: React.FC = ({ module, isOpen, moduleIs
-
- {module.name}
-
+ {module.name}
setModuleDeleteModal(true)}>
@@ -431,10 +404,7 @@ export const ModuleDetailsSidebar: React.FC = ({ module, isOpen, moduleIs
-
+
{module.completed_issues}/{module.total_issues}
@@ -446,9 +416,7 @@ export const ModuleDetailsSidebar: React.FC = ({ module, isOpen, moduleIs
{({ open }) => (
-
+
Progress
@@ -470,11 +438,7 @@ export const ModuleDetailsSidebar: React.FC
= ({ module, isOpen, moduleIs
) : (
-
+
Invalid date. Please enter valid date.
@@ -492,8 +456,7 @@ export const ModuleDetailsSidebar: React.FC
= ({ module, isOpen, moduleIs
Pending Issues -{" "}
- {module.total_issues -
- (module.completed_issues + module.cancelled_issues)}{" "}
+ {module.total_issues - (module.completed_issues + module.cancelled_issues)}{" "}
@@ -530,9 +493,7 @@ export const ModuleDetailsSidebar: React.FC = ({ module, isOpen, moduleIs
{({ open }) => (
-
+
Other Information
@@ -547,11 +508,7 @@ export const ModuleDetailsSidebar: React.FC
= ({ module, isOpen, moduleIs
) : (
-
+
No issues found. Please add issue.
diff --git a/web/components/notifications/notification-popover.tsx b/web/components/notifications/notification-popover.tsx
index f01fdafd155..d465d8c776c 100644
--- a/web/components/notifications/notification-popover.tsx
+++ b/web/components/notifications/notification-popover.tsx
@@ -9,12 +9,9 @@ import { Popover, Transition } from "@headlessui/react";
import useUserNotification from "hooks/use-user-notifications";
// components
-import { Loader, EmptyState, Tooltip } from "components/ui";
-import {
- SnoozeNotificationModal,
- NotificationCard,
- NotificationHeader,
-} from "components/notifications";
+import { EmptyState, Tooltip } from "components/ui";
+import { SnoozeNotificationModal, NotificationCard, NotificationHeader } from "components/notifications";
+import { Loader } from "@plane/ui";
// icons
import { NotificationsOutlined } from "@mui/icons-material";
// images
@@ -63,11 +60,7 @@ export const NotificationPopover = () => {
isOpen={selectedNotificationForSnooze !== null}
onClose={() => setSelectedNotificationForSnooze(null)}
onSubmit={markSnoozeNotification}
- notification={
- notifications?.find(
- (notification) => notification.id === selectedNotificationForSnooze
- ) || null
- }
+ notification={notifications?.find((notification) => notification.id === selectedNotificationForSnooze) || null}
onSuccess={() => {
setSelectedNotificationForSnooze(null);
}}
diff --git a/web/components/notifications/select-snooze-till-modal.tsx b/web/components/notifications/select-snooze-till-modal.tsx
index 99281350e32..46600549c45 100644
--- a/web/components/notifications/select-snooze-till-modal.tsx
+++ b/web/components/notifications/select-snooze-till-modal.tsx
@@ -15,13 +15,8 @@ import { getAllTimeIn30MinutesInterval } from "helpers/date-time.helper";
import useToast from "hooks/use-toast";
// components
-import {
- PrimaryButton,
- SecondaryButton,
- Icon,
- CustomDatePicker,
- CustomSelect,
-} from "components/ui";
+import { Button } from "@plane/ui";
+import { Icon, CustomDatePicker, CustomSelect } from "components/ui";
// types
import type { IUserNotification } from "types";
@@ -158,10 +153,7 @@ export const SnoozeNotificationModal: React.FC
= (props) => {
-
+
Customize Snooze Time
@@ -174,9 +166,7 @@ export const SnoozeNotificationModal: React.FC = (props) => {
-
- Pick a date
-
+ Pick a date
= (props) => {
/>
-
- Pick a time
-
+ Pick a time
= (props) => {
{value} {watch("period").toLowerCase()}
) : (
-
- Select a time
-
+ Select a time
)}
}
@@ -259,9 +245,7 @@ export const SnoozeNotificationModal: React.FC
= (props) => {
))
) : (
-
- No available time for this date.
-
+ No available time for this date.
)}
)}
@@ -271,10 +255,12 @@ export const SnoozeNotificationModal: React.FC = (props) => {
-
Cancel
-
+
+ Cancel
+
+
{isSubmitting ? "Submitting..." : "Submit"}
-
+
diff --git a/web/components/onboarding/invite-members.tsx b/web/components/onboarding/invite-members.tsx
index 8f1b1fa4103..cf05bc9aeb4 100644
--- a/web/components/onboarding/invite-members.tsx
+++ b/web/components/onboarding/invite-members.tsx
@@ -3,20 +3,13 @@ import React, { useEffect, useRef, useState } from "react";
// headless ui
import { Listbox, Transition } from "@headlessui/react";
// react-hook-form
-import {
- Control,
- Controller,
- FieldArrayWithId,
- UseFieldArrayRemove,
- useFieldArray,
- useForm,
-} from "react-hook-form";
+import { Control, Controller, FieldArrayWithId, UseFieldArrayRemove, useFieldArray, useForm } from "react-hook-form";
// services
import workspaceService from "services/workspace.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { Input, PrimaryButton, SecondaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// hooks
import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown";
// icons
@@ -60,12 +53,7 @@ const InviteMemberForm: React.FC = (props) => {
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
- useDynamicDropdownPosition(
- isDropdownOpen,
- () => setIsDropdownOpen(false),
- buttonRef,
- dropdownRef
- );
+ useDynamicDropdownPosition(isDropdownOpen, () => setIsDropdownOpen(false), buttonRef, dropdownRef);
return (
@@ -80,15 +68,18 @@ const InviteMemberForm: React.FC = (props) => {
message: "Invalid Email ID",
},
}}
- render={({ field }) => (
- <>
-
- {errors.emails?.[index]?.email && (
-
- {errors.emails?.[index]?.email?.message}
-
- )}
- >
+ render={({ field: { value, onChange, ref } }) => (
+
)}
/>
@@ -266,12 +257,12 @@ export const InviteMembers: React.FC = (props) => {
-
+
{isSubmitting ? "Sending..." : "Send Invite"}
-
-
+
+
Skip this step
-
+
);
diff --git a/web/components/onboarding/join-workspaces.tsx b/web/components/onboarding/join-workspaces.tsx
index 84b5bdfc971..43828961728 100644
--- a/web/components/onboarding/join-workspaces.tsx
+++ b/web/components/onboarding/join-workspaces.tsx
@@ -7,7 +7,7 @@ import workspaceService from "services/workspace.service";
// hooks
import useUser from "hooks/use-user";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { CheckCircleIcon } from "@heroicons/react/24/outline";
// helpers
@@ -25,11 +25,7 @@ type Props = {
updateLastWorkspace: () => Promise;
};
-export const JoinWorkspaces: React.FC = ({
- finishOnboarding,
- stepChange,
- updateLastWorkspace,
-}) => {
+export const JoinWorkspaces: React.FC = ({ finishOnboarding, stepChange, updateLastWorkspace }) => {
const [isJoiningWorkspaces, setIsJoiningWorkspaces] = useState(false);
const [invitationsRespond, setInvitationsRespond] = useState([]);
@@ -39,16 +35,11 @@ export const JoinWorkspaces: React.FC = ({
workspaceService.userWorkspaceInvitations()
);
- const handleInvitation = (
- workspace_invitation: IWorkspaceMemberInvitation,
- action: "accepted" | "withdraw"
- ) => {
+ const handleInvitation = (workspace_invitation: IWorkspaceMemberInvitation, action: "accepted" | "withdraw") => {
if (action === "accepted") {
setInvitationsRespond((prevData) => [...prevData, workspace_invitation.id]);
} else if (action === "withdraw") {
- setInvitationsRespond((prevData) =>
- prevData.filter((item: string) => item !== workspace_invitation.id)
- );
+ setInvitationsRespond((prevData) => prevData.filter((item: string) => item !== workspace_invitation.id));
}
};
@@ -57,8 +48,7 @@ export const JoinWorkspaces: React.FC = ({
await stepChange({ workspace_join: true });
- if (user.onboarding_step.workspace_create && user.onboarding_step.workspace_invite)
- await finishOnboarding();
+ if (user.onboarding_step.workspace_create && user.onboarding_step.workspace_invite) await finishOnboarding();
};
const submitInvitations = async () => {
@@ -91,9 +81,7 @@ export const JoinWorkspaces: React.FC = ({
handleInvitation(invitation, isSelected ? "withdraw" : "accepted")}
>
@@ -115,16 +103,10 @@ export const JoinWorkspaces: React.FC
= ({
-
- {truncateText(invitation.workspace.name, 30)}
-
+
{truncateText(invitation.workspace.name, 30)}
{ROLE[invitation.role]}
-
+
@@ -132,7 +114,8 @@ export const JoinWorkspaces: React.FC = ({
})}
-
= ({
loading={isJoiningWorkspaces}
>
Accept & Join
-
-
+
+
Skip for now
-
+
);
diff --git a/web/components/onboarding/tour/root.tsx b/web/components/onboarding/tour/root.tsx
index a28d93d975b..001e13be8ae 100644
--- a/web/components/onboarding/tour/root.tsx
+++ b/web/components/onboarding/tour/root.tsx
@@ -7,7 +7,7 @@ import useUser from "hooks/use-user";
// components
import { TourSidebar } from "components/onboarding";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { XMarkIcon } from "@heroicons/react/24/outline";
// images
@@ -52,8 +52,7 @@ const TOUR_STEPS: {
{
key: "modules",
title: "Break into modules",
- description:
- "Modules break your big thing into Projects or Features, to help you organize better.",
+ description: "Modules break your big thing into Projects or Features, to help you organize better.",
image: ModulesTour,
prevStep: "cycles",
nextStep: "views",
@@ -97,11 +96,13 @@ export const TourRoot: React.FC
= ({ onComplete }) => {
Welcome to Plane, {user?.first_name} {user?.last_name}
- We{"'"}re glad that you decided to try out Plane. You can now manage your projects
- with ease. Get started by creating a project.
+ We{"'"}re glad that you decided to try out Plane. You can now manage your projects with ease. Get
+ started by creating a project.
-
setStep("issues")}>Take a Product Tour
+
setStep("issues")}>
+ Take a Product Tour
+
= ({ onComplete }) => {
{currentStep?.prevStep && (
-
setStep(currentStep.prevStep ?? "welcome")}>
+ setStep(currentStep.prevStep ?? "welcome")}>
Back
-
+
)}
{currentStep?.nextStep && (
-
setStep(currentStep.nextStep ?? "issues")}>
+ setStep(currentStep.nextStep ?? "issues")}>
Next
-
+
)}
- {TOUR_STEPS.findIndex((tourStep) => tourStep.key === step) ===
- TOUR_STEPS.length - 1 && (
-
Create my first project
+ {TOUR_STEPS.findIndex((tourStep) => tourStep.key === step) === TOUR_STEPS.length - 1 && (
+
+ Create my first project
+
)}
diff --git a/web/components/onboarding/user-details.tsx b/web/components/onboarding/user-details.tsx
index 2911bbc80f4..a8f8e616a20 100644
--- a/web/components/onboarding/user-details.tsx
+++ b/web/components/onboarding/user-details.tsx
@@ -9,7 +9,8 @@ import useToast from "hooks/use-toast";
// services
import userService from "services/user.service";
// ui
-import { CustomSearchSelect, CustomSelect, Input, PrimaryButton } from "components/ui";
+import { CustomSearchSelect, CustomSelect } from "components/ui";
+import { Button, Input } from "@plane/ui";
// types
import { ICurrentUserResponse, IUser } from "types";
// fetch-keys
@@ -113,38 +114,56 @@ export const UserDetails: React.FC = ({ user }) => {
-
+
{isSubmitting ? "Updating..." : "Continue"}
-
+
);
};
diff --git a/web/components/onboarding/workspace.tsx b/web/components/onboarding/workspace.tsx
index 8f744243273..e433268b7a6 100644
--- a/web/components/onboarding/workspace.tsx
+++ b/web/components/onboarding/workspace.tsx
@@ -1,7 +1,7 @@
import { useState } from "react";
// ui
-import { SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
import { ICurrentUserResponse, IWorkspace, TOnboardingSteps } from "types";
// constants
@@ -15,13 +15,7 @@ type Props = {
workspaces: IWorkspace[] | undefined;
};
-export const Workspace: React.FC
= ({
- finishOnboarding,
- stepChange,
- updateLastWorkspace,
- user,
- workspaces,
-}) => {
+export const Workspace: React.FC = ({ finishOnboarding, stepChange, updateLastWorkspace, user, workspaces }) => {
const [defaultValues, setDefaultValues] = useState({
name: "",
slug: "",
@@ -61,9 +55,9 @@ export const Workspace: React.FC = ({
}}
secondaryButton={
workspaces ? (
-
+
{workspaces.length > 0 ? "Skip & continue" : "Back"}
-
+
) : undefined
}
/>
diff --git a/web/components/pages/create-block.tsx b/web/components/pages/create-block.tsx
index 6f6159ad037..69a1b96bf7d 100644
--- a/web/components/pages/create-block.tsx
+++ b/web/components/pages/create-block.tsx
@@ -7,14 +7,14 @@ import { mutate } from "swr";
import { PaperAirplaneIcon } from "@heroicons/react/24/outline";
// react-hook-form
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// services
import pagesService from "services/page.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { TextArea } from "components/ui";
+import { TextArea } from "@plane/ui";
// types
import { ICurrentUserResponse, IPageBlock } from "types";
// fetch-keys
@@ -44,7 +44,7 @@ export const CreateBlock: React.FC = ({ user }) => {
setValue,
setFocus,
reset,
- formState: { isSubmitting },
+ formState: { errors, isSubmitting },
} = useForm({
defaultValues,
});
@@ -99,16 +99,23 @@ export const CreateBlock: React.FC = ({ user }) => {
onSubmit={handleSubmit(createPageBlock)}
>
- (
+
+ )}
/>
diff --git a/web/components/pages/create-update-block-inline.tsx b/web/components/pages/create-update-block-inline.tsx
index 14e5c283e0d..3639b48191e 100644
--- a/web/components/pages/create-update-block-inline.tsx
+++ b/web/components/pages/create-update-block-inline.tsx
@@ -12,7 +12,7 @@ import useToast from "hooks/use-toast";
// components
import { GptAssistantModal } from "components/core";
import { TipTapEditor } from "components/tiptap";
-import { PrimaryButton, SecondaryButton, TextArea } from "components/ui";
+import { Button, TextArea } from "@plane/ui";
// types
import { ICurrentUserResponse, IPageBlock } from "types";
// fetch-keys
@@ -59,7 +59,7 @@ export const CreateUpdateBlockInline: React.FC = ({
setValue,
setFocus,
reset,
- formState: { isSubmitting },
+ formState: { errors, isSubmitting },
} = useForm({
defaultValues,
});
@@ -261,14 +261,22 @@ export const CreateUpdateBlockInline: React.FC = ({
>
- (
+
+ )}
/>
@@ -346,10 +354,12 @@ export const CreateUpdateBlockInline: React.FC
= ({
-
Cancel
-
+
+ Cancel
+
+
{data ? (isSubmitting ? "Updating..." : "Update block") : isSubmitting ? "Adding..." : "Add block"}
-
+
= ({ isOpen, s
- Cancel
-
+
+ Cancel
+
+
{isDeleteLoading ? "Deleting..." : "Delete"}
-
+
diff --git a/web/components/pages/page-form.tsx b/web/components/pages/page-form.tsx
index c4c669e1e71..160a0f4f0db 100644
--- a/web/components/pages/page-form.tsx
+++ b/web/components/pages/page-form.tsx
@@ -1,9 +1,9 @@
import { useEffect } from "react";
// react-hook-form
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// ui
-import { Input, Loader, PrimaryButton, SecondaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// types
import { IPage } from "types";
@@ -24,6 +24,7 @@ export const PageForm: React.FC = ({ handleFormSubmit, handleClose, statu
register,
formState: { errors, isSubmitting },
handleSubmit,
+ control,
reset,
} = useForm({
defaultValues,
@@ -47,34 +48,41 @@ export const PageForm: React.FC = ({ handleFormSubmit, handleClose, statu
return (
-
- {status ? "Update" : "Create"} Page
-
+
{status ? "Update" : "Create"} Page
-
Cancel
-
+
+ Cancel
+
+
{status
? isSubmitting
? "Updating Page..."
@@ -82,7 +90,7 @@ export const PageForm: React.FC = ({ handleFormSubmit, handleClose, statu
: isSubmitting
? "Creating Page..."
: "Create Page"}
-
+
);
diff --git a/web/components/pages/pages-list/recent-pages-list.tsx b/web/components/pages/pages-list/recent-pages-list.tsx
index 6ea8f9d010c..f302d607b23 100644
--- a/web/components/pages/pages-list/recent-pages-list.tsx
+++ b/web/components/pages/pages-list/recent-pages-list.tsx
@@ -9,7 +9,8 @@ import pagesService from "services/page.service";
// components
import { PagesView } from "components/pages";
// ui
-import { EmptyState, Loader } from "components/ui";
+import { EmptyState } from "components/ui";
+import { Loader } from "@plane/ui";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
// images
diff --git a/web/components/pages/pages-view.tsx b/web/components/pages/pages-view.tsx
index b7fc0249c51..ba385a3168e 100644
--- a/web/components/pages/pages-view.tsx
+++ b/web/components/pages/pages-view.tsx
@@ -12,7 +12,8 @@ import useUserAuth from "hooks/use-user-auth";
// components
import { CreateUpdatePageModal, DeletePageModal, SinglePageDetailedItem, SinglePageListItem } from "components/pages";
// ui
-import { EmptyState, Loader } from "components/ui";
+import { EmptyState } from "components/ui";
+import { Loader } from "@plane/ui";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
// images
diff --git a/web/components/pages/single-page-block.tsx b/web/components/pages/single-page-block.tsx
index 5d784d98a49..ac2ea925acd 100644
--- a/web/components/pages/single-page-block.tsx
+++ b/web/components/pages/single-page-block.tsx
@@ -21,7 +21,8 @@ import { GptAssistantModal } from "components/core";
import { CreateUpdateBlockInline } from "components/pages";
import { TipTapEditor } from "components/tiptap";
// ui
-import { CustomMenu, TextArea } from "components/ui";
+import { CustomMenu } from "components/ui";
+import { TextArea } from "@plane/ui";
// icons
import { LayerDiagonalIcon } from "components/icons";
import { ArrowPathIcon, LinkIcon } from "@heroicons/react/20/solid";
@@ -63,7 +64,14 @@ export const SinglePageBlock: React.FC = ({ block, projectDetails, showBl
const { setToastAlert } = useToast();
- const { handleSubmit, watch, reset, setValue, register } = useForm({
+ const {
+ handleSubmit,
+ watch,
+ reset,
+ setValue,
+ register,
+ formState: { errors, isSubmitting },
+ } = useForm({
defaultValues: {
name: "",
description: {},
@@ -414,10 +422,11 @@ export const SinglePageBlock: React.FC = ({ block, projectDetails, showBl
)}
diff --git a/web/components/profile/overview/activity.tsx b/web/components/profile/overview/activity.tsx
index 0458123632f..e2cc01c8f24 100644
--- a/web/components/profile/overview/activity.tsx
+++ b/web/components/profile/overview/activity.tsx
@@ -7,7 +7,8 @@ import userService from "services/user.service";
// components
import { ActivityMessage } from "components/core";
// ui
-import { ProfileEmptyState, Icon, Loader } from "components/ui";
+import { ProfileEmptyState, Icon } from "components/ui";
+import { Loader } from "@plane/ui";
// image
import recentActivityEmptyState from "public/empty-state/recent_activity.svg";
// helpers
@@ -20,9 +21,7 @@ export const ProfileActivity = () => {
const { workspaceSlug, userId } = router.query;
const { data: userProfileActivity } = useSWR(
- workspaceSlug && userId
- ? USER_PROFILE_ACTIVITY(workspaceSlug.toString(), userId.toString())
- : null,
+ workspaceSlug && userId ? USER_PROFILE_ACTIVITY(workspaceSlug.toString(), userId.toString()) : null,
workspaceSlug && userId
? () => userService.getUserProfileActivity(workspaceSlug.toString(), userId.toString())
: null
@@ -54,9 +53,7 @@ export const ProfileActivity = () => {
-
- {activity.actor_detail.display_name}{" "}
-
+ {activity.actor_detail.display_name}
{activity.field ? (
) : (
diff --git a/web/components/profile/overview/priority-distribution.tsx b/web/components/profile/overview/priority-distribution.tsx
index d72985285dd..de88cf5175f 100644
--- a/web/components/profile/overview/priority-distribution.tsx
+++ b/web/components/profile/overview/priority-distribution.tsx
@@ -1,5 +1,6 @@
// ui
-import { BarGraph, ProfileEmptyState, Loader } from "components/ui";
+import { BarGraph, ProfileEmptyState } from "components/ui";
+import { Loader } from "@plane/ui";
// image
import emptyBarGraph from "public/empty-state/empty_bar_graph.svg";
// helpers
diff --git a/web/components/profile/overview/stats.tsx b/web/components/profile/overview/stats.tsx
index 0277ac5b387..f6ec73778cd 100644
--- a/web/components/profile/overview/stats.tsx
+++ b/web/components/profile/overview/stats.tsx
@@ -2,7 +2,8 @@ import { useRouter } from "next/router";
import Link from "next/link";
// ui
-import { Icon, Loader } from "components/ui";
+import { Icon } from "components/ui";
+import { Loader } from "@plane/ui";
// types
import { IUserProfileData } from "types";
diff --git a/web/components/profile/profile-issues-view-options.tsx b/web/components/profile/profile-issues-view-options.tsx
index 2118c6eb955..56947a27464 100644
--- a/web/components/profile/profile-issues-view-options.tsx
+++ b/web/components/profile/profile-issues-view-options.tsx
@@ -10,7 +10,8 @@ import useEstimateOption from "hooks/use-estimate-option";
// components
import { MyIssuesSelectFilters } from "components/issues";
// ui
-import { CustomMenu, ToggleSwitch, Tooltip } from "components/ui";
+import { CustomMenu, Tooltip } from "components/ui";
+import { ToggleSwitch } from "@plane/ui";
// icons
import { ChevronDownIcon } from "@heroicons/react/24/outline";
import { FormatListBulletedOutlined, GridViewOutlined } from "@mui/icons-material";
diff --git a/web/components/profile/sidebar.tsx b/web/components/profile/sidebar.tsx
index 59cc5528bec..b61c20e369f 100644
--- a/web/components/profile/sidebar.tsx
+++ b/web/components/profile/sidebar.tsx
@@ -10,7 +10,8 @@ import userService from "services/user.service";
// hooks
import useUser from "hooks/use-user";
// ui
-import { Icon, Loader, Tooltip } from "components/ui";
+import { Icon, Tooltip } from "components/ui";
+import { Loader } from "@plane/ui";
// icons
import { EditOutlined } from "@mui/icons-material";
// helpers
@@ -26,12 +27,9 @@ export const ProfileSidebar = () => {
const { user } = useUser();
const { data: userProjectsData } = useSWR(
+ workspaceSlug && userId ? USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString()) : null,
workspaceSlug && userId
- ? USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString())
- : null,
- workspaceSlug && userId
- ? () =>
- userService.getUserProfileProjectsSegregation(workspaceSlug.toString(), userId.toString())
+ ? () => userService.getUserProfileProjectsSegregation(workspaceSlug.toString(), userId.toString())
: null
);
@@ -54,8 +52,7 @@ export const ProfileSidebar = () => {
label: "Timezone",
value: (
- {timeString}{" "}
- {userProjectsData?.user_data.user_timezone}
+ {timeString} {userProjectsData?.user_data.user_timezone}
),
},
@@ -81,8 +78,7 @@ export const ProfileSidebar = () => {
)}
{
{userProjectsData.user_data.first_name} {userProjectsData.user_data.last_name}
-
- ({userProjectsData.user_data.display_name})
-
+
({userProjectsData.user_data.display_name})
{userDetails.map((detail) => (
@@ -121,10 +115,7 @@ export const ProfileSidebar = () => {
{userProjectsData.project_data.map((project, index) => {
const totalIssues =
- project.created_issues +
- project.assigned_issues +
- project.pending_issues +
- project.completed_issues;
+ project.created_issues + project.assigned_issues + project.pending_issues + project.completed_issues;
const completedIssuePercentage =
project.assigned_issues === 0
@@ -132,11 +123,7 @@ export const ProfileSidebar = () => {
: Math.round((project.completed_issues / project.assigned_issues) * 100);
return (
-
+
{({ open }) => (
@@ -154,9 +141,7 @@ export const ProfileSidebar = () => {
{project?.name.charAt(0)}
)}
-
- {project.name}
-
+ {project.name}
{project.assigned_issues > 0 && (
diff --git a/web/components/project/card-list.tsx b/web/components/project/card-list.tsx
index 0aff18b3755..1c8e5958e49 100644
--- a/web/components/project/card-list.tsx
+++ b/web/components/project/card-list.tsx
@@ -4,7 +4,8 @@ import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { ProjectCard } from "components/project";
-import { Loader, EmptyState } from "components/ui";
+import { EmptyState } from "components/ui";
+import { Loader } from "@plane/ui";
// images
import emptyProject from "public/empty-state/project.svg";
// icons
diff --git a/web/components/project/confirm-project-member-remove.tsx b/web/components/project/confirm-project-member-remove.tsx
index 4edc278219c..772a3045e84 100644
--- a/web/components/project/confirm-project-member-remove.tsx
+++ b/web/components/project/confirm-project-member-remove.tsx
@@ -4,7 +4,7 @@ import { Dialog, Transition } from "@headlessui/react";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
-import { SecondaryButton, DangerButton } from "components/ui";
+import { Button } from "@plane/ui";
type Props = {
isOpen: boolean;
@@ -57,33 +57,29 @@ const ConfirmProjectMemberRemove: React.FC
= ({ isOpen, onClose, data, ha
-
+
-
+
Remove {data?.display_name}?
Are you sure you want to remove member-{" "}
- {data?.display_name} ? They will no
- longer have access to this project. This action cannot be undone.
+ {data?.display_name} ? They will no longer have access to
+ this project. This action cannot be undone.
- Cancel
-
+
+ Cancel
+
+
{isDeleteLoading ? "Removing..." : "Remove"}
-
+
diff --git a/web/components/project/create-project-modal.tsx b/web/components/project/create-project-modal.tsx
index f07e8193bfd..d80c25c576f 100644
--- a/web/components/project/create-project-modal.tsx
+++ b/web/components/project/create-project-modal.tsx
@@ -12,16 +12,8 @@ import useToast from "hooks/use-toast";
import { useWorkspaceMyMembership } from "contexts/workspace-member.context";
import useWorkspaceMembers from "hooks/use-workspace-members";
// ui
-import {
- Input,
- TextArea,
- CustomSelect,
- PrimaryButton,
- SecondaryButton,
- Icon,
- Avatar,
- CustomSearchSelect,
-} from "components/ui";
+import { CustomSelect, Icon, Avatar, CustomSearchSelect } from "components/ui";
+import { Button, Input, TextArea } from "@plane/ui";
// components
import { ImagePickerPopover } from "components/core";
import EmojiIconPicker from "components/emoji-icon-picker";
@@ -234,6 +226,7 @@ export const CreateProjectModal: React.FC = (props) => {
onChange={(image) => {
setValue("cover_image", image);
}}
+ control={control}
value={watch("cover_image")}
/>
@@ -259,36 +252,36 @@ export const CreateProjectModal: React.FC
= (props) => {
@@ -398,10 +411,12 @@ export const CreateProjectModal: React.FC
= (props) => {
-
Cancel
-
+
+ Cancel
+
+
{isSubmitting ? "Creating..." : "Create Project"}
-
+
diff --git a/web/components/project/delete-project-modal.tsx b/web/components/project/delete-project-modal.tsx
index 8d0833001aa..d2cfdc5b111 100644
--- a/web/components/project/delete-project-modal.tsx
+++ b/web/components/project/delete-project-modal.tsx
@@ -7,7 +7,7 @@ import useToast from "hooks/use-toast";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
-import { DangerButton, Input, SecondaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// types
import type { IProject } from "types";
// fetch-keys
@@ -36,7 +36,7 @@ export const DeleteProjectModal: React.FC = (props) => {
// form info
const {
control,
- formState: { isSubmitting },
+ formState: { errors, isSubmitting },
handleSubmit,
reset,
watch,
@@ -121,13 +121,17 @@ export const DeleteProjectModal: React.FC = (props) => {
(
+ render={({ field: { value, onChange, ref } }) => (
)}
/>
@@ -140,22 +144,28 @@ export const DeleteProjectModal: React.FC = (props) => {
(
+ render={({ field: { value, onChange, ref } }) => (
)}
/>
- Cancel
-
+
+ Cancel
+
+
{isSubmitting ? "Deleting..." : "Delete Project"}
-
+
diff --git a/web/components/project/form-loader.tsx b/web/components/project/form-loader.tsx
index 325807b83a6..039cdd25f6f 100644
--- a/web/components/project/form-loader.tsx
+++ b/web/components/project/form-loader.tsx
@@ -1,6 +1,6 @@
import { FC } from "react";
// components
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
export interface IProjectDetailsFormLoader {}
diff --git a/web/components/project/form.tsx b/web/components/project/form.tsx
index ae154a59cad..d581a01e867 100644
--- a/web/components/project/form.tsx
+++ b/web/components/project/form.tsx
@@ -3,8 +3,8 @@ import { Controller, useForm } from "react-hook-form";
// components
import EmojiIconPicker from "components/emoji-icon-picker";
import { ImagePickerPopover } from "components/core";
-import { Input, TextArea, CustomSelect, PrimaryButton } from "components/ui";
-import { Input as InputElement } from "@plane/ui";
+import { CustomSelect } from "components/ui";
+import { Button, Input, TextArea } from "@plane/ui";
// types
import { IProject, IWorkspace } from "types";
// helpers
@@ -147,7 +147,13 @@ export const ProjectDetailsForm: FC
= (props) => {
control={control}
name="cover_image"
render={({ field: { value, onChange } }) => (
-
+
)}
/>
@@ -164,7 +170,7 @@ export const ProjectDetailsForm: FC = (props) => {
required: "Name is required",
}}
render={({ field: { value, onChange, ref } }) => (
- = (props) => {
Description
- (
+
+ )}
/>
Identifier
- /^[A-Z0-9]+$/.test(value.toUpperCase()) || "Identifier must be in uppercase.",
minLength: {
@@ -216,7 +224,20 @@ export const ProjectDetailsForm: FC = (props) => {
message: "Identifier must at most be of 5 characters",
},
}}
- disabled={!isAdmin}
+ render={({ field: { value, ref } }) => (
+
+ )}
/>
@@ -248,9 +269,9 @@ export const ProjectDetailsForm: FC
= (props) => {
<>
-
+
{isSubmitting ? "Updating Project..." : "Update Project"}
-
+
Created on {renderShortDateWithYearFormat(project?.created_at)}
diff --git a/web/components/project/join-project-modal.tsx b/web/components/project/join-project-modal.tsx
index 984fafa85ec..ef6874db928 100644
--- a/web/components/project/join-project-modal.tsx
+++ b/web/components/project/join-project-modal.tsx
@@ -1,7 +1,7 @@
import { useState, Fragment } from "react";
import { Transition, Dialog } from "@headlessui/react";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
import type { IProject } from "types";
// lib
@@ -73,10 +73,12 @@ export const JoinProjectModal: React.FC
= (props) => {
-
Cancel
-
+
+ Cancel
+
+
{isJoiningLoading ? "Joining..." : "Join Project"}
-
+
diff --git a/web/components/project/leave-project-modal.tsx b/web/components/project/leave-project-modal.tsx
index 90da32d74a3..584ad9d5b78 100644
--- a/web/components/project/leave-project-modal.tsx
+++ b/web/components/project/leave-project-modal.tsx
@@ -5,7 +5,7 @@ import { Dialog, Transition } from "@headlessui/react";
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
import { observer } from "mobx-react-lite";
// ui
-import { DangerButton, Input, SecondaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// fetch-keys
import { PROJECTS_LIST } from "constants/fetch-keys";
// mobx react lite
@@ -51,7 +51,7 @@ export const LeaveProjectModal: FC = observer((props) => {
const {
control,
- formState: { isSubmitting },
+ formState: { errors, isSubmitting },
handleSubmit,
reset,
} = useForm({ defaultValues });
@@ -155,13 +155,20 @@ export const LeaveProjectModal: FC = observer((props) => {
(
+ rules={{
+ required: "Label title is required",
+ }}
+ render={({ field: { value, onChange, ref } }) => (
)}
/>
@@ -174,22 +181,28 @@ export const LeaveProjectModal: FC = observer((props) => {
(
+ render={({ field: { value, onChange, ref } }) => (
)}
/>
- Cancel
-
+
+ Cancel
+
+
{isSubmitting ? "Leaving..." : "Leave Project"}
-
+
diff --git a/web/components/project/publish-project/modal.tsx b/web/components/project/publish-project/modal.tsx
index 51ad8c9aa6b..7a16da91d0f 100644
--- a/web/components/project/publish-project/modal.tsx
+++ b/web/components/project/publish-project/modal.tsx
@@ -6,7 +6,8 @@ import { Controller, useForm } from "react-hook-form";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// ui components
-import { ToggleSwitch, PrimaryButton, SecondaryButton, Icon, DangerButton, Loader } from "components/ui";
+import { Button, Loader, ToggleSwitch } from "@plane/ui";
+import { Icon } from "components/ui";
import { CustomPopover } from "./popover";
// mobx react lite
import { observer } from "mobx-react-lite";
@@ -306,13 +307,13 @@ export const PublishProjectModal: React.FC = observer(() => {
Publish
{projectPublish.projectPublishSettings !== "not-initialized" && (
- handleUnpublishProject(watch("id") ?? "")}
- className="!px-2 !py-1.5"
loading={isUnpublishing}
>
{isUnpublishing ? "Unpublishing..." : "Unpublish"}
-
+
)}
@@ -475,19 +476,21 @@ export const PublishProjectModal: React.FC = observer(() => {
{!projectPublish.fetchSettingsLoader && (
-
Cancel
+
+ Cancel
+
{watch("id") ? (
<>
{isUpdateRequired && (
-
+
{isSubmitting ? "Updating..." : "Update settings"}
-
+
)}
>
) : (
-
+
{isSubmitting ? "Publishing..." : "Publish"}
-
+
)}
)}
diff --git a/web/components/project/send-project-invitation-modal.tsx b/web/components/project/send-project-invitation-modal.tsx
index 07b90840c86..1ffb2bf7cbf 100644
--- a/web/components/project/send-project-invitation-modal.tsx
+++ b/web/components/project/send-project-invitation-modal.tsx
@@ -8,13 +8,8 @@ import { useForm, Controller, useFieldArray } from "react-hook-form";
import { Dialog, Transition } from "@headlessui/react";
// ui
-import {
- Avatar,
- CustomSearchSelect,
- CustomSelect,
- PrimaryButton,
- SecondaryButton,
-} from "components/ui";
+import { Button } from "@plane/ui";
+import { Avatar, CustomSearchSelect, CustomSelect } from "components/ui";
//icons
import { PlusIcon, XMarkIcon } from "@heroicons/react/24/outline";
import { ChevronDownIcon } from "@heroicons/react/20/solid";
@@ -178,24 +173,16 @@ const SendProjectInvitationModal: React.FC = (props) => {
-
+
Invite Members
-
- Invite members to work on your project.
-
+
Invite members to work on your project.
{fields.map((field, index) => (
-
+
= (props) => {
{value && value !== "" ? (
-
p.member.id === value)?.member
- }
- />
- {
- people?.find((p) => p.member.id === value)?.member
- .display_name
- }
+ p.member.id === value)?.member} />
+ {people?.find((p) => p.member.id === value)?.member.display_name}
) : (
-
- Select co-worker
-
+ Select co-worker
)}
@@ -307,14 +285,14 @@ const SendProjectInvitationModal: React.FC = (props) => {
Add more
-
Cancel
-
+
+ Cancel
+
+
{isSubmitting
- ? `${
- fields && fields.length > 1 ? "Adding Members..." : "Adding Member..."
- }`
+ ? `${fields && fields.length > 1 ? "Adding Members..." : "Adding Member..."}`
: `${fields && fields.length > 1 ? "Add Members" : "Add Member"}`}
-
+
diff --git a/web/components/project/settings/single-label.tsx b/web/components/project/settings/single-label.tsx
index f6ed8be3b2d..6b0c58afbca 100644
--- a/web/components/project/settings/single-label.tsx
+++ b/web/components/project/settings/single-label.tsx
@@ -7,7 +7,8 @@ import { TwitterPicker } from "react-color";
// headless ui
import { Popover, Transition } from "@headlessui/react";
// ui
-import { CustomMenu, Input, PrimaryButton, SecondaryButton } from "components/ui";
+import { CustomMenu } from "components/ui";
+import { Button, Input } from "@plane/ui";
// icons
import { PencilIcon, RectangleGroupIcon } from "@heroicons/react/24/outline";
// types
@@ -54,9 +55,7 @@ const SingleLabel: React.FC
= ({ label, issueLabels, editLabel, handleLab
{/* Convert to group */}
editLabel(label)}>Edit
- handleLabelDelete(label.id)}>
- Delete
-
+ handleLabelDelete(label.id)}>Delete
@@ -93,10 +92,7 @@ const SingleLabel: React.FC
= ({ label, issueLabels, editLabel, handleLab
name="color"
control={control}
render={({ field: { value, onChange } }) => (
- onChange(value.hex)}
- />
+ onChange(value.hex)} />
)}
/>
@@ -106,20 +102,33 @@ const SingleLabel: React.FC = ({ label, issueLabels, editLabel, handleLab
- (
+
+ )}
/>
-
setNewLabelForm(false)}>Cancel
-
{isSubmitting ? "Adding" : "Add"}
+
setNewLabelForm(false)}>
+ Cancel
+
+
+ {isSubmitting ? "Adding" : "Add"}
+
) : (
diff --git a/web/components/states/create-state-modal.tsx b/web/components/states/create-state-modal.tsx
index 171f4f17e42..de109b9987e 100644
--- a/web/components/states/create-state-modal.tsx
+++ b/web/components/states/create-state-modal.tsx
@@ -15,7 +15,8 @@ import stateService from "services/project_state.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { CustomSelect, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
+import { CustomSelect } from "components/ui";
+import { Button, Input, TextArea } from "@plane/ui";
// icons
import { ChevronDownIcon } from "@heroicons/react/24/outline";
// types
@@ -136,18 +137,30 @@ export const CreateStateModal: React.FC = ({ isOpen, projectId, handleClo
-
Cancel
-
+
+ Cancel
+
+
{isSubmitting ? "Creating State..." : "Create State"}
-
+
diff --git a/web/components/states/create-update-state-inline.tsx b/web/components/states/create-update-state-inline.tsx
index 3cd5bfb8d40..46d8a068c43 100644
--- a/web/components/states/create-update-state-inline.tsx
+++ b/web/components/states/create-update-state-inline.tsx
@@ -15,7 +15,8 @@ import stateService from "services/project_state.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { CustomSelect, Input, PrimaryButton, SecondaryButton, Tooltip } from "components/ui";
+import { CustomSelect, Tooltip } from "components/ui";
+import { Button, Input } from "@plane/ui";
// types
import type { ICurrentUserResponse, IState, IStateResponse } from "types";
// fetch-keys
@@ -206,17 +207,25 @@ export const CreateUpdateStateInline: React.FC = ({ data, onClose, select
)}
-
(
+
+ )}
/>
{data && (
= ({ data, onClose, select
)}
/>
)}
- (
+
+ )}
/>
- Cancel
-
+
+ Cancel
+
+
{isSubmitting ? (data ? "Updating..." : "Creating...") : data ? "Update" : "Create"}
-
+
);
};
diff --git a/web/components/states/delete-state-modal.tsx b/web/components/states/delete-state-modal.tsx
index 580d42bdc34..7d089319351 100644
--- a/web/components/states/delete-state-modal.tsx
+++ b/web/components/states/delete-state-modal.tsx
@@ -13,7 +13,7 @@ import stateServices from "services/project_state.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { DangerButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// types
import type { ICurrentUserResponse, IState, IStateResponse } from "types";
// fetch-keys
@@ -129,10 +129,12 @@ export const DeleteStateModal: React.FC = ({ isOpen, onClose, data, user
- Cancel
-
+
+ Cancel
+
+
{isDeleteLoading ? "Deleting..." : "Delete"}
-
+
diff --git a/web/components/ui/index.ts b/web/components/ui/index.ts
index b77ee2615e0..3f981553354 100644
--- a/web/components/ui/index.ts
+++ b/web/components/ui/index.ts
@@ -19,6 +19,7 @@ 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";
diff --git a/web/components/ui/product-updates-modal.tsx b/web/components/ui/product-updates-modal.tsx
new file mode 100644
index 00000000000..4f5bad7b3f1
--- /dev/null
+++ b/web/components/ui/product-updates-modal.tsx
@@ -0,0 +1,113 @@
+import React from "react";
+
+import useSWR from "swr";
+
+// headless ui
+import { Dialog, Transition } from "@headlessui/react";
+// services
+import workspaceService from "services/workspace.service";
+// components
+import { Loader, MarkdownRenderer } from "components/ui";
+// icons
+import { XMarkIcon } from "@heroicons/react/20/solid";
+// helpers
+import { renderLongDateFormat } from "helpers/date-time.helper";
+
+type Props = {
+ isOpen: boolean;
+ setIsOpen: React.Dispatch>;
+};
+
+export const ProductUpdatesModal: React.FC = ({ isOpen, setIsOpen }) => {
+ const { data: updates } = useSWR("PRODUCT_UPDATES", () => workspaceService.getProductUpdates());
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ Product Updates
+
+ setIsOpen(false)}>
+
+
+
+
+ {updates && updates.length > 0 ? (
+
+ {updates.map((item, index) => (
+
+
+
+ {item.tag_name}
+
+ {renderLongDateFormat(item.published_at)}
+ {index === 0 && (
+
+ New
+
+ )}
+
+
+
+ ))}
+
+ ) : (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+
+
+
+
+ );
+};
diff --git a/web/components/ui/tooltip.tsx b/web/components/ui/tooltip.tsx
index 0f9163521a4..3a4c5d71fef 100644
--- a/web/components/ui/tooltip.tsx
+++ b/web/components/ui/tooltip.tsx
@@ -51,11 +51,17 @@ export const Tooltip: React.FC = ({
content={
{tooltipHeading && (
-
+
{tooltipHeading}
)}
diff --git a/web/components/web-view/add-comment.tsx b/web/components/web-view/add-comment.tsx
index b4f49d7beb0..7111a128178 100644
--- a/web/components/web-view/add-comment.tsx
+++ b/web/components/web-view/add-comment.tsx
@@ -16,10 +16,11 @@ import { TipTapEditor } from "components/tiptap";
import { Send } from "lucide-react";
// ui
-import { Icon, SecondaryButton, Tooltip, PrimaryButton } from "components/ui";
+import { Icon, Tooltip } from "components/ui";
// types
import type { IIssueComment } from "types";
+import { Button } from "@plane/ui";
const defaultValues: Partial = {
access: "INTERNAL",
@@ -120,13 +121,9 @@ export const AddComment: React.FC = ({ disabled = false, onSubmit }) => {
);
diff --git a/web/components/web-view/create-update-link-form.tsx b/web/components/web-view/create-update-link-form.tsx
index 692ffb9c9e2..fb356758d45 100644
--- a/web/components/web-view/create-update-link-form.tsx
+++ b/web/components/web-view/create-update-link-form.tsx
@@ -8,7 +8,7 @@ import { useRouter } from "next/router";
import { mutate } from "swr";
// react hooks form
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// services
import issuesService from "services/issue.service";
@@ -20,10 +20,10 @@ import { ISSUE_DETAILS } from "constants/fetch-keys";
import useToast from "hooks/use-toast";
// ui
-import { PrimaryButton, Input } from "components/ui";
+import { Button, Input } from "@plane/ui";
// types
-import type { linkDetails, IIssueLink } from "types";
+import type { linkDetails, IIssueLink, IIssue } from "types";
type Props = {
isOpen: boolean;
@@ -43,6 +43,7 @@ export const CreateUpdateLinkForm: React.FC = (props) => {
const {
register,
handleSubmit,
+ control,
reset,
formState: { errors, isSubmitting },
} = useForm({
@@ -122,43 +123,63 @@ export const CreateUpdateLinkForm: React.FC = (props) => {
-
+
{data ? (isSubmitting ? "Updating Link..." : "Update Link") : isSubmitting ? "Adding Link..." : "Add Link"}
-
+
);
diff --git a/web/components/web-view/issue-link-list.tsx b/web/components/web-view/issue-link-list.tsx
index 5df652300df..746ea7eb6c6 100644
--- a/web/components/web-view/issue-link-list.tsx
+++ b/web/components/web-view/issue-link-list.tsx
@@ -19,7 +19,7 @@ import { Link as LinkIcon, Plus, Pencil, X } from "lucide-react";
import { Label, WebViewModal, CreateUpdateLinkForm } from "components/web-view";
// ui
-import { SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// fetch keys
import { ISSUE_DETAILS } from "constants/fetch-keys";
@@ -123,15 +123,9 @@ export const IssueLinks: React.FC = (props) => {
)}
))}
- setIsOpen(true)}
- className="w-full !py-2 text-custom-text-300 !text-base flex items-center justify-center"
- >
-
- Add
-
+ } disabled={!allowed} onClick={() => setIsOpen(true)}>
+ Add
+
);
diff --git a/web/components/web-view/issue-properties-detail.tsx b/web/components/web-view/issue-properties-detail.tsx
index 65a2eb173bb..27457333b6e 100644
--- a/web/components/web-view/issue-properties-detail.tsx
+++ b/web/components/web-view/issue-properties-detail.tsx
@@ -27,7 +27,8 @@ import { ChevronDown, PlayIcon, User, X, CalendarDays, LayoutGrid, Users } from
import useEstimateOption from "hooks/use-estimate-option";
// ui
-import { SecondaryButton, CustomDatePicker } from "components/ui";
+import { Button } from "@plane/ui";
+import { CustomDatePicker } from "components/ui";
// components
import {
@@ -391,14 +392,13 @@ export const IssuePropertiesDetail: React.FC = (props) => {
>
)}
- }
onClick={() => setIsViewAllOpen((prev) => !prev)}
- className="w-full flex justify-center items-center gap-1 !py-2"
>
- {isViewAllOpen ? "View less" : "View all"}
-
-
+ {isViewAllOpen ? "View less" : "View all"}
+
);
diff --git a/web/components/web-view/issue-web-view-form.tsx b/web/components/web-view/issue-web-view-form.tsx
index ff9383fd0af..a9c837132ac 100644
--- a/web/components/web-view/issue-web-view-form.tsx
+++ b/web/components/web-view/issue-web-view-form.tsx
@@ -13,7 +13,7 @@ import { useDebouncedCallback } from "use-debounce";
import useReloadConfirmations from "hooks/use-reload-confirmation";
// ui
-import { TextArea } from "components/ui";
+import { TextArea } from "@plane/ui";
// components
import { TipTapEditor } from "components/tiptap";
@@ -78,32 +78,34 @@ export const IssueWebViewForm: React.FC = (props) => {
Title
{isAllowed ? (
-
setCharacterLimit(true)}
- onChange={(e) => {
- setCharacterLimit(false);
- setIsSubmitting("submitting");
- debouncedTitleSave();
- }}
- required={true}
- className="min-h-10 block w-full resize-none overflow-hidden rounded border bg-transparent px-3 py-2 text-xl outline-none ring-0 focus:ring-1 focus:ring-custom-primary"
- role="textbox"
- disabled={!isAllowed}
+ control={control}
+ render={({ field: { value, onChange } }) => (
+ setCharacterLimit(true)}
+ onChange={() => {
+ setCharacterLimit(false);
+ setIsSubmitting("submitting");
+ debouncedTitleSave();
+ }}
+ required={true}
+ className="min-h-10 block w-full resize-none overflow-hidden rounded border bg-transparent px-3 py-2 text-xl outline-none ring-0 focus:ring-1 focus:ring-custom-primary"
+ role="textbox"
+ disabled={!isAllowed}
+ />
+ )}
/>
) : (
{issueDetails?.name}
)}
{characterLimit && isAllowed && (
-
255 ? "text-red-500" : ""
- }`}
- >
+ 255 ? "text-red-500" : ""}`}>
{watch("name").length}
/255
@@ -123,9 +125,7 @@ export const IssueWebViewForm: React.FC = (props) => {
return (
"
: value
}
@@ -133,17 +133,13 @@ export const IssueWebViewForm: React.FC = (props) => {
debouncedUpdatesEnabled={true}
setShouldShowAlert={setShowAlert}
setIsSubmitting={setIsSubmitting}
- customClassName={
- isAllowed ? "min-h-[150px] shadow-sm" : "!p-0 !pt-2 text-custom-text-200"
- }
+ customClassName={isAllowed ? "min-h-[150px] shadow-sm" : "!p-0 !pt-2 text-custom-text-200"}
noBorder={!isAllowed}
onChange={(description: Object, description_html: string) => {
setShowAlert(true);
setIsSubmitting("submitting");
onChange(description_html);
- handleSubmit(handleDescriptionFormSubmit)().finally(() =>
- setIsSubmitting("submitted")
- );
+ handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted"));
}}
editable={isAllowed}
/>
diff --git a/web/components/web-view/sub-issues.tsx b/web/components/web-view/sub-issues.tsx
index a4e1809716c..8d44fd814b8 100644
--- a/web/components/web-view/sub-issues.tsx
+++ b/web/components/web-view/sub-issues.tsx
@@ -20,7 +20,7 @@ import { SUB_ISSUES } from "constants/fetch-keys";
import useUser from "hooks/use-user";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
import { IIssue } from "types";
// components
diff --git a/web/components/workspace/confirm-workspace-member-remove.tsx b/web/components/workspace/confirm-workspace-member-remove.tsx
index 9ca80c3dc67..aa2f4cd4dc1 100644
--- a/web/components/workspace/confirm-workspace-member-remove.tsx
+++ b/web/components/workspace/confirm-workspace-member-remove.tsx
@@ -4,7 +4,7 @@ import { Dialog, Transition } from "@headlessui/react";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
-import { DangerButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
type Props = {
isOpen: boolean;
@@ -57,33 +57,29 @@ const ConfirmWorkspaceMemberRemove: React.FC = ({ isOpen, onClose, data,
-
+
-
+
Remove {data?.display_name}?
Are you sure you want to remove member-{" "}
- {data?.display_name} ? They will no
- longer have access to this workspace. This action cannot be undone.
+ {data?.display_name} ? They will no longer have access to
+ this workspace. This action cannot be undone.
- Cancel
-
+
+ Cancel
+
+
{isDeleteLoading ? "Removing..." : "Remove"}
-
+
diff --git a/web/components/workspace/create-workspace-form.tsx b/web/components/workspace/create-workspace-form.tsx
index c7eb584b9ab..27e00245c77 100644
--- a/web/components/workspace/create-workspace-form.tsx
+++ b/web/components/workspace/create-workspace-form.tsx
@@ -9,7 +9,8 @@ import workspaceService from "services/workspace.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { CustomSelect, Input, PrimaryButton } from "components/ui";
+import { CustomSelect } from "components/ui";
+import { Button, Input } from "@plane/ui";
// types
import { ICurrentUserResponse, IWorkspace } from "types";
// fetch-keys
@@ -90,11 +91,7 @@ export const CreateWorkspaceForm: React.FC = ({
message: "Workspace created successfully.",
});
- mutate(
- USER_WORKSPACES,
- (prevData) => [res, ...(prevData ?? [])],
- false
- );
+ mutate(USER_WORKSPACES, (prevData) => [res, ...(prevData ?? [])], false);
if (onSubmit) await onSubmit(res);
})
.catch(() =>
@@ -128,54 +125,61 @@ export const CreateWorkspaceForm: React.FC = ({
Workspace Name
-
- setValue("slug", e.target.value.toLocaleLowerCase().trim().replace(/ /g, "-"))
- }
- validations={{
+ rules={{
required: "Workspace name is required",
validate: (value) =>
- /^[\w\s-]*$/.test(value) ||
- `Name can only contain (" "), ( - ), ( _ ) & alphanumeric characters.`,
+ /^[\w\s-]*$/.test(value) || `Name can only contain (" "), ( - ), ( _ ) & alphanumeric characters.`,
maxLength: {
value: 80,
message: "Workspace name should not exceed 80 characters",
},
}}
- placeholder="Enter workspace name..."
- error={errors.name}
+ render={({ field: { value, ref } }) => (
+ setValue("slug", e.target.value.toLocaleLowerCase().trim().replace(/ /g, "-"))}
+ ref={ref}
+ hasError={Boolean(errors.name)}
+ placeholder="Enter workspace name..."
+ className="w-full"
+ />
+ )}
/>
Workspace URL
-
- {window && window.location.host}/
-
- {window && window.location.host}/
+
- /^[a-zA-Z0-9_-]+$/.test(e.target.value)
- ? setInvalidSlug(false)
- : setInvalidSlug(true)
- }
+ render={({ field: { value, ref } }) => (
+
+ /^[a-zA-Z0-9_-]+$/.test(e.target.value) ? setInvalidSlug(false) : setInvalidSlug(true)
+ }
+ ref={ref}
+ hasError={Boolean(errors.slug)}
+ placeholder="Enter workspace name..."
+ className="block rounded-md bg-transparent py-2 !px-0 text-sm w-full"
+ />
+ )}
/>
- {slugError && (
-
Workspace URL is already taken!
- )}
+ {slugError &&
Workspace URL is already taken! }
{invalidSlug && (
{`URL can only contain ( - ), ( _ ) & alphanumeric characters.`}
)}
@@ -216,9 +220,9 @@ export const CreateWorkspaceForm: React.FC
= ({
{secondaryButton}
-
+
{isSubmitting ? primaryButtonText.loading : primaryButtonText.default}
-
+
);
diff --git a/web/components/workspace/delete-workspace-modal.tsx b/web/components/workspace/delete-workspace-modal.tsx
index 80cf08cd140..3e18d7575e4 100644
--- a/web/components/workspace/delete-workspace-modal.tsx
+++ b/web/components/workspace/delete-workspace-modal.tsx
@@ -15,7 +15,7 @@ import useToast from "hooks/use-toast";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
-import { DangerButton, Input, SecondaryButton } from "components/ui";
+import { Button, Input } from "@plane/ui";
// types
import type { ICurrentUserResponse, IWorkspace } from "types";
// fetch-keys
@@ -40,14 +40,13 @@ export const DeleteWorkspaceModal: React.FC = ({ isOpen, data, onClose, u
const {
control,
- formState: { isSubmitting },
+ formState: { errors, isSubmitting },
handleSubmit,
reset,
watch,
} = useForm({ defaultValues });
- const canDelete =
- watch("workspaceName") === data?.name && watch("confirmDelete") === "delete my workspace";
+ const canDelete = watch("workspaceName") === data?.name && watch("confirmDelete") === "delete my workspace";
const handleClose = () => {
const timer = setTimeout(() => {
@@ -68,10 +67,7 @@ export const DeleteWorkspaceModal: React.FC = ({ isOpen, data, onClose, u
router.push("/");
- mutate(
- USER_WORKSPACES,
- (prevData) => prevData?.filter((workspace) => workspace.id !== data.id)
- );
+ mutate(USER_WORKSPACES, (prevData) => prevData?.filter((workspace) => workspace.id !== data.id));
setToastAlert({
type: "success",
@@ -118,10 +114,7 @@ export const DeleteWorkspaceModal: React.FC = ({ isOpen, data, onClose, u
-
+
Delete Workspace
@@ -131,28 +124,30 @@ export const DeleteWorkspaceModal: React.FC = ({ isOpen, data, onClose, u
Are you sure you want to delete workspace{" "}
- {data?.name} ? All of the
- data related to the workspace will be permanently removed. This action cannot
- be undone.
+ {data?.name} ? All of the data related to the
+ workspace will be permanently removed. This action cannot be undone.
- Enter the workspace name{" "}
- {data?.name} to
+ Enter the workspace name {data?.name} to
continue:
(
+ render={({ field: { value, onChange, ref } }) => (
)}
/>
@@ -160,30 +155,35 @@ export const DeleteWorkspaceModal: React.FC = ({ isOpen, data, onClose, u
- Cancel
-
+
+ Cancel
+
+
{isSubmitting ? "Deleting..." : "Delete Workspace"}
-
+
diff --git a/web/components/workspace/issues-list.tsx b/web/components/workspace/issues-list.tsx
index 0cb8416c04b..a27951280e4 100644
--- a/web/components/workspace/issues-list.tsx
+++ b/web/components/workspace/issues-list.tsx
@@ -8,7 +8,7 @@ import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
import { truncateText } from "helpers/string.helper";
// types
import { IIssueLite } from "types";
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
import { LayerDiagonalIcon } from "components/icons";
type Props = {
@@ -55,24 +55,15 @@ export const IssuesList: React.FC = ({ issues, type }) => {
const dateDifference = getDateDifference(new Date(date as string));
return (
-
+
6
- ? "text-red-500"
- : "text-yellow-400"
- : ""
+ type === "overdue" ? (dateDifference > 6 ? "text-red-500" : "text-yellow-400") : ""
}`}
>
- {type === "overdue" && (
-
- )}
+ {type === "overdue" && }
{dateDifference} {dateDifference > 1 ? "days" : "day"}
{truncateText(issue.name, 30)}
@@ -89,8 +80,7 @@ export const IssuesList: React.FC
= ({ issues, type }) => {
- No issues found. Use{" "}
- C {" "}
+ No issues found. Use C {" "}
shortcut to create a new issue
diff --git a/web/components/workspace/issues-stats.tsx b/web/components/workspace/issues-stats.tsx
index 2c874d5033b..76e6a197053 100644
--- a/web/components/workspace/issues-stats.tsx
+++ b/web/components/workspace/issues-stats.tsx
@@ -1,7 +1,8 @@
// components
import { ActivityGraph } from "components/workspace";
// ui
-import { Loader, Tooltip } from "components/ui";
+import { Tooltip } from "components/ui";
+import { Loader } from "@plane/ui";
// icons
import { InformationCircleIcon } from "@heroicons/react/24/outline";
// types
@@ -23,10 +24,7 @@ export const IssuesStats: React.FC = ({ data }) => {
Issues assigned to you
{data ? (
- router.push(`/${workspaceSlug}/me/my-issues`)}
- >
+
router.push(`/${workspaceSlug}/me/my-issues`)}>
{data.assigned_issues_count}
) : (
diff --git a/web/components/workspace/send-workspace-invitation-modal.tsx b/web/components/workspace/send-workspace-invitation-modal.tsx
index c9d090405a3..c243fd1c911 100644
--- a/web/components/workspace/send-workspace-invitation-modal.tsx
+++ b/web/components/workspace/send-workspace-invitation-modal.tsx
@@ -11,7 +11,8 @@ import workspaceService from "services/workspace.service";
// hooks
import useToast from "hooks/use-toast";
// ui
-import { CustomSelect, Input, PrimaryButton, SecondaryButton } from "components/ui";
+import { CustomSelect } from "components/ui";
+import { Button, Input } from "@plane/ui";
// icons
import { PlusIcon, XMarkIcon } from "@heroicons/react/24/outline";
// types
@@ -145,16 +146,11 @@ const SendWorkspaceInvitationModal: React.FC
= (props) => {
}}
>
-
+
Invite people to collaborate
-
- Invite members to work on your workspace.
-
+
Invite members to work on your workspace.
@@ -171,12 +167,18 @@ const SendWorkspaceInvitationModal: React.FC
= (props) => {
message: "Invalid Email ID",
},
}}
- render={({ field }) => (
+ render={({ field: { value, onChange, ref } }) => (
<>
{errors.emails?.[index]?.email && (
@@ -233,10 +235,12 @@ const SendWorkspaceInvitationModal: React.FC = (props) => {
Add more
-
Cancel
-
+
+ Cancel
+
+
{isSubmitting ? "Sending Invitation..." : "Send Invitation"}
-
+
diff --git a/web/components/workspace/sidebar-dropdown.tsx b/web/components/workspace/sidebar-dropdown.tsx
index f3bbc029b6d..8d9ae1ff6c0 100644
--- a/web/components/workspace/sidebar-dropdown.tsx
+++ b/web/components/workspace/sidebar-dropdown.tsx
@@ -14,7 +14,8 @@ import useToast from "hooks/use-toast";
import userService from "services/user.service";
import authenticationService from "services/authentication.service";
// components
-import { Avatar, Icon, Loader } from "components/ui";
+import { Avatar, Icon } from "components/ui";
+import { Loader } from "@plane/ui";
// icons
import { CheckIcon, PlusIcon } from "@heroicons/react/24/outline";
// helpers
@@ -171,9 +172,7 @@ export const WorkspaceSidebarDropdown = () => {
{truncateText(workspace.name, 18)}
@@ -261,18 +260,16 @@ export const WorkspaceSidebarDropdown = () => {
>
{user?.email}
- {profileLinks(workspaceSlug?.toString() ?? "", user?.id ?? "").map(
- (link, index) => (
-
-
-
-
- {link.name}
-
-
-
- )
- )}
+ {profileLinks(workspaceSlug?.toString() ?? "", user?.id ?? "").map((link, index) => (
+
+
+
+
+ {link.name}
+
+
+
+ ))}
= observer((props) => {
- Cancel
-
+
+ Cancel
+
+
{isDeleteLoading ? "Deleting..." : "Delete"}
-
+
diff --git a/web/components/workspace/views/form.tsx b/web/components/workspace/views/form.tsx
index 8af899e5230..61d899d358e 100644
--- a/web/components/workspace/views/form.tsx
+++ b/web/components/workspace/views/form.tsx
@@ -8,7 +8,9 @@ import { useMobxStore } from "lib/mobx/store-provider";
// components
import { AppliedFiltersList, FilterSelection, FiltersDropdown } from "components/issues";
// ui
-import { Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
+import { Button, Input, TextArea } from "@plane/ui";
+// helpers
+import { checkIfArraysHaveSameElements } from "helpers/array.helper";
// types
import { IWorkspaceView } from "types";
// constants
@@ -35,9 +37,9 @@ export const WorkspaceViewForm: React.FC = observer((props) => {
const { workspace: workspaceStore, project: projectStore } = useMobxStore();
const {
- control,
formState: { errors, isSubmitting },
handleSubmit,
+ control,
register,
reset,
setValue,
@@ -76,32 +78,46 @@ export const WorkspaceViewForm: React.FC = observer((props) => {
{data ? "Update" : "Create"} View
-
Cancel
-
+
+ Cancel
+
+
{data
? isSubmitting
? "Updating View..."
@@ -161,7 +179,7 @@ export const WorkspaceViewForm: React.FC = observer((props) => {
: isSubmitting
? "Creating View..."
: "Create View"}
-
+
);
diff --git a/web/components/workspace/views/views-list.tsx b/web/components/workspace/views/views-list.tsx
index ccfeba75b80..5a06293052a 100644
--- a/web/components/workspace/views/views-list.tsx
+++ b/web/components/workspace/views/views-list.tsx
@@ -5,7 +5,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
// components
import { GlobalViewListItem } from "components/workspace";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
type Props = {
searchQuery: string;
diff --git a/web/layouts/auth-layout-legacy/project-authorization-wrapper.tsx b/web/layouts/auth-layout-legacy/project-authorization-wrapper.tsx
index 85191fdd522..98ee0d668f2 100644
--- a/web/layouts/auth-layout-legacy/project-authorization-wrapper.tsx
+++ b/web/layouts/auth-layout-legacy/project-authorization-wrapper.tsx
@@ -13,7 +13,8 @@ import AppSidebar from "layouts/app-layout-legacy/app-sidebar";
import { NotAuthorizedView, JoinProject } from "components/auth-screens";
import { CommandPalette } from "components/command-palette";
// ui
-import { EmptyState, PrimaryButton, Spinner } from "components/ui";
+import { Button, Spinner } from "@plane/ui";
+import { EmptyState } from "components/ui";
// icons
import { LayerDiagonalIcon } from "components/icons";
// images
@@ -90,9 +91,9 @@ const ProjectAuthorizationWrapped: React.FC = ({
actionButton={
-
- Go to issues
-
+ }>
+ Go to issues
+
}
diff --git a/web/layouts/auth-layout-legacy/user-authorization-wrapper.tsx b/web/layouts/auth-layout-legacy/user-authorization-wrapper.tsx
index 9e795aed778..8f323268b88 100644
--- a/web/layouts/auth-layout-legacy/user-authorization-wrapper.tsx
+++ b/web/layouts/auth-layout-legacy/user-authorization-wrapper.tsx
@@ -5,7 +5,7 @@ import useSWR from "swr";
// services
import userService from "services/user.service";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
// fetch-keys
import { CURRENT_USER } from "constants/fetch-keys";
diff --git a/web/layouts/auth-layout-legacy/workspace-authorization-wrapper.tsx b/web/layouts/auth-layout-legacy/workspace-authorization-wrapper.tsx
index c66945d4234..94451a9bd3f 100644
--- a/web/layouts/auth-layout-legacy/workspace-authorization-wrapper.tsx
+++ b/web/layouts/auth-layout-legacy/workspace-authorization-wrapper.tsx
@@ -14,10 +14,10 @@ import AppSidebar from "layouts/app-layout-legacy/app-sidebar";
import AppHeader from "layouts/app-layout-legacy/app-header";
import { UserAuthorizationLayout } from "./user-authorization-wrapper";
// components
+import { Button, Spinner } from "@plane/ui";
import { NotAuthorizedView, NotAWorkspaceMember } from "components/auth-screens";
import { CommandPalette } from "components/command-palette";
// icons
-import { PrimaryButton, Spinner } from "components/ui";
import { LayerDiagonalIcon } from "components/icons";
// fetch-keys
import { WORKSPACE_MEMBERS_ME } from "constants/fetch-keys";
@@ -89,9 +89,9 @@ export const WorkspaceAuthorizationLayout: React.FC = ({
actionButton={
-
- Go to workspace
-
+ }>
+ Go to workspace
+
}
diff --git a/web/layouts/auth-layout/user-wrapper.tsx b/web/layouts/auth-layout/user-wrapper.tsx
index e37b4064e5d..3c30910513b 100644
--- a/web/layouts/auth-layout/user-wrapper.tsx
+++ b/web/layouts/auth-layout/user-wrapper.tsx
@@ -4,7 +4,7 @@ import useSWR from "swr";
// services
import userService from "services/user.service";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
// fetch-keys
import { CURRENT_USER } from "constants/fetch-keys";
diff --git a/web/layouts/web-view-layout/index.tsx b/web/layouts/web-view-layout/index.tsx
index 8a58407c3de..66039e971b5 100644
--- a/web/layouts/web-view-layout/index.tsx
+++ b/web/layouts/web-view-layout/index.tsx
@@ -11,7 +11,7 @@ import { CURRENT_USER } from "constants/fetch-keys";
import { AlertCircle } from "lucide-react";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
type Props = {
children: React.ReactNode;
diff --git a/web/pages/404.tsx b/web/pages/404.tsx
index 6386093a707..e5f5ee7fd68 100644
--- a/web/pages/404.tsx
+++ b/web/pages/404.tsx
@@ -6,7 +6,7 @@ import Image from "next/image";
// layouts
import DefaultLayout from "layouts/default-layout";
// ui
-import { SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
// images
import Image404 from "public/404.svg";
// types
@@ -22,13 +22,15 @@ const PageNotFound: NextPage = () => (
Oops! Something went wrong.
- Sorry, the page you are looking for cannot be found. It may have been removed, had its
- name changed, or is temporarily unavailable.
+ Sorry, the page you are looking for cannot be found. It may have been removed, had its name changed, or is
+ temporarily unavailable.
- Go to Home
+
+ Go to Home
+
diff --git a/web/pages/[workspaceSlug]/editor.tsx b/web/pages/[workspaceSlug]/editor.tsx
index e52e26d5739..1754e089309 100644
--- a/web/pages/[workspaceSlug]/editor.tsx
+++ b/web/pages/[workspaceSlug]/editor.tsx
@@ -5,7 +5,7 @@ import { Controller, useForm } from "react-hook-form";
import issuesService from "services/issue.service";
import { ICurrentUserResponse, IIssue } from "types";
import useReloadConfirmations from "hooks/use-reload-confirmation";
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
import Image404 from "public/404.svg";
import DefaultLayout from "layouts/default-layout";
import Image from "next/image";
diff --git a/web/pages/[workspaceSlug]/me/my-issues.tsx b/web/pages/[workspaceSlug]/me/my-issues.tsx
index de12f5b3248..697e739e54b 100644
--- a/web/pages/[workspaceSlug]/me/my-issues.tsx
+++ b/web/pages/[workspaceSlug]/me/my-issues.tsx
@@ -11,7 +11,7 @@ import useMyIssuesFilters from "hooks/my-issues/use-my-issues-filter";
// components
import { MyIssuesView, MyIssuesViewOptions } from "components/issues";
// ui
-import { PrimaryButton } from "components/ui";
+import { Button } from "@plane/ui";
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
// types
import type { NextPage } from "next";
@@ -85,16 +85,16 @@ const MyIssuesPage: NextPage = () => {
right={
-
}
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "c" });
document.dispatchEvent(e);
}}
>
-
Add Issue
-
+
}
>
diff --git a/web/pages/[workspaceSlug]/me/profile/activity.tsx b/web/pages/[workspaceSlug]/me/profile/activity.tsx
index df2ae803568..f6b08133b30 100644
--- a/web/pages/[workspaceSlug]/me/profile/activity.tsx
+++ b/web/pages/[workspaceSlug]/me/profile/activity.tsx
@@ -13,8 +13,9 @@ import { TipTapEditor } from "components/tiptap";
// icons
import { ArrowTopRightOnSquareIcon, ChatBubbleLeftEllipsisIcon } from "@heroicons/react/24/outline";
// ui
-import { Icon, Loader } from "components/ui";
+import { Icon } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
+import { Loader } from "@plane/ui";
// fetch-keys
import { USER_ACTIVITY } from "constants/fetch-keys";
// helper
diff --git a/web/pages/[workspaceSlug]/me/profile/index.tsx b/web/pages/[workspaceSlug]/me/profile/index.tsx
index dcd682611b1..0a19117702e 100644
--- a/web/pages/[workspaceSlug]/me/profile/index.tsx
+++ b/web/pages/[workspaceSlug]/me/profile/index.tsx
@@ -16,7 +16,8 @@ import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
import { ImagePickerPopover, ImageUploadModal } from "components/core";
import { SettingsSidebar } from "components/project";
// ui
-import { CustomSearchSelect, CustomSelect, Input, PrimaryButton, Spinner } from "components/ui";
+import { Button, Input, Spinner } from "@plane/ui";
+import { CustomSearchSelect, CustomSelect } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { UserIcon } from "@heroicons/react/24/outline";
@@ -211,6 +212,7 @@ const Profile: NextPage = () => {
onChange={(imageUrl) => {
setValue("cover_image", imageUrl);
}}
+ control={control}
value={watch("cover_image") ?? "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab"}
/>
)}
@@ -239,42 +241,66 @@ const Profile: NextPage = () => {
-
+
{isSubmitting ? "Updating Profile..." : "Update Profile"}
-
+
diff --git a/web/pages/[workspaceSlug]/me/profile/preferences.tsx b/web/pages/[workspaceSlug]/me/profile/preferences.tsx
index bd8ea1fd04d..15357e95652 100644
--- a/web/pages/[workspaceSlug]/me/profile/preferences.tsx
+++ b/web/pages/[workspaceSlug]/me/profile/preferences.tsx
@@ -6,7 +6,7 @@ import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
// components
import { CustomThemeSelector, ThemeSwitch } from "components/core";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// types
import { ICustomTheme } from "types";
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx
index db2c296f7df..7d6eae3313a 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx
@@ -16,8 +16,9 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
// components
import { IssueDetailsSidebar, IssueMainContent } from "components/issues";
// ui
-import { Icon, Loader } from "components/ui";
+import { Icon } from "components/ui";
import { Breadcrumbs } from "components/breadcrumbs";
+import { Loader } from "@plane/ui";
// types
import { IIssue } from "types";
import type { NextPage } from "next";
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx
index 5a615d935b1..40ab0b4819f 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx
@@ -23,7 +23,8 @@ import useUserAuth from "hooks/use-user-auth";
// components
import { AnalyticsProjectModal } from "components/analytics";
// ui
-import { CustomMenu, EmptyState, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
+import { CustomMenu, EmptyState } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// images
import emptyCycle from "public/empty-state/cycle.svg";
@@ -132,13 +133,9 @@ const SingleCycle: React.FC = () => {
right={
-
setAnalyticsModal(true)}
- className="!py-1.5 font-normal rounded-md text-custom-text-200 hover:text-custom-text-100"
- outline
- >
+ setAnalyticsModal(true)}>
Analytics
-
+
{
}
right={
- }
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "q" });
document.dispatchEvent(e);
}}
>
-
Add Cycle
-
+
}
>
{
}
right={
-
}
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "c" });
document.dispatchEvent(e);
}}
>
-
Add Issue
-
+
}
>
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx
index 4f1c8c88704..ccc10fdd378 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx
@@ -15,8 +15,9 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
// components
import { IssueDetailsSidebar, IssueMainContent } from "components/issues";
// ui
-import { EmptyState, Loader } from "components/ui";
+import { EmptyState } from "components/ui";
import { Breadcrumbs } from "components/breadcrumbs";
+import { Loader } from "@plane/ui";
// images
import emptyIssue from "public/empty-state/issue.svg";
// types
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx
index 5d8b461a2c2..598cad15baa 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx
@@ -18,7 +18,7 @@ import { ExistingIssuesListModal, IssuesFilterView } from "components/core";
import { ModuleDetailsSidebar } from "components/modules";
import { AnalyticsProjectModal } from "components/analytics";
// ui
-import { CustomMenu, EmptyState, SecondaryButton } from "components/ui";
+import { CustomMenu, EmptyState } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// images
import emptyModule from "public/empty-state/module.svg";
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx
index 72454e124e8..66fb2ea0c8c 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx
@@ -14,7 +14,8 @@ import modulesService from "services/modules.service";
// components
import { CreateUpdateModuleModal, ModulesListGanttChartView, SingleModuleCard } from "components/modules";
// ui
-import { EmptyState, Icon, Loader, PrimaryButton, Tooltip } from "components/ui";
+import { Button, Loader } from "@plane/ui";
+import { EmptyState, Icon, Tooltip } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
@@ -101,16 +102,16 @@ const ProjectModules: NextPage = () => {
))}
- }
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "m" });
document.dispatchEvent(e);
}}
>
-
Add Module
-
+
}
>
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx
index f25091b43f5..3e4fb3c33fb 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx
@@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import useSWR, { mutate } from "swr";
// react-hook-form
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// headless ui
import { Popover, Transition } from "@headlessui/react";
// react-color
@@ -28,7 +28,8 @@ import { CreateLabelModal } from "components/labels";
import { CreateBlock } from "components/pages/create-block";
// ui
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
-import { CustomSearchSelect, EmptyState, Loader, TextArea, ToggleSwitch, Tooltip } from "components/ui";
+import { CustomSearchSelect, EmptyState, Tooltip } from "components/ui";
+import { TextArea, Loader, ToggleSwitch } from "@plane/ui";
// images
import emptyPage from "public/empty-state/page.svg";
// icons
@@ -73,7 +74,7 @@ const SinglePage: NextPage = () => {
const { user } = useUser();
- const { handleSubmit, reset, watch, setValue } = useForm({
+ const { handleSubmit, reset, watch, setValue, control } = useForm({
defaultValues: { name: "" },
});
@@ -337,17 +338,22 @@ const SinglePage: NextPage = () => {
- setValue("name", e.target.value)}
- required={true}
- className="min-h-10 block w-full resize-none overflow-hidden rounded border-none bg-transparent px-3 py-2 text-xl font-semibold outline-none ring-0"
- role="textbox"
- noPadding
+ control={control}
+ render={({ field: { value, onChange } }) => (
+ setValue("name", e.target.value)}
+ required={true}
+ className="min-h-10 block w-full resize-none overflow-hidden rounded border-none bg-transparent !px-3 !py-2 text-xl font-semibold outline-none ring-0"
+ role="textbox"
+ />
+ )}
/>
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx
index 3e5e07478e5..1ebf7d5a027 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx
@@ -19,7 +19,7 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
// components
import { RecentPagesList, CreateUpdatePageModal, TPagesListProps } from "components/pages";
// ui
-import { PrimaryButton } from "components/ui";
+import { Button } from "@plane/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { ListBulletIcon, Squares2X2Icon } from "@heroicons/react/24/outline";
@@ -99,16 +99,16 @@ const ProjectPages: NextPage = () => {
}
right={
- }
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "d" });
document.dispatchEvent(e);
}}
>
-
Create Page
-
+
}
>
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx
index 1f2f5595286..a08174334ff 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx
@@ -18,7 +18,8 @@ import { SettingsSidebar } from "components/project";
import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// ui
-import { EmptyState, Loader, PrimaryButton, SecondaryButton } from "components/ui";
+import { Button, Loader } from "@plane/ui";
+import { EmptyState } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
@@ -130,16 +131,19 @@ const EstimatesSettings: NextPage = () => {
Estimates
-
{
setEstimateToUpdate(undefined);
setEstimateFormOpen(true);
}}
>
Add Estimate
-
+
{projectDetails?.estimate && (
-
Disable Estimates
+
+ Disable Estimates
+
)}
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx
index bd9e8222439..c9325d337a0 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx
@@ -15,7 +15,7 @@ import useUserAuth from "hooks/use-user-auth";
// components
import { SettingsSidebar } from "components/project";
// ui
-import { ToggleSwitch } from "components/ui";
+import { ToggleSwitch } from "@plane/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { ModuleIcon } from "components/icons";
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx
index 4d38582322a..a85482081b4 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx
@@ -11,7 +11,8 @@ import { DeleteProjectModal, ProjectDetailsForm, ProjectDetailsFormLoader, Setti
// hooks
import useUserAuth from "hooks/use-user-auth";
// components
-import { Loader, DangerButton, Icon } from "components/ui";
+import { Button, Loader } from "@plane/ui";
+import { Icon } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// helpers
import { truncateText } from "helpers/string.helper";
@@ -128,13 +129,9 @@ const GeneralSettings: NextPage = observer(() => {
{projectDetails ? (
- setSelectedProject(projectDetails.id ?? null)}
- className="!text-sm"
- outline
- >
+ setSelectedProject(projectDetails.id ?? null)}>
Delete my project
-
+
) : (
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx
index db5340f8791..5d665f3e63d 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx
@@ -12,8 +12,9 @@ import projectService from "services/project.service";
// components
import { SettingsSidebar, SingleIntegration } from "components/project";
// ui
-import { EmptyState, IntegrationAndImportExportBanner, Loader } from "components/ui";
+import { EmptyState, IntegrationAndImportExportBanner } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
+import { Loader } from "@plane/ui";
// icons
import { PlusIcon, PuzzlePieceIcon } from "@heroicons/react/24/outline";
// images
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx
index 4f6a236df77..0911c8bf256 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx
@@ -21,7 +21,8 @@ import {
} from "components/labels";
import { SettingsSidebar } from "components/project";
// ui
-import { EmptyState, Loader, PrimaryButton } from "components/ui";
+import { Button, Loader } from "@plane/ui";
+import { EmptyState } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
@@ -117,9 +118,9 @@ const LabelsSettings: NextPage = () => {
{labelForm && (
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx
index 4e7d684af0f..e1c63147a03 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx
@@ -21,15 +21,8 @@ import ConfirmProjectMemberRemove from "components/project/confirm-project-membe
import SendProjectInvitationModal from "components/project/send-project-invitation-modal";
import { MemberSelect, SettingsSidebar } from "components/project";
// ui
-import {
- CustomMenu,
- CustomSearchSelect,
- CustomSelect,
- Icon,
- Loader,
- PrimaryButton,
- SecondaryButton,
-} from "components/ui";
+import { Button, Loader } from "@plane/ui";
+import { CustomMenu, CustomSearchSelect, CustomSelect, Icon } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { PlusIcon, XMarkIcon } from "@heroicons/react/24/outline";
@@ -331,7 +324,9 @@ const MembersSettings: NextPage = () => {
Members
-
setInviteModal(true)}>Add Member
+
setInviteModal(true)}>
+ Add Member
+
{!projectMembers || !projectInvitations ? (
diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx
index aaf3e86f1f1..ccb1950e7b4 100644
--- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx
+++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx
@@ -15,7 +15,7 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
import { CreateUpdateStateInline, DeleteStateModal, SingleState, StateGroup } from "components/states";
import { SettingsSidebar } from "components/project";
// ui
-import { Loader } from "components/ui";
+import { Loader } from "@plane/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
diff --git a/web/pages/[workspaceSlug]/projects/index.tsx b/web/pages/[workspaceSlug]/projects/index.tsx
index 1beeb0c5557..7af8d852214 100644
--- a/web/pages/[workspaceSlug]/projects/index.tsx
+++ b/web/pages/[workspaceSlug]/projects/index.tsx
@@ -11,7 +11,8 @@ import useUserAuth from "hooks/use-user-auth";
// layouts
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
// ui
-import { Icon, PrimaryButton } from "components/ui";
+import { Button } from "@plane/ui";
+import { Icon } from "components/ui";
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
@@ -53,16 +54,16 @@ const ProjectsPage: NextPage = () => {
/>
- }
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "p" });
document.dispatchEvent(e);
}}
>
-
Add Project
-
+
}
>
diff --git a/web/pages/[workspaceSlug]/settings/billing.tsx b/web/pages/[workspaceSlug]/settings/billing.tsx
index 1379eb4979f..c852fe9e1ce 100644
--- a/web/pages/[workspaceSlug]/settings/billing.tsx
+++ b/web/pages/[workspaceSlug]/settings/billing.tsx
@@ -11,7 +11,7 @@ import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
// component
import { SettingsSidebar } from "components/project";
// ui
-import { SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// types
import type { NextPage } from "next";
@@ -57,7 +57,7 @@ const BillingSettings: NextPage = () => {
Current plan
You are currently using the free plan
- View Plans
+ View Plans
diff --git a/web/pages/[workspaceSlug]/settings/index.tsx b/web/pages/[workspaceSlug]/settings/index.tsx
index 2e3c31a1ce1..aadc38b2321 100644
--- a/web/pages/[workspaceSlug]/settings/index.tsx
+++ b/web/pages/[workspaceSlug]/settings/index.tsx
@@ -20,7 +20,8 @@ import { DeleteWorkspaceModal } from "components/workspace";
import { SettingsSidebar } from "components/project";
// ui
import { Disclosure, Transition } from "@headlessui/react";
-import { Spinner, Input, CustomSelect, DangerButton, PrimaryButton, Icon } from "components/ui";
+import { CustomSelect, Icon } from "components/ui";
+import { Button, Input, Spinner } from "@plane/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { Pencil } from "lucide-react";
@@ -232,21 +233,30 @@ const WorkspaceSettings: NextPage = () => {
-
+
{isSubmitting ? "Updating..." : "Update Workspace"}
-
+
{isAdmin && (
@@ -328,9 +345,9 @@ const WorkspaceSettings: NextPage = () => {
that workspace will be permanently removed and cannot be recovered.
- setIsOpen(true)} className="!text-sm" outline>
+ setIsOpen(true)}>
Delete my workspace
-
+
diff --git a/web/pages/[workspaceSlug]/settings/integrations.tsx b/web/pages/[workspaceSlug]/settings/integrations.tsx
index 8b1f603543e..840350f716e 100644
--- a/web/pages/[workspaceSlug]/settings/integrations.tsx
+++ b/web/pages/[workspaceSlug]/settings/integrations.tsx
@@ -13,8 +13,9 @@ import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
import { SingleIntegrationCard } from "components/integration";
import { SettingsSidebar } from "components/project";
// ui
-import { IntegrationAndImportExportBanner, Loader } from "components/ui";
+import { IntegrationAndImportExportBanner } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
+import { Loader } from "@plane/ui";
// types
import type { NextPage } from "next";
// fetch-keys
diff --git a/web/pages/[workspaceSlug]/settings/members.tsx b/web/pages/[workspaceSlug]/settings/members.tsx
index e5f65a40bcc..a4058b1ece2 100644
--- a/web/pages/[workspaceSlug]/settings/members.tsx
+++ b/web/pages/[workspaceSlug]/settings/members.tsx
@@ -18,7 +18,8 @@ import ConfirmWorkspaceMemberRemove from "components/workspace/confirm-workspace
import SendWorkspaceInvitationModal from "components/workspace/send-workspace-invitation-modal";
import { SettingsSidebar } from "components/project";
// ui
-import { CustomMenu, CustomSelect, Icon, Loader, PrimaryButton } from "components/ui";
+import { Button, Loader } from "@plane/ui";
+import { CustomMenu, CustomSelect, Icon } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { XMarkIcon } from "components/icons";
@@ -181,7 +182,9 @@ const MembersSettings: NextPage = () => {
Members
-
setInviteModal(true)}>Add Member
+
setInviteModal(true)}>
+ Add Member
+
{!workspaceMembers || !workspaceInvitations ? (
diff --git a/web/pages/[workspaceSlug]/workspace-views/index.tsx b/web/pages/[workspaceSlug]/workspace-views/index.tsx
index 9b46cdf9abb..1b698e25093 100644
--- a/web/pages/[workspaceSlug]/workspace-views/index.tsx
+++ b/web/pages/[workspaceSlug]/workspace-views/index.tsx
@@ -10,7 +10,7 @@ import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
import { GlobalDefaultViewListItem, GlobalViewsList } from "components/workspace";
import { GlobalIssuesHeader } from "components/headers";
// ui
-import { Input } from "components/ui";
+import { Input } from "@plane/ui";
// icons
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
// types
@@ -49,7 +49,6 @@ const WorkspaceViews: NextPage = () => {
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search"
- mode="trueTransparent"
/>
diff --git a/web/pages/_error.tsx b/web/pages/_error.tsx
index 3595c6ce77a..c285dd41542 100644
--- a/web/pages/_error.tsx
+++ b/web/pages/_error.tsx
@@ -9,7 +9,7 @@ import useToast from "hooks/use-toast";
// layouts
import DefaultLayout from "layouts/default-layout";
// ui
-import { PrimaryButton, SecondaryButton } from "components/ui";
+import { Button } from "@plane/ui";
const CustomErrorComponent = () => {
const router = useRouter();
@@ -36,9 +36,8 @@ const CustomErrorComponent = () => {
Exception Detected!
- We{"'"}re Sorry! An exception has been detected, and our engineering team has been
- notified. We apologize for any inconvenience this may have caused. Please reach out to
- our engineering team at{" "}
+ We{"'"}re Sorry! An exception has been detected, and our engineering team has been notified. We apologize
+ for any inconvenience this may have caused. Please reach out to our engineering team at{" "}
support@plane.so
{" "}
@@ -55,12 +54,12 @@ const CustomErrorComponent = () => {
-
router.back()}>
+ router.back()}>
Go back
-
-
+
+
Sign out
-
+
diff --git a/web/pages/accounts/reset-password.tsx b/web/pages/accounts/reset-password.tsx
index fa17d2333e2..533f9df1204 100644
--- a/web/pages/accounts/reset-password.tsx
+++ b/web/pages/accounts/reset-password.tsx
@@ -6,7 +6,7 @@ import Image from "next/image";
// next-themes
import { useTheme } from "next-themes";
// react-hook-form
-import { useForm } from "react-hook-form";
+import { Controller, useForm } from "react-hook-form";
// hooks
import useToast from "hooks/use-toast";
// services
@@ -14,7 +14,7 @@ import userService from "services/user.service";
// layouts
import DefaultLayout from "layouts/default-layout";
// ui
-import { Input, PrimaryButton, Spinner } from "components/ui";
+import { Button, Input, Spinner } from "@plane/ui";
// images
import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
// types
@@ -38,6 +38,7 @@ const ResetPasswordPage: NextPage = () => {
const {
register,
handleSubmit,
+ control,
formState: { errors, isSubmitting },
} = useForm();
@@ -73,9 +74,7 @@ const ResetPasswordPage: NextPage = () => {
setToastAlert({
type: "error",
title: "Error!",
- message:
- err?.error ||
- "Something went wrong. Please try again later or contact the support team.",
+ message: err?.error || "Something went wrong. Please try again later or contact the support team.",
})
);
};
@@ -110,49 +109,56 @@ const ResetPasswordPage: NextPage = () => {
>
diff --git a/web/pages/installations/[provider]/index.tsx b/web/pages/installations/[provider]/index.tsx
index 15dad934429..abdcf94cc10 100644
--- a/web/pages/installations/[provider]/index.tsx
+++ b/web/pages/installations/[provider]/index.tsx
@@ -5,7 +5,7 @@ import { useRouter } from "next/router";
// services
import appInstallationsService from "services/app_installation.service";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
const AppPostInstallation = () => {
const router = useRouter();
diff --git a/web/pages/invitations/index.tsx b/web/pages/invitations/index.tsx
index 283e54abffd..0f6c68edcb5 100644
--- a/web/pages/invitations/index.tsx
+++ b/web/pages/invitations/index.tsx
@@ -17,7 +17,7 @@ import useToast from "hooks/use-toast";
import DefaultLayout from "layouts/default-layout";
import { UserAuthorizationLayout } from "layouts/auth-layout-legacy/user-authorization-wrapper";
// ui
-import { SecondaryButton, PrimaryButton, EmptyState } from "components/ui";
+import { Button } from "@plane/ui";
// icons
import { CheckCircleIcon } from "@heroicons/react/24/outline";
// images
@@ -174,7 +174,8 @@ const OnBoard: NextPage = () => {
})}
diff --git a/web/pages/m/[workspaceSlug]/editor.tsx b/web/pages/m/[workspaceSlug]/editor.tsx
index 2bfac63b85a..a613aff4155 100644
--- a/web/pages/m/[workspaceSlug]/editor.tsx
+++ b/web/pages/m/[workspaceSlug]/editor.tsx
@@ -15,7 +15,7 @@ import WebViewLayout from "layouts/web-view-layout";
// components
import { TipTapEditor } from "components/tiptap";
-import { PrimaryButton, Spinner } from "components/ui";
+import { Button, Spinner } from "@plane/ui";
const Editor: NextPage = () => {
const [isLoading, setIsLoading] = useState(false);
@@ -55,9 +55,7 @@ const Editor: NextPage = () => {
{
)}
/>
{isEditable && (
- {
console.log(
@@ -88,7 +87,7 @@ const Editor: NextPage = () => {
}}
>
Submit
-
+
)}
>
)}
diff --git a/web/pages/m/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx b/web/pages/m/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx
index eb3df545893..3d25987cb9c 100644
--- a/web/pages/m/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx
+++ b/web/pages/m/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx
@@ -24,7 +24,7 @@ import useProjectMembers from "hooks/use-project-members";
import WebViewLayout from "layouts/web-view-layout";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
// components
import {
diff --git a/web/pages/onboarding/index.tsx b/web/pages/onboarding/index.tsx
index 51148b19e35..169fa1db184 100644
--- a/web/pages/onboarding/index.tsx
+++ b/web/pages/onboarding/index.tsx
@@ -17,7 +17,7 @@ import DefaultLayout from "layouts/default-layout";
// components
import { InviteMembers, JoinWorkspaces, UserDetails, Workspace } from "components/onboarding";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
// images
import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
import BlackHorizontalLogo from "public/plane-logos/black-horizontal-with-blue-logo.svg";
@@ -38,9 +38,7 @@ const Onboarding: NextPage = () => {
const { workspaces } = useWorkspaces();
const userWorkspaces = workspaces?.filter((w) => w.created_by === user?.id);
- const { data: invitations } = useSWR(USER_WORKSPACE_INVITATIONS, () =>
- workspaceService.userWorkspaceInvitations()
- );
+ const { data: invitations } = useSWR(USER_WORKSPACE_INVITATIONS, () => workspaceService.userWorkspaceInvitations());
// update last active workspace details
const updateLastWorkspace = async () => {
@@ -129,13 +127,8 @@ const Onboarding: NextPage = () => {
if (!onboardingStep.profile_complete && step !== 1) setStep(1);
if (onboardingStep.profile_complete) {
- if (!onboardingStep.workspace_join && invitations.length > 0 && step !== 2 && step !== 4)
- setStep(4);
- else if (
- !onboardingStep.workspace_create &&
- (step !== 4 || onboardingStep.workspace_join) &&
- step !== 2
- )
+ if (!onboardingStep.workspace_join && invitations.length > 0 && step !== 2 && step !== 4) setStep(4);
+ else if (!onboardingStep.workspace_create && (step !== 4 || onboardingStep.workspace_join) && step !== 2)
setStep(2);
}
diff --git a/web/pages/workspace-invitations/index.tsx b/web/pages/workspace-invitations/index.tsx
index e351310a43e..86bce7f5192 100644
--- a/web/pages/workspace-invitations/index.tsx
+++ b/web/pages/workspace-invitations/index.tsx
@@ -3,14 +3,7 @@ import React from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
-import {
- CheckIcon,
- CubeIcon,
- ShareIcon,
- StarIcon,
- UserIcon,
- XMarkIcon,
-} from "@heroicons/react/24/outline";
+import { CheckIcon, CubeIcon, ShareIcon, StarIcon, UserIcon, XMarkIcon } from "@heroicons/react/24/outline";
// swr
// services
import workspaceService from "services/workspace.service";
@@ -19,7 +12,7 @@ import useUser from "hooks/use-user";
// layouts
import DefaultLayout from "layouts/default-layout";
// ui
-import { Spinner } from "components/ui";
+import { Spinner } from "@plane/ui";
// icons
import { EmptySpace, EmptySpaceItem } from "components/ui/empty-space";
// types
@@ -77,11 +70,7 @@ const WorkspaceInvitation: NextPage = () => {
title={`You are already a member of ${invitationDetail.workspace.name}`}
description="Your workspace is where you'll create projects, collaborate on your issues, and organize different streams of work in your Plane account."
>
- router.push("/")}
- />
+ router.push("/")} />
>
) : (
diff --git a/yarn.lock b/yarn.lock
index 2f6c546da69..35cddaecdd4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1248,7 +1248,7 @@
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.2.tgz#b7e9309ccce5a0a40ac482cb894f120dba2b357f"
integrity sha512-ou3elfqG/hZsbmF4bxeJhPHIf3G2pm0ujc39hYEZrfVqt7Vk/Zji6CXc3W0pmYM8BW1g40U+akTl9DKZhFhInQ==
-"@headlessui/react@^1.7.13", "@headlessui/react@^1.7.3":
+"@headlessui/react@^1.7.13", "@headlessui/react@^1.7.17", "@headlessui/react@^1.7.3":
version "1.7.17"
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.17.tgz#a0ec23af21b527c030967245fd99776aa7352bc6"
integrity sha512-4am+tzvkqDSSgiwrsEpGWqgGo9dz8qU5M3znCkC4PgkpY4HcCZzEDEvozltGGGHIKl9jbXbZPSH5TWn4sWJdow==