v5.5.0 Partage v2 : fenêtre Share rechargée, sidebar « Par moi »/« Avec moi », Library dir=made/received, badge 👥 + indicateurs
- Correctif : la fenêtre Share rechargait ses partages à chaque ouverture (before: liste vide après refresh) - Sidebar « Shared » scindée en sous-groupes « Par moi » (partages nominatifs + liens) et « Avec moi » (partages reçus), sans doublons - Bibliothèque : filtre « Tous / Par moi / Avec moi » sur l'onglet Shared ; /api/library/shared?dir=made|received|all + share_dir par élément - Document : bouton barre affiche « 👥 Shared ▾ » quand la page est partagée (membre, lien ou publiée), recalculé à la volée - Workspace local : emoji 👥 juste avant le nom des fichiers partagés (is_shared exposé par /api/local-workspace/tree) - Tests +6 (tests/test_sharing.py) : direction made/received/all, fallback dir invalide, rendu pageIsShared ; suite 325 verte (+3 PDF pré-existants)
This commit is contained in:
@@ -806,6 +806,7 @@
|
||||
activityOpen:false,pageCreated:'{{ page.get("created_at", "") }}',
|
||||
shareTab:'share',favorited:false,
|
||||
pagePublished:{{ page_published | tojson }},
|
||||
pageIsShared:{{ page_is_shared | tojson }},
|
||||
generalAccess:'{{ page_share_mode }}',publicPerm:'viewer',
|
||||
pubAllowEdit:false,pubAllowComments:true,
|
||||
pageUrl:window.location.href,publishedUrl:'',
|
||||
@@ -1062,7 +1063,7 @@ applyAIBlocks(text){
|
||||
else{this.activityOpen=false;}
|
||||
},
|
||||
toggleShareOpen(){
|
||||
if(!this.shareOpen){this.shareOpen=true;this._justOpened=true;setTimeout(()=>this._justOpened=false,200);}
|
||||
if(!this.shareOpen){this.shareOpen=true;this._justOpened=true;setTimeout(()=>this._justOpened=false,200);this.loadShares();}
|
||||
else{this.shareOpen=false;}
|
||||
},
|
||||
toggleMoreOpen(){
|
||||
@@ -1070,10 +1071,11 @@ applyAIBlocks(text){
|
||||
else{this.moreOpen=false;}
|
||||
},
|
||||
_justOpened:false,
|
||||
togglePublish(){this.pagePublished=!this.pagePublished;this.saveShare();},
|
||||
_syncIsShared(){this.pageIsShared=!!(this.pagePublished||this.generalAccess==='anyone'||(this.accessList||[]).length>0);},
|
||||
togglePublish(){this.pagePublished=!this.pagePublished;this._syncIsShared();this.saveShare();},
|
||||
saveShare(){
|
||||
const csrf=document.cookie.match(/csrf_token=([^;]+)/);
|
||||
fetch(`/board/api/share/${this.pid}`,{method:'POST',headers:{'Content-Type':'application/json','X-CSRF-Token':csrf?csrf[1]:''},body:JSON.stringify({mode:this.generalAccess,published:this.pagePublished})}).catch(()=>{});
|
||||
fetch(`/board/api/share/${this.pid}`,{method:'POST',headers:{'Content-Type':'application/json','X-CSRF-Token':csrf?csrf[1]:''},body:JSON.stringify({mode:this.generalAccess,published:this.pagePublished})}).then(()=>this._syncIsShared()).catch(()=>{});
|
||||
},
|
||||
async copyPageLink(){
|
||||
console.log('copyPageLink invoked');
|
||||
@@ -1203,7 +1205,8 @@ applyAIBlocks(text){
|
||||
var self = this;
|
||||
fetch('/api/pages/' + this.pid + '/shares').then(function(r){ return r.json(); }).then(function(d){
|
||||
self.accessList = d.shares || [];
|
||||
}).catch(function(){ self.accessList = []; });
|
||||
self._syncIsShared();
|
||||
}).catch(function(){ self.accessList = []; self._syncIsShared(); });
|
||||
},
|
||||
removeShare(sid) {
|
||||
var self = this;
|
||||
|
||||
+22
-8
@@ -393,14 +393,28 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section-items" x-show="sectionsOpen.shared" x-transition>
|
||||
<ul class="sidebar-items" data-section="shared">
|
||||
{% for page in shared_pages %}
|
||||
{{ render_tree_item(page) }}
|
||||
{% endfor %}
|
||||
{% if not shared_pages %}
|
||||
<li class="sidebar-item empty-hint"><span class="page-icon page-icon-svg">{{ fd_icon("users",16) }}</span><span class="page-name text-dim">No shared pages</span></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<div class="sidebar-subgroup">
|
||||
<div class="sidebar-subgroup-label">Par moi</div>
|
||||
<ul class="sidebar-items" data-section="shared-made">
|
||||
{% for page in shared_made_pages %}
|
||||
{{ render_tree_item(page) }}
|
||||
{% endfor %}
|
||||
{% if not shared_made_pages %}
|
||||
<li class="sidebar-item empty-hint"><span class="page-icon page-icon-svg">{{ fd_icon("link",16) }}</span><span class="page-name text-dim">Aucun partage par moi</span></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sidebar-subgroup">
|
||||
<div class="sidebar-subgroup-label">Avec moi</div>
|
||||
<ul class="sidebar-items" data-section="shared-received">
|
||||
{% for page in shared_received_pages %}
|
||||
{{ render_tree_item(page) }}
|
||||
{% endfor %}
|
||||
{% if not shared_received_pages %}
|
||||
<li class="sidebar-item empty-hint"><span class="page-icon page-icon-svg">{{ fd_icon("users",16) }}</span><span class="page-name text-dim">Aucun partage avec moi</span></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -88,6 +88,12 @@
|
||||
.row-title:hover{text-decoration:underline;}
|
||||
.row-title input{width:100%;font-size:13px;padding:2px 4px;background:var(--bg-primary);border:1px solid var(--accent);border-radius:4px;color:var(--text-primary);outline:none;}
|
||||
|
||||
/* ── Shared direction sub-filter pils ── */
|
||||
.lib-share-directory{display:flex;align-items:center;gap:6px;padding:4px 16px;}
|
||||
.lib-dir-pill{font-size:12px;padding:3px 10px;border-radius:999px;border:1px solid var(--border);background:transparent;color:var(--text-secondary);cursor:pointer;transition:background 0.15s,color 0.15s,border-color 0.15s;}
|
||||
.lib-dir-pill:hover{background:var(--bg-hover);color:var(--text-primary);}
|
||||
.lib-dir-pill.active{background:var(--accent);border-color:var(--accent);color:#fff;}
|
||||
|
||||
/* ── Hover-only elements (hidden until row hover, or when checked/dragging) ── */
|
||||
.hover-only{opacity:0;transition:opacity 0.12s;flex-shrink:0;}
|
||||
.lib-row:hover .hover-only,.lib-row.selected .hover-only{opacity:1;}
|
||||
@@ -247,7 +253,7 @@
|
||||
</button>
|
||||
<div class="lib-toolbar-wrap">
|
||||
<button class="lib-icon-btn" :class="{active: viewOpen}" title="View options" @click.stop="viewOpen=!viewOpen; filterOpen=false; sortOpen=false">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/><circle cx="9" cy="6" r="1.5" fill="currentColor" stroke="none"/><circle cx="15" cy="12" r="1.5" fill="currentColor" stroke="none"/><circle cx="9" cy="18" r="1.5" fill="currentColor" stroke="none"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/><circle cx="9" cy="6" r="1.5" fill="currentColor" stroke="none"/><circle cx="15" cy="12" r="1.5" fill="currentColor" stroke="none"/><circle cx="9" cy="18" r="1.5" fill="currentColor" stroke="none"/></svg>
|
||||
</button>
|
||||
<div class="lib-dropdown" x-show="viewOpen" @click.outside="viewOpen=false" x-transition>
|
||||
<div class="dd-label">Show columns</div>
|
||||
@@ -258,6 +264,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Shared direction sub-filter (Par moi / Avec moi) -->
|
||||
<div class="lib-share-directory" x-show="tab === 'shared'">
|
||||
<button class="lib-dir-pill" :class="{ active: shareDir === 'all' }" @click="setShareDir('all')">Tous</button>
|
||||
<button class="lib-dir-pill" :class="{ active: shareDir === 'made' }" @click="setShareDir('made')">Par moi</button>
|
||||
<button class="lib-dir-pill" :class="{ active: shareDir === 'received' }" @click="setShareDir('received')">Avec moi</button>
|
||||
</div>
|
||||
|
||||
<!-- Search bar (toggleable) -->
|
||||
<div class="lib-search-bar" x-show="searchOpen" x-transition>
|
||||
<input id="lib-search-input" type="text" placeholder="Search in this list..." x-model="searchQuery" @input="doSearch()">
|
||||
@@ -485,6 +498,7 @@ function libraryPage() {
|
||||
sortOpen: false,
|
||||
viewOpen: false,
|
||||
sourceFilter: 'all',
|
||||
shareDir: 'all',
|
||||
showAuthor: false,
|
||||
showSource: false,
|
||||
|
||||
@@ -837,6 +851,7 @@ function libraryPage() {
|
||||
if (this.tab === t) return;
|
||||
if (t === 'repository' && !this.isGiteaActive) return;
|
||||
this.tab = t;
|
||||
this.shareDir = 'all';
|
||||
this.items = [];
|
||||
this.selected = {};
|
||||
this.selectedCount = 0;
|
||||
@@ -875,6 +890,9 @@ function libraryPage() {
|
||||
} else if (this.tab !== 'repository' && this.tab !== 'workspace' && this.sourceFilter && this.sourceFilter !== 'all') {
|
||||
url += sep + 'source_type=' + encodeURIComponent(this.sourceFilter); sep = '&';
|
||||
}
|
||||
if (this.tab === 'shared' && this.shareDir && this.shareDir !== 'all') {
|
||||
url += sep + 'dir=' + encodeURIComponent(this.shareDir); sep = '&';
|
||||
}
|
||||
var r = await fetch(url);
|
||||
var d = await r.json();
|
||||
// Backend already computes has_children correctly for each item (children
|
||||
@@ -899,6 +917,12 @@ function libraryPage() {
|
||||
this.loadTab();
|
||||
},
|
||||
|
||||
setShareDir(v) {
|
||||
if (this.shareDir === v) return;
|
||||
this.shareDir = v;
|
||||
this.loadTab();
|
||||
},
|
||||
|
||||
setSort(field) {
|
||||
this.sortBy = field;
|
||||
this.sortOpen = false;
|
||||
|
||||
@@ -165,6 +165,7 @@
|
||||
.ws-tree-item .name.file{display:inline-flex;align-items:center;max-width:100%;overflow:hidden;}
|
||||
.ws-tree-item .name.file .inline-rename-input{flex:0 1 auto;}
|
||||
.ws-tree-item .name.file .btn-open{flex:0 0 auto;}
|
||||
.ws-shared-badge{flex-shrink:0;margin-right:4px;font-size:13px;line-height:1;opacity:.9;}
|
||||
.ws-tree-item .actions{display:none;gap:2px;}
|
||||
.ws-tree-item:hover .actions{display:flex;}
|
||||
.ws-chevron{width:16px;height:16px;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;background:none;border:none;color:var(--text-tertiary);cursor:pointer;font-size:8px;padding:0;border-radius:3px;transition:transform 150ms,color 100ms;}
|
||||
@@ -1210,6 +1211,7 @@ window._wsInitData = (function() {
|
||||
+ ' title="Click to rename, double-click to open"'
|
||||
+ ' onmouseenter="var d=window._wsData;if(d)d.showPreview(event,{id:'+escId+',name:\''+escName+'\',is_folder:false,content_format:\''+(c.content_format||'')+'\'})"'
|
||||
+ ' onmouseleave="var d=window._wsData;if(d)d.hidePreview()">'
|
||||
+ (c.is_shared ? '<span class="ws-shared-badge" title="Partag\u00e9" onclick="event.stopPropagation()">👥</span>' : '')
|
||||
+ '<span id="rc-name-'+escId+'">'+c.name+'</span>'
|
||||
+ '<input id="rc-input-'+escId+'" class="inline-rename-input" style="display:none"'
|
||||
+ ' onkeydown="if(event.key===\'Enter\')window._wsData.commitRenderChildRename('+escId+')"'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
page_title %}{{ page.title }}{% endblock %} {% block topbar %}
|
||||
{% set page_icon = "file" if page.content_format != 'file' else "paperclip" %}
|
||||
{% set page_title = page.title %}
|
||||
{% set right_actions = '<span class="topbar-edited" style="cursor:pointer;" @click="window.E && window.E.toggleActivityOpen()">Edited <span x-text="window.E && window.E.timeAgo || \'\'"></span> ▾</span><button class="topbar-btn" @click="window.E && window.E.toggleComments()" title="Comments"><span class="fd-comment-btn-ico">💬</span><span class="fd-comment-count" x-text="window.E && window.E.commentCount>0 ? window.E.commentCount : \'\'"></span></button><button class="topbar-btn share-btn" @click="window.E && window.E.toggleShareOpen()">' ~ fd_icon("lock",14) ~ ' Share ▾</button><button class="topbar-btn" @click="window.E && window.E.copyPageLink()" title="Copy link">' ~ fd_icon("link",14) ~ '</button><button class="topbar-btn star-btn" @click="window.E && window.E.toggleFavorite()" x-html="(window.E && window.E.favorited) ? getSvgIcon(\'star\',14) : getSvgIcon(\'star\',14)"></button><button class="topbar-btn relative" @click="window.E && window.E.toggleMoreOpen()">⋯</button>' %}
|
||||
{% set right_actions = '<span class="topbar-edited" style="cursor:pointer;" @click="window.E && window.E.toggleActivityOpen()">Edited <span x-text="window.E && window.E.timeAgo || \'\'"></span> ▾</span><button class="topbar-btn" @click="window.E && window.E.toggleComments()" title="Comments"><span class="fd-comment-btn-ico">💬</span><span class="fd-comment-count" x-text="window.E && window.E.commentCount>0 ? window.E.commentCount : \'\'"></span></button><button class="topbar-btn share-btn" @click="window.E && window.E.toggleShareOpen()"><span x-show="!window.E || !window.E.pageIsShared">' ~ fd_icon("lock",14) ~ ' Share ▾</span><span x-show="window.E && window.E.pageIsShared" title="This page is shared">👥 Shared ▾</span></button><button class="topbar-btn" @click="window.E && window.E.copyPageLink()" title="Copy link">' ~ fd_icon("link",14) ~ '</button><button class="topbar-btn star-btn" @click="window.E && window.E.toggleFavorite()" x-html="(window.E && window.E.favorited) ? getSvgIcon(\'star\',14) : getSvgIcon(\'star\',14)"></button><button class="topbar-btn relative" @click="window.E && window.E.toggleMoreOpen()">⋯</button>' %}
|
||||
{% include '_header.html' %}
|
||||
{% endblock %} {% block content %}
|
||||
{% include "_page_editor_content.html" %}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
page_title %}{{ page.title }}{% endblock %} {% block topbar %}
|
||||
{% set page_icon = "file" %}
|
||||
{% set page_title = page.title %}
|
||||
{% set right_actions = '<span class="topbar-edited" style="cursor:pointer;" @click="window.E && window.E.toggleActivityOpen()">Edited <span x-text="window.E && window.E.timeAgo || \'\'"></span> ▾</span><button class="topbar-btn share-btn" @click="window.E && window.E.toggleShareOpen()">' ~ fd_icon("lock",14) ~ ' Share ▾</button><button class="topbar-btn" @click="window.E && window.E.copyPageLink()" title="Copy link">' ~ fd_icon("link",14) ~ '</button><button class="topbar-btn star-btn" @click="window.E && window.E.toggleFavorite()" x-html="(window.E && window.E.favorited) ? getSvgIcon(\'star\',14) : getSvgIcon(\'star\',14)"></button><button class="topbar-btn relative" @click="window.E && window.E.toggleMoreOpen()">⋯</button>' %}
|
||||
{% set right_actions = '<span class="topbar-edited" style="cursor:pointer;" @click="window.E && window.E.toggleActivityOpen()">Edited <span x-text="window.E && window.E.timeAgo || \'\'"></span> ▾</span><button class="topbar-btn share-btn" @click="window.E && window.E.toggleShareOpen()"><span x-show="!window.E || !window.E.pageIsShared">' ~ fd_icon("lock",14) ~ ' Share ▾</span><span x-show="window.E && window.E.pageIsShared" title="This page is shared">👥 Shared ▾</span></button><button class="topbar-btn" @click="window.E && window.E.copyPageLink()" title="Copy link">' ~ fd_icon("link",14) ~ '</button><button class="topbar-btn star-btn" @click="window.E && window.E.toggleFavorite()" x-html="(window.E && window.E.favorited) ? getSvgIcon(\'star\',14) : getSvgIcon(\'star\',14)"></button><button class="topbar-btn relative" @click="window.E && window.E.toggleMoreOpen()">⋯</button>' %}
|
||||
{% include '_header.html' %}
|
||||
{% endblock %} {% block content %}
|
||||
{% include "_database_table.html" %}
|
||||
|
||||
Reference in New Issue
Block a user