Make dashlet edition / refresh better interact with listener and gridstack library in order to allow multiple edits without breaking

This commit is contained in:
Stephen Abello
2026-01-13 16:29:53 +01:00
parent cd6d130bcb
commit c075a5c145
2 changed files with 75 additions and 43 deletions

View File

@@ -88,11 +88,32 @@ class IboGrid extends HTMLElement {
RefreshDashlet (sDashlet, aOptions = {}) {
const oParser = new DOMParser();
const oDocument = oParser.parseFromString(sDashlet, 'text/html');
const oNewDashlet = oDocument.body.firstChild;
const oNewDashlet = oDocument.body.firstElementChild;
// Can't use oNewDashet.sDashletId as it's not in the DOM yet and connectedCallback hasn't been called yet
const oExistingDashlet = this.GetDashletElement(oNewDashlet.getAttribute('data-dashlet-id') );
oExistingDashlet.replaceWith(oNewDashlet);
// Copy attributes
for (const sAttr of oNewDashlet.attributes) {
oExistingDashlet.setAttribute(sAttr.name, sAttr.value);
}
// If we refresh a dashlet, its parent slot remains the same, we just need to update its content
let oSlotForExistingDashlet = null;
const aSlots = this.getSlots();
for (let oSlot of aSlots) {
if (oSlot.oDashlet && oSlot.oDashlet.sDashletId === oNewDashlet.getAttribute('data-dashlet-id')) {
oSlotForExistingDashlet = oSlot;
break;
}
}
// There must be a slot for the existing dashlet
if(oSlotForExistingDashlet !== null) {
this.oGrid.removeWidget(oSlotForExistingDashlet);
oSlotForExistingDashlet.innerHTML = oNewDashlet.outerHTML;
this.oGrid.makeWidget(oSlotForExistingDashlet);
}
}
CloneDashlet(sDashletId) {

View File

@@ -52,6 +52,10 @@ class IboDashboard extends HTMLElement {
// TODO 3.3: Implement cancel functionality (reload last saved state)
this.SetEditMode(false)
});
// Bind IboDashboard object to these listener so we can access current instance
this._ListenToDashletFormSubmission = this._ListenToDashletFormSubmission.bind(this);
this._ListenToDashletFormCancellation = this._ListenToDashletFormCancellation.bind(this);
}
SetupGrid() {
if(this.oGrid !== null){
@@ -96,19 +100,17 @@ class IboDashboard extends HTMLElement {
}
RefreshDashlet(sDashletId) {
const oDashletElem = this.oGrid.GetDashletElement(sDashletId);
let sGetDashletUrl = GetAbsoluteUrlAppRoot() + '/pages/UI.php?route=dashboard.get_dashlet&dashlet_class=' + encodeURIComponent(oDashletElem.sType)
+'&dashlet_id=' + encodeURIComponent(oDashletElem.sDashletId);
if(oDashletElem.formData.length > 0) {
sGetDashletUrl += '&values=' + encodeURIComponent(oDashletElem.formData);
RefreshDashlet(oDashlet) {
let sGetDashletUrl = GetAbsoluteUrlAppRoot() + '/pages/UI.php?route=dashboard.get_dashlet&dashlet_class=' + encodeURIComponent(oDashlet.sType)
+'&dashlet_id=' + encodeURIComponent(oDashlet.sDashletId);
if(oDashlet.formData.length > 0) {
sGetDashletUrl += '&values=' + encodeURIComponent(oDashlet.formData);
}
return fetch(sGetDashletUrl)
.then(async data => {
const sDashletId = this.oGrid.RefreshDashlet(await data.text());
this.oGrid.RefreshDashlet(await data.text());
});
}
@@ -135,11 +137,9 @@ class IboDashboard extends HTMLElement {
}
EditDashlet(sDashletId) {
console.log(this.oGrid);
const oDashlet = this.oGrid.GetDashletElement(sDashletId);
const me = this;
// TODO 3.3: Implement dashlet editing when forms are ready
console.log("Edit dashlet: "+sDashletId);
// Create backdrop to block interactions with other dashlets
if(this.oGrid.querySelector('.ibo-dashboard--grid--backdrop') === null) {
@@ -165,40 +165,52 @@ class IboDashboard extends HTMLElement {
this.HideDashletTogglers();
this.SetDashletForm(sFormData);
// Listen to form submission event to display
document.addEventListener('itop:TurboStreamEvent', function (event) {
console.log(event);
if(event.detail.id === oDashlet.sType + '-turbo-stream-event' && event.detail.valid === "1") {
// Notify it all went well
CombodoToast.OpenToast('Dashlet created/updated');
// Clean edit mode
me.querySelector('ibo-dashlet[data-dashlet-id="'+sDashletId+'"]').setAttribute('data-edit-mode', 'view');
me.ShowDashletTogglers();
me.ClearDashletForm();
// Update local dashlet and refresh it
oDashlet.formData = event.detail.view_data;
me.RefreshDashlet(oDashlet.sDashletId);
// TODO 3.3 Remove both event listener by making this code a dedicated function and call removeEventListener on it
}
});
document.querySelector('.ibo-dashlet-panel--form-container button[name="dashboard_cancel"]').addEventListener('click', function (event) {
// TODO 3.3 Remove both event listener by making this code a dedicated function and call removeEventListener on it
// Clean edit mode
me.querySelector('ibo-dashlet[data-dashlet-id="'+sDashletId+'"]').setAttribute('data-edit-mode', 'view');
me.ShowDashletTogglers();
me.ClearDashletForm();
// TODO 3.3 If this is an addition, remove the previewed dashlet
// TODO 3.3 If this is an edition, revert the dashlet to its initial state
})
// Listen to form submission event and cancellation
document.addEventListener('itop:TurboStreamEvent', me._ListenToDashletFormSubmission);
document.querySelector('.ibo-dashlet-panel--form-container button[name="dashboard_cancel"]').addEventListener('click', me._ListenToDashletFormCancellation);
});
}
_ListenToDashletFormSubmission(event) {
const oDashlet = this.querySelector('ibo-dashlet[data-edit-mode="edit"]');
const sDashletId = oDashlet.GetDashletId();
if(event.detail.id === oDashlet.sType + '-turbo-stream-event' && event.detail.valid === "1") {
// Remove events
document.addEventListener('itop:TurboStreamEvent', this._ListenToDashletFormSubmission);
document.querySelector('.ibo-dashlet-panel--form-container button[name="dashboard_cancel"]').removeEventListener('click', this._ListenToDashletFormCancellation);
// Notify it all went well
CombodoToast.OpenToast('Dashlet created/updated', 'success');
// Clean edit mode
this.querySelector('ibo-dashlet[data-dashlet-id="'+sDashletId+'"]').setAttribute('data-edit-mode', 'view');
this.ShowDashletTogglers();
this.ClearDashletForm();
// Update local dashlet and refresh it
oDashlet.formData = event.detail.view_data;
this.RefreshDashlet(oDashlet);
}
}
_ListenToDashletFormCancellation(event) {
const oDashlet = this.querySelector('ibo-dashlet[data-edit-mode="edit"]');
const sDashletId = oDashlet.GetDashletId();
// Remove events
document.addEventListener('itop:TurboStreamEvent', this._ListenToDashletFormSubmission);
document.querySelector('.ibo-dashlet-panel--form-container button[name="dashboard_cancel"]').removeEventListener('click', this._ListenToDashletFormCancellation);
// Clean edit mode
this.querySelector('ibo-dashlet[data-dashlet-id="'+sDashletId+'"]').setAttribute('data-edit-mode', 'view');
this.ShowDashletTogglers();
this.ClearDashletForm();
// TODO 3.3 If this is an addition, remove the previewed dashlet
// TODO 3.3 If this is an edition, revert the dashlet to its initial state
}
CloneDashlet(sDashletId) {
this.oGrid.CloneDashlet(sDashletId);
}
@@ -226,7 +238,6 @@ class IboDashboard extends HTMLElement {
const aPayload = this.Serialize();
// TODO 3.3: Implement saving dashboard state to server when backend is ready
// May try to save as serialized PHP if XML format is not yet decided
console.log(aPayload);
// Fetch dashlet form from server
let sSaveUrl = GetAbsoluteUrlAppRoot() + '/pages/UI.php?route=dashboard.save&values='+encodeURIComponent(JSON.stringify(aPayload));
fetch(sSaveUrl)