mirror of
https://github.com/makeplane/plane.git
synced 2026-08-29 01:58:36 +02:00
refactor: migrate web Input to @makeplane/propel Input (#9708)
Replace @plane/ui Input in apps/web with Propel Input and InputGroup. hasError maps to Field invalid. Default size is 2xl to match the old h-10 height.
This commit is contained in:
committed by
GitHub
parent
3478d4fac4
commit
4a6f9edff6
@@ -7,10 +7,11 @@
|
||||
import React, { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// plane imports
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { DEFAULT_GLOBAL_VIEWS_LIST } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { SearchIcon } from "@plane/propel/icons";
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
// components
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { GlobalDefaultViewListItem } from "@/components/workspace/views/default-view-list-item";
|
||||
@@ -30,15 +31,17 @@ function WorkspaceViewsPage() {
|
||||
<>
|
||||
<PageHead title={pageTitle} />
|
||||
<div className="flex h-full w-full flex-col overflow-hidden">
|
||||
<div className="flex h-11 w-full items-center gap-2.5 overflow-hidden border-b border-subtle px-5 py-3">
|
||||
<SearchIcon className="text-secondary" width={14} height={14} strokeWidth={2} />
|
||||
<Input
|
||||
className="w-full bg-transparent !p-0 text-11 leading-5 text-secondary placeholder:text-placeholder focus:outline-none"
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
placeholder="Search"
|
||||
mode="true-transparent"
|
||||
/>
|
||||
<div className="flex h-11 w-full items-center overflow-hidden border-b border-subtle px-5 py-3">
|
||||
<InputGroup size="2xl">
|
||||
<SearchIcon className="text-secondary" width={14} height={14} strokeWidth={2} />
|
||||
<Input
|
||||
size="2xl"
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
placeholder="Search"
|
||||
aria-label="Search"
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
<div className="vertical-scrollbar scrollbar-lg flex h-full w-full flex-col">
|
||||
{DEFAULT_GLOBAL_VIEWS_LIST.filter((v) => t(v.i18n_label).toLowerCase().includes(query.toLowerCase())).map(
|
||||
|
||||
@@ -10,11 +10,13 @@ import { observer } from "mobx-react";
|
||||
// icons
|
||||
import { CircleAlert, XCircle } from "lucide-react";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import type { IEmailCheckData } from "@plane/types";
|
||||
import { Input, Spinner } from "@plane/ui";
|
||||
import { cn, checkEmailValidity } from "@plane/utils";
|
||||
import { Spinner } from "@plane/ui";
|
||||
import { checkEmailValidity } from "@plane/utils";
|
||||
// helpers
|
||||
type TAuthEmailForm = {
|
||||
defaultEmail: string;
|
||||
@@ -54,45 +56,44 @@ export const AuthEmailForm = observer(function AuthEmailForm(props: TAuthEmailFo
|
||||
<label htmlFor="email" className="text-13 font-medium text-tertiary">
|
||||
{t("auth.common.email.label")}
|
||||
</label>
|
||||
<div
|
||||
className={cn(
|
||||
`relative flex items-center rounded-md border bg-surface-1`,
|
||||
!isFocused && Boolean(emailError?.email) ? `border-danger-strong` : `border-strong`
|
||||
)}
|
||||
onFocus={() => {
|
||||
setIsFocused(true);
|
||||
}}
|
||||
onBlur={() => {
|
||||
setIsFocused(false);
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className={`h-10 w-full border-0 disable-autofill-style placeholder:text-placeholder autofill:bg-danger-primary focus:bg-none active:bg-transparent`}
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
ref={inputRef}
|
||||
/>
|
||||
{email.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setEmail("");
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
className="absolute right-3 grid size-5 place-items-center"
|
||||
aria-label={t("aria_labels.auth_forms.clear_email")}
|
||||
tabIndex={-1}
|
||||
>
|
||||
<XCircle className="size-5 stroke-placeholder" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<Field name="email" invalid={!isFocused && Boolean(emailError?.email)}>
|
||||
<InputGroup
|
||||
size="2xl"
|
||||
onFocus={() => {
|
||||
setIsFocused(true);
|
||||
}}
|
||||
onBlur={() => {
|
||||
setIsFocused(false);
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
size="2xl"
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
ref={inputRef}
|
||||
/>
|
||||
{email.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setEmail("");
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
className="grid size-5 place-items-center"
|
||||
aria-label={t("aria_labels.auth_forms.clear_email")}
|
||||
tabIndex={-1}
|
||||
>
|
||||
<XCircle className="size-5 stroke-placeholder" />
|
||||
</button>
|
||||
)}
|
||||
</InputGroup>
|
||||
</Field>
|
||||
{emailError?.email && !isFocused && (
|
||||
<p className="flex items-center gap-1 px-0.5 text-11 text-danger-primary">
|
||||
<CircleAlert height={12} width={12} />
|
||||
|
||||
@@ -11,10 +11,12 @@ import { Controller, useForm } from "react-hook-form";
|
||||
// icons
|
||||
import { CircleCheck } from "lucide-react";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button, getButtonStyling } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
import { cn, checkEmailValidity } from "@plane/utils";
|
||||
// hooks
|
||||
import useTimer from "@/hooks/use-timer";
|
||||
@@ -94,19 +96,22 @@ export const ForgotPasswordForm = observer(function ForgotPasswordForm() {
|
||||
validate: (value) => checkEmailValidity(value) || t("auth.common.email.errors.invalid"),
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.email)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
autoComplete="off"
|
||||
disabled={resendTimerCode > 0}
|
||||
/>
|
||||
<Field name="email" invalid={Boolean(errors.email)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
autoComplete="off"
|
||||
disabled={resendTimerCode > 0}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{resendTimerCode > 0 && (
|
||||
|
||||
@@ -10,11 +10,12 @@ import Link from "next/link";
|
||||
// icons
|
||||
import { Eye, EyeOff, Info, XCircle } from "lucide-react";
|
||||
// plane imports
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { API_BASE_URL, E_PASSWORD_STRENGTH } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { CloseIcon } from "@plane/propel/icons";
|
||||
import { Input, PasswordStrengthIndicator, Spinner } from "@plane/ui";
|
||||
import { PasswordStrengthIndicator, Spinner } from "@plane/ui";
|
||||
import { getPasswordStrength } from "@plane/utils";
|
||||
// components
|
||||
import { ForgotPasswordPopover } from "@/components/account/auth-forms/forgot-password-popover";
|
||||
@@ -173,43 +174,43 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||
<label htmlFor="email" className="text-13 font-medium text-tertiary">
|
||||
{t("auth.common.email.label")}
|
||||
</label>
|
||||
<div className={`relative flex items-center rounded-md border border-strong bg-surface-1`}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={passwordFormData.email}
|
||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className={`h-10 w-full border-0 disable-autofill-style placeholder:text-placeholder`}
|
||||
disabled
|
||||
/>
|
||||
{passwordFormData.email.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
className="absolute right-3 size-5"
|
||||
className="grid size-5 place-items-center"
|
||||
onClick={handleEmailClear}
|
||||
aria-label={t("aria_labels.auth_forms.clear_email")}
|
||||
>
|
||||
<XCircle className="size-5 stroke-placeholder" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label htmlFor="password" className="text-13 font-medium text-tertiary">
|
||||
{mode === EAuthModes.SIGN_IN ? t("auth.common.password.label") : t("auth.common.password.set_password")}
|
||||
</label>
|
||||
<div className="relative flex items-center rounded-md bg-surface-1">
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
type={showPassword?.password ? "text" : "password"}
|
||||
id="password"
|
||||
name="password"
|
||||
value={passwordFormData.password}
|
||||
onChange={(e) => handleFormChange("password", e.target.value)}
|
||||
placeholder={t("auth.common.password.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 disable-autofill-style placeholder:text-placeholder"
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="off"
|
||||
@@ -218,7 +219,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
className="absolute right-3 grid size-5 place-items-center"
|
||||
className="grid size-5 place-items-center"
|
||||
aria-label={t(
|
||||
showPassword?.password ? "aria_labels.auth_forms.hide_password" : "aria_labels.auth_forms.show_password"
|
||||
)}
|
||||
@@ -229,7 +230,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||
<Eye className="size-5 stroke-placeholder" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</InputGroup>
|
||||
{passwordSupport}
|
||||
</div>
|
||||
|
||||
@@ -238,22 +239,22 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||
<label htmlFor="confirm-password" className="text-13 font-medium text-tertiary">
|
||||
{t("auth.common.password.confirm_password.label")}
|
||||
</label>
|
||||
<div className="relative flex items-center rounded-md bg-surface-1">
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
type={showPassword?.retypePassword ? "text" : "password"}
|
||||
id="confirm-password"
|
||||
name="confirm_password"
|
||||
value={passwordFormData.confirm_password}
|
||||
onChange={(e) => handleFormChange("confirm_password", e.target.value)}
|
||||
placeholder={t("auth.common.password.confirm_password.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 disable-autofill-style placeholder:text-placeholder"
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="off"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="absolute right-3 grid size-5 place-items-center"
|
||||
className="grid size-5 place-items-center"
|
||||
aria-label={t(
|
||||
showPassword?.retypePassword
|
||||
? "aria_labels.auth_forms.hide_password"
|
||||
@@ -267,7 +268,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||
<Eye className="size-5 stroke-placeholder" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</InputGroup>
|
||||
{!!passwordFormData.confirm_password &&
|
||||
passwordFormData.password !== passwordFormData.confirm_password &&
|
||||
renderPasswordMatchError && (
|
||||
|
||||
@@ -10,10 +10,11 @@ import { useSearchParams } from "next/navigation";
|
||||
// icons
|
||||
import { Eye, EyeOff } from "lucide-react";
|
||||
// ui
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { API_BASE_URL, E_PASSWORD_STRENGTH } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { Input, PasswordStrengthIndicator } from "@plane/ui";
|
||||
import { PasswordStrengthIndicator } from "@plane/ui";
|
||||
// components
|
||||
import { getPasswordStrength } from "@plane/utils";
|
||||
// helpers
|
||||
@@ -114,81 +115,81 @@ export const ResetPasswordForm = observer(function ResetPasswordForm() {
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="email">
|
||||
{t("auth.common.email.label")}
|
||||
</label>
|
||||
<div className="relative flex items-center rounded-md bg-surface-1">
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={resetFormData.email}
|
||||
//hasError={Boolean(errors.email)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className="h-10 w-full cursor-not-allowed border border-strong !bg-surface-1 pr-12 text-placeholder"
|
||||
autoComplete="off"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</InputGroup>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="password">
|
||||
{t("auth.common.password.label")}
|
||||
</label>
|
||||
<div className="relative flex items-center rounded-md bg-surface-1">
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
type={showPassword.password ? "text" : "password"}
|
||||
name="password"
|
||||
id="password"
|
||||
value={resetFormData.password}
|
||||
onChange={(e) => handleFormChange("password", e.target.value)}
|
||||
//hasError={Boolean(errors.password)}
|
||||
placeholder={t("auth.common.password.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
minLength={8}
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
autoFocus
|
||||
/>
|
||||
{showPassword.password ? (
|
||||
<EyeOff
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
/>
|
||||
) : (
|
||||
<Eye
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
className="grid size-5 place-items-center"
|
||||
>
|
||||
{showPassword.password ? (
|
||||
<EyeOff className="size-5 stroke-placeholder" />
|
||||
) : (
|
||||
<Eye className="size-5 stroke-placeholder" />
|
||||
)}
|
||||
</button>
|
||||
</InputGroup>
|
||||
<PasswordStrengthIndicator password={resetFormData.password} isFocused={isPasswordInputFocused} />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="confirm_password">
|
||||
{t("auth.common.password.confirm_password.label")}
|
||||
</label>
|
||||
<div className="relative flex items-center rounded-md bg-surface-1">
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
type={showPassword.retypePassword ? "text" : "password"}
|
||||
name="confirm_password"
|
||||
id="confirm_password"
|
||||
value={resetFormData.confirm_password}
|
||||
onChange={(e) => handleFormChange("confirm_password", e.target.value)}
|
||||
placeholder={t("auth.common.password.confirm_password.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
{showPassword.retypePassword ? (
|
||||
<EyeOff
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("retypePassword")}
|
||||
/>
|
||||
) : (
|
||||
<Eye
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("retypePassword")}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleShowPassword("retypePassword")}
|
||||
className="grid size-5 place-items-center"
|
||||
>
|
||||
{showPassword.retypePassword ? (
|
||||
<EyeOff className="size-5 stroke-placeholder" />
|
||||
) : (
|
||||
<Eye className="size-5 stroke-placeholder" />
|
||||
)}
|
||||
</button>
|
||||
</InputGroup>
|
||||
{!!resetFormData.confirm_password &&
|
||||
resetFormData.password !== resetFormData.confirm_password &&
|
||||
renderPasswordMatchError && (
|
||||
|
||||
@@ -11,11 +11,12 @@ import { useSearchParams } from "next/navigation";
|
||||
// icons
|
||||
import { Eye, EyeOff } from "lucide-react";
|
||||
// plane imports
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { E_PASSWORD_STRENGTH } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import { Input, PasswordStrengthIndicator } from "@plane/ui";
|
||||
import { PasswordStrengthIndicator } from "@plane/ui";
|
||||
// components
|
||||
import { getPasswordStrength } from "@plane/utils";
|
||||
// hooks
|
||||
@@ -117,81 +118,81 @@ export const SetPasswordForm = observer(function SetPasswordForm() {
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="email">
|
||||
{t("auth.common.email.label")}
|
||||
</label>
|
||||
<div className="relative flex items-center rounded-md bg-surface-1">
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={user?.email}
|
||||
//hasError={Boolean(errors.email)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className="h-10 w-full cursor-not-allowed border border-strong !bg-surface-1 pr-12 text-placeholder"
|
||||
autoComplete="off"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</InputGroup>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="password">
|
||||
{t("auth.common.password.label")}
|
||||
</label>
|
||||
<div className="relative flex items-center rounded-md bg-surface-1">
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
type={showPassword.password ? "text" : "password"}
|
||||
name="password"
|
||||
id="password"
|
||||
value={passwordFormData.password}
|
||||
onChange={(e) => handleFormChange("password", e.target.value)}
|
||||
//hasError={Boolean(errors.password)}
|
||||
placeholder={t("auth.common.password.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
minLength={8}
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
autoFocus
|
||||
/>
|
||||
{showPassword.password ? (
|
||||
<EyeOff
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
/>
|
||||
) : (
|
||||
<Eye
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
className="grid size-5 place-items-center"
|
||||
>
|
||||
{showPassword.password ? (
|
||||
<EyeOff className="size-5 stroke-placeholder" />
|
||||
) : (
|
||||
<Eye className="size-5 stroke-placeholder" />
|
||||
)}
|
||||
</button>
|
||||
</InputGroup>
|
||||
<PasswordStrengthIndicator password={passwordFormData.password} isFocused={isPasswordInputFocused} />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="confirm_password">
|
||||
{t("auth.common.password.confirm_password.label")}
|
||||
</label>
|
||||
<div className="relative flex items-center rounded-md bg-surface-1">
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
type={showPassword.retypePassword ? "text" : "password"}
|
||||
name="confirm_password"
|
||||
id="confirm_password"
|
||||
value={passwordFormData.confirm_password}
|
||||
onChange={(e) => handleFormChange("confirm_password", e.target.value)}
|
||||
placeholder={t("auth.common.password.confirm_password.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
{showPassword.retypePassword ? (
|
||||
<EyeOff
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("retypePassword")}
|
||||
/>
|
||||
) : (
|
||||
<Eye
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("retypePassword")}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleShowPassword("retypePassword")}
|
||||
className="grid size-5 place-items-center"
|
||||
>
|
||||
{showPassword.retypePassword ? (
|
||||
<EyeOff className="size-5 stroke-placeholder" />
|
||||
) : (
|
||||
<Eye className="size-5 stroke-placeholder" />
|
||||
)}
|
||||
</button>
|
||||
</InputGroup>
|
||||
{!!passwordFormData.confirm_password &&
|
||||
passwordFormData.password !== passwordFormData.confirm_password &&
|
||||
renderPasswordMatchError && (
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { CircleCheck, XCircle } from "lucide-react";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { API_BASE_URL } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { Input, Spinner } from "@plane/ui";
|
||||
import { Spinner } from "@plane/ui";
|
||||
// constants
|
||||
// helpers
|
||||
import { EAuthModes } from "@/helpers/authentication.helper";
|
||||
@@ -98,45 +99,47 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||
<label htmlFor="email" className="text-13 font-medium text-tertiary">
|
||||
{t("auth.common.email.label")}
|
||||
</label>
|
||||
<div className={`relative flex items-center rounded-md border border-strong bg-surface-1`}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={uniqueCodeFormData.email}
|
||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className="h-10 w-full border-0 disable-autofill-style placeholder:text-placeholder"
|
||||
autoComplete="off"
|
||||
disabled
|
||||
/>
|
||||
{uniqueCodeFormData.email.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
className="absolute right-3 grid size-5 place-items-center"
|
||||
className="grid size-5 place-items-center"
|
||||
aria-label={t("aria_labels.auth_forms.clear_email")}
|
||||
onClick={handleEmailClear}
|
||||
>
|
||||
<XCircle className="size-5 stroke-placeholder" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label htmlFor="unique-code" className="text-13 font-medium text-tertiary">
|
||||
{t("auth.common.unique_code.label")}
|
||||
</label>
|
||||
<Input
|
||||
name="code"
|
||||
id="unique-code"
|
||||
value={uniqueCodeFormData.code}
|
||||
onChange={(e) => handleFormChange("code", e.target.value)}
|
||||
placeholder={t("auth.common.unique_code.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 disable-autofill-style placeholder:text-placeholder"
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
name="code"
|
||||
id="unique-code"
|
||||
value={uniqueCodeFormData.code}
|
||||
onChange={(e) => handleFormChange("code", e.target.value)}
|
||||
placeholder={t("auth.common.unique_code.placeholder")}
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
</InputGroup>
|
||||
<div className="flex w-full items-center justify-between px-1 pt-1 text-11">
|
||||
<p className="flex items-center gap-1 font-medium text-success-primary">
|
||||
<CircleCheck height={12} width={12} />
|
||||
|
||||
@@ -9,13 +9,15 @@ import { add } from "date-fns";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Calendar } from "lucide-react";
|
||||
// types
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { IApiToken } from "@plane/types";
|
||||
// ui
|
||||
import { Switch } from "@makeplane/propel/components/switch";
|
||||
import { CustomSelect, Input, TextArea } from "@plane/ui";
|
||||
import { CustomSelect, TextArea } from "@plane/ui";
|
||||
import { cn, renderFormattedDate, renderFormattedTime } from "@plane/utils";
|
||||
// components
|
||||
import { DateDropdown } from "@/components/dropdowns/date";
|
||||
@@ -144,14 +146,18 @@ export function CreateApiTokenForm(props: Props) {
|
||||
validate: (val) => val.trim() !== "" || t("title_is_required"),
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Input
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
hasError={Boolean(errors.label)}
|
||||
placeholder={t("title")}
|
||||
className="w-full text-14"
|
||||
/>
|
||||
<Field name="input" invalid={Boolean(errors.label)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder={t("title")}
|
||||
aria-label={t("title")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{errors.label && <span className="text-11 text-danger-primary">{errors.label.message}</span>}
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
import { useParams } from "next/navigation";
|
||||
// react-hook-form
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import type { IProject } from "@plane/types";
|
||||
// ui
|
||||
import { Input, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||
|
||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||
// types
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
@@ -63,19 +64,22 @@ export function SelectMonthModal({ type, initialValues, isOpen, handleClose, han
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<div className="relative flex w-full flex-col justify-center gap-1">
|
||||
<Input
|
||||
id="close_in"
|
||||
name="close_in"
|
||||
type="number"
|
||||
value={value?.toString()}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.close_in)}
|
||||
placeholder="Enter Months"
|
||||
className="w-full border-subtle"
|
||||
min={1}
|
||||
max={12}
|
||||
/>
|
||||
<Field name="close_in" invalid={Boolean(errors.close_in)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="close_in"
|
||||
name="close_in"
|
||||
type="number"
|
||||
value={value?.toString()}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Enter Months"
|
||||
min={1}
|
||||
max={12}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<span className="absolute top-2.5 right-8 text-13 text-secondary">Months</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -97,19 +101,22 @@ export function SelectMonthModal({ type, initialValues, isOpen, handleClose, han
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<div className="relative flex w-full flex-col justify-center gap-1">
|
||||
<Input
|
||||
id="archive_in"
|
||||
name="archive_in"
|
||||
type="number"
|
||||
value={value?.toString()}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.archive_in)}
|
||||
placeholder="Enter Months"
|
||||
className="w-full border-subtle"
|
||||
min={1}
|
||||
max={12}
|
||||
/>
|
||||
<Field name="archive_in" invalid={Boolean(errors.archive_in)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="archive_in"
|
||||
name="archive_in"
|
||||
type="number"
|
||||
value={value?.toString()}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Enter Months"
|
||||
min={1}
|
||||
max={12}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<span className="absolute top-2.5 right-8 text-13 text-secondary">Months</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -13,13 +13,14 @@ import { Controller } from "react-hook-form";
|
||||
import useSWR from "swr";
|
||||
import { Popover } from "@headlessui/react";
|
||||
// plane imports
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ACCEPTED_COVER_IMAGE_MIME_TYPES_FOR_REACT_DROPZONE, MAX_FILE_SIZE } from "@plane/constants";
|
||||
import { useOutsideClickDetector } from "@plane/hooks";
|
||||
import { Tabs } from "@plane/propel/tabs";
|
||||
import { Button, getButtonStyling } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import { EFileAssetType } from "@plane/types";
|
||||
import { Input, Loader } from "@plane/ui";
|
||||
import { Loader } from "@plane/ui";
|
||||
// helpers
|
||||
import { STATIC_COVER_IMAGES, getCoverImageDisplayURL } from "@/helpers/cover-image.helper";
|
||||
// hooks
|
||||
@@ -223,22 +224,24 @@ function ImagePickerPopoverComponent<TFieldValues extends FieldValues = FieldVal
|
||||
control={control}
|
||||
name={"search" as FieldPath<TFieldValues>}
|
||||
render={({ field: { value, ref } }) => (
|
||||
<Input
|
||||
id="search"
|
||||
name="search"
|
||||
type="text"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
setSearchParams(formData.search);
|
||||
}
|
||||
}}
|
||||
value={value}
|
||||
onChange={(e) => setFormData({ ...formData, search: e.target.value })}
|
||||
ref={ref}
|
||||
placeholder="Search for images"
|
||||
className="w-full text-13"
|
||||
/>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="search"
|
||||
name="search"
|
||||
type="text"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
setSearchParams(formData.search);
|
||||
}
|
||||
}}
|
||||
value={value}
|
||||
onChange={(e) => setFormData({ ...formData, search: e.target.value })}
|
||||
ref={ref}
|
||||
placeholder="Search for images"
|
||||
/>
|
||||
</InputGroup>
|
||||
)}
|
||||
/>
|
||||
<Button variant="primary" size="xl" onClick={() => setSearchParams(formData.search)}>
|
||||
|
||||
@@ -8,10 +8,12 @@ import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import { Input, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||
import { cn } from "@plane/utils";
|
||||
// helpers
|
||||
import { authErrorHandler } from "@/helpers/authentication.helper";
|
||||
@@ -151,22 +153,22 @@ export const ChangeEmailModal = observer(function ChangeEmailModal(props: Props)
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.email)}
|
||||
placeholder={changeEmailT("form.email.placeholder")}
|
||||
className={cn(
|
||||
{ "border-danger-strong": errors.email },
|
||||
{ "cursor-not-allowed !bg-surface-2": secondStep }
|
||||
)}
|
||||
autoComplete="off"
|
||||
disabled={secondStep}
|
||||
/>
|
||||
<Field name="email" invalid={Boolean(errors.email)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={changeEmailT("form.email.placeholder")}
|
||||
autoComplete="off"
|
||||
disabled={secondStep}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{errors?.email && <span className="text-11 text-danger-primary">{errors?.email?.message}</span>}
|
||||
@@ -180,17 +182,19 @@ export const ChangeEmailModal = observer(function ChangeEmailModal(props: Props)
|
||||
name="code"
|
||||
rules={{ required: changeEmailT("form.code.errors.required") }}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="code"
|
||||
name="code"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={changeEmailT("form.code.placeholder")}
|
||||
className={cn({ "border-danger-strong": errors.code })}
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="code"
|
||||
name="code"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={changeEmailT("form.code.placeholder")}
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
/>
|
||||
</InputGroup>
|
||||
)}
|
||||
/>
|
||||
{errors?.code ? (
|
||||
|
||||
@@ -12,10 +12,11 @@ import { usePopper } from "react-popper";
|
||||
import { AlertCircle } from "lucide-react";
|
||||
import { Popover, Transition } from "@headlessui/react";
|
||||
// plane imports
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import type { EditorRefApi } from "@plane/editor";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
// components
|
||||
import { RichTextEditor } from "@/components/editor/rich-text";
|
||||
// services
|
||||
@@ -260,19 +261,21 @@ export function GptAssistantPopover(props: Props) {
|
||||
control={control}
|
||||
name="task"
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="task"
|
||||
name="task"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={`${
|
||||
prompt && prompt !== "" ? "Tell AI what action to perform on this content..." : "Ask AI anything..."
|
||||
}`}
|
||||
className="w-full"
|
||||
autoFocus
|
||||
/>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="task"
|
||||
name="task"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={`${
|
||||
prompt && prompt !== "" ? "Tell AI what action to perform on this content..." : "Ask AI anything..."
|
||||
}`}
|
||||
autoFocus
|
||||
/>
|
||||
</InputGroup>
|
||||
)}
|
||||
/>
|
||||
<div className="flex justify-between gap-2">
|
||||
|
||||
@@ -7,13 +7,15 @@
|
||||
import { useEffect } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ETabIndices } from "@plane/constants";
|
||||
// types
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import type { ICycle } from "@plane/types";
|
||||
// ui
|
||||
import { Input, TextArea } from "@plane/ui";
|
||||
import { TextArea } from "@plane/ui";
|
||||
import { getDate, renderFormattedPayloadDate, getTabIndex } from "@plane/utils";
|
||||
// components
|
||||
import { DateRangeDropdown } from "@/components/dropdowns/date-range";
|
||||
@@ -113,18 +115,21 @@ export function CycleForm(props: Props) {
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Input
|
||||
name="name"
|
||||
type="text"
|
||||
placeholder={t("title")}
|
||||
className="w-full text-14"
|
||||
value={value}
|
||||
inputSize="md"
|
||||
onChange={onChange}
|
||||
hasError={Boolean(errors?.name)}
|
||||
tabIndex={getIndex("description")}
|
||||
autoFocus
|
||||
/>
|
||||
<Field name="name" invalid={Boolean(errors?.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
name="name"
|
||||
type="text"
|
||||
placeholder={t("title")}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
tabIndex={getIndex("description")}
|
||||
autoFocus
|
||||
aria-label={t("title")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<span className="text-11 text-danger-primary">{errors?.name?.message}</span>
|
||||
|
||||
@@ -9,10 +9,12 @@ import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// plane types
|
||||
// plane ui
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import type { TLinkEditableFields } from "@plane/types";
|
||||
import { Input, ModalCore } from "@plane/ui";
|
||||
import { ModalCore } from "@plane/ui";
|
||||
import type { TLinkOperations } from "./use-links";
|
||||
|
||||
export type TLinkOperationsModal = Exclude<TLinkOperations, "remove">;
|
||||
@@ -87,16 +89,19 @@ export const LinkCreateUpdateModal = observer(function LinkCreateUpdateModal(pro
|
||||
required: t("link.modal.url.required"),
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="url"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.url)}
|
||||
placeholder={t("link.modal.url.placeholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
<Field name="url" invalid={Boolean(errors.url)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="url"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={t("link.modal.url.placeholder")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{errors.url && <span className="text-11 text-danger-primary">{t("link.modal.url.required")}</span>}
|
||||
@@ -110,16 +115,19 @@ export const LinkCreateUpdateModal = observer(function LinkCreateUpdateModal(pro
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="title"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.title)}
|
||||
placeholder={t("link.modal.title.placeholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
<Field name="title" invalid={Boolean(errors.title)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="title"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={t("link.modal.title.placeholder")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
// plane imports
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ETabIndices } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import type { TIssue } from "@plane/types";
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
// helpers
|
||||
import { getTabIndex } from "@plane/utils";
|
||||
// hooks
|
||||
@@ -30,17 +31,19 @@ export const InboxIssueTitle = observer(function InboxIssueTitle(props: TInboxIs
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={data?.name}
|
||||
onChange={(e) => handleData("name", e.target.value)}
|
||||
placeholder={t("title")}
|
||||
className="w-full text-14"
|
||||
tabIndex={getIndex("name")}
|
||||
required
|
||||
/>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={data?.name}
|
||||
onChange={(e) => handleData("name", e.target.value)}
|
||||
placeholder={t("title")}
|
||||
tabIndex={getIndex("name")}
|
||||
required
|
||||
/>
|
||||
</InputGroup>
|
||||
{isTitleLengthMoreThan255Character && (
|
||||
<span className="text-11 text-danger-primary">{t("title_should_be_less_than_255_characters")}</span>
|
||||
)}
|
||||
|
||||
@@ -10,10 +10,12 @@ import { Controller, useForm } from "react-hook-form";
|
||||
import { usePopper } from "react-popper";
|
||||
import { Loader } from "lucide-react";
|
||||
import { Popover } from "@headlessui/react";
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { PlusIcon, CloseIcon } from "@plane/propel/icons";
|
||||
import type { IIssueLabel } from "@plane/types";
|
||||
// hooks
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
// ui
|
||||
// types
|
||||
import type { TLabelOperations } from "./root";
|
||||
@@ -134,18 +136,21 @@ export function LabelCreate(props: ILabelCreate) {
|
||||
required: "This is required",
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value ?? ""}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.name)}
|
||||
placeholder="Title"
|
||||
className="w-full px-1.5 py-1 text-11"
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
<Field name="name" invalid={Boolean(errors.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value ?? ""}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Title"
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<button
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
import { useEffect } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// plane types
|
||||
import { Button } from "@plane/propel/button";
|
||||
import type { TIssueLinkEditableFields, TIssueServiceType } from "@plane/types";
|
||||
// plane ui
|
||||
import { Input, ModalCore } from "@plane/ui";
|
||||
import { ModalCore } from "@plane/ui";
|
||||
// hooks
|
||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||
// types
|
||||
@@ -93,16 +95,19 @@ export const IssueLinkCreateUpdateModal = observer(function IssueLinkCreateUpdat
|
||||
required: "URL is required",
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="url"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.url)}
|
||||
placeholder={t("common.type_or_paste_a_url")}
|
||||
className="w-full"
|
||||
/>
|
||||
<Field name="url" invalid={Boolean(errors.url)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="url"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={t("common.type_or_paste_a_url")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{errors.url && (
|
||||
@@ -118,16 +123,19 @@ export const IssueLinkCreateUpdateModal = observer(function IssueLinkCreateUpdat
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="title"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.title)}
|
||||
placeholder={t("common.link_title_placeholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
<Field name="title" invalid={Boolean(errors.title)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="title"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={t("common.link_title_placeholder")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -9,12 +9,14 @@ import { observer } from "mobx-react";
|
||||
import type { Control, FormState } from "react-hook-form";
|
||||
import { Controller } from "react-hook-form";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ETabIndices } from "@plane/constants";
|
||||
// types
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import type { TIssue } from "@plane/types";
|
||||
// ui
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
// helpers
|
||||
import { getTabIndex } from "@plane/utils";
|
||||
// hooks
|
||||
@@ -60,22 +62,25 @@ export const IssueTitleInput = observer(function IssueTitleInput(props: TIssueTi
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
handleFormChange();
|
||||
}}
|
||||
ref={issueTitleRef || ref}
|
||||
hasError={Boolean(errors.name)}
|
||||
placeholder={t("title")}
|
||||
className="w-full text-body-sm-regular"
|
||||
autoFocus
|
||||
tabIndex={getIndex("name")}
|
||||
/>
|
||||
<Field name="name" invalid={Boolean(errors.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
handleFormChange();
|
||||
}}
|
||||
ref={issueTitleRef || ref}
|
||||
placeholder={t("title")}
|
||||
autoFocus
|
||||
tabIndex={getIndex("name")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<span className="text-caption-sm-medium text-danger-primary">{errors?.name?.message}</span>
|
||||
|
||||
@@ -11,12 +11,13 @@ import type { SubmitHandler } from "react-hook-form";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Popover, Transition } from "@headlessui/react";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { getRandomLabelColor, LABEL_COLOR_OPTIONS } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { IIssueLabel } from "@plane/types";
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
// error codes
|
||||
const errorCodes = {
|
||||
@@ -219,18 +220,21 @@ export const CreateUpdateLabelInline = observer(
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="labelName"
|
||||
name="name"
|
||||
type="text"
|
||||
autoFocus
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.name)}
|
||||
placeholder={t("project_settings.labels.label_title")}
|
||||
className="w-full"
|
||||
/>
|
||||
<Field name="name" invalid={Boolean(errors.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="labelName"
|
||||
name="name"
|
||||
type="text"
|
||||
autoFocus
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={t("project_settings.labels.label_title")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
import { useEffect } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ETabIndices } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import type { IModule } from "@plane/types";
|
||||
// ui
|
||||
import { Input, TextArea } from "@plane/ui";
|
||||
import { TextArea } from "@plane/ui";
|
||||
import { getDate, renderFormattedPayloadDate, getTabIndex } from "@plane/utils";
|
||||
// components
|
||||
import { DateRangeDropdown } from "@/components/dropdowns/date-range";
|
||||
@@ -124,18 +126,21 @@ export function ModuleForm(props: Props) {
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
hasError={Boolean(errors?.name)}
|
||||
placeholder={t("title")}
|
||||
className="w-full text-14"
|
||||
tabIndex={getIndex("name")}
|
||||
autoFocus
|
||||
/>
|
||||
<Field name="name" invalid={Boolean(errors?.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder={t("title")}
|
||||
tabIndex={getIndex("name")}
|
||||
autoFocus
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<span className="text-11 text-danger-primary">{errors?.name?.message}</span>
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
import { useEffect } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// plane types
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { ILinkDetails, ModuleLink } from "@plane/types";
|
||||
// plane ui
|
||||
import { Input, ModalCore } from "@plane/ui";
|
||||
|
||||
import { ModalCore } from "@plane/ui";
|
||||
type Props = {
|
||||
createLink: (formData: ModuleLink) => Promise<void>;
|
||||
data?: ILinkDetails | null;
|
||||
@@ -99,16 +100,19 @@ export function CreateUpdateModuleLinkModal(props: Props) {
|
||||
required: "URL is required",
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="url"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.url)}
|
||||
placeholder="Type or paste a URL"
|
||||
className="w-full"
|
||||
/>
|
||||
<Field name="url" invalid={Boolean(errors.url)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="url"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Type or paste a URL"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -121,16 +125,19 @@ export function CreateUpdateModuleLinkModal(props: Props) {
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="title"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.title)}
|
||||
placeholder="What you'd like to see this link as"
|
||||
className="w-full"
|
||||
/>
|
||||
<Field name="title" invalid={Boolean(errors.title)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="title"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="What you'd like to see this link as"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,8 @@ import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// constants
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ORGANIZATION_SIZE, RESTRICTED_URLS } from "@plane/constants";
|
||||
// types
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -15,7 +17,7 @@ import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { IUser, IWorkspace, TOnboardingSteps } from "@plane/types";
|
||||
// ui
|
||||
import { CustomSelect, Input, Spinner } from "@plane/ui";
|
||||
import { CustomSelect, Spinner } from "@plane/ui";
|
||||
import { validateWorkspaceName, validateSlug } from "@plane/utils";
|
||||
// hooks
|
||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
@@ -147,24 +149,27 @@ export const CreateWorkspace = observer(function CreateWorkspace(props: Props) {
|
||||
}}
|
||||
render={({ field: { value, ref, onChange } }) => (
|
||||
<div className="relative flex items-center rounded-md">
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(event) => {
|
||||
onChange(event.target.value);
|
||||
setValue("name", event.target.value);
|
||||
setValue("slug", event.target.value.toLocaleLowerCase().trim().replace(/ /g, "-"), {
|
||||
shouldValidate: true,
|
||||
});
|
||||
}}
|
||||
placeholder={t("workspace_creation.form.name.placeholder")}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.name)}
|
||||
className="w-full border-strong placeholder:text-placeholder"
|
||||
autoFocus
|
||||
/>
|
||||
<Field name="name" invalid={Boolean(errors.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(event) => {
|
||||
onChange(event.target.value);
|
||||
setValue("name", event.target.value);
|
||||
setValue("slug", event.target.value.toLocaleLowerCase().trim().replace(/ /g, "-"), {
|
||||
shouldValidate: true,
|
||||
});
|
||||
}}
|
||||
placeholder={t("workspace_creation.form.name.placeholder")}
|
||||
ref={ref}
|
||||
autoFocus
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
@@ -188,29 +193,26 @@ export const CreateWorkspace = observer(function CreateWorkspace(props: Props) {
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, ref, onChange } }) => (
|
||||
<div
|
||||
className={`relative flex items-center rounded-md border-[0.5px] px-3 ${
|
||||
invalidSlug ? "border-danger-strong" : "border-strong"
|
||||
}`}
|
||||
>
|
||||
<span className="text-13 whitespace-nowrap">{window && window.location.host}/</span>
|
||||
<Input
|
||||
id="slug"
|
||||
name="slug"
|
||||
type="text"
|
||||
value={value.toLocaleLowerCase().trim().replace(/ /g, "-")}
|
||||
onChange={(e) => {
|
||||
const validation = validateSlug(e.target.value);
|
||||
if (validation === true) setInvalidSlug(false);
|
||||
else setInvalidSlug(true);
|
||||
onChange(e.target.value.toLowerCase());
|
||||
}}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.slug)}
|
||||
placeholder={t("workspace_creation.form.url.placeholder")}
|
||||
className="w-full border-none !px-0"
|
||||
/>
|
||||
</div>
|
||||
<Field name="slug" invalid={invalidSlug || Boolean(errors.slug)}>
|
||||
<InputGroup size="2xl">
|
||||
<span className="text-13 whitespace-nowrap">{window && window.location.host}/</span>
|
||||
<Input
|
||||
size="2xl"
|
||||
id="slug"
|
||||
name="slug"
|
||||
type="text"
|
||||
value={value.toLocaleLowerCase().trim().replace(/ /g, "-")}
|
||||
onChange={(e) => {
|
||||
const validation = validateSlug(e.target.value);
|
||||
if (validation === true) setInvalidSlug(false);
|
||||
else setInvalidSlug(true);
|
||||
onChange(e.target.value.toLowerCase());
|
||||
}}
|
||||
ref={ref}
|
||||
placeholder={t("workspace_creation.form.url.placeholder")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<p className="text-13 text-tertiary">{t("workspace_creation.form.url.edit_slug")}</p>
|
||||
|
||||
@@ -20,6 +20,8 @@ import { usePopper } from "react-popper";
|
||||
import { XCircle } from "lucide-react";
|
||||
import { Listbox } from "@headlessui/react";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import type { EUserPermissions } from "@plane/constants";
|
||||
import { ROLE, ROLE_DETAILS } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -29,7 +31,7 @@ import { PlusIcon, CheckIcon, ChevronDownIcon } from "@plane/propel/icons";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { IUser, IWorkspace } from "@plane/types";
|
||||
// ui
|
||||
import { Input, Spinner } from "@plane/ui";
|
||||
import { Spinner } from "@plane/ui";
|
||||
// services
|
||||
import { WorkspaceService } from "@/services/workspace.service";
|
||||
// components
|
||||
@@ -153,21 +155,24 @@ const InviteMemberInput = observer(function InviteMemberInput(props: InviteMembe
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id={`emails.${index}.email`}
|
||||
name={`emails.${index}.email`}
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(event) => {
|
||||
emailOnChange(event);
|
||||
onChange(event);
|
||||
}}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.emails?.[index]?.email)}
|
||||
placeholder={placeholderEmails[index % placeholderEmails.length]}
|
||||
className="w-full border-strong text-11 placeholder:text-placeholder sm:text-13"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<Field name="input" invalid={Boolean(errors.emails?.[index]?.email)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id={`emails.${index}.email`}
|
||||
name={`emails.${index}.email`}
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(event) => {
|
||||
emailOnChange(event);
|
||||
onChange(event);
|
||||
}}
|
||||
ref={ref}
|
||||
placeholder={placeholderEmails[index % placeholderEmails.length]}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,8 @@ import { useMemo, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Eye, EyeOff } from "lucide-react";
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { E_PASSWORD_STRENGTH } from "@plane/constants";
|
||||
// types
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -15,7 +17,7 @@ import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { IUser, TUserProfile, TOnboardingSteps } from "@plane/types";
|
||||
// ui
|
||||
import { Input, PasswordStrengthIndicator, Spinner } from "@plane/ui";
|
||||
import { PasswordStrengthIndicator, Spinner } from "@plane/ui";
|
||||
// components
|
||||
import { cn, getFileURL, getPasswordStrength, validatePersonName } from "@plane/utils";
|
||||
import { UserImageUploadModal } from "@/components/core/modals/user-image-upload-modal";
|
||||
@@ -310,19 +312,22 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="first_name"
|
||||
name="first_name"
|
||||
type="text"
|
||||
value={value}
|
||||
autoFocus
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.first_name)}
|
||||
placeholder="Wilbur"
|
||||
className="w-full border-strong"
|
||||
autoComplete="on"
|
||||
/>
|
||||
<Field name="first_name" invalid={Boolean(errors.first_name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="first_name"
|
||||
name="first_name"
|
||||
type="text"
|
||||
value={value}
|
||||
autoFocus
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Wilbur"
|
||||
autoComplete="on"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{errors.first_name && (
|
||||
@@ -348,18 +353,21 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="last_name"
|
||||
name="last_name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.last_name)}
|
||||
placeholder="Wright"
|
||||
className="w-full border-strong"
|
||||
autoComplete="on"
|
||||
/>
|
||||
<Field name="last_name" invalid={Boolean(errors.last_name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="last_name"
|
||||
name="last_name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Wright"
|
||||
autoComplete="on"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{errors.last_name && <span className="text-13 text-danger-primary">{errors.last_name.message}</span>}
|
||||
@@ -380,32 +388,34 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||
required: false,
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<div className="relative flex items-center rounded-md">
|
||||
<Input
|
||||
type={showPassword.password ? "text" : "password"}
|
||||
name="password"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.password)}
|
||||
placeholder="New password..."
|
||||
className="w-full border-[0.5px] border-subtle pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
{showPassword.password ? (
|
||||
<EyeOff
|
||||
className="absolute right-3 h-4 w-4 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
<Field name="password" invalid={Boolean(errors.password)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
type={showPassword.password ? "text" : "password"}
|
||||
name="password"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="New password..."
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
aria-label="New password..."
|
||||
/>
|
||||
) : (
|
||||
<Eye
|
||||
className="absolute right-3 h-4 w-4 stroke-placeholder hover:cursor-pointer"
|
||||
<button
|
||||
type="button"
|
||||
className="grid size-5 place-items-center"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
>
|
||||
{showPassword.password ? (
|
||||
<EyeOff className="size-4 stroke-placeholder" />
|
||||
) : (
|
||||
<Eye className="size-4 stroke-placeholder" />
|
||||
)}
|
||||
</button>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<PasswordStrengthIndicator password={watch("password") ?? ""} isFocused={isPasswordInputFocused} />
|
||||
@@ -423,30 +433,32 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||
watch("password") ? (value === watch("password") ? true : "Passwords don't match") : true,
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<div className="relative flex items-center rounded-md">
|
||||
<Input
|
||||
type={showPassword.retypePassword ? "text" : "password"}
|
||||
name="confirm_password"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.confirm_password)}
|
||||
placeholder={t("auth.common.password.confirm_password.placeholder")}
|
||||
className="w-full border-subtle pr-12 placeholder:text-placeholder"
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
{showPassword.retypePassword ? (
|
||||
<EyeOff
|
||||
className="absolute right-3 h-4 w-4 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("retypePassword")}
|
||||
<Field name="confirm_password" invalid={Boolean(errors.confirm_password)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
type={showPassword.retypePassword ? "text" : "password"}
|
||||
name="confirm_password"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={t("auth.common.password.confirm_password.placeholder")}
|
||||
autoComplete="new-password"
|
||||
aria-label={t("auth.common.password.confirm_password.placeholder")}
|
||||
/>
|
||||
) : (
|
||||
<Eye
|
||||
className="absolute right-3 h-4 w-4 stroke-placeholder hover:cursor-pointer"
|
||||
<button
|
||||
type="button"
|
||||
className="grid size-5 place-items-center"
|
||||
onClick={() => handleShowPassword("retypePassword")}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
>
|
||||
{showPassword.retypePassword ? (
|
||||
<EyeOff className="size-4 stroke-placeholder" />
|
||||
) : (
|
||||
<Eye className="size-4 stroke-placeholder" />
|
||||
)}
|
||||
</button>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{errors.confirm_password && (
|
||||
|
||||
@@ -19,6 +19,8 @@ import { usePopper } from "react-popper";
|
||||
import { XCircle } from "lucide-react";
|
||||
import { Listbox } from "@headlessui/react";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import type { EUserPermissions } from "@plane/constants";
|
||||
import { ROLE, ROLE_DETAILS } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -26,7 +28,7 @@ import { Button } from "@plane/propel/button";
|
||||
import { PlusIcon, CheckIcon, ChevronDownIcon } from "@plane/propel/icons";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import { EOnboardingSteps } from "@plane/types";
|
||||
import { Input, Spinner } from "@plane/ui";
|
||||
import { Spinner } from "@plane/ui";
|
||||
// hooks
|
||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
// services
|
||||
@@ -149,21 +151,24 @@ const InviteMemberInput = observer(function InviteMemberInput(props: InviteMembe
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id={`emails.${index}.email`}
|
||||
name={`emails.${index}.email`}
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(event) => {
|
||||
emailOnChange(event);
|
||||
onChange(event);
|
||||
}}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.emails?.[index]?.email)}
|
||||
placeholder={placeholderEmails[index % placeholderEmails.length]}
|
||||
className="w-full border-strong text-11 placeholder:text-placeholder sm:text-13"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<Field name="input" invalid={Boolean(errors.emails?.[index]?.email)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id={`emails.${index}.email`}
|
||||
name={`emails.${index}.email`}
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(event) => {
|
||||
emailOnChange(event);
|
||||
onChange(event);
|
||||
}}
|
||||
ref={ref}
|
||||
placeholder={placeholderEmails[index % placeholderEmails.length]}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useState } from "react";
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
|
||||
// plane imports
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ETabIndices, EPageAccess } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
@@ -16,7 +17,7 @@ import { EmojiPicker, EmojiIconPickerTypes, Logo } from "@plane/propel/emoji-ico
|
||||
import { GlobeIcon, LockIcon, PageIcon } from "@plane/propel/icons";
|
||||
import type { ISvgIcons } from "@plane/propel/icons";
|
||||
import type { TPage } from "@plane/types";
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
import { getTabIndex } from "@plane/utils";
|
||||
// components
|
||||
import { AccessField } from "@/components/common/access-field";
|
||||
@@ -114,17 +115,19 @@ export function PageForm(props: Props) {
|
||||
}
|
||||
/>
|
||||
<div className="flew-grow w-full space-y-1">
|
||||
<Input
|
||||
id="name"
|
||||
type="text"
|
||||
value={formData.name}
|
||||
onChange={(e) => handleFormData("name", e.target.value)}
|
||||
placeholder="Title"
|
||||
className="w-full resize-none text-14"
|
||||
tabIndex={getIndex("name")}
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
type="text"
|
||||
value={formData.name}
|
||||
onChange={(e) => handleFormData("name", e.target.value)}
|
||||
placeholder="Title"
|
||||
tabIndex={getIndex("name")}
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
</InputGroup>
|
||||
{isTitleLengthMoreThan255Character && (
|
||||
<span className="text-11 text-danger-primary">
|
||||
Max length of the name should be less than 255 characters
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
import { useState, Fragment } from "react";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
// plane imports
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { CloseIcon, SearchIcon } from "@plane/propel/icons";
|
||||
import { ScrollArea } from "@plane/propel/scrollarea";
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
// hooks
|
||||
import { usePowerK } from "@/hooks/store/use-power-k";
|
||||
// local imports
|
||||
@@ -70,20 +71,21 @@ export function ShortcutsModal(props: Props) {
|
||||
</button>
|
||||
</Dialog.Title>
|
||||
<div className="px-5">
|
||||
<div className="flex w-full items-center rounded-sm border-[0.5px] border-subtle bg-surface-2 px-2">
|
||||
<InputGroup size="2xl">
|
||||
<SearchIcon className="h-3.5 w-3.5 text-secondary" />
|
||||
<Input
|
||||
size="2xl"
|
||||
id="search"
|
||||
name="search"
|
||||
type="text"
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
placeholder="Search for shortcuts"
|
||||
className="w-full border-none bg-transparent py-1 text-11 text-secondary outline-none"
|
||||
aria-label="Search for shortcuts"
|
||||
autoFocus
|
||||
tabIndex={1}
|
||||
/>
|
||||
</div>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
||||
<ScrollArea size="sm" rootClassName="overflow-y-scroll px-5">
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { TwitterPicker } from "react-color";
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import type { IState } from "@plane/types";
|
||||
import { Popover, Input, TextArea } from "@plane/ui";
|
||||
|
||||
import { Popover, TextArea } from "@plane/ui";
|
||||
type TStateForm = {
|
||||
data: Partial<IState>;
|
||||
onSubmit: (formData: Partial<IState>) => Promise<{ status: string }>;
|
||||
@@ -73,18 +74,21 @@ export function StateForm(props: TStateForm) {
|
||||
|
||||
<div className="w-full space-y-2">
|
||||
{/* title */}
|
||||
<Input
|
||||
id="name"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="Name"
|
||||
value={formData?.name}
|
||||
onChange={(e) => handleFormData("name", e.target.value)}
|
||||
hasError={(errors && Boolean(errors.name)) || false}
|
||||
className="w-full"
|
||||
maxLength={100}
|
||||
autoFocus
|
||||
/>
|
||||
<Field name="name" invalid={(errors && Boolean(errors.name)) || false}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="Name"
|
||||
value={formData?.name}
|
||||
onChange={(e) => handleFormData("name", e.target.value)}
|
||||
maxLength={100}
|
||||
autoFocus
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
|
||||
{/* description */}
|
||||
<TextArea
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
import type { ChangeEvent } from "react";
|
||||
import type { UseFormSetValue } from "react-hook-form";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { InfoIcon } from "@plane/propel/icons";
|
||||
// plane imports
|
||||
import { ETabIndices } from "@plane/constants";
|
||||
@@ -14,7 +16,7 @@ import { useTranslation } from "@plane/i18n";
|
||||
import type { TProject } from "@plane/types";
|
||||
// ui
|
||||
import { Tooltip } from "@plane/propel/tooltip";
|
||||
import { Input, TextArea } from "@plane/ui";
|
||||
import { TextArea } from "@plane/ui";
|
||||
import { cn, projectIdentifierSanitizer, getTabIndex } from "@plane/utils";
|
||||
|
||||
type Props = {
|
||||
@@ -68,17 +70,20 @@ function ProjectCommonAttributes(props: Props) {
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={handleNameChange(onChange)}
|
||||
hasError={Boolean(errors.name)}
|
||||
placeholder={t("project_name")}
|
||||
className="focus:border-blue-400 w-full"
|
||||
tabIndex={getIndex("name")}
|
||||
/>
|
||||
<Field name="name" invalid={Boolean(errors.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={handleNameChange(onChange)}
|
||||
placeholder={t("project_name")}
|
||||
tabIndex={getIndex("name")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<span className="text-11 text-danger-primary">{errors?.name?.message}</span>
|
||||
@@ -102,19 +107,20 @@ function ProjectCommonAttributes(props: Props) {
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Input
|
||||
id="identifier"
|
||||
name="identifier"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={handleIdentifierChange(onChange)}
|
||||
hasError={Boolean(errors.identifier)}
|
||||
placeholder={t("project_id")}
|
||||
className={cn("focus:border-blue-400 w-full pr-7 text-11", {
|
||||
uppercase: value,
|
||||
})}
|
||||
tabIndex={getIndex("identifier")}
|
||||
/>
|
||||
<Field name="identifier" invalid={Boolean(errors.identifier)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="identifier"
|
||||
name="identifier"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={handleIdentifierChange(onChange)}
|
||||
placeholder={t("project_id")}
|
||||
tabIndex={getIndex("identifier")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<Tooltip
|
||||
|
||||
@@ -8,10 +8,12 @@ import { useParams } from "next/navigation";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { AlertTriangle } from "lucide-react";
|
||||
// Plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { IProject } from "@plane/types";
|
||||
import { Input, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||
// hooks
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
@@ -100,18 +102,21 @@ export function DeleteProjectModal(props: DeleteProjectModal) {
|
||||
control={control}
|
||||
name="projectName"
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="projectName"
|
||||
name="projectName"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.projectName)}
|
||||
placeholder="Project name"
|
||||
className="mt-2 w-full"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<Field name="projectName" invalid={Boolean(errors.projectName)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="projectName"
|
||||
name="projectName"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Project name"
|
||||
autoComplete="off"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -123,18 +128,21 @@ export function DeleteProjectModal(props: DeleteProjectModal) {
|
||||
control={control}
|
||||
name="confirmDelete"
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="confirmDelete"
|
||||
name="confirmDelete"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.confirmDelete)}
|
||||
placeholder="Enter 'delete my project'"
|
||||
className="mt-2 w-full"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<Field name="confirmDelete" invalid={Boolean(errors.confirmDelete)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="confirmDelete"
|
||||
name="confirmDelete"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Enter 'delete my project'"
|
||||
autoComplete="off"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Info } from "lucide-react";
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { NETWORK_CHOICES } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// plane imports
|
||||
@@ -17,7 +19,7 @@ import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import { Tooltip } from "@plane/propel/tooltip";
|
||||
import { EFileAssetType } from "@plane/types";
|
||||
import type { IProject, IWorkspace } from "@plane/types";
|
||||
import { CustomSelect, Input, TextArea } from "@plane/ui";
|
||||
import { CustomSelect, TextArea } from "@plane/ui";
|
||||
import { renderFormattedDate } from "@plane/utils";
|
||||
import { CoverImage } from "@/components/common/cover-image";
|
||||
import { ImagePickerPopover } from "@/components/core/image-picker-popover";
|
||||
@@ -287,18 +289,21 @@ export function ProjectDetailsForm(props: IProjectDetailsForm) {
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
ref={ref}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
hasError={Boolean(errors.name)}
|
||||
className="rounded-md !p-3 font-medium"
|
||||
placeholder={t("common.project_name")}
|
||||
disabled={!isAdmin}
|
||||
/>
|
||||
<Field name="name" invalid={Boolean(errors.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
ref={ref}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder={t("common.project_name")}
|
||||
disabled={!isAdmin}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<span className="text-11 text-danger-primary">{errors?.name?.message}</span>
|
||||
@@ -342,18 +347,21 @@ export function ProjectDetailsForm(props: IProjectDetailsForm) {
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, ref } }) => (
|
||||
<Input
|
||||
id="identifier"
|
||||
name="identifier"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={handleIdentifierChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.identifier)}
|
||||
placeholder={t("project_settings.general.enter_project_id")}
|
||||
className="w-full font-medium"
|
||||
disabled={!isAdmin}
|
||||
/>
|
||||
<Field name="identifier" invalid={Boolean(errors.identifier)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="identifier"
|
||||
name="identifier"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={handleIdentifierChange}
|
||||
ref={ref}
|
||||
placeholder={t("project_settings.general.enter_project_id")}
|
||||
disabled={!isAdmin}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<Tooltip
|
||||
|
||||
@@ -9,10 +9,12 @@ import { useParams } from "next/navigation";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { AlertTriangleIcon } from "lucide-react";
|
||||
// Plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { IProject } from "@plane/types";
|
||||
import { Input, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||
// hooks
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
@@ -125,17 +127,20 @@ export const LeaveProjectModal = observer(function LeaveProjectModal(props: ILea
|
||||
required: "Label title is required",
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="projectName"
|
||||
name="projectName"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.projectName)}
|
||||
placeholder="Enter project name"
|
||||
className="mt-2 w-full"
|
||||
/>
|
||||
<Field name="projectName" invalid={Boolean(errors.projectName)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="projectName"
|
||||
name="projectName"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Enter project name"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -148,17 +153,20 @@ export const LeaveProjectModal = observer(function LeaveProjectModal(props: ILea
|
||||
control={control}
|
||||
name="confirmLeave"
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="confirmLeave"
|
||||
name="confirmLeave"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.confirmLeave)}
|
||||
placeholder="Enter 'leave project'"
|
||||
className="mt-2 w-full"
|
||||
/>
|
||||
<Field name="confirmLeave" invalid={Boolean(errors.confirmLeave)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="confirmLeave"
|
||||
name="confirmLeave"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Enter 'leave project'"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -9,12 +9,14 @@ import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { CircleUserRound } from "lucide-react";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/propel/toast";
|
||||
import { EFileAssetType } from "@plane/types";
|
||||
import type { IUser, TUserProfile } from "@plane/types";
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
import { getFileURL } from "@plane/utils";
|
||||
// components
|
||||
import { DeactivateAccountModal } from "@/components/account/deactivate-account-modal";
|
||||
@@ -279,19 +281,22 @@ export const GeneralProfileSettingsForm = observer(function GeneralProfileSettin
|
||||
validate: validatePersonName,
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="first_name"
|
||||
name="first_name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.first_name)}
|
||||
placeholder="Enter your first name"
|
||||
className={`w-full rounded-md ${errors.first_name ? "border-danger-strong" : ""}`}
|
||||
maxLength={50}
|
||||
autoComplete="on"
|
||||
/>
|
||||
<Field name="first_name" invalid={Boolean(errors.first_name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="first_name"
|
||||
name="first_name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Enter your first name"
|
||||
maxLength={50}
|
||||
autoComplete="on"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{errors.first_name && <span className="text-11 text-danger-primary">{errors.first_name.message}</span>}
|
||||
@@ -305,19 +310,22 @@ export const GeneralProfileSettingsForm = observer(function GeneralProfileSettin
|
||||
validate: validatePersonName,
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="last_name"
|
||||
name="last_name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.last_name)}
|
||||
placeholder="Enter your last name"
|
||||
className="w-full rounded-md"
|
||||
maxLength={50}
|
||||
autoComplete="on"
|
||||
/>
|
||||
<Field name="last_name" invalid={Boolean(errors.last_name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="last_name"
|
||||
name="last_name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Enter your last name"
|
||||
maxLength={50}
|
||||
autoComplete="on"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{errors.last_name && <span className="text-11 text-danger-primary">{errors.last_name.message}</span>}
|
||||
@@ -335,18 +343,21 @@ export const GeneralProfileSettingsForm = observer(function GeneralProfileSettin
|
||||
validate: validateDisplayName,
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="display_name"
|
||||
name="display_name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors?.display_name)}
|
||||
placeholder="Enter your display name"
|
||||
className={`w-full ${errors?.display_name ? "border-danger-strong" : ""}`}
|
||||
maxLength={50}
|
||||
/>
|
||||
<Field name="display_name" invalid={Boolean(errors?.display_name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="display_name"
|
||||
name="display_name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder="Enter your display name"
|
||||
maxLength={50}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{errors?.display_name && (
|
||||
@@ -365,20 +376,21 @@ export const GeneralProfileSettingsForm = observer(function GeneralProfileSettin
|
||||
required: "Email is required.",
|
||||
}}
|
||||
render={({ field: { value, ref } }) => (
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={value}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.email)}
|
||||
placeholder="Enter your email"
|
||||
className={`w-full cursor-not-allowed rounded-md !bg-surface-2 ${
|
||||
errors.email ? "border-danger-strong" : ""
|
||||
}`}
|
||||
autoComplete="on"
|
||||
disabled
|
||||
/>
|
||||
<Field name="email" invalid={Boolean(errors.email)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={value}
|
||||
ref={ref}
|
||||
placeholder="Enter your email"
|
||||
autoComplete="on"
|
||||
disabled
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{isSMTPConfigured && (
|
||||
|
||||
@@ -9,11 +9,13 @@ import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Eye, EyeOff } from "lucide-react";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { E_PASSWORD_STRENGTH } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import { Input, PasswordStrengthIndicator } from "@plane/ui";
|
||||
import { PasswordStrengthIndicator } from "@plane/ui";
|
||||
import { getPasswordStrength } from "@plane/utils";
|
||||
// components
|
||||
import { ProfileSettingsHeading } from "@/components/settings/profile/heading";
|
||||
@@ -138,38 +140,40 @@ export const SecurityProfileSettings = observer(function SecurityProfileSettings
|
||||
{oldPasswordRequired && (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
<h4 className="text-13">{t("auth.common.password.current_password.label")}</h4>
|
||||
<div className="relative flex items-center rounded-md">
|
||||
<Controller
|
||||
control={control}
|
||||
name="old_password"
|
||||
rules={{
|
||||
required: t("common.errors.required"),
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Input
|
||||
id="old_password"
|
||||
type={showPassword?.oldPassword ? "text" : "password"}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder={t("old_password")}
|
||||
className="w-full"
|
||||
hasError={Boolean(errors.old_password)}
|
||||
autoComplete="current-password"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{showPassword?.oldPassword ? (
|
||||
<EyeOff
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("oldPassword")}
|
||||
/>
|
||||
) : (
|
||||
<Eye
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("oldPassword")}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="old_password"
|
||||
rules={{
|
||||
required: t("common.errors.required"),
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Field name="old_password" invalid={Boolean(errors.old_password)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="old_password"
|
||||
type={showPassword?.oldPassword ? "text" : "password"}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder={t("old_password")}
|
||||
autoComplete="current-password"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="grid size-5 place-items-center"
|
||||
onClick={() => handleShowPassword("oldPassword")}
|
||||
aria-label={showPassword?.oldPassword ? "Hide password" : "Show password"}
|
||||
>
|
||||
{showPassword?.oldPassword ? (
|
||||
<EyeOff className="size-5 stroke-placeholder" />
|
||||
) : (
|
||||
<Eye className="size-5 stroke-placeholder" />
|
||||
)}
|
||||
</button>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
</div>
|
||||
/>
|
||||
{errors.old_password && (
|
||||
<span className="text-11 text-danger-primary">{errors.old_password.message}</span>
|
||||
)}
|
||||
@@ -178,40 +182,42 @@ export const SecurityProfileSettings = observer(function SecurityProfileSettings
|
||||
<div className="grid gap-x-4 gap-y-7 sm:grid-cols-2">
|
||||
<div className="flex flex-col gap-y-2">
|
||||
<h4 className="text-13">{t("auth.common.password.new_password.label")}</h4>
|
||||
<div className="relative flex items-center rounded-md">
|
||||
<Controller
|
||||
control={control}
|
||||
name="new_password"
|
||||
rules={{
|
||||
required: t("common.errors.required"),
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Input
|
||||
id="new_password"
|
||||
type={showPassword?.password ? "text" : "password"}
|
||||
value={value}
|
||||
placeholder={t("auth.common.password.new_password.placeholder")}
|
||||
onChange={onChange}
|
||||
className="w-full"
|
||||
hasError={Boolean(errors.new_password)}
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{showPassword?.password ? (
|
||||
<EyeOff
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
/>
|
||||
) : (
|
||||
<Eye
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="new_password"
|
||||
rules={{
|
||||
required: t("common.errors.required"),
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Field name="new_password" invalid={Boolean(errors.new_password)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="new_password"
|
||||
type={showPassword?.password ? "text" : "password"}
|
||||
value={value}
|
||||
placeholder={t("auth.common.password.new_password.placeholder")}
|
||||
onChange={onChange}
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="grid size-5 place-items-center"
|
||||
onClick={() => handleShowPassword("password")}
|
||||
aria-label={showPassword?.password ? "Hide password" : "Show password"}
|
||||
>
|
||||
{showPassword?.password ? (
|
||||
<EyeOff className="size-5 stroke-placeholder" />
|
||||
) : (
|
||||
<Eye className="size-5 stroke-placeholder" />
|
||||
)}
|
||||
</button>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
</div>
|
||||
/>
|
||||
{passwordSupport}
|
||||
{errors.new_password && (
|
||||
<span className="text-11 text-danger-primary">{errors.new_password.message}</span>
|
||||
@@ -224,40 +230,42 @@ export const SecurityProfileSettings = observer(function SecurityProfileSettings
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-2">
|
||||
<h4 className="text-13">{t("auth.common.password.confirm_password.label")}</h4>
|
||||
<div className="relative flex items-center rounded-md">
|
||||
<Controller
|
||||
control={control}
|
||||
name="confirm_password"
|
||||
rules={{
|
||||
required: t("common.errors.required"),
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Input
|
||||
id="confirm_password"
|
||||
type={showPassword?.confirmPassword ? "text" : "password"}
|
||||
placeholder={t("auth.common.password.confirm_password.placeholder")}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
className="w-full"
|
||||
hasError={Boolean(errors.confirm_password)}
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{showPassword?.confirmPassword ? (
|
||||
<EyeOff
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("confirmPassword")}
|
||||
/>
|
||||
) : (
|
||||
<Eye
|
||||
className="absolute right-3 h-5 w-5 stroke-placeholder hover:cursor-pointer"
|
||||
onClick={() => handleShowPassword("confirmPassword")}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="confirm_password"
|
||||
rules={{
|
||||
required: t("common.errors.required"),
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Field name="confirm_password" invalid={Boolean(errors.confirm_password)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="confirm_password"
|
||||
type={showPassword?.confirmPassword ? "text" : "password"}
|
||||
placeholder={t("auth.common.password.confirm_password.placeholder")}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="grid size-5 place-items-center"
|
||||
onClick={() => handleShowPassword("confirmPassword")}
|
||||
aria-label={showPassword?.confirmPassword ? "Hide password" : "Show password"}
|
||||
>
|
||||
{showPassword?.confirmPassword ? (
|
||||
<EyeOff className="size-5 stroke-placeholder" />
|
||||
) : (
|
||||
<Eye className="size-5 stroke-placeholder" />
|
||||
)}
|
||||
</button>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
</div>
|
||||
/>
|
||||
{!!confirmPassword && password !== confirmPassword && renderPasswordMatchError && (
|
||||
<span className="text-13 text-danger-primary">{t("auth.common.password.errors.match")}</span>
|
||||
)}
|
||||
|
||||
@@ -8,6 +8,8 @@ import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ETabIndices, ISSUE_DISPLAY_FILTERS_BY_PAGE } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
@@ -21,7 +23,7 @@ import type {
|
||||
IIssueFilters,
|
||||
} from "@plane/types";
|
||||
import { EViewAccess, EIssuesStoreType } from "@plane/types";
|
||||
import { Input, TextArea } from "@plane/ui";
|
||||
import { TextArea } from "@plane/ui";
|
||||
import { getComputedDisplayFilters, getComputedDisplayProperties, getTabIndex } from "@plane/utils";
|
||||
// components
|
||||
import { DisplayFiltersSelection, FiltersDropdown } from "@/components/issues/issue-layouts/filters";
|
||||
@@ -162,19 +164,22 @@ export const ProjectViewForm = observer(function ProjectViewForm(props: Props) {
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Input
|
||||
id="name"
|
||||
type="name"
|
||||
name="name"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
hasError={Boolean(errors.name)}
|
||||
placeholder={t("common.title")}
|
||||
className="w-full text-14"
|
||||
tabIndex={getIndex("name")}
|
||||
// oxlint-disable-next-line jsx_a11y/no-autofocus
|
||||
autoFocus
|
||||
/>
|
||||
<Field name="name" invalid={Boolean(errors.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
type="name"
|
||||
name="name"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder={t("common.title")}
|
||||
tabIndex={getIndex("name")}
|
||||
// oxlint-disable-next-line jsx_a11y/no-autofocus
|
||||
autoFocus
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<span className="text-11 text-danger-primary">{errors?.name?.message?.toString()}</span>
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
type Props = {
|
||||
value: string;
|
||||
@@ -19,16 +20,20 @@ export function WebhookInput(props: Props) {
|
||||
return (
|
||||
<>
|
||||
<h6 className="text-13 font-medium">{t("workspace_settings.settings.webhooks.modal.payload")}</h6>
|
||||
<Input
|
||||
type="url"
|
||||
className="h-11 w-full"
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
value={value}
|
||||
autoComplete="off"
|
||||
hasError={hasError}
|
||||
placeholder="https://example.com/post"
|
||||
autoFocus
|
||||
/>
|
||||
<Field name="payload" invalid={hasError}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
type="url"
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
value={value}
|
||||
autoComplete="off"
|
||||
placeholder="https://example.com/post"
|
||||
autoFocus
|
||||
aria-label={t("workspace_settings.settings.webhooks.modal.payload")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,13 +8,15 @@ import type { Dispatch, SetStateAction } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ORGANIZATION_SIZE, RESTRICTED_URLS } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { IWorkspace } from "@plane/types";
|
||||
// ui
|
||||
import { CustomSelect, Input } from "@plane/ui";
|
||||
import { CustomSelect } from "@plane/ui";
|
||||
import { validateWorkspaceName, validateSlug } from "@plane/utils";
|
||||
// hooks
|
||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
@@ -134,22 +136,25 @@ export const CreateWorkspaceForm = observer(function CreateWorkspaceForm(props:
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, ref, onChange } }) => (
|
||||
<Input
|
||||
id="workspaceName"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
setValue("name", e.target.value);
|
||||
setValue("slug", e.target.value.toLocaleLowerCase().trim().replace(/ /g, "-"), {
|
||||
shouldValidate: true,
|
||||
});
|
||||
}}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.name)}
|
||||
placeholder={t("workspace_creation.form.name.placeholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
<Field name="workspaceName" invalid={Boolean(errors.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="workspaceName"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
setValue("name", e.target.value);
|
||||
setValue("slug", e.target.value.toLocaleLowerCase().trim().replace(/ /g, "-"), {
|
||||
shouldValidate: true,
|
||||
});
|
||||
}}
|
||||
ref={ref}
|
||||
placeholder={t("workspace_creation.form.name.placeholder")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<span className="text-11 text-danger-primary">{errors?.name?.message}</span>
|
||||
@@ -160,37 +165,38 @@ export const CreateWorkspaceForm = observer(function CreateWorkspaceForm(props:
|
||||
{t("workspace_creation.form.url.label")}
|
||||
<span className="ml-0.5 text-danger-primary">*</span>
|
||||
</label>
|
||||
<div className="flex w-full items-center rounded-md border border-subtle bg-layer-2 px-3">
|
||||
<span className="text-12 whitespace-nowrap text-secondary">{window && window.location.host}/</span>
|
||||
<Controller
|
||||
control={control}
|
||||
name="slug"
|
||||
rules={{
|
||||
required: t("common.errors.required"),
|
||||
maxLength: {
|
||||
value: 48,
|
||||
message: t("workspace_creation.errors.validation.url_length"),
|
||||
},
|
||||
}}
|
||||
render={({ field: { onChange, value, ref } }) => (
|
||||
<Input
|
||||
id="workspaceUrl"
|
||||
type="text"
|
||||
value={value.toLocaleLowerCase().trim().replace(/ /g, "-")}
|
||||
onChange={(e) => {
|
||||
const validation = validateSlug(e.target.value);
|
||||
if (validation === true) setInvalidSlug(false);
|
||||
else setInvalidSlug(true);
|
||||
onChange(e.target.value.toLowerCase());
|
||||
}}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.slug)}
|
||||
placeholder={t("workspace_creation.form.url.placeholder")}
|
||||
className="block w-full rounded-md border-none bg-transparent !px-0 py-2 text-12"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="slug"
|
||||
rules={{
|
||||
required: t("common.errors.required"),
|
||||
maxLength: {
|
||||
value: 48,
|
||||
message: t("workspace_creation.errors.validation.url_length"),
|
||||
},
|
||||
}}
|
||||
render={({ field: { onChange, value, ref } }) => (
|
||||
<Field name="workspaceUrl" invalid={invalidSlug || Boolean(errors.slug)}>
|
||||
<InputGroup size="2xl">
|
||||
<span className="text-12 whitespace-nowrap text-secondary">{window && window.location.host}/</span>
|
||||
<Input
|
||||
size="2xl"
|
||||
id="workspaceUrl"
|
||||
type="text"
|
||||
value={value.toLocaleLowerCase().trim().replace(/ /g, "-")}
|
||||
onChange={(e) => {
|
||||
const validation = validateSlug(e.target.value);
|
||||
if (validation === true) setInvalidSlug(false);
|
||||
else setInvalidSlug(true);
|
||||
onChange(e.target.value.toLowerCase());
|
||||
}}
|
||||
ref={ref}
|
||||
placeholder={t("workspace_creation.form.url.placeholder")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{slugError && (
|
||||
<p className="-mt-3 text-13 text-danger-primary">
|
||||
{t("workspace_creation.errors.validation.url_already_taken")}
|
||||
|
||||
@@ -8,11 +8,13 @@ import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { AlertTriangle } from "lucide-react";
|
||||
// Plane Imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { IWorkspace } from "@plane/types";
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
import { cn } from "@plane/utils";
|
||||
// hooks
|
||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
@@ -106,18 +108,21 @@ export const DeleteWorkspaceForm = observer(function DeleteWorkspaceForm(props:
|
||||
control={control}
|
||||
name="workspaceName"
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="workspaceName"
|
||||
name="workspaceName"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.workspaceName)}
|
||||
placeholder={data?.name}
|
||||
className="mt-2 w-full"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<Field name="workspaceName" invalid={Boolean(errors.workspaceName)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="workspaceName"
|
||||
name="workspaceName"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={data?.name}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -132,18 +137,21 @@ export const DeleteWorkspaceForm = observer(function DeleteWorkspaceForm(props:
|
||||
control={control}
|
||||
name="confirmDelete"
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="confirmDelete"
|
||||
name="confirmDelete"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.confirmDelete)}
|
||||
placeholder=""
|
||||
className="mt-2 w-full"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<Field name="confirmDelete" invalid={Boolean(errors.confirmDelete)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="confirmDelete"
|
||||
name="confirmDelete"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder=""
|
||||
autoComplete="off"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -8,10 +8,12 @@ import { observer } from "mobx-react";
|
||||
import type { Control, FieldArrayWithId, FormState } from "react-hook-form";
|
||||
import { Controller } from "react-hook-form";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ROLE } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { CloseIcon } from "@plane/propel/icons";
|
||||
import { CustomSelect, Input } from "@plane/ui";
|
||||
import { CustomSelect } from "@plane/ui";
|
||||
import { cn } from "@plane/utils";
|
||||
// hooks
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
@@ -62,17 +64,20 @@ export const InvitationFields = observer(function InvitationFields(props: TInvit
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<>
|
||||
<Input
|
||||
id={`emails.${index}.email`}
|
||||
name={`emails.${index}.email`}
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.emails?.[index]?.email)}
|
||||
placeholder={t("workspace_settings.settings.members.modal.placeholder")}
|
||||
className="w-full text-caption-sm-regular sm:text-body-xs-regular"
|
||||
/>
|
||||
<Field name="input" invalid={Boolean(errors.emails?.[index]?.email)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id={`emails.${index}.email`}
|
||||
name={`emails.${index}.email`}
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={t("workspace_settings.settings.members.modal.placeholder")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
{errors.emails?.[index]?.email && (
|
||||
<span className="ml-1 text-caption-sm-regular text-danger-primary">
|
||||
{errors.emails?.[index]?.email?.message}
|
||||
|
||||
@@ -8,13 +8,15 @@ import { useEffect, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// Plane Imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ORGANIZATION_SIZE, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { EditIcon } from "@plane/propel/icons";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { IWorkspace } from "@plane/types";
|
||||
import { CustomSelect, Input } from "@plane/ui";
|
||||
import { CustomSelect } from "@plane/ui";
|
||||
import { cn, copyUrlToClipboard, getFileURL, validateWorkspaceName } from "@plane/utils";
|
||||
// components
|
||||
import { WorkspaceImageUploadModal } from "@/components/core/modals/workspace-image-upload-modal";
|
||||
@@ -198,18 +200,21 @@ export const WorkspaceDetails = observer(function WorkspaceDetails() {
|
||||
validate: (value) => validateWorkspaceName(value, true),
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.name)}
|
||||
placeholder={t("workspace_settings.settings.general.name")}
|
||||
className="w-full rounded-md"
|
||||
disabled={!isAdmin}
|
||||
/>
|
||||
<Field name="name" invalid={Boolean(errors.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={t("workspace_settings.settings.general.name")}
|
||||
disabled={!isAdmin}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
{errors.name && <p className="text-caption-sm-regular text-danger-primary">{errors.name.message}</p>}
|
||||
@@ -248,20 +253,23 @@ export const WorkspaceDetails = observer(function WorkspaceDetails() {
|
||||
control={control}
|
||||
name="url"
|
||||
render={({ field: { onChange, ref } }) => (
|
||||
<Input
|
||||
id="url"
|
||||
name="url"
|
||||
type="url"
|
||||
value={`${
|
||||
typeof window !== "undefined" &&
|
||||
window.location.origin.replace("http://", "").replace("https://", "")
|
||||
}/${currentWorkspace.slug}`}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.url)}
|
||||
className="w-full cursor-not-allowed rounded-md !bg-layer-1"
|
||||
disabled
|
||||
/>
|
||||
<Field name="url" invalid={Boolean(errors.url)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="url"
|
||||
name="url"
|
||||
type="url"
|
||||
value={`${
|
||||
typeof window !== "undefined" &&
|
||||
window.location.origin.replace("http://", "").replace("https://", "")
|
||||
}/${currentWorkspace.slug}`}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
disabled
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -9,13 +9,14 @@ import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { SubmitHandler } from "react-hook-form";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { useOutsideClickDetector } from "@plane/hooks";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// plane helpers
|
||||
// plane ui
|
||||
import { FavoriteFolderIcon } from "@plane/propel/icons";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import { Input } from "@plane/ui";
|
||||
|
||||
// hooks
|
||||
import { useFavorite } from "@/hooks/store/use-favorite";
|
||||
|
||||
@@ -146,12 +147,14 @@ export const NewFavoriteFolder = observer(function NewFavoriteFolder(props: TPro
|
||||
control={control}
|
||||
rules={{ required: true }}
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
className="w-full"
|
||||
placeholder={t("new_folder")}
|
||||
aria-label={t("aria_labels.projects_sidebar.enter_folder_name")}
|
||||
{...field}
|
||||
/>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
placeholder={t("new_folder")}
|
||||
aria-label={t("aria_labels.projects_sidebar.enter_folder_name")}
|
||||
{...field}
|
||||
/>
|
||||
</InputGroup>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
import { observer } from "mobx-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// plane imports
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
import { ISSUE_DISPLAY_FILTERS_BY_PAGE } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import type { IIssueDisplayFilterOptions, IIssueDisplayProperties, IWorkspaceView, IIssueFilters } from "@plane/types";
|
||||
import { EViewAccess, EIssueLayoutTypes, EIssuesStoreType } from "@plane/types";
|
||||
import { Input, TextArea } from "@plane/ui";
|
||||
import { TextArea } from "@plane/ui";
|
||||
import { getComputedDisplayFilters, getComputedDisplayProperties } from "@plane/utils";
|
||||
// components
|
||||
import { DisplayFiltersSelection, FiltersDropdown } from "@/components/issues/issue-layouts/filters";
|
||||
@@ -90,17 +92,20 @@ export const WorkspaceViewForm = observer(function WorkspaceViewForm(props: Prop
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id="name"
|
||||
name="name"
|
||||
type="name"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
hasError={Boolean(errors.name)}
|
||||
placeholder={t("common.title")}
|
||||
className="w-full text-14"
|
||||
/>
|
||||
<Field name="name" invalid={Boolean(errors.name)}>
|
||||
<InputGroup size="2xl">
|
||||
<Input
|
||||
size="2xl"
|
||||
id="name"
|
||||
name="name"
|
||||
type="name"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
ref={ref}
|
||||
placeholder={t("common.title")}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<span className="text-11 text-danger-primary">{errors?.name?.message}</span>
|
||||
|
||||
Reference in New Issue
Block a user