Compare commits
3 Commits
5c55441e6c
...
refactor/s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27d51ffdb1 | ||
|
|
53d4d5768b | ||
|
|
3ff89d43ed |
@@ -33,7 +33,7 @@ export function useToast() {
|
||||
message,
|
||||
type,
|
||||
visible: true,
|
||||
duration: type === 'error' ? 0 : duration,
|
||||
duration,
|
||||
}
|
||||
|
||||
if (toasts.value.length >= MAX_TOASTS) {
|
||||
@@ -42,8 +42,7 @@ export function useToast() {
|
||||
|
||||
toasts.value.push(toast)
|
||||
|
||||
// Only auto-dismiss non-error toasts
|
||||
if (type !== 'error' && duration > 0) {
|
||||
if (duration > 0) {
|
||||
setTimeout(() => {
|
||||
removeToast(id)
|
||||
}, duration)
|
||||
@@ -56,8 +55,8 @@ export function useToast() {
|
||||
return showToast(message, 'success', duration)
|
||||
}
|
||||
|
||||
const showError = (message: string): number => {
|
||||
return showToast(message, 'error', 0)
|
||||
const showError = (message: string, duration = 8000): number => {
|
||||
return showToast(message, 'error', duration)
|
||||
}
|
||||
|
||||
const showWarning = (message: string, duration = 6000): number => {
|
||||
|
||||
@@ -715,10 +715,12 @@
|
||||
</p>
|
||||
<p class="text-base-content/70 leading-relaxed mb-4">
|
||||
<strong>Pourquoi ?</strong> Certaines informations n'ont de sens que quand
|
||||
l'element est monte sur une machine. Par exemple, la "position sur la machine"
|
||||
d'une pompe : dans le catalogue, la pompe n'est montee nulle part, donc ce champ
|
||||
ne sert a rien. Mais quand on regarde cette pompe depuis la fiche d'une machine,
|
||||
on veut savoir ou elle est installee.
|
||||
l'element est monte sur une machine. Prenons l'exemple d'un palier : sur une
|
||||
machine, vous en avez souvent deux, un en haut (le palier de tete) et un en
|
||||
bas (le palier de pied). Dans le catalogue, le palier n'est monte nulle part,
|
||||
donc savoir s'il est "en haut" ou "en bas" ne veut rien dire. Mais des qu'on
|
||||
regarde ce palier depuis la fiche d'une machine, on veut savoir lequel des
|
||||
deux c'est.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -731,16 +733,16 @@
|
||||
<p class="text-xs text-base-content/40 mb-4">Quand on consulte l'element tout seul</p>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-base-content/70">Debit max</span>
|
||||
<span>120 L/min</span>
|
||||
<span class="text-base-content/70">Diametre interieur</span>
|
||||
<span>50 mm</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-base-content/70">ATEX</span>
|
||||
<span>Oui</span>
|
||||
<span class="text-base-content/70">Type</span>
|
||||
<span>Roulement a billes</span>
|
||||
</div>
|
||||
<div class="border-t border-dashed border-base-300 pt-2 mt-2">
|
||||
<div class="flex justify-between opacity-30">
|
||||
<span class="line-through">Position sur la machine</span>
|
||||
<span class="line-through">Emplacement</span>
|
||||
<span class="text-xs italic">pas affiche ici</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -753,17 +755,17 @@
|
||||
<p class="text-xs text-base-content/40 mb-4">Quand on regarde l'element dans sa machine</p>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-base-content/70">Debit max</span>
|
||||
<span>120 L/min</span>
|
||||
<span class="text-base-content/70">Diametre interieur</span>
|
||||
<span>50 mm</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-base-content/70">ATEX</span>
|
||||
<span>Oui</span>
|
||||
<span class="text-base-content/70">Type</span>
|
||||
<span>Roulement a billes</span>
|
||||
</div>
|
||||
<div class="border-t border-primary/20 pt-2 mt-2">
|
||||
<div class="flex justify-between bg-primary/10 rounded px-2 py-1.5">
|
||||
<span class="text-base-content font-medium">Position sur la machine</span>
|
||||
<span class="font-bold">Secteur B - Ligne 3</span>
|
||||
<span class="text-base-content font-medium">Emplacement</span>
|
||||
<span class="font-bold">Haut (palier de tete)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
106
migrations/Version20260506140000_FixComposantCascadeFKs.php
Normal file
106
migrations/Version20260506140000_FixComposantCascadeFKs.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20260506140000_FixComposantCascadeFKs extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add missing CASCADE FKs documents.composantid and machine_component_links.composantid; cleanup pre-existing orphan rows';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// 1. Trace des suppressions à venir dans audit_logs (actor = NULL = "system").
|
||||
// On copie un snapshot minimal avant DELETE pour cohérence avec les autres "delete".
|
||||
$this->addSql(<<<'SQL'
|
||||
INSERT INTO audit_logs (id, entitytype, entityid, action, snapshot, actorprofileid, createdat)
|
||||
SELECT
|
||||
'cl' || substring(md5(random()::text || clock_timestamp()::text), 1, 24),
|
||||
'document',
|
||||
d.id,
|
||||
'delete',
|
||||
json_build_object(
|
||||
'id', d.id,
|
||||
'name', d.name,
|
||||
'filename', d.filename,
|
||||
'composantId', d.composantid,
|
||||
'note', 'Cleaned by FK cascade fix migration (Version20260506140000) - referenced composant no longer existed'
|
||||
),
|
||||
NULL,
|
||||
NOW()
|
||||
FROM documents d
|
||||
WHERE d.composantid IS NOT NULL
|
||||
AND d.composantid NOT IN (SELECT id FROM composants)
|
||||
SQL);
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
INSERT INTO audit_logs (id, entitytype, entityid, action, snapshot, actorprofileid, createdat)
|
||||
SELECT
|
||||
'cl' || substring(md5(random()::text || clock_timestamp()::text), 1, 24),
|
||||
'machine_component_link',
|
||||
l.id,
|
||||
'delete',
|
||||
json_build_object(
|
||||
'id', l.id,
|
||||
'machineId', l.machineid,
|
||||
'composantId', l.composantid,
|
||||
'note', 'Cleaned by FK cascade fix migration (Version20260506140000) - referenced composant no longer existed'
|
||||
),
|
||||
NULL,
|
||||
NOW()
|
||||
FROM machine_component_links l
|
||||
WHERE l.composantid IS NOT NULL
|
||||
AND l.composantid NOT IN (SELECT id FROM composants)
|
||||
SQL);
|
||||
|
||||
// 2. Nettoyage des orphelins.
|
||||
$this->addSql(<<<'SQL'
|
||||
DELETE FROM documents
|
||||
WHERE composantid IS NOT NULL
|
||||
AND composantid NOT IN (SELECT id FROM composants)
|
||||
SQL);
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
DELETE FROM machine_component_links
|
||||
WHERE composantid IS NOT NULL
|
||||
AND composantid NOT IN (SELECT id FROM composants)
|
||||
SQL);
|
||||
|
||||
// 3. Ajout idempotent des 2 FK manquantes (alignement avec les entités Doctrine).
|
||||
$this->addSql(<<<'SQL'
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.table_constraints
|
||||
WHERE constraint_name = 'fk_documents_composant' AND table_name = 'documents'
|
||||
) THEN
|
||||
ALTER TABLE documents ADD CONSTRAINT fk_documents_composant
|
||||
FOREIGN KEY (composantid) REFERENCES composants(id) ON DELETE CASCADE;
|
||||
END IF;
|
||||
END $$;
|
||||
SQL);
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.table_constraints
|
||||
WHERE constraint_name = 'fk_mcl_composant' AND table_name = 'machine_component_links'
|
||||
) THEN
|
||||
ALTER TABLE machine_component_links ADD CONSTRAINT fk_mcl_composant
|
||||
FOREIGN KEY (composantid) REFERENCES composants(id) ON DELETE CASCADE;
|
||||
END IF;
|
||||
END $$;
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE documents DROP CONSTRAINT IF EXISTS fk_documents_composant');
|
||||
$this->addSql('ALTER TABLE machine_component_links DROP CONSTRAINT IF EXISTS fk_mcl_composant');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user