feat(v4.0): wire Share/Publish modal with real API calls
FlowDeck CI / test (push) Failing after 4s
FlowDeck CI / docker (push) Has been skipped

- publishPage() → POST /api/pages/{id}/publish
- unpublishPage() → DELETE /api/pages/{id}/publish
- shareInvite() → POST /api/pages/{id}/share
- loadShares() → GET /api/pages/{id}/shares
- removeShare() → DELETE /api/pages/{id}/share/{sid}
- All buttons now call real API instead of local state toggle
This commit is contained in:
2026-07-14 12:23:05 -04:00
parent 15bd9d5ed9
commit 724ff4c880
+56 -4
View File
@@ -75,9 +75,9 @@ page_title %}{{ page.title }}{% endblock %} {% block topbar %}
class="sd-input"
placeholder="Add people, groups or emails..."
x-model="inviteEmail"
@keydown.enter="invitePerson"
@keydown.enter="shareInvite()"
/>
<button class="sd-btn-primary" @click="invitePerson">
<button class="sd-btn-primary" @click="shareInvite()">
Invite
</button>
</div>
@@ -268,7 +268,7 @@ page_title %}{{ page.title }}{% endblock %} {% block topbar %}
</p>
<button
class="sd-btn-primary sd-btn-full"
@click="pagePublished = true"
@click="publishPage()"
>
Publish
</button>
@@ -354,7 +354,7 @@ page_title %}{{ page.title }}{% endblock %} {% block topbar %}
<button
class="sd-danger-btn"
@click="pagePublished = false"
@click="unpublishPage()"
>
Unpublish
</button>
@@ -657,6 +657,58 @@ page_title %}{{ page.title }}{% endblock %} {% block topbar %}
clearTimeout(this._toastTimer);
this._toastTimer = setTimeout(() => { this.toastVisible = false; }, 2500);
},
publishPage() {
var self = this;
var csrf = document.cookie.match(/csrf_token=([^;]+)/);
fetch('/api/pages/' + this.pid + '/publish', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrf ? csrf[1] : '' }
}).then(function(r){ return r.json(); }).then(function(d){
if (d.status === 'ok') { self.pagePublished = true; self.publishedUrl = d.url || self.publishedUrl; self.showToast('Published to web'); }
else { self.showToast(d.detail || 'Publish failed'); }
}).catch(function(){ self.showToast('Publish failed'); });
},
unpublishPage() {
var self = this;
var csrf = document.cookie.match(/csrf_token=([^;]+)/);
fetch('/api/pages/' + this.pid + '/publish', {
method: 'DELETE',
headers: { 'X-CSRF-Token': csrf ? csrf[1] : '' }
}).then(function(r){ return r.json(); }).then(function(d){
if (d.status === 'ok') { self.pagePublished = false; self.publishedUrl = ''; self.showToast('Unpublished'); }
else { self.showToast(d.detail || 'Unpublish failed'); }
}).catch(function(){ self.showToast('Unpublish failed'); });
},
shareInvite() {
var self = this;
if (!this.inviteEmail.trim()) return;
var csrf = document.cookie.match(/csrf_token=([^;]+)/);
fetch('/api/pages/' + this.pid + '/share', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrf ? csrf[1] : '' },
body: JSON.stringify({ email: this.inviteEmail.trim(), permission: this.invitePermission })
}).then(function(r){ return r.json(); }).then(function(d){
if (d.status === 'ok') { self.inviteEmail = ''; self.showToast('Invitation sent'); self.loadShares(); }
else { self.showToast(d.detail || 'Share failed'); }
}).catch(function(){ self.showToast('Share failed'); });
},
loadShares() {
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 = []; });
},
removeShare(sid) {
var self = this;
var csrf = document.cookie.match(/csrf_token=([^;]+)/);
fetch('/api/pages/' + this.pid + '/share/' + sid, {
method: 'DELETE',
headers: { 'X-CSRF-Token': csrf ? csrf[1] : '' }
}).then(function(r){ return r.json(); }).then(function(d){
if (d.status === 'ok') { self.showToast('Share removed'); self.loadShares(); }
else { self.showToast(d.detail || 'Remove failed'); }
}).catch(function(){ self.showToast('Remove failed'); });
},
invitePerson(){if(!this.inviteEmail.trim())return;this.accessList.push({email:this.inviteEmail,permission:this.invitePermission,permOpen:false});this.inviteEmail='';},
removeAccess(email){this.accessList=this.accessList.filter(a=>a.email!==email);},
exportPage(){this.moreOpen=false;},