Compare commits

...

8 Commits

Author SHA1 Message Date
gitea-actions 1991c43f8c chore: bump version to v0.4.12
Auto Tag Develop / tag (push) Successful in 8s
Build & Push Docker Image / build (push) Successful in 57s
2026-05-26 09:08:30 +00:00
Matthieu e9ca00aeb2 fix(ui) : espace vertical dans le corps des drawers (champ focus rogné)
Auto Tag Develop / tag (push) Successful in 10s
Le body scrollable de MalioDrawer (overflow-y-auto) n'avait aucun
padding vertical : le label flottant du premier champ, qui remonte au
focus, dépassait le bord haut et se faisait rogner sous l'entête. Idem
pour le dernier champ en bas.

Ajoute une feuille app.css (hors thème sombre) qui donne 1rem de padding
haut/bas au corps de tous les drawers, via l'API data-test stable de
@malio/layer-ui (sans modifier la lib ni chaque drawer).
2026-05-26 11:08:19 +02:00
gitea-actions b13ba41674 chore: bump version to v0.4.11
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 44s
2026-05-26 09:02:57 +00:00
Matthieu ac615875f3 fix(absences) : dates du drawer employé en pleine largeur (1 par ligne)
Auto Tag Develop / tag (push) Successful in 7s
Dans le drawer « Informations employé », les champs Date d'embauche et
Date de sortie étaient sur une grille 2 colonnes : le popover du
calendrier MalioDate, coincé en demi-largeur, chevauchait le champ
voisin. Passage en pleine largeur (sm:col-span-2) pour laisser le
calendrier s'afficher correctement.
2026-05-26 11:02:50 +02:00
gitea-actions f8322f8b1e chore: bump version to v0.4.10
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 45s
2026-05-26 08:49:58 +00:00
Matthieu cd474d5089 feat(absences) : réserve « Mes absences » aux employés
Auto Tag Develop / tag (push) Successful in 6s
Un utilisateur non coché « Employé » (isEmployee = false) ne voit plus
l'entrée « Mes absences » dans le menu et ne peut plus accéder à la page
/absences (nouveau middleware employee qui redirige vers l'accueil).
L'entête de section « Absences » est masquée si l'utilisateur n'est ni
employé ni admin.
2026-05-26 10:49:52 +02:00
gitea-actions 2feba57cb6 chore: bump version to v0.4.9
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 20s
2026-05-26 08:42:59 +00:00
Matthieu f74f0e1ad3 fix(absences) : seed des politiques par défaut en prod via migration
Auto Tag Develop / tag (push) Successful in 7s
Les 6 AbsencePolicy par défaut (barème Syntec / IDCC 1486) n'étaient
créées que par les fixtures, jamais en prod : l'écran « Politiques
d'absence » était vide en production.

Ajoute une migration de données idempotente (INSERT ... ON CONFLICT
(type) DO NOTHING sur l'index unique uniq_absence_policy_type) qui sème
les mêmes valeurs que les fixtures. Sans effet en dev (lignes déjà
présentes), peuple la prod au déploiement.
2026-05-26 10:42:27 +02:00
8 changed files with 122 additions and 16 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
parameters:
app.version: '0.4.8'
app.version: '0.4.12'
+21
View File
@@ -0,0 +1,21 @@
/*
* App-level layout fixes (not theme-related).
*/
/*
* MalioDrawer : donne au corps scrollable un peu d'espace vertical.
*
* Le body du drawer est `overflow-y-auto` sans padding vertical. Or le label
* flottant d'un champ Malio remonte (-1.25rem) au focus/remplissage : pour le
* PREMIER champ, collé en haut du body, ce label dépasse le bord supérieur et
* se fait rogner (il « grossit et passe sous l'entête »). Le dernier champ
* (popover de date, hint) souffre du même rognage en bas.
*
* On ajoute donc un padding vertical au body de TOUS les drawers via l'API de
* test stable de la lib (@malio/layer-ui), sans la modifier ni toucher chaque
* drawer un par un. Le sélecteur reste limité au panneau du drawer.
*/
[data-test="panel"] > [data-test="body"] {
padding-top: 1rem;
padding-bottom: 1rem;
}
+16 -10
View File
@@ -7,16 +7,22 @@
</div>
</template>
<form v-if="user" class="grid grid-cols-1 gap-4 sm:grid-cols-2" @submit.prevent="save">
<MalioDate
v-model="form.hireDate"
:label="$t('absences.admin.employees.fields.hireDate')"
group-class="w-full"
/>
<MalioDate
v-model="form.endDate"
:label="$t('absences.admin.employees.fields.endDate')"
group-class="w-full"
/>
<!-- Dates en pleine largeur (1 par ligne) : le popover du calendrier
a besoin de toute la largeur pour s'afficher correctement. -->
<div class="sm:col-span-2">
<MalioDate
v-model="form.hireDate"
:label="$t('absences.admin.employees.fields.hireDate')"
group-class="w-full"
/>
</div>
<div class="sm:col-span-2">
<MalioDate
v-model="form.endDate"
:label="$t('absences.admin.employees.fields.endDate')"
group-class="w-full"
/>
</div>
<MalioSelect
v-model="form.contractType"
:label="$t('absences.admin.employees.fields.contractType')"
+9 -4
View File
@@ -119,11 +119,14 @@
</div>
<!-- Section : Absences -->
<p v-if="!sidebarIsCollapsed" class="px-4 pt-5 pb-1 text-xs font-semibold uppercase tracking-wider text-neutral-400">
Absences
</p>
<div v-else class="mx-2 my-3 border-t border-secondary-500" />
<template v-if="isAbsenceSectionVisible">
<p v-if="!sidebarIsCollapsed" class="px-4 pt-5 pb-1 text-xs font-semibold uppercase tracking-wider text-neutral-400">
Absences
</p>
<div v-else class="mx-2 my-3 border-t border-secondary-500" />
</template>
<SidebarLink
v-if="isEmployee"
to="/absences"
icon="mdi:umbrella-beach-outline"
label="Mes absences"
@@ -211,6 +214,8 @@ const {version} = useAppVersion()
const route = useRoute()
const isAdmin = computed(() => (auth.user?.roles ?? []).includes('ROLE_ADMIN'))
const isEmployee = computed(() => Boolean(auth.user?.isEmployee))
const isAbsenceSectionVisible = computed(() => isEmployee.value || isAdmin.value)
const isMailVisible = computed(() => {
const roles: string[] = auth.user?.roles ?? []
+9
View File
@@ -0,0 +1,9 @@
export default defineNuxtRouteMiddleware(() => {
const auth = useAuthStore()
// "Mes absences" is reserved for users flagged as employees (subject to the
// absence management). Non-employees are redirected to the home page.
if (!auth.isAuthenticated || !auth.user?.isEmployee) {
return navigateTo('/')
}
})
+1 -1
View File
@@ -2,7 +2,7 @@ export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: {enabled: false},
ssr: false,
css: ['~/assets/css/dark.css'],
css: ['~/assets/css/app.css', '~/assets/css/dark.css'],
app: {
baseURL: process.env.NODE_ENV === 'production'
? (process.env.NUXT_PUBLIC_APP_BASE || '/')
+2
View File
@@ -75,6 +75,8 @@ import { useAbsenceHelpers } from '~/composables/useAbsenceHelpers'
type Row = AbsenceRequest & { typeLabelText: string; periodText: string; daysText: string; createdAtText: string }
definePageMeta({ middleware: ['employee'] })
const { t } = useI18n()
const service = useAbsenceService()
const { statusLabel, statusVariant, statusIcon, formatRange, formatDays, formatDate } = useAbsenceHelpers()
+63
View File
@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Seed the default absence policies (Syntec / IDCC 1486 legal baseline).
*
* These rows were previously created only by AppFixtures, so they existed in
* dev but never in production: the "Politiques d'absence" admin screen was
* empty in prod. This data migration seeds the same 6 policies idempotently
* (ON CONFLICT on the unique `type` index), so prod gets populated and dev,
* where fixtures already created them, is left untouched.
*
* Values mirror AppFixtures and the legal compliance design
* (docs/superpowers/specs/2026-05-22-absence-legal-compliance-fixes-design.md):
* - CP: 25 jours ouvrés/an, préavis 30 j, pas de justificatif.
* - Mariage/PACS: 4 j/événement ; Naissance: 3 j/événement.
* - Décès / Congé parental / Maladie: pas de forfait codé en dur
* (montant selon lien de parenté ou suspension), justificatif requis.
*/
final class Version20260526100000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Seed default absence policies (Syntec IDCC 1486) idempotently for prod';
}
public function up(Schema $schema): void
{
// [type, days_per_year, days_per_event, justification_required, notice_days, count_working_days_only]
$policies = [
['cp', '25', null, 'false', 30, 'true'],
['mariage_pacs', null, '4', 'true', 0, 'true'],
['naissance', null, '3', 'true', 0, 'true'],
['conge_parental', null, null, 'true', 30, 'true'],
['deces', null, null, 'true', 0, 'true'],
['maladie', null, null, 'true', 0, 'true'],
];
foreach ($policies as [$type, $daysPerYear, $daysPerEvent, $justif, $notice, $workingOnly]) {
$daysPerYear = null === $daysPerYear ? 'NULL' : $daysPerYear;
$daysPerEvent = null === $daysPerEvent ? 'NULL' : $daysPerEvent;
$this->addSql(<<<SQL
INSERT INTO absence_policy
(type, days_per_year, days_per_event, justification_required, notice_days, count_working_days_only, active)
VALUES
('{$type}', {$daysPerYear}, {$daysPerEvent}, {$justif}, {$notice}, {$workingOnly}, true)
ON CONFLICT (type) DO NOTHING
SQL);
}
}
public function down(Schema $schema): void
{
$this->addSql("DELETE FROM absence_policy WHERE type IN ('cp', 'mariage_pacs', 'naissance', 'conge_parental', 'deces', 'maladie')");
}
}