diff --git a/packages/tailwind-config-custom/tailwind.config.js b/packages/tailwind-config-custom/tailwind.config.js
index 061168c4f..4e727ecc1 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 48321708f..e3b790024 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;
- className?: string;
- mode?: "primary" | "transparent" | "true-transparent";
+interface ButtonProps extends React.ButtonHTMLAttributes {
+ variant?: TButtonVariant;
size?: "sm" | "md" | "lg";
- hasError?: boolean;
- placeholder?: string;
+ className?: string;
+ 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";
+ 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 72851d0e7..7ac83b1ae 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 97590dbcf..d9112b832 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 1f95e468b..9385a26c7 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 000000000..a11ce9e8b
--- /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 000000000..1eaee5134
--- /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 000000000..f1a2d03d4
--- /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 000000000..9888dd205
--- /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 de1b0da31..000000000
--- 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 7c9389848..648b78aa7 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 e9b748230..93a850059 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 1e80ad867..36eb08ef4 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 000000000..cd12bc22f
--- /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 caee5259d..288a0c1fc 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 000000000..d241e3d5e
--- /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 c850b305c..ee71890ec 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 1e68cbb29..1a4b1208d 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 0a219741f..76c7e523b 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 66917ed7c..508f5722e 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 3152596c8..9d84573ae 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 787fa79bd..e39f726cd 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 dc7e65515..aef15880f 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 73b824b63..7e2c8cebd 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 ee63b5883..6737115a0 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 d0c9a1be6..563381e69 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 664967d0f..30beed9da 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 18239d62b..0fc42361a 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 d51d269cd..04c42f8cf 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 3cc16c236..50e396da3 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 82f9b398c..44f3d5442 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 4f5bad7b3..2c88419dd 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 4a1ec0e8b..a94dd809e 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 79fa9c984..a190ebfda 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 cfe18cd97..7ab0ec6bf 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 964b47d48..7ecbb3a13 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 ed3902a4a..ea66eaa54 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 fd2de641f..c48c72796 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 df4f21e12..eb299af3c 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 bed74fca0..2e8531bd6 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 1498c9bad..3ff214b57 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 73d71e46b..a34aa05cb 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 27817c82a..b94232c81 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 fd69ed443..931bd3b49 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 553c7b723..6ded660bd 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 6d2891328..ff3754cc0 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 152ede98d..258026a4b 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 7816f0edb..763919846 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 923bdc20a..ec8a40837 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 5d025e4fd..da858bf52 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 42e0a4272..2404c27da 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 35b8e118e..c2e5085b2 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 acf5dbf5f..c4188ea00 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 e2ca98d3f..aa52aa27f 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 a49c7665f..a604bc7e6 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 1242742d4..5cf9140d7 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 b4c08b421..ce5eb9db5 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 43edfcb2c..318310780 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 553c7c19b..5df8b1d93 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 772119f25..2eea98875 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 2aec274d9..85a5031cf 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 2e4aa588a..45601ef8a 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 be557536b..bca83a3ec 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 b3168915a..48786da55 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 a00057113..fc4f7fd0f 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 86bc15d01..ea397a35a 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 6c0960729..5b0fb1da7 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 5f0fd116a..31fb3e7e6 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 8dbb58faa..6bf683412 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 23b956644..b4de8b387 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 b530b4a24..c94bfacd5 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 ca5a55a77..f804d32dd 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 8a7383062..65f3e82b2 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 eeae3f28d..32f765277 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 e4caf349b..ad0654438 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 b53ae2f01..1e78f9241 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 13671ac89..b66b135c3 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 3d8e5d39a..6ed5d03f3 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 3fc5d9641..d549114df 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 edd35231f..e9609dfec 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 2a4b572ec..b1b5fa746 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 8dbc60bf5..081de7378 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 728b582f1..6455011d4 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 e6f54f512..5e5f5b4df 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 62dc3cffe..3dead2d39 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 33d7f2289..64198784d 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 f8feab73d..98b4eaf48 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 e7f748975..1b54f2c09 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 2f23f3f63..0dcf08f5e 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 54ea0a976..cacfc7a6d 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 bf6d511e3..7b16117cc 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 dd382d43f..3931ba58c 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 df359e97c..778feb57f 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 fe14e32f6..c02be5084 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 9c5ba1db1..283fac906 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 9e41784f8..eace4bec5 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 9be5bd05c..5d8978ffd 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 a41405076..37f6846f9 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 93163dd91..de02e9692 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 ae719758a..6f3472c8e 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 bf02efafe..8a3c9871c 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 4ceb15fc6..0c2373dd8 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 a29fa6521..8c74439a6 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 9c04e0b6a..47d0d1e7d 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 1bdeed479..cb3e8316b 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 3080c1af2..5e5672561 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 2052a0d56..4e373a1c0 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 7c7970b5a..90ac18f64 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 f4123633f..158eefb94 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 0f5dcbeff..de87a1341 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 452fcd798..99362741f 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 9faede08f..06bf44a4b 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 2715ba266..fa52e227f 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 e815d1950..f53d48998 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 f01fdafd1..d465d8c77 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 99281350e..46600549c 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 8f1b1fa41..cf05bc9ae 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 84b5bdfc9..438289617 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 a28d93d97..001e13be8 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 2911bbc80..a8f8e616a 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 8f7442432..e433268b7 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 6f6159ad0..69a1b96bf 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 14e5c283e..3639b4819 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 c4c669e1e..160a0f4f0 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 6ea8f9d01..f302d607b 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 b7fc0249c..ba385a316 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 5d784d98a..ac2ea925a 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 045812363..e2cc01c8f 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 d72985285..de88cf517 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 0277ac5b3..f6ec73778 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 2118c6eb9..56947a274 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 59cc5528b..b61c20e36 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 0aff18b37..1c8e5958e 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 4edc27821..772a3045e 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 f07e8193b..d80c25c57 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 8d0833001..d2cfdc5b1 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 325807b83..039cdd25f 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 ae154a59c..d581a01e8 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 984fafa85..ef6874db9 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 90da32d74..584ad9d5b 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 51ad8c9aa..7a16da91d 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 07b90840c..1ffb2bf7c 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 f6ed8be3b..6b0c58afb 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 171f4f17e..de109b998 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 3cd5bfb8d..46d8a068c 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 580d42bdc..7d0893193 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 b77ee2615..3f9815533 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 000000000..4f5bad7b3
--- /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 0f9163521..3a4c5d71f 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 b4f49d7be..7111a1281 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 692ffb9c9..fb356758d 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 5df652300..746ea7eb6 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 65a2eb173..27457333b 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 ff9383fd0..a9c837132 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 a4e180971..8d44fd814 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 9ca80c3dc..aa2f4cd4d 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 c7eb584b9..27e00245c 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 80cf08cd1..3e18d7575 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 0cb8416c0..a27951280 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 2c874d503..76e6a1970 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 c9d090405..c243fd1c9 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 f3bbc029b..8d9ae1ff6 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 8af899e52..61d899d35 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 ccfeba75b..5a0629305 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 85191fdd5..98ee0d668 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 9e795aed7..8f323268b 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 c66945d42..94451a9bd 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 e37b4064e..3c3091051 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 8a58407c3..66039e971 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 6386093a7..e5f5ee7fd 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 e52e26d57..1754e0893 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 de12f5b32..697e739e5 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 df2ae8035..f6b08133b 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 dcd682611..0a1911770 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 bd8ea1fd0..15357e956 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 db2c296f7..7d6eae331 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 5a615d935..40ab0b481 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 4f1c8c887..ccc10fdd3 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 5d8b461a2..598cad15b 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 72454e124..66fb2ea0c 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 f25091b43..3e4fb3c33 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 3e5e07478..1ebf7d5a0 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 1f2f55952..a08174334 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 bd9e82224..c9325d337 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 4d3858232..a85482081 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 db5340f87..5d665f3e6 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 4f6a236df..0911c8bf2 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 4e7d684af..e1c63147a 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 aaf3e86f1..ccb1950e7 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 1beeb0c55..7af8d8522 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 1379eb497..c852fe9e1 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 2e3c31a1c..aadc38b23 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 8b1f60354..840350f71 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 e5f65a40b..a4058b1ec 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 9b46cdf9a..1b698e250 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 3595c6ce7..c285dd415 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 fa17d2333..533f9df12 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 15dad9344..abdcf94cc 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 283e54abf..0f6c68edc 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 2bfac63b8..a613aff41 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 eb3df5458..3d25987cb 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 51148b19e..169fa1db1 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 e351310a4..86bce7f51 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 2f6c546da..35cddaecd 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==