chore: standardised the eslint config structure accross the project (#11814)

This commit is contained in:
Mridang Agarwalla
2026-03-12 11:02:52 +01:00
committed by GitHub
parent 621fd9bdec
commit 7cdee1703f
61 changed files with 1025 additions and 2011 deletions
+11 -20
View File
@@ -13,30 +13,21 @@ interface AvatarProps {
}
export function getInitials(name: string, loginName: string) {
let credentials = "";
if (name) {
const split = name.split(" ");
if (split) {
const initials = split[0].charAt(0) + (split[1] ? split[1].charAt(0) : "");
credentials = initials;
} else {
credentials = name.charAt(0);
}
} else {
const username = loginName.split("@")[0];
let separator = "_";
if (username.includes("-")) {
separator = "-";
}
if (username.includes(".")) {
separator = ".";
}
const split = username.split(separator);
const initials = split[0].charAt(0) + (split[1] ? split[1].charAt(0) : "");
credentials = initials;
return split[0].charAt(0) + (split[1] ? split[1].charAt(0) : "");
}
return credentials;
const username = loginName.split("@")[0];
let separator = "_";
if (username.includes("-")) {
separator = "-";
}
if (username.includes(".")) {
separator = ".";
}
const split = username.split(separator);
return split[0].charAt(0) + (split[1] ? split[1].charAt(0) : "");
}
// Helper function to get avatar roundness from theme
-1
View File
@@ -65,7 +65,6 @@ function getDefaultButtonAppearance(): string {
return appearance?.button || "border border-button-light-border dark:border-button-dark-border"; // Fallback to flat design
}
// eslint-disable-next-line react/display-name
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(
{
-1
View File
@@ -35,7 +35,6 @@ function getDefaultCardStyling(): string {
return appearance?.card || "shadow-sm border-0"; // Fallback to material design
}
// eslint-disable-next-line react/display-name
export const Card = forwardRef<HTMLDivElement, CardProps>(
(
{
+1 -1
View File
@@ -26,7 +26,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(function Che
checked={enabled}
onChange={(event) => {
setEnabled(event.target?.checked);
onChangeVal && onChangeVal(event.target?.checked);
if (onChangeVal) onChangeVal(event.target?.checked);
}}
disabled={disabled}
type="checkbox"
@@ -17,7 +17,7 @@ export function CopyToClipboard({ value }: Props) {
const to = setTimeout(setCopied, 1000, false);
return () => clearTimeout(to);
}
}, [copied]);
}, [copied, value]);
return (
<div className="flex flex-row items-center px-2">
@@ -91,7 +91,7 @@ export function IdpProcessHandler({
setError(err instanceof Error ? err.message : t("processing.unexpectedError"));
setLoading(false);
});
}, [provider, id, token, requestId, organization, link, sessionId, postErrorRedirectUrl, router]);
}, [provider, id, token, requestId, organization, link, sessionId, linkFingerprint, postErrorRedirectUrl, router, t]);
return (
<div className="flex min-h-screen items-center justify-center">
-1
View File
@@ -37,7 +37,6 @@ function getDefaultInputRoundness(): string {
return getComponentRoundness("input");
}
// eslint-disable-next-line react/display-name
export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(
(
{
+31 -28
View File
@@ -11,7 +11,7 @@ import { Button, ButtonVariants } from "./button";
import { Spinner } from "./spinner";
import { Translated } from "./translated";
type Inputs = {};
type Inputs = Record<string, never>;
type Props = {
sessionId?: string;
@@ -44,6 +44,35 @@ export function RegisterPasskey({
const router = useRouter();
const continueAndLogin = useCallback(
(loginName?: string) => {
const params = new URLSearchParams();
if (organization) {
params.set("organization", organization);
}
if (requestId) {
params.set("requestId", requestId);
}
if (sessionId) {
params.set("sessionId", sessionId);
}
if (userId) {
params.set("userId", userId);
}
if (loginName ?? initialLoginName) {
params.set("loginName", loginName ?? initialLoginName ?? "");
}
router.push("/passkey?" + params);
},
[organization, requestId, sessionId, userId, initialLoginName, router],
);
async function submitVerify(
passkeyId: string,
passkeyName: string,
@@ -166,7 +195,7 @@ export function RegisterPasskey({
}
continueAndLogin(verificationResponse.loginName);
}, [sessionId, userId, code]);
}, [sessionId, userId, code, codeId, continueAndLogin]);
// Auto-submit when code is provided (similar to VerifyForm)
useEffect(() => {
@@ -175,32 +204,6 @@ export function RegisterPasskey({
}
}, [code, submitRegisterAndContinue]);
function continueAndLogin(loginName?: string) {
const params = new URLSearchParams();
if (organization) {
params.set("organization", organization);
}
if (requestId) {
params.set("requestId", requestId);
}
if (sessionId) {
params.set("sessionId", sessionId);
}
if (userId) {
params.set("userId", userId);
}
if (loginName ?? initialLoginName) {
params.set("loginName", loginName ?? initialLoginName ?? "");
}
router.push("/passkey?" + params);
}
return (
<form className="w-full">
{error && (
@@ -4,7 +4,7 @@ import { clearSession } from "@/lib/server/session";
import { timestampDate } from "@zitadel/client";
import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
import { redirect, useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { Alert, AlertType } from "./alert";
import { SessionClearItem } from "./session-clear-item";
import { Translated } from "./translated";
@@ -20,7 +20,7 @@ export function SessionsClearList({ sessions, logoutHint, postLogoutRedirectUri,
const [list, setList] = useState<Session[]>(sessions);
const router = useRouter();
async function clearHintedSession() {
const clearHintedSession = useCallback(async () => {
console.log("Clearing session for login hint:", logoutHint);
// If a login hint is provided, we logout that specific session
const sessionIdToBeCleared = sessions.find((session) => {
@@ -53,13 +53,13 @@ export function SessionsClearList({ sessions, logoutHint, postLogoutRedirectUri,
} else {
console.warn(`No session found for login hint: ${logoutHint}`);
}
}
}, [logoutHint, sessions, postLogoutRedirectUri, organization, router]);
useEffect(() => {
if (logoutHint) {
clearHintedSession();
}
}, []);
}, [logoutHint, clearHintedSession]);
return sessions ? (
<div className="flex flex-col space-y-2">
+24 -21
View File
@@ -5,7 +5,7 @@ import { sendLoginname } from "@/lib/server/loginname";
import { LoginSettings } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { useTranslations } from "next-intl";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { Alert } from "./alert";
import { AutoSubmitForm } from "./auto-submit-form";
@@ -55,34 +55,37 @@ export function UsernameForm({
const [error, setError] = useState<string>("");
const [samlData, setSamlData] = useState<{ url: string; fields: Record<string, string> } | null>(null);
async function submitLoginName(values: Inputs, organization?: string) {
setLoading(true);
const submitLoginName = useCallback(
async (values: Inputs, organization?: string) => {
setLoading(true);
try {
const res = await sendLoginname({
loginName: values.loginName,
organization,
defaultOrganization,
requestId,
suffix,
ignoreUnknownUsernames: loginSettings?.ignoreUnknownUsernames,
});
try {
const res = await sendLoginname({
loginName: values.loginName,
organization,
defaultOrganization,
requestId,
suffix,
ignoreUnknownUsernames: loginSettings?.ignoreUnknownUsernames,
});
handleServerActionResponse(res, router, setSamlData, setError);
return res;
} catch {
setError(t("errors.internalError"));
} finally {
setLoading(false);
}
}
handleServerActionResponse(res, router, setSamlData, setError);
return res;
} catch {
setError(t("errors.internalError"));
} finally {
setLoading(false);
}
},
[defaultOrganization, requestId, suffix, loginSettings, router, t],
);
useEffect(() => {
if (submit && loginName) {
// When we navigate to this page, we always want to be redirected if submit is true and the parameters are valid.
submitLoginName({ loginName }, organization);
}
}, []);
}, [submit, loginName, organization, submitLoginName]);
let inputLabel = t("labels.loginname");
if (loginSettings?.disableLoginWithEmail && loginSettings?.disableLoginWithPhone) {
+1 -1
View File
@@ -101,7 +101,7 @@ export function VerifyForm({ userId, loginName, organization, requestId, code, i
setLoading(false);
}
},
[isInvite, userId],
[isInvite, userId, loginName, organization, requestId, router, t],
);
useEffect(() => {
+15 -34
View File
@@ -341,58 +341,39 @@ export function hashCode(str: string, seed = 0): number {
export function getMembershipColor(role: string): ColorShade {
const hash = hashCode(role);
let color = COLORS[hash % COLORS.length];
switch (role) {
case "IAM_OWNER":
color = COLORS[0];
break;
return COLORS[0];
case "IAM_OWNER_VIEWER":
color = COLORS[14];
break;
return COLORS[14];
case "IAM_ORG_MANAGER":
color = COLORS[11];
break;
return COLORS[11];
case "IAM_USER_MANAGER":
color = COLORS[8];
break;
return COLORS[8];
case "ORG_OWNER":
color = COLORS[16];
break;
return COLORS[16];
case "ORG_USER_MANAGER":
color = COLORS[8];
break;
return COLORS[8];
case "ORG_OWNER_VIEWER":
color = COLORS[14];
break;
return COLORS[14];
case "ORG_USER_PERMISSION_EDITOR":
color = COLORS[7];
break;
return COLORS[7];
case "ORG_PROJECT_PERMISSION_EDITOR":
color = COLORS[11];
break;
return COLORS[11];
case "ORG_PROJECT_CREATOR":
color = COLORS[12];
break;
return COLORS[12];
case "PROJECT_OWNER":
color = COLORS[9];
break;
return COLORS[9];
case "PROJECT_OWNER_VIEWER":
color = COLORS[10];
break;
return COLORS[10];
case "PROJECT_OWNER_GLOBAL":
color = COLORS[11];
break;
return COLORS[11];
case "PROJECT_OWNER_VIEWER_GLOBAL":
color = COLORS[12];
break;
return COLORS[12];
default:
color = COLORS[hash % COLORS.length];
break;
return COLORS[hash % COLORS.length];
}
return color;
}
+1 -1
View File
@@ -52,7 +52,7 @@ export default getRequestConfig(async () => {
const i18nOrganization = _headers.get("x-zitadel-i18n-organization") || ""; // You may need to set this header in middleware
let translations: JsonObject | {} = {};
let translations: JsonObject | Record<string, never> = {};
try {
const i18nJSON = await getHostedLoginTranslation({
serviceConfig,
+3 -1
View File
@@ -46,6 +46,8 @@ export async function loginServiceKeyToken() {
key: key,
});
} catch (err) {
throw new Error(`Failed to read login service key file "${keyFile}": ${err instanceof Error ? err.message : err}`);
throw new Error(`Failed to read login service key file "${keyFile}": ${err instanceof Error ? err.message : err}`, {
cause: err,
});
}
}
+34 -29
View File
@@ -374,24 +374,26 @@ export async function sendLoginname(command: SendLoginnameCommand) {
};
}
const paramsPassword = new URLSearchParams({
loginName: command.ignoreUnknownUsernames
? command.loginName
: (session?.factors?.user?.loginName ?? user.preferredLoginName),
});
{
const paramsPassword = new URLSearchParams({
loginName: command.ignoreUnknownUsernames
? command.loginName
: (session?.factors?.user?.loginName ?? user.preferredLoginName),
});
if (organization) {
paramsPassword.append("organization", organization);
if (organization) {
paramsPassword.append("organization", organization);
}
if (command.requestId) {
paramsPassword.append("requestId", command.requestId);
}
return {
redirect: "/password?" + paramsPassword,
};
}
if (command.requestId) {
paramsPassword.append("requestId", command.requestId);
}
return {
redirect: "/password?" + paramsPassword,
};
case AuthenticationMethodType.PASSKEY: // AuthenticationMethodType.AUTHENTICATION_METHOD_TYPE_PASSKEY
if (userLoginSettings?.passkeysType === PasskeysType.NOT_ALLOWED || !userLoginSettings?.allowLocalAuthentication) {
if (command.ignoreUnknownUsernames) {
@@ -402,22 +404,24 @@ export async function sendLoginname(command: SendLoginnameCommand) {
};
}
const paramsPasskey = new URLSearchParams({
loginName: command.ignoreUnknownUsernames
? command.loginName
: (session?.factors?.user?.loginName ?? user.preferredLoginName),
});
if (command.requestId) {
paramsPasskey.append("requestId", command.requestId);
{
const paramsPasskey = new URLSearchParams({
loginName: command.ignoreUnknownUsernames
? command.loginName
: (session?.factors?.user?.loginName ?? user.preferredLoginName),
});
if (command.requestId) {
paramsPasskey.append("requestId", command.requestId);
}
if (organization) {
paramsPasskey.append("organization", organization);
}
return { redirect: "/passkey?" + paramsPasskey };
}
if (organization) {
paramsPasskey.append("organization", organization);
}
return { redirect: "/passkey?" + paramsPasskey };
case AuthenticationMethodType.IDP:
case AuthenticationMethodType.IDP: {
const resp = await redirectUserToIDP(userId, organization);
if (resp?.error) {
@@ -425,6 +429,7 @@ export async function sendLoginname(command: SendLoginnameCommand) {
}
return resp;
}
}
} else {
// prefer passkey in favor of other methods
@@ -317,7 +317,6 @@ describe("sendPassword", () => {
const { completeFlowOrGetUrl } = await import("../client");
vi.mocked(completeFlowOrGetUrl).mockResolvedValue({ redirect: "https://example.com" });
// eslint-disable-next-line
const verifyHelper = await import("../verify-helper");
vi.mocked(verifyHelper.checkPasswordChangeRequired).mockReturnValue(undefined);
vi.mocked(verifyHelper.checkEmailVerification).mockReturnValue(undefined);
+2 -2
View File
@@ -293,7 +293,7 @@ export async function sendPassword(
return {
error: t(messageKey, {
failedAttempts: error.failedAttempts,
maxPasswordAttempts: hasLimit ? (lockoutSettings?.maxPasswordAttempts).toString() : "?",
maxPasswordAttempts: hasLimit ? String(lockoutSettings?.maxPasswordAttempts ?? 0) : "?",
lockoutMessage: locked ? t("errors.accountLockedContactAdmin") : "",
}),
};
@@ -565,7 +565,7 @@ export async function checkSessionAndSetPassword({
return {
error: t(messageKey, {
failedAttempts: error.failedAttempts,
maxPasswordAttempts: hasLimit ? (lockoutSettings?.maxPasswordAttempts).toString() : "?",
maxPasswordAttempts: hasLimit ? String(lockoutSettings?.maxPasswordAttempts ?? 0) : "?",
lockoutMessage: locked ? t("errors.accountLockedContactAdmin") : "",
}),
};
+2
View File
@@ -164,6 +164,7 @@ export async function checkMFAFactors(
// TODO: provide a way to setup passkeys on mfa page?
return { redirect: `/mfa/set?` + params };
/* eslint-disable no-dupe-else-if -- TODO: this branch is unreachable, conditions overlap with the previous branch */
} else if (
loginSettings?.mfaInitSkipLifetime &&
(loginSettings.mfaInitSkipLifetime.nanos > 0 || loginSettings.mfaInitSkipLifetime.seconds > 0) &&
@@ -171,6 +172,7 @@ export async function checkMFAFactors(
session?.factors?.user?.id &&
shouldEnforceMFA(session, loginSettings)
) {
/* eslint-enable no-dupe-else-if */
const userResponse = await getUserByID({ serviceConfig, userId: session.factors?.user?.id });
const humanUser = userResponse?.user?.type.case === "human" ? userResponse?.user.type.value : undefined;
+1 -3
View File
@@ -1237,20 +1237,18 @@ export interface ServiceConfig {
/**
* Base type that all function parameters must extend to ensure serviceConfig is always required
*/
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export type WithServiceConfig<T = {}> = T & {
serviceConfig: ServiceConfig;
};
export function createServerTransport(token: string, serviceConfig: ServiceConfig) {
// Build interceptors list - OTEL interceptor is always included for trace propagation
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const interceptors: any[] = [otelGrpcInterceptor];
// Add custom headers interceptor if needed
if (process.env.CUSTOM_REQUEST_HEADERS || serviceConfig.instanceHost || serviceConfig.publicHost) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
interceptors.push((next: any) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (req: any) => {
// Apply headers from serviceConfig
if (serviceConfig.instanceHost) {