feat: éditeur visuel d'automations (pipeline steps) + fix CSP multi-instructions (v7.45.0)
Added — Settings → Automations, pipeline visuel (API steps v7.0) :
- Cartes ordinees (trigger/condition/delay/action) : resume + edition
TYPÉE par kind/type (datalist evenements, 7 ops, 8 types d'action avec
leurs champs reels), ajout/edition/suppression/haut-bas via
POST/PUT/DELETE /workspace/automations[/steps]/...
- ✨ Convertir le JSON en pipeline (legacy → steps ordonnes) ; textareas
JSON masques des qu'un step existe.
- Gate E2E « editeur visuel de steps » : creation → edition → ajout →
carte « Action · webhook » sous CSP reel.
Fixed (trouve par le gate) — 51 expressions Alpine MULTI-INSTRUCTIONS
(`a=1; b()`) = interdites par le parseur CSP (une seule expression par
directive ; ';' = token inattendu) — INVISIBLE pour le scan par tokens :
- Conversion en methodes dans 11 fichiers : nav settings x8 (navTo),
menu section base x7 (closeAndSetCount/Move/...), parts+editeur x13
(setSharePerm, more*, markAndSave...), breadcrumb x5 (hover*/goClose),
library/local x6 (menus popup), board x3 (pickStatus/...), ctx-menu x2
(addTagAndClear), agent/card/gitea/workspaces x6.
- Scanner dedie scan_semi (inventaire ';' hors chaines) ajoute au lot.
Verifs : 39 templates Jinja parse OK · scan expressions = 0 incompatible
(4 faux positifs en chaines) · **E2E 8/8** · suite **1094/1094** ·
ruff OK · docs a jour
This commit is contained in:
@@ -145,6 +145,41 @@ test('A20-ph3 : éditeur de page (right_actions) sous build CSP', async ({ page
|
||||
}
|
||||
});
|
||||
|
||||
test('UI : éditeur visuel de steps automations (API v7.0)', async ({ page }) => {
|
||||
// crée une automation, ouvre l'édition, ajoute une étape (POST /steps),
|
||||
// vérifie la carte résumée — sous CSP réel (expressions du nouveau bloc)
|
||||
await login(page);
|
||||
await page.goto(`${FD_BASE}/settings`, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForTimeout(500);
|
||||
await page.click('.settings-nav-item:has-text("Automations")');
|
||||
const name = 'e2e-steps-' + Date.now();
|
||||
await page.fill('input[placeholder*="Notifier le statut"]', name);
|
||||
await page.click('button:has-text("Créer")');
|
||||
await page.waitForTimeout(700);
|
||||
const row = page.locator('.setting-row', { hasText: name }).last();
|
||||
await row.locator('button:has-text("✎")').click();
|
||||
await page.waitForTimeout(700);
|
||||
await expect(page.locator('text=Pipeline visuel (steps)')).toBeVisible();
|
||||
await page.click('button:has-text("Ajouter l\'étape")');
|
||||
await page.waitForFunction(
|
||||
() => Array.from(document.querySelectorAll('.setting-label'))
|
||||
.some((e) => (e.textContent || '').includes('Action · webhook')),
|
||||
null,
|
||||
{ timeout: 8000 }
|
||||
);
|
||||
// nettoyage API
|
||||
await page.evaluate(async (n) => {
|
||||
const d = await (await fetch('/workspace/automations')).json();
|
||||
const a = (d.automations || []).find((x) => x.name === n);
|
||||
if (a) {
|
||||
const csrf = (document.cookie.match(/csrf_token=([^;]+)/) || [])[1] || '';
|
||||
await fetch('/workspace/automations/' + a.id,
|
||||
{ method: 'DELETE', headers: { 'X-CSRF-Token': csrf } });
|
||||
await fetch('/workspace/automations/' + a.id + '/steps', { method: 'DELETE' }).catch(() => {});
|
||||
}
|
||||
}, name);
|
||||
});
|
||||
|
||||
test('A20-ph3 : settings sous build Alpine CSP', async ({ page }) => {
|
||||
await login(page);
|
||||
await page.goto(`${FD_BASE}/settings`, { waitUntil: 'domcontentloaded' });
|
||||
|
||||
Reference in New Issue
Block a user