v5.4.1 Partage : correctif permissions + autocomplete membres (inclut v5.4.0 Interactions de bloc)
FlowDeck CI / test (push) Failing after 18s
FlowDeck CI / docker (push) Skipped

- Fix "Invalid permission" : le client envoyait editor/commenter/viewer alors que
  l'API attend view/comment/edit (invitePermission -> 'edit', menu participants aligné)
- PUT /api/pages/{page_id}/share/{share_id} : mise à jour de permission persistée
- Autocomplete des membres existants dans le champ d'invitation (search users + debounce,
  navigation clavier, envoi user_id pour lier le partage au compte)
- Upsert anti-doublon dans le partage + trim email backend
- 12 tests tests/test_sharing.py ; suite 319 verte (+3 PDF pre-existants)

Sans oublier v5.4.0 (non publie jusque-la) :
- Undo/Redo (Ctrl+Z/Ctrl+Shift+Z/Ctrl+Y), duplicate (Ctrl+D), menu de bloc (turn
  into, couleurs, lien #fdblk-, move to, delete), drag&drop multi-selection,
  slash "Actions", en-tetes de tableau (has_header/first_col_header) + exports,
  sync realtime immédiat apres mutation ; 9 tests test_block_interactions.py
This commit is contained in:
2026-09-08 09:34:41 -04:00
parent f84ff201ea
commit b3c90efa73
12 changed files with 1055 additions and 119 deletions
+66 -18
View File
@@ -33,17 +33,65 @@
<!-- ═══════ SHARE TAB ═══════ -->
<div class="sd-body" x-show="shareTab === 'share'" x-transition>
<!-- Invite input -->
<div class="sd-invite-row">
<input
type="email"
class="sd-input"
placeholder="Add people, groups or emails..."
x-model="inviteEmail"
@keydown.enter="shareInvite()"
/>
<button class="sd-btn-primary" @click="shareInvite()">
Invite
</button>
<div class="sd-invite-wrap">
<div class="sd-invite-row">
<input
type="text"
class="sd-input"
x-ref="inviteInput"
placeholder="Add people, emails or type a name..."
x-model="inviteEmail"
@input="inviteInput()"
@focus="inviteInput()"
@keydown.enter.prevent="inviteEnter()"
@keydown.down.prevent="inviteMove(1)"
@keydown.up.prevent="inviteMove(-1)"
@keydown.escape="inviteSuggestOpen = false; inviteUsers = []"
autocomplete="off"
/>
<button class="sd-btn-primary" @click="shareInvite()">
Invite
</button>
</div>
<!-- Existing users autocomplete -->
<div
class="sd-user-suggest"
x-ref="inviteSuggest"
x-show="inviteSuggestOpen"
@click.outside="inviteSuggestOpen = false"
x-transition.opacity
>
<template x-for="(u, i) in inviteUsers" :key="u.id">
<div
class="sd-user-item"
:class="{ active: inviteSel === i }"
@mouseenter="inviteSel = i"
@click="pickInviteUser(u)"
>
<div
class="sd-user-avatar"
:style="{ background: u.avatar_color || '#3A3A3A' }"
>
<img
x-show="u.avatar_url"
:src="u.avatar_url"
:alt="u.login"
style="width:100%;height:100%;border-radius:50%;object-fit:cover;"
/>
<span
x-show="!u.avatar_url"
x-text="((u.full_name || u.login || '?').charAt(0).toUpperCase())"
></span>
</div>
<div class="sd-user-meta">
<div class="sd-user-login" x-text="u.login"></div>
<div class="sd-user-name" x-text="u.full_name"></div>
</div>
<div class="sd-user-add">Invite</div>
</div>
</template>
<div class="sd-user-empty" x-show="!inviteUsers.length">No matching users</div>
</div>
</div>
<!-- Context card (shown when independent permissions) -->
@@ -78,7 +126,7 @@
@click="a.permOpen = !a.permOpen"
>
<span
x-text="a.permission === 'editor' ? 'Full access' : a.permission === 'commenter' ? 'Can comment' : 'Can view'"
x-text="a.permission === 'edit' ? 'Full access' : a.permission === 'comment' ? 'Can comment' : 'Can view'"
></span>
▾
</button>
@@ -89,8 +137,8 @@
>
<div
class="sd-perm-option"
:class="{ active: a.permission === 'editor' }"
@click="a.permission='editor'; a.permOpen=false"
:class="{ active: a.permission === 'edit' }"
@click="updateShare(a.id, 'edit'); a.permOpen=false"
>
<span>Can edit</span>
<span class="sd-perm-desc"
@@ -99,8 +147,8 @@
</div>
<div
class="sd-perm-option"
:class="{ active: a.permission === 'commenter' }"
@click="a.permission='commenter'; a.permOpen=false"
:class="{ active: a.permission === 'comment' }"
@click="updateShare(a.id, 'comment'); a.permOpen=false"
>
<span>Can comment</span>
<span class="sd-perm-desc"
@@ -109,8 +157,8 @@
</div>
<div
class="sd-perm-option"
:class="{ active: a.permission === 'viewer' }"
@click="a.permission='viewer'; a.permOpen=false"
:class="{ active: a.permission === 'view' }"
@click="updateShare(a.id, 'view'); a.permOpen=false"
>
<span>Can view</span>
<span class="sd-perm-desc"