UI - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: дизайн и русификация God Mode
This commit is contained in:
@@ -22,7 +22,7 @@ export function AuthenticationMethodCard(props: Props) {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn("flex w-full items-center gap-14 rounded-lg bg-layer-2", {
|
||||
className={cn("nodedc-settings-card flex w-full items-center gap-14 rounded-lg bg-layer-2", {
|
||||
"border border-subtle px-4 py-3": withBorder,
|
||||
})}
|
||||
>
|
||||
|
||||
@@ -35,7 +35,7 @@ export const GiteaConfiguration = observer(function GiteaConfiguration(props: Pr
|
||||
{GiteaConfigured ? (
|
||||
<div className="flex items-center gap-4">
|
||||
<Link href="/authentication/gitea" className={cn(getButtonStyling("link", "base"), "font-medium")}>
|
||||
Edit
|
||||
Изменить
|
||||
</Link>
|
||||
<ToggleSwitch
|
||||
value={Boolean(parseInt(GiteaConfig))}
|
||||
@@ -51,7 +51,7 @@ export const GiteaConfiguration = observer(function GiteaConfiguration(props: Pr
|
||||
) : (
|
||||
<Link href="/authentication/gitea" className={cn(getButtonStyling("secondary", "base"), "text-tertiary")}>
|
||||
<Settings2 className="h-4 w-4 p-0.5 text-tertiary" />
|
||||
Configure
|
||||
Настроить
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -34,7 +34,7 @@ export const GithubConfiguration = observer(function GithubConfiguration(props:
|
||||
{isGithubConfigured ? (
|
||||
<div className="flex items-center gap-4">
|
||||
<Link href="/authentication/github" className={cn(getButtonStyling("link", "base"), "font-medium")}>
|
||||
Edit
|
||||
Изменить
|
||||
</Link>
|
||||
<ToggleSwitch
|
||||
value={Boolean(parseInt(enableGithubConfig))}
|
||||
@@ -49,7 +49,7 @@ export const GithubConfiguration = observer(function GithubConfiguration(props:
|
||||
) : (
|
||||
<Link href="/authentication/github" className={cn(getButtonStyling("secondary", "base"), "text-tertiary")}>
|
||||
<Settings2 className="h-4 w-4 p-0.5 text-tertiary" />
|
||||
Configure
|
||||
Настроить
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -34,7 +34,7 @@ export const GitlabConfiguration = observer(function GitlabConfiguration(props:
|
||||
{isGitlabConfigured ? (
|
||||
<div className="flex items-center gap-4">
|
||||
<Link href="/authentication/gitlab" className={cn(getButtonStyling("link", "base"), "font-medium")}>
|
||||
Edit
|
||||
Изменить
|
||||
</Link>
|
||||
<ToggleSwitch
|
||||
value={Boolean(parseInt(enableGitlabConfig))}
|
||||
@@ -49,7 +49,7 @@ export const GitlabConfiguration = observer(function GitlabConfiguration(props:
|
||||
) : (
|
||||
<Link href="/authentication/gitlab" className={cn(getButtonStyling("secondary", "base"), "text-tertiary")}>
|
||||
<Settings2 className="h-4 w-4 p-0.5 text-tertiary" />
|
||||
Configure
|
||||
Настроить
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -34,7 +34,7 @@ export const GoogleConfiguration = observer(function GoogleConfiguration(props:
|
||||
{isGoogleConfigured ? (
|
||||
<div className="flex items-center gap-4">
|
||||
<Link href="/authentication/google" className={cn(getButtonStyling("link", "base"), "font-medium")}>
|
||||
Edit
|
||||
Изменить
|
||||
</Link>
|
||||
<ToggleSwitch
|
||||
value={Boolean(parseInt(enableGoogleConfig))}
|
||||
@@ -49,7 +49,7 @@ export const GoogleConfiguration = observer(function GoogleConfiguration(props:
|
||||
) : (
|
||||
<Link href="/authentication/google" className={cn(getButtonStyling("secondary", "base"), "text-tertiary")}>
|
||||
<Settings2 className="h-4 w-4 p-0.5 text-tertiary" />
|
||||
Configure
|
||||
Настроить
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -11,26 +11,35 @@ type Props = {
|
||||
label?: string;
|
||||
href?: string;
|
||||
icon?: React.ReactNode | undefined;
|
||||
isCurrent?: boolean;
|
||||
};
|
||||
|
||||
export function BreadcrumbLink(props: Props) {
|
||||
const { href, label, icon } = props;
|
||||
const { href, label, icon, isCurrent = false } = props;
|
||||
|
||||
const content = (
|
||||
<>
|
||||
{icon && <div className="flex h-5 w-5 items-center justify-center overflow-hidden !text-16">{icon}</div>}
|
||||
<div className="relative line-clamp-1 block max-w-[150px] truncate overflow-hidden">{label}</div>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<Tooltip tooltipContent={label} position="bottom">
|
||||
<li className="flex items-center space-x-2" tabIndex={-1}>
|
||||
<div className="flex flex-wrap items-center gap-2.5">
|
||||
{href ? (
|
||||
<Link className="flex items-center gap-1 text-13 font-medium text-tertiary hover:text-primary" href={href}>
|
||||
{icon && <div className="flex h-5 w-5 items-center justify-center overflow-hidden !text-16">{icon}</div>}
|
||||
<div className="relative line-clamp-1 block max-w-[150px] truncate overflow-hidden">{label}</div>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="flex cursor-default items-center gap-1 text-13 font-medium text-primary">
|
||||
{icon && <div className="flex h-5 w-5 items-center justify-center overflow-hidden">{icon}</div>}
|
||||
<div className="relative line-clamp-1 block max-w-[150px] truncate overflow-hidden">{label}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<li className="flex items-center" tabIndex={-1}>
|
||||
{href && !isCurrent ? (
|
||||
<Link className="nodedc-admin-breadcrumb-pill flex items-center gap-1.5 text-13 font-medium" href={href}>
|
||||
{content}
|
||||
</Link>
|
||||
) : (
|
||||
<div
|
||||
className="nodedc-admin-breadcrumb-pill flex cursor-default items-center gap-1.5 text-13 font-medium"
|
||||
data-current={isCurrent}
|
||||
aria-current={isCurrent ? "page" : undefined}
|
||||
>
|
||||
{content}
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
@@ -16,7 +16,7 @@ export function CodeBlock({ children, className, darkerShade }: TProps) {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"rounded-md border border-subtle bg-surface-2 px-0.5 text-11 font-semibold text-tertiary",
|
||||
"nodedc-code-chip rounded-md border border-subtle bg-surface-2 px-0.5 text-11 font-semibold text-tertiary",
|
||||
{
|
||||
"border-subtle bg-layer-1 text-secondary": darkerShade,
|
||||
},
|
||||
|
||||
@@ -45,27 +45,25 @@ export function ConfirmDiscardModal(props: Props) {
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-[30rem]">
|
||||
<Dialog.Panel className="nodedc-glass-modal relative transform overflow-hidden rounded-[1.75rem] bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-[30rem]">
|
||||
<div className="px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div className="sm:flex sm:items-start">
|
||||
<div className="mt-3 text-center sm:mt-0 sm:text-left">
|
||||
<Dialog.Title as="h3" className="text-16 leading-6 font-medium text-tertiary">
|
||||
You have unsaved changes
|
||||
Есть несохраненные изменения
|
||||
</Dialog.Title>
|
||||
<div className="mt-2">
|
||||
<p className="text-13 text-placeholder">
|
||||
Changes you made will be lost if you go back. Do you wish to go back?
|
||||
</p>
|
||||
<p className="text-13 text-placeholder">Если уйти назад, текущие правки будут потеряны.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-end gap-2 p-4 sm:px-6">
|
||||
<Button variant="secondary" size="lg" onClick={handleClose}>
|
||||
Keep editing
|
||||
Продолжить редактирование
|
||||
</Button>
|
||||
<Link href={onDiscardHref} className={getButtonStyling("primary", "base")}>
|
||||
Go back
|
||||
Уйти назад
|
||||
</Link>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
|
||||
@@ -46,7 +46,7 @@ export function ControllerInput(props: Props) {
|
||||
<Controller
|
||||
control={control}
|
||||
name={name}
|
||||
rules={{ required: required ? `${label} is required.` : false }}
|
||||
rules={{ required: required ? `Поле "${label}" обязательно.` : false }}
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
<Input
|
||||
id={name}
|
||||
@@ -57,7 +57,7 @@ export function ControllerInput(props: Props) {
|
||||
ref={ref}
|
||||
hasError={error}
|
||||
placeholder={placeholder}
|
||||
className={cn("w-full rounded-md font-medium", {
|
||||
className={cn("nodedc-settings-input w-full rounded-md font-medium", {
|
||||
"pr-10": type === "password",
|
||||
})}
|
||||
/>
|
||||
|
||||
@@ -27,7 +27,7 @@ export function ControllerSwitch<T extends FieldValues>(props: Props<T>) {
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-1">
|
||||
<h4 className="text-sm text-custom-text-300">Refresh user attributes from {label} during sign in</h4>
|
||||
<h4 className="text-sm text-custom-text-300">Обновлять атрибуты пользователя из {label} при входе</h4>
|
||||
<div className="relative">
|
||||
<Controller
|
||||
control={control}
|
||||
|
||||
@@ -32,18 +32,18 @@ export function CopyField(props: Props) {
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="lg"
|
||||
className="flex items-center justify-between py-2"
|
||||
className="nodedc-settings-secondary-button flex w-full items-center justify-between gap-3 py-2 text-left"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(url);
|
||||
setToast({
|
||||
type: TOAST_TYPE.INFO,
|
||||
title: "Copied to clipboard",
|
||||
message: `The ${label} has been successfully copied to your clipboard`,
|
||||
title: "Скопировано",
|
||||
message: `${label} скопировано в буфер обмена`,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<p className="text-13 font-medium">{url}</p>
|
||||
<CopyIcon width={18} height={18} color="#B9B9B9" />
|
||||
<p className="min-w-0 truncate text-13 font-medium">{url}</p>
|
||||
<CopyIcon width={18} height={18} color="#B9B9B9" className="shrink-0" />
|
||||
</Button>
|
||||
<div className="text-11 text-tertiary">{description}</div>
|
||||
</div>
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
*/
|
||||
|
||||
export const CORE_HEADER_SEGMENT_LABELS: Record<string, string> = {
|
||||
general: "General",
|
||||
ai: "Artificial Intelligence",
|
||||
email: "Email",
|
||||
authentication: "Authentication",
|
||||
image: "Image",
|
||||
general: "Основное",
|
||||
ai: "Искусственный интеллект",
|
||||
email: "Почта",
|
||||
authentication: "Аутентификация",
|
||||
image: "Изображения",
|
||||
google: "Google",
|
||||
github: "GitHub",
|
||||
gitlab: "GitLab",
|
||||
gitea: "Gitea",
|
||||
workspace: "Workspace",
|
||||
create: "Create",
|
||||
workspace: "Воркспейсы",
|
||||
create: "Создание",
|
||||
};
|
||||
|
||||
@@ -4,11 +4,10 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { Fragment } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { Menu, Settings } from "lucide-react";
|
||||
// icons
|
||||
import { Breadcrumbs } from "@plane/ui";
|
||||
import { ChevronRight, Menu, Settings } from "lucide-react";
|
||||
// components
|
||||
import { BreadcrumbLink } from "../breadcrumb-link";
|
||||
// hooks
|
||||
@@ -22,6 +21,7 @@ export const HamburgerToggle = observer(function HamburgerToggle() {
|
||||
return (
|
||||
<button
|
||||
className="group flex size-7 cursor-pointer items-center justify-center rounded-sm bg-layer-1 transition-all hover:bg-layer-1-hover md:hidden"
|
||||
aria-label="Открыть меню"
|
||||
onClick={() => toggleSidebar(!isSidebarCollapsed)}
|
||||
>
|
||||
<Menu size={14} className="text-secondary transition-all group-hover:text-primary" />
|
||||
@@ -56,32 +56,28 @@ export const AdminHeader = observer(function AdminHeader() {
|
||||
const breadcrumbItems = generateBreadcrumbItems(pathName || "");
|
||||
|
||||
return (
|
||||
<div className="relative z-10 flex h-header w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-subtle bg-surface-1 p-4">
|
||||
<div className="nodedc-admin-header nodedc-glass-modal relative z-10 flex h-header w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-subtle bg-surface-1 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<HamburgerToggle />
|
||||
{breadcrumbItems.length >= 0 && (
|
||||
<div>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item
|
||||
component={
|
||||
<BreadcrumbLink
|
||||
href="/general/"
|
||||
label="Settings"
|
||||
icon={<Settings className="h-4 w-4 text-tertiary" />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{breadcrumbItems.map(
|
||||
(item) =>
|
||||
item.title && (
|
||||
<Breadcrumbs.Item
|
||||
key={item.title}
|
||||
component={<BreadcrumbLink href={item.href} label={item.title} />}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Breadcrumbs>
|
||||
</div>
|
||||
<nav className="min-w-0" aria-label="Навигация God Mode">
|
||||
<ol className="nodedc-admin-breadcrumbs">
|
||||
<BreadcrumbLink href="/general/" label="Настройки" icon={<Settings className="h-4 w-4" />} />
|
||||
{breadcrumbItems.map((item, index) => {
|
||||
if (!item.title) return null;
|
||||
const isCurrent = index === breadcrumbItems.length - 1;
|
||||
|
||||
return (
|
||||
<Fragment key={`${item.href}-${item.title}`}>
|
||||
<li className="nodedc-admin-breadcrumb-separator" aria-hidden="true">
|
||||
<ChevronRight className="size-4" />
|
||||
</li>
|
||||
<BreadcrumbLink href={item.href} label={item.title} isCurrent={isCurrent} />
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</ol>
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,20 +24,19 @@ export const NewUserPopup = observer(function NewUserPopup() {
|
||||
|
||||
if (!isNewUserPopup) return <></>;
|
||||
return (
|
||||
<div className="shadow-md absolute right-8 bottom-8 w-96 rounded-lg border border-subtle bg-surface-1 p-6">
|
||||
<div className="nodedc-glass-modal shadow-md absolute right-8 bottom-8 w-96 rounded-[1.75rem] border border-subtle bg-surface-1 p-6">
|
||||
<div className="flex gap-4">
|
||||
<div className="grow">
|
||||
<div className="text-14 font-semibold">Create workspace</div>
|
||||
<div className="text-14 font-semibold">Создать воркспейс</div>
|
||||
<div className="py-2 text-13 font-medium text-tertiary">
|
||||
Instance setup done! Welcome to Plane instance portal. Start your journey with by creating your first
|
||||
workspace.
|
||||
Настройка инстанса завершена. Создайте первое рабочее пространство, чтобы начать работу.
|
||||
</div>
|
||||
<div className="flex items-center gap-4 pt-2">
|
||||
<Link href="/workspace/create" className={getButtonStyling("primary", "lg")}>
|
||||
Create workspace
|
||||
Создать воркспейс
|
||||
</Link>
|
||||
<Button variant="secondary" size="lg" onClick={toggleNewUserPopup}>
|
||||
Close
|
||||
Закрыть
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -46,7 +45,7 @@ export const NewUserPopup = observer(function NewUserPopup() {
|
||||
src={resolveGeneralTheme(resolvedTheme) === "dark" ? TakeoffIconDark : TakeoffIconLight}
|
||||
height={80}
|
||||
width={80}
|
||||
alt="Plane icon"
|
||||
alt="NODE.DC"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,8 @@ type TPageHeader = {
|
||||
};
|
||||
|
||||
export function PageHeader(props: TPageHeader) {
|
||||
const { title = "God Mode - Plane", description = "Plane god mode" } = props;
|
||||
const { title = "NODE.DC - глобальное администрирование", description = "Глобальное администрирование NODE.DC" } =
|
||||
props;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -24,16 +24,16 @@ export const PageWrapper = (props: TPageWrapperProps) => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn("mx-auto h-full w-full space-y-6 py-4", {
|
||||
className={cn("nodedc-page mx-auto h-full w-full space-y-6 py-4", {
|
||||
"max-w-[1000px] md:px-4 2xl:max-w-[1200px]": size === "md",
|
||||
"px-4 lg:px-12": size === "lg",
|
||||
})}
|
||||
>
|
||||
{customHeader ? (
|
||||
<div className="mx-4 shrink-0 space-y-1 border-b border-subtle py-4">{customHeader}</div>
|
||||
<div className="nodedc-page-header mx-4 shrink-0 space-y-1 border-b border-subtle py-4">{customHeader}</div>
|
||||
) : (
|
||||
header && (
|
||||
<div className="mx-4 flex shrink-0 items-center justify-between gap-4 space-y-1 border-b border-subtle py-4">
|
||||
<div className="nodedc-page-header mx-4 flex shrink-0 items-center justify-between gap-4 space-y-1 border-b border-subtle py-4">
|
||||
<div className={header.actions ? "flex flex-col gap-1" : "space-y-1"}>
|
||||
<div className="text-h5-semibold text-primary">{header.title}</div>
|
||||
<div className="text-body-sm-regular text-secondary">{header.description}</div>
|
||||
@@ -42,7 +42,7 @@ export const PageWrapper = (props: TPageWrapperProps) => {
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
<div className="vertical-scrollbar scrollbar-sm flex-grow overflow-hidden overflow-y-scroll px-4 pb-4">
|
||||
<div className="nodedc-page-body vertical-scrollbar scrollbar-sm flex-grow overflow-hidden overflow-y-scroll px-4 pb-4">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -27,15 +27,15 @@ export const InstanceFailureView = observer(function InstanceFailureView() {
|
||||
<div className="mt-10 flex w-full flex-grow flex-col items-center justify-center py-6">
|
||||
<div className="relative flex w-full max-w-[22.5rem] flex-col gap-6">
|
||||
<div className="relative flex flex-col items-center justify-center space-y-4">
|
||||
<img src={instanceImage} alt="Instance failure illustration" />
|
||||
<h3 className="text-center text-20 font-medium text-on-color">Unable to fetch instance details.</h3>
|
||||
<img src={instanceImage} alt="Ошибка загрузки инстанса" />
|
||||
<h3 className="text-center text-20 font-medium text-on-color">Не удалось загрузить данные инстанса.</h3>
|
||||
<p className="text-center text-14 font-medium">
|
||||
We were unable to fetch the details of the instance. Fret not, it might just be a connectivity issue.
|
||||
Проверьте соединение с API и попробуйте обновить страницу.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-center">
|
||||
<Button size="lg" onClick={handleRetry}>
|
||||
Retry
|
||||
Повторить
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,15 +14,15 @@ export function InstanceNotReady() {
|
||||
<div className="relative container mx-auto flex h-full w-full items-center justify-center px-5">
|
||||
<div className="relative w-auto max-w-2xl space-y-8 py-10">
|
||||
<div className="relative flex flex-col items-center justify-center space-y-4">
|
||||
<h1 className="pb-3 text-24 font-bold">Welcome aboard Plane!</h1>
|
||||
<img src={PlaneTakeOffImage} alt="Plane Logo" />
|
||||
<p className="text-14 font-medium text-placeholder">Get started by setting up your instance and workspace</p>
|
||||
<h1 className="pb-3 text-24 font-bold">Добро пожаловать в NODE.DC</h1>
|
||||
<img src={PlaneTakeOffImage} alt="NODE.DC" />
|
||||
<p className="text-14 font-medium text-placeholder">Начните с настройки инстанса и первого воркспейса</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link href={"/setup/?auth_enabled=0"}>
|
||||
<Button size="xl" className="w-full">
|
||||
Get started
|
||||
Начать
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -140,10 +140,10 @@ export function InstanceSetupForm() {
|
||||
<>
|
||||
<AuthHeader />
|
||||
<div className="mt-10 flex w-full flex-grow flex-col items-center justify-center py-6">
|
||||
<div className="relative flex w-full max-w-[22.5rem] flex-col gap-6">
|
||||
<div className="nodedc-auth-card relative flex w-full max-w-[22.5rem] flex-col gap-6">
|
||||
<FormHeader
|
||||
heading="Setup your Plane Instance"
|
||||
subHeading="Post setup you will be able to manage this Plane instance."
|
||||
heading="Настройка инстанса NODE.DC"
|
||||
subHeading="После настройки вы получите доступ к глобальному администрированию."
|
||||
/>
|
||||
{errorData.type &&
|
||||
errorData?.message &&
|
||||
@@ -163,15 +163,15 @@ export function InstanceSetupForm() {
|
||||
<div className="flex flex-col items-center gap-4 sm:flex-row">
|
||||
<div className="w-full space-y-1">
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="first_name">
|
||||
First name <span className="text-danger-primary">*</span>
|
||||
Имя <span className="text-danger-primary">*</span>
|
||||
</label>
|
||||
<Input
|
||||
className="w-full border border-subtle !bg-surface-1 placeholder:text-placeholder"
|
||||
className="nodedc-settings-input w-full border border-subtle !bg-surface-1 placeholder:text-placeholder"
|
||||
id="first_name"
|
||||
name="first_name"
|
||||
type="text"
|
||||
inputSize="md"
|
||||
placeholder="Wilber"
|
||||
placeholder="Иван"
|
||||
value={formData.first_name}
|
||||
onChange={(e) => {
|
||||
const validation = validatePersonName(e.target.value);
|
||||
@@ -186,15 +186,15 @@ export function InstanceSetupForm() {
|
||||
</div>
|
||||
<div className="w-full space-y-1">
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="last_name">
|
||||
Last name <span className="text-danger-primary">*</span>
|
||||
Фамилия <span className="text-danger-primary">*</span>
|
||||
</label>
|
||||
<Input
|
||||
className="w-full border border-subtle !bg-surface-1 placeholder:text-placeholder"
|
||||
className="nodedc-settings-input w-full border border-subtle !bg-surface-1 placeholder:text-placeholder"
|
||||
id="last_name"
|
||||
name="last_name"
|
||||
type="text"
|
||||
inputSize="md"
|
||||
placeholder="Wright"
|
||||
placeholder="Иванов"
|
||||
value={formData.last_name}
|
||||
onChange={(e) => {
|
||||
const validation = validatePersonName(e.target.value);
|
||||
@@ -210,10 +210,10 @@ export function InstanceSetupForm() {
|
||||
|
||||
<div className="w-full space-y-1">
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="email">
|
||||
Email <span className="text-danger-primary">*</span>
|
||||
Электронная почта <span className="text-danger-primary">*</span>
|
||||
</label>
|
||||
<Input
|
||||
className="w-full border border-subtle !bg-surface-1 placeholder:text-placeholder"
|
||||
className="nodedc-settings-input w-full border border-subtle !bg-surface-1 placeholder:text-placeholder"
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
@@ -231,15 +231,15 @@ export function InstanceSetupForm() {
|
||||
|
||||
<div className="w-full space-y-1">
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="company_name">
|
||||
Company name <span className="text-danger-primary">*</span>
|
||||
Название компании <span className="text-danger-primary">*</span>
|
||||
</label>
|
||||
<Input
|
||||
className="w-full border border-subtle !bg-surface-1 placeholder:text-placeholder"
|
||||
className="nodedc-settings-input w-full border border-subtle !bg-surface-1 placeholder:text-placeholder"
|
||||
id="company_name"
|
||||
name="company_name"
|
||||
type="text"
|
||||
inputSize="md"
|
||||
placeholder="Company name"
|
||||
placeholder="Название компании"
|
||||
value={formData.company_name}
|
||||
onChange={(e) => {
|
||||
const validation = validateCompanyName(e.target.value, false);
|
||||
@@ -253,16 +253,16 @@ export function InstanceSetupForm() {
|
||||
|
||||
<div className="w-full space-y-1">
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="password">
|
||||
Set a password <span className="text-danger-primary">*</span>
|
||||
Задайте пароль <span className="text-danger-primary">*</span>
|
||||
</label>
|
||||
<div className="relative">
|
||||
<Input
|
||||
className="w-full border border-subtle !bg-surface-1 placeholder:text-placeholder"
|
||||
className="nodedc-settings-input w-full border border-subtle !bg-surface-1 placeholder:text-placeholder"
|
||||
id="password"
|
||||
name="password"
|
||||
type={showPassword.password ? "text" : "password"}
|
||||
inputSize="md"
|
||||
placeholder="New password"
|
||||
placeholder="Новый пароль"
|
||||
value={formData.password}
|
||||
onChange={(e) => handleFormChange("password", e.target.value)}
|
||||
hasError={errorData.type && errorData.type === EErrorCodes.INVALID_PASSWORD ? true : false}
|
||||
@@ -298,7 +298,7 @@ export function InstanceSetupForm() {
|
||||
|
||||
<div className="w-full space-y-1">
|
||||
<label className="text-13 font-medium text-tertiary" htmlFor="confirm_password">
|
||||
Confirm password <span className="text-danger-primary">*</span>
|
||||
Подтвердите пароль <span className="text-danger-primary">*</span>
|
||||
</label>
|
||||
<div className="relative">
|
||||
<Input
|
||||
@@ -308,8 +308,8 @@ export function InstanceSetupForm() {
|
||||
inputSize="md"
|
||||
value={formData.confirm_password}
|
||||
onChange={(e) => handleFormChange("confirm_password", e.target.value)}
|
||||
placeholder="Confirm password"
|
||||
className="w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
placeholder="Повторите пароль"
|
||||
className="nodedc-settings-input w-full border border-subtle !bg-surface-1 pr-12 placeholder:text-placeholder"
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="new-password"
|
||||
@@ -336,9 +336,7 @@ export function InstanceSetupForm() {
|
||||
</div>
|
||||
{!!formData.confirm_password &&
|
||||
formData.password !== formData.confirm_password &&
|
||||
renderPasswordMatchError && (
|
||||
<span className="text-13 text-danger-primary">Passwords don{"'"}t match</span>
|
||||
)}
|
||||
renderPasswordMatchError && <span className="text-13 text-danger-primary">Пароли не совпадают</span>}
|
||||
</div>
|
||||
|
||||
<div className="relative flex gap-2">
|
||||
@@ -352,7 +350,7 @@ export function InstanceSetupForm() {
|
||||
/>
|
||||
</div>
|
||||
<label className="cursor-pointer text-13 font-medium text-tertiary" htmlFor="is_telemetry_enabled">
|
||||
Allow Plane to anonymously collect usage events.{" "}
|
||||
Разрешить NODE.DC анонимно собирать события использования.{" "}
|
||||
<a
|
||||
tabIndex={-1}
|
||||
href="https://developers.plane.so/self-hosting/telemetry"
|
||||
@@ -360,14 +358,14 @@ export function InstanceSetupForm() {
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-500 hover:text-blue-600 flex-shrink-0 text-13 font-medium"
|
||||
>
|
||||
See More
|
||||
Подробнее
|
||||
</a>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="py-2">
|
||||
<Button type="submit" size="xl" className="w-full" disabled={isButtonDisabled}>
|
||||
{isSubmitting ? <Spinner height="20px" width="20px" /> : "Continue"}
|
||||
{isSubmitting ? <Spinner height="20px" width="20px" /> : "Продолжить"}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user