This commit is contained in:
Louis Mazin 2026-09-21 14:18:14 +02:00
parent 29eacb2578
commit 7875f21b4d
2 changed files with 112 additions and 23 deletions

View File

@ -13,11 +13,16 @@ class UsersConfig(AppConfig):
# Only run when the server is actually starting # Only run when the server is actually starting
if 'runserver' in sys.argv: if 'runserver' in sys.argv:
try: try:
# Import here to avoid issues during Django startup
from .models import User from .models import User
from decouple import config from decouple import config
from django.db import transaction from django.db import transaction
# Don't create/synchronize the configured admin if another
# superuser already exists.
if User.objects.filter(is_superuser=True).exists():
print('A superuser already exists; no admin user was created.')
return
username = config('ADMIN_USERNAME', default='').strip() username = config('ADMIN_USERNAME', default='').strip()
password = config('ADMIN_PASSWORD', default='') password = config('ADMIN_PASSWORD', default='')
first_name = config('ADMIN_FIRST_NAME', default='').strip() first_name = config('ADMIN_FIRST_NAME', default='').strip()
@ -50,6 +55,7 @@ class UsersConfig(AppConfig):
action = 'created' if created else 'synchronized' action = 'created' if created else 'synchronized'
print(f'Admin user "{username}" {action}.') print(f'Admin user "{username}" {action}.')
except Exception as e: except Exception as e:
# Don't fail the entire Django startup if there's an error # Don't fail the entire Django startup if there's an error
print(f'Error creating admin user: {e}') print(f'Error creating admin user: {e}')

View File

@ -8,7 +8,6 @@ import {
SidebarFooter, SidebarFooter,
SidebarGroup, SidebarGroup,
SidebarGroupContent, SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader, SidebarHeader,
SidebarMenu, SidebarMenu,
SidebarMenuButton, SidebarMenuButton,
@ -86,6 +85,82 @@ const NavBar = () => {
}, },
]; ];
/*
* Hauteur d'une ligne de navigation.
*
* Le SidebarMenuButton natif fait 32px.
* On lui donne une ligne de 48px et on le centre.
*
* Le header de groupe fait lui aussi 32px.
* En mode plié, il est remplacé visuellement par
* une séparation, mais conserve exactement ses 32px.
*/
const menuItemClass = 'h-12 min-h-12 flex items-center';
const buttonClass = `
w-full
h-8
min-h-8
group-data-[collapsible=icon]:size-8!
group-data-[collapsible=icon]:p-2!
`;
const linkClass = `
flex
h-full
w-full
items-center
gap-2
text-base
`;
/*
* Header de groupe :
*
* Déplié :
* [ Navigation ] 32px
*
* Plié :
* [ ---------------------- ] 32px
*
* Même hauteur dans les deux cas.
*/
const GroupHeader = ({ children }) => (
<div
className="
flex
h-8
min-h-8
w-full
items-center
px-2
"
>
{/* Nom du groupe */}
<span
className="
truncate
text-lg
font-medium
group-data-[collapsible=icon]:hidden
"
>
{children}
</span>
{/* Séparation en mode plié */}
<div
className="
hidden
w-full
border-t
border-sidebar-border
group-data-[collapsible=icon]:block
"
/>
</div>
);
return ( return (
<Sidebar <Sidebar
className="border-0" className="border-0"
@ -94,13 +169,18 @@ const NavBar = () => {
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}
> >
{/* Logo / nom de la boulangerie */} {/* Logo / nom de la boulangerie */}
<SidebarHeader> <SidebarHeader className="h-16 p-2 pl-0">
<SidebarMenu> <SidebarMenu>
<SidebarMenuItem> <SidebarMenuItem className="h-12 flex items-center">
<SidebarMenuButton <SidebarMenuButton
size="lg" size="lg"
tooltip="Le Fournil du Bocage" className="
onClick={handleCloseMenu} h-12
w-full
group-data-[collapsible=icon]:h-8!
group-data-[collapsible=icon]:w-10!
group-data-[collapsible=icon]:p-2!
"
render={ render={
<Link <Link
to="/" to="/"
@ -126,12 +206,12 @@ const NavBar = () => {
</SidebarMenu> </SidebarMenu>
</SidebarHeader> </SidebarHeader>
{/* Navigation */}
<SidebarContent> <SidebarContent>
<SidebarGroup> {/* Navigation */}
<SidebarGroupLabel className="text-lg"> <SidebarGroup className="p-2">
<GroupHeader>
Navigation Navigation
</SidebarGroupLabel> </GroupHeader>
<SidebarGroupContent> <SidebarGroupContent>
<SidebarMenu> <SidebarMenu>
@ -139,15 +219,18 @@ const NavBar = () => {
const Icon = item.icon; const Icon = item.icon;
return ( return (
<SidebarMenuItem key={item.href}> <SidebarMenuItem
key={item.href}
className={menuItemClass}
>
<SidebarMenuButton <SidebarMenuButton
tooltip={item.title} tooltip={item.title}
onClick={handleCloseMenu} onClick={handleCloseMenu}
className="w-full" className={buttonClass}
render={ render={
<NavLink <NavLink
to={item.href} to={item.href}
className="flex w-full items-center gap-2 text-base" className={linkClass}
> >
<Icon className="size-6 shrink-0" /> <Icon className="size-6 shrink-0" />
@ -166,22 +249,22 @@ const NavBar = () => {
{/* Administration */} {/* Administration */}
{user.is_admin && ( {user.is_admin && (
<SidebarGroup> <SidebarGroup className="p-2">
<SidebarGroupLabel className="text-lg"> <GroupHeader>
Administration Administration
</SidebarGroupLabel> </GroupHeader>
<SidebarGroupContent> <SidebarGroupContent>
<SidebarMenu> <SidebarMenu>
<SidebarMenuItem> <SidebarMenuItem className={menuItemClass}>
<SidebarMenuButton <SidebarMenuButton
tooltip="Comptes existants" tooltip="Comptes existants"
onClick={handleCloseMenu} onClick={handleCloseMenu}
className="w-full" className={buttonClass}
render={ render={
<NavLink <NavLink
to="/users" to="/users"
className="flex w-full items-center gap-2 text-base" className={linkClass}
> >
<Users className="size-6 shrink-0" /> <Users className="size-6 shrink-0" />
@ -201,16 +284,16 @@ const NavBar = () => {
{/* Déconnexion */} {/* Déconnexion */}
<SidebarFooter> <SidebarFooter>
<SidebarMenu> <SidebarMenu>
<SidebarMenuItem> <SidebarMenuItem className={menuItemClass}>
<SidebarMenuButton <SidebarMenuButton
tooltip="Déconnexion" tooltip="Déconnexion"
onClick={handleCloseMenu} onClick={handleCloseMenu}
className="w-full" className={buttonClass}
render={ render={
<button <button
type="button" type="button"
onClick={logout} onClick={logout}
className="flex w-full items-center gap-2 text-base" className={linkClass}
> >
<LogOut className="size-6 shrink-0" /> <LogOut className="size-6 shrink-0" />