mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-01 00:22:19 +03:00
Miscellaneous fixes (0.17 beta) (#21867)
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
* Adjust title prompt to have less rigidity * Improve motion boxes handling for features that don't require motion * Improve handling of classes starting with digits * Improve vehicle nuance * tweak lpr docs * Improve grammar * Don't allow # in face name * add password requirements to new user dialog * change password requirements * Clenaup --------- Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
This commit is contained in:
co-authored by
Josh Hawkins
parent
e4fe021279
commit
2d83992284
@@ -32,11 +32,17 @@ import {
|
||||
SelectValue,
|
||||
} from "../ui/select";
|
||||
import { Shield, User } from "lucide-react";
|
||||
import { LuCheck, LuX } from "react-icons/lu";
|
||||
import { LuCheck, LuX, LuEye, LuEyeOff } from "react-icons/lu";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { isDesktop, isMobile } from "react-device-detect";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import {
|
||||
calculatePasswordStrength,
|
||||
getPasswordRequirements,
|
||||
getPasswordStrengthLabel,
|
||||
getPasswordStrengthColor,
|
||||
} from "@/utils/passwordUtil";
|
||||
import {
|
||||
MobilePage,
|
||||
MobilePageContent,
|
||||
@@ -59,6 +65,10 @@ export default function CreateUserDialog({
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
const { t } = useTranslation(["views/settings"]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [showPasswordVisible, setShowPasswordVisible] =
|
||||
useState<boolean>(false);
|
||||
const [showConfirmPassword, setShowConfirmPassword] =
|
||||
useState<boolean>(false);
|
||||
|
||||
const roles = useMemo(() => {
|
||||
const existingRoles = config ? Object.keys(config.auth?.roles || {}) : [];
|
||||
@@ -73,7 +83,9 @@ export default function CreateUserDialog({
|
||||
.regex(/^[A-Za-z0-9._]+$/, {
|
||||
message: t("users.dialog.createUser.usernameOnlyInclude"),
|
||||
}),
|
||||
password: z.string().min(1, t("users.dialog.form.passwordIsRequired")),
|
||||
password: z
|
||||
.string()
|
||||
.min(12, t("users.dialog.form.password.requirements.length")),
|
||||
confirmPassword: z
|
||||
.string()
|
||||
.min(1, t("users.dialog.createUser.confirmPassword")),
|
||||
@@ -108,13 +120,27 @@ export default function CreateUserDialog({
|
||||
const passwordsMatch = password === confirmPassword;
|
||||
const showMatchIndicator = password && confirmPassword;
|
||||
|
||||
// Password strength calculation
|
||||
const passwordStrength = useMemo(
|
||||
() => calculatePasswordStrength(password),
|
||||
[password],
|
||||
);
|
||||
|
||||
const requirements = useMemo(
|
||||
() => getPasswordRequirements(password),
|
||||
[password],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!show) {
|
||||
form.reset({
|
||||
user: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
role: "viewer",
|
||||
});
|
||||
setShowPasswordVisible(false);
|
||||
setShowConfirmPassword(false);
|
||||
}
|
||||
}, [show, form]);
|
||||
|
||||
@@ -122,8 +148,11 @@ export default function CreateUserDialog({
|
||||
form.reset({
|
||||
user: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
role: "viewer",
|
||||
});
|
||||
setShowPasswordVisible(false);
|
||||
setShowConfirmPassword(false);
|
||||
onCancel();
|
||||
};
|
||||
|
||||
@@ -184,13 +213,88 @@ export default function CreateUserDialog({
|
||||
{t("users.dialog.form.password.title")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={t("users.dialog.form.password.placeholder")}
|
||||
type="password"
|
||||
className="h-10"
|
||||
{...field}
|
||||
/>
|
||||
<div className="relative">
|
||||
<Input
|
||||
placeholder={t(
|
||||
"users.dialog.form.password.placeholder",
|
||||
)}
|
||||
type={showPasswordVisible ? "text" : "password"}
|
||||
className="h-10 pr-10"
|
||||
{...field}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
tabIndex={-1}
|
||||
aria-label={
|
||||
showPasswordVisible
|
||||
? t("users.dialog.form.password.hide", {
|
||||
ns: "views/settings",
|
||||
})
|
||||
: t("users.dialog.form.password.show", {
|
||||
ns: "views/settings",
|
||||
})
|
||||
}
|
||||
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
|
||||
onClick={() =>
|
||||
setShowPasswordVisible(!showPasswordVisible)
|
||||
}
|
||||
>
|
||||
{showPasswordVisible ? (
|
||||
<LuEyeOff className="size-4" />
|
||||
) : (
|
||||
<LuEye className="size-4" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</FormControl>
|
||||
|
||||
{password && (
|
||||
<div className="mt-2 space-y-2">
|
||||
<div className="flex h-1.5 w-full overflow-hidden rounded-full bg-secondary-foreground">
|
||||
<div
|
||||
className={`${getPasswordStrengthColor(
|
||||
password,
|
||||
)} transition-all duration-300`}
|
||||
style={{ width: `${passwordStrength * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t("users.dialog.form.password.strength.title")}
|
||||
<span className="font-medium">
|
||||
{getPasswordStrengthLabel(password, t)}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<div className="space-y-1 rounded-md bg-muted/50 p-2">
|
||||
<p className="text-xs font-medium text-muted-foreground">
|
||||
{t("users.dialog.form.password.requirements.title")}
|
||||
</p>
|
||||
<ul className="space-y-1">
|
||||
<li className="flex items-center gap-2 text-xs">
|
||||
{requirements.length ? (
|
||||
<LuCheck className="size-3.5 text-green-500" />
|
||||
) : (
|
||||
<LuX className="size-3.5 text-red-500" />
|
||||
)}
|
||||
<span
|
||||
className={
|
||||
requirements.length
|
||||
? "text-green-600"
|
||||
: "text-red-600"
|
||||
}
|
||||
>
|
||||
{t(
|
||||
"users.dialog.form.password.requirements.length",
|
||||
)}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
@@ -204,14 +308,41 @@ export default function CreateUserDialog({
|
||||
{t("users.dialog.form.password.confirm.title")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={t(
|
||||
"users.dialog.form.password.confirm.placeholder",
|
||||
)}
|
||||
type="password"
|
||||
className="h-10"
|
||||
{...field}
|
||||
/>
|
||||
<div className="relative">
|
||||
<Input
|
||||
placeholder={t(
|
||||
"users.dialog.form.password.confirm.placeholder",
|
||||
)}
|
||||
type={showConfirmPassword ? "text" : "password"}
|
||||
className="h-10 pr-10"
|
||||
{...field}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
tabIndex={-1}
|
||||
aria-label={
|
||||
showConfirmPassword
|
||||
? t("users.dialog.form.password.hide", {
|
||||
ns: "views/settings",
|
||||
})
|
||||
: t("users.dialog.form.password.show", {
|
||||
ns: "views/settings",
|
||||
})
|
||||
}
|
||||
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
|
||||
onClick={() =>
|
||||
setShowConfirmPassword(!showConfirmPassword)
|
||||
}
|
||||
>
|
||||
{showConfirmPassword ? (
|
||||
<LuEyeOff className="size-4" />
|
||||
) : (
|
||||
<LuEye className="size-4" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</FormControl>
|
||||
{showMatchIndicator && (
|
||||
<div className="mt-1 flex items-center gap-1.5 text-xs">
|
||||
|
||||
Reference in New Issue
Block a user