Merge origin/release/v2 into feat/fix-v2-stack-review-findings
This commit is contained in:
commit
e1775e524b
583 files changed
+16433
-9067
No files matched your search
@@ -11,7 +11,7 @@ import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import { UserCreatePasswordFields } from "@homarr/forms-collection";
|
||||
import { showErrorNotification } from "@homarr/notifications";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
import { Link } from "@homarr/ui";
|
||||
import { groupCreateSchema } from "@homarr/validation/group";
|
||||
import { userInitSchema } from "@homarr/validation/user";
|
||||
@@ -41,7 +41,7 @@ export const AccountSetup = ({ environment }: OnboardingStudioProps) => {
|
||||
};
|
||||
|
||||
const CredentialsSetup = () => {
|
||||
const t = useScopedI18n("init.studio.account");
|
||||
const t = useI18n("init.studio.account");
|
||||
const [requiresSignIn, setRequiresSignIn] = useState(false);
|
||||
const [submitError, setSubmitError] = useState<string | null>(null);
|
||||
const recoveryActionRef = useRef<HTMLAnchorElement>(null);
|
||||
@@ -104,7 +104,7 @@ const CredentialsSetup = () => {
|
||||
|
||||
return (
|
||||
<AccountShell title={t("title")} description={t("description")}>
|
||||
<form onSubmit={form.onSubmit((values) => void submitAsync(values))}>
|
||||
<form onSubmit={form.onSubmit((values) => submitAsync(values))}>
|
||||
<Stack gap="md">
|
||||
<TextInput label={t("username")} autoComplete="username" withAsterisk {...form.getInputProps("username")} />
|
||||
<UserCreatePasswordFields
|
||||
@@ -119,7 +119,7 @@ const CredentialsSetup = () => {
|
||||
{submitError}
|
||||
</Alert>
|
||||
) : null}
|
||||
<Button type="submit" size="md" loading={mutation.isPending} rightSection={<IconArrowRight size={18} />}>
|
||||
<Button type="submit" size="md" loading={form.submitting} rightSection={<IconArrowRight size={18} />}>
|
||||
{t("create")}
|
||||
</Button>
|
||||
</Stack>
|
||||
@@ -129,7 +129,7 @@ const CredentialsSetup = () => {
|
||||
};
|
||||
|
||||
const ExternalGroupSetup = () => {
|
||||
const t = useScopedI18n("init.studio.externalGroup");
|
||||
const t = useI18n("init.studio.externalGroup");
|
||||
const [submitError, setSubmitError] = useState<string | null>(null);
|
||||
const sounds = useOnboardingSounds();
|
||||
const mutation = clientApi.group.createInitialExternalGroup.useMutation({
|
||||
|
||||
@@ -6,7 +6,7 @@ import { IconArrowRight, IconBook2, IconSparkles, IconTool } from "@tabler/icons
|
||||
import confetti from "canvas-confetti";
|
||||
|
||||
import { createDocumentationLink } from "@homarr/definitions";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
import { Link } from "@homarr/ui";
|
||||
|
||||
import { OnboardingBackdrop } from "./onboarding-backdrop";
|
||||
@@ -16,7 +16,7 @@ import { useOnboardingSounds } from "./use-onboarding-sounds";
|
||||
import classes from "./onboarding-studio.module.css";
|
||||
|
||||
export const Finish = ({ environment }: OnboardingStudioProps) => {
|
||||
const t = useScopedI18n("init.studio.finish");
|
||||
const t = useI18n("init.studio.finish");
|
||||
const sounds = useOnboardingSounds();
|
||||
const primaryColor = environment.initialBoard?.primaryColor ?? "#fa5252";
|
||||
const secondaryColor = environment.initialBoard?.secondaryColor ?? "#fd7e14";
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { ReactNode } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Alert, Button, Center, Paper, Stack, Text, Title } from "@mantine/core";
|
||||
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
import { Link } from "@homarr/ui";
|
||||
|
||||
import type { OnboardingStudioProps } from "./types";
|
||||
@@ -22,8 +22,8 @@ const getInitialClaimState = (accessState: ReturnType<typeof getOnboardingAccess
|
||||
};
|
||||
|
||||
export const OnboardingStudio = (props: OnboardingStudioProps) => {
|
||||
const t = useScopedI18n("init.studio.claim");
|
||||
const tCommon = useScopedI18n("common.action");
|
||||
const t = useI18n("init.studio.claim");
|
||||
const tCommon = useI18n("common.action");
|
||||
const accessState = getOnboardingAccessState(props.environment);
|
||||
const [claimState, setClaimState] = useState<ClaimState>(() => getInitialClaimState(accessState));
|
||||
const [claimError, setClaimError] = useState<string | null>(null);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useRef, useState } from "react";
|
||||
import { FloatingIndicator, Stack, TextInput, UnstyledButton } from "@mantine/core";
|
||||
|
||||
import type { UrlTemplateMode } from "@homarr/definitions";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
|
||||
import { useOnboardingSounds } from "./use-onboarding-sounds";
|
||||
import classes from "./onboarding-studio.module.css";
|
||||
@@ -78,7 +78,7 @@ export const ServiceUrlTemplate = ({
|
||||
readOnly,
|
||||
required,
|
||||
}: ServiceUrlTemplateProps) => {
|
||||
const t = useScopedI18n("common.serviceUrlTemplate");
|
||||
const t = useI18n("common.serviceUrlTemplate");
|
||||
|
||||
return (
|
||||
<Stack gap="sm">
|
||||
|
||||
@@ -90,7 +90,7 @@ import {
|
||||
} from "@homarr/definitions";
|
||||
import { showErrorNotification, showSuccessNotification, showWarningNotification } from "@homarr/notifications";
|
||||
import type { SupportedLanguage } from "@homarr/translation";
|
||||
import { useCurrentLocale, useScopedI18n } from "@homarr/translation/client";
|
||||
import { useCurrentLocale, useI18n } from "@homarr/translation/client";
|
||||
import { BoardColorInput, ColorSchemeCombobox, IntegrationAvatar, LanguageCombobox, Link } from "@homarr/ui";
|
||||
import { IntegrationMultiSelectGrid } from "@homarr/ui/integration-select-grid";
|
||||
|
||||
@@ -154,8 +154,8 @@ const emptyDiscoveredIntegrations: DockerDiscoveryData["integrations"] = [];
|
||||
const emptyDiscoveredApps: DockerDiscoveryData["apps"] = [];
|
||||
|
||||
export const SetupStudio = ({ environment, assistantConfiguration }: OnboardingStudioProps) => {
|
||||
const t = useScopedI18n("init.studio");
|
||||
const tCommon = useScopedI18n("common.action");
|
||||
const t = useI18n("init.studio");
|
||||
const tCommon = useI18n("common.action");
|
||||
const currentLocale = useCurrentLocale();
|
||||
const { colorScheme, setColorScheme } = useMantineColorScheme();
|
||||
const sounds = useOnboardingSounds();
|
||||
@@ -781,7 +781,7 @@ export const SetupStudio = ({ environment, assistantConfiguration }: OnboardingS
|
||||
rightSection={<IconArrowRight size={16} />}
|
||||
onClick={continueOnboarding}
|
||||
>
|
||||
{t("continue")}
|
||||
{tCommon("continue")}
|
||||
</Button>
|
||||
</Group>
|
||||
)}
|
||||
@@ -887,7 +887,7 @@ const SectionHeading = ({
|
||||
);
|
||||
|
||||
const Essentials = (props: StudioSectionProps) => {
|
||||
const t = useScopedI18n("init.studio.essentials");
|
||||
const t = useI18n("init.studio.essentials");
|
||||
const [isHydrated, setIsHydrated] = useState(false);
|
||||
useEffect(() => setIsHydrated(true), []);
|
||||
return (
|
||||
@@ -936,7 +936,7 @@ const Essentials = (props: StudioSectionProps) => {
|
||||
};
|
||||
|
||||
const Discovery = (props: StudioSectionProps) => {
|
||||
const t = useScopedI18n("init.studio.discover");
|
||||
const t = useI18n("init.studio.discover");
|
||||
const dockerStatus = !props.environment.dockerConfigured
|
||||
? "disabled"
|
||||
: props.docker.isPending
|
||||
@@ -1064,7 +1064,7 @@ const CapabilityRow = ({
|
||||
detail: string;
|
||||
action?: ReactNode;
|
||||
}) => {
|
||||
const t = useScopedI18n("init.studio.discover.status");
|
||||
const t = useI18n("init.studio.discover.status");
|
||||
const color =
|
||||
status === "available"
|
||||
? "green"
|
||||
@@ -1107,7 +1107,7 @@ const CapabilityRow = ({
|
||||
};
|
||||
|
||||
const Connections = (props: StudioSectionProps) => {
|
||||
const t = useScopedI18n("init.studio.connect");
|
||||
const t = useI18n("init.studio.connect");
|
||||
return (
|
||||
<Stack gap="xl">
|
||||
<SectionHeading headingRef={props.headingRef} title={t("title")} description={t("description")} />
|
||||
@@ -1248,7 +1248,8 @@ const IntegrationEditor = ({
|
||||
update: (patch: Partial<IntegrationDraft>) => void;
|
||||
selectSecretOption: (option: number) => void;
|
||||
}) => {
|
||||
const t = useScopedI18n("init.studio.connect");
|
||||
const t = useI18n("init.studio.connect");
|
||||
const tCommon = useI18n("common.field");
|
||||
const sounds = useOnboardingSounds();
|
||||
const options = getAllSecretKindOptions(draft.kind);
|
||||
const apiKeyUrl = getIntegrationApiKeyUrl(draft.url, draft.kind);
|
||||
@@ -1313,7 +1314,7 @@ const IntegrationEditor = ({
|
||||
<Stack>
|
||||
<SimpleGrid cols={{ base: 1, sm: 2 }}>
|
||||
<TextInput
|
||||
label={t("name")}
|
||||
label={tCommon("name")}
|
||||
value={draft.name}
|
||||
onChange={(event) => updateAndResetTest({ name: event.currentTarget.value })}
|
||||
/>
|
||||
@@ -1415,7 +1416,7 @@ const formatSecretKind = (kind: IntegrationSecretKind) =>
|
||||
kind.replace(/([A-Z])/g, " $1").replace(/^./, (letter) => letter.toUpperCase());
|
||||
|
||||
const BoardBuilder = (props: StudioSectionProps) => {
|
||||
const t = useScopedI18n("init.studio.board");
|
||||
const t = useI18n("init.studio.board");
|
||||
const sounds = useOnboardingSounds();
|
||||
const validationErrors = getBoardValidationErrors({
|
||||
attempted: props.boardValidationAttempted,
|
||||
@@ -1634,7 +1635,7 @@ const BoardPreview = ({
|
||||
};
|
||||
|
||||
const Extensions = (props: StudioSectionProps) => {
|
||||
const t = useScopedI18n("init.studio.extend");
|
||||
const t = useI18n("init.studio.extend");
|
||||
return (
|
||||
<Stack gap={0}>
|
||||
<Title id="studio-section-title" ref={props.headingRef} order={2} tabIndex={-1} mb="xs">
|
||||
@@ -1649,7 +1650,7 @@ const Extensions = (props: StudioSectionProps) => {
|
||||
{t("assistant")}
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab value="mcp" leftSection={<IconCode size={16} />}>
|
||||
{t("mcp")}
|
||||
MCP
|
||||
</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel value="workshop" pt="xs">
|
||||
@@ -1673,7 +1674,7 @@ const AssistantSetup = ({
|
||||
environment: StudioSectionProps["environment"];
|
||||
configuration: ReactNode;
|
||||
}) => {
|
||||
const t = useScopedI18n("init.studio.extend.assistantSetup");
|
||||
const t = useI18n("init.studio.extend.assistantSetup");
|
||||
if (!environment.canConfigurePrivileged) {
|
||||
return (
|
||||
<Alert icon={<IconKey size={18} />} title={t("loginTitle")}>
|
||||
@@ -1697,7 +1698,7 @@ const WorkshopSetup = ({
|
||||
environment: StudioSectionProps["environment"];
|
||||
runtimeCapabilities: StudioSectionProps["runtimeCapabilities"];
|
||||
}) => {
|
||||
const t = useScopedI18n("init.studio.extend.workshopSetup");
|
||||
const t = useI18n("init.studio.extend.workshopSetup");
|
||||
const status = runtimeCapabilities.isPending
|
||||
? "checking"
|
||||
: runtimeCapabilities.data?.workshop.status === "available"
|
||||
@@ -1755,7 +1756,7 @@ const WorkshopFeature = ({ title, description }: { title: string; description: s
|
||||
);
|
||||
|
||||
const McpSetup = ({ environment }: { environment: StudioSectionProps["environment"] }) => {
|
||||
const t = useScopedI18n("init.studio.extend.mcpSetup");
|
||||
const t = useI18n("init.studio.extend.mcpSetup");
|
||||
const [apiKey, setApiKey] = useState<string | null>(null);
|
||||
const sounds = useOnboardingSounds();
|
||||
const createKey = clientApi.apiKeys.create.useMutation({
|
||||
@@ -1861,7 +1862,7 @@ const McpSetup = ({ environment }: { environment: StudioSectionProps["environmen
|
||||
};
|
||||
|
||||
const Review = (props: StudioSectionProps) => {
|
||||
const t = useScopedI18n("init.studio.review");
|
||||
const t = useI18n("init.studio.review");
|
||||
const themeLabel = {
|
||||
auto: t("themeAuto"),
|
||||
light: t("themeLight"),
|
||||
|
||||
@@ -7,7 +7,7 @@ import { IconArrowRight, IconDatabaseImport } from "@tabler/icons-react";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||
import { showErrorNotification } from "@homarr/notifications";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
|
||||
import { OnboardingBackdrop } from "./onboarding-backdrop";
|
||||
import { OnboardingWordmark } from "./onboarding-wordmark";
|
||||
@@ -16,8 +16,8 @@ import { useOnboardingSounds, useWelcomeSound } from "./use-onboarding-sounds";
|
||||
import classes from "./onboarding-studio.module.css";
|
||||
|
||||
export const Welcome = ({ environment, sqliteRestore }: OnboardingStudioProps) => {
|
||||
const t = useScopedI18n("init.studio.welcome");
|
||||
const claimT = useScopedI18n("init.studio.claim");
|
||||
const t = useI18n("init.studio.welcome");
|
||||
const claimT = useI18n("init.studio.claim");
|
||||
const [showRestore, setShowRestore] = useState(false);
|
||||
const [claimPending, setClaimPending] = useState(false);
|
||||
const [claimError, setClaimError] = useState<string | null>(null);
|
||||
|
||||
Reference in new issue
Block a user