Skip to content

Commit 73cf774

Browse files
authored
✨ [Frontend] Feature: Saving pipeline (#8054)
1 parent a3781ad commit 73cf774

File tree

4 files changed

+76
-20
lines changed

4 files changed

+76
-20
lines changed

services/static-webserver/client/source/class/osparc/data/model/Study.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,13 @@ qx.Class.define("osparc.data.model.Study", {
249249
init: null,
250250
event: "changeTrashedBy",
251251
},
252+
253+
savePending: {
254+
check: "Boolean",
255+
nullable: true,
256+
event: "changeSavePending",
257+
init: false
258+
},
252259
// ------ ignore for serializing ------
253260
},
254261

@@ -259,6 +266,7 @@ qx.Class.define("osparc.data.model.Study", {
259266
"pipelineRunning",
260267
"readOnly",
261268
"trashedAt",
269+
"savePending",
262270
],
263271

264272
IgnoreModelizationProps: [

services/static-webserver/client/source/class/osparc/desktop/StudyEditor.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ qx.Class.define("osparc.desktop.StudyEditor", {
105105

106106
statics: {
107107
AUTO_SAVE_INTERVAL: 3000,
108+
DIFF_CHECK_INTERVAL: 300,
108109
READ_ONLY_TEXT: qx.locale.Manager.tr("You do not have writing permissions.<br>Your changes will not be saved."),
109110
},
110111

@@ -114,6 +115,7 @@ qx.Class.define("osparc.desktop.StudyEditor", {
114115
__workbenchView: null,
115116
__slideshowView: null,
116117
__autoSaveTimer: null,
118+
__savingTimer: null,
117119
__studyEditorIdlingTracker: null,
118120
__studyDataInBackend: null,
119121
__updatingStudy: null,
@@ -226,6 +228,7 @@ qx.Class.define("osparc.desktop.StudyEditor", {
226228

227229
if (osparc.data.model.Study.canIWrite(study.getAccessRights())) {
228230
this.__startAutoSaveTimer();
231+
this.__startSavingTimer();
229232
} else {
230233
const msg = this.self().READ_ONLY_TEXT;
231234
osparc.FlashMessenger.logAs(msg, "WARNING");
@@ -794,6 +797,7 @@ qx.Class.define("osparc.desktop.StudyEditor", {
794797
}, this);
795798
},
796799

800+
// ------------------ IDLING TRACKER ------------------
797801
__startIdlingTracker: function() {
798802
if (this.__studyEditorIdlingTracker) {
799803
this.__studyEditorIdlingTracker.stop();
@@ -810,7 +814,9 @@ qx.Class.define("osparc.desktop.StudyEditor", {
810814
this.__studyEditorIdlingTracker = null;
811815
}
812816
},
817+
// ------------------ IDLING TRACKER ------------------
813818

819+
// ------------------ AUTO SAVER ------------------
814820
__startAutoSaveTimer: function() {
815821
// Save every 3 seconds
816822
const timer = this.__autoSaveTimer = new qx.event.Timer(this.self().AUTO_SAVE_INTERVAL);
@@ -835,10 +841,32 @@ qx.Class.define("osparc.desktop.StudyEditor", {
835841
this.__autoSaveTimer.restart();
836842
}
837843
},
844+
// ------------------ AUTO SAVER ------------------
845+
846+
// ---------------- SAVING TIMER ------------------
847+
__startSavingTimer: function() {
848+
const timer = this.__savingTimer = new qx.event.Timer(this.self().DIFF_CHECK_INTERVAL);
849+
timer.addListener("interval", () => {
850+
if (!osparc.wrapper.WebSocket.getInstance().isConnected()) {
851+
return;
852+
}
853+
this.getStudy().setSavePending(this.didStudyChange());
854+
}, this);
855+
timer.start();
856+
},
857+
858+
__stopSavingTimer: function() {
859+
if (this.__savingTimer && this.__savingTimer.isEnabled()) {
860+
this.__savingTimer.stop();
861+
this.__savingTimer.setEnabled(false);
862+
}
863+
},
864+
// ---------------- SAVING TIMER ------------------
838865

839866
__stopTimers: function() {
840867
this.__stopIdlingTracker();
841868
this.__stopAutoSaveTimer();
869+
this.__stopSavingTimer();
842870
},
843871

844872
__getStudyDiffs: function() {
@@ -857,6 +885,7 @@ qx.Class.define("osparc.desktop.StudyEditor", {
857885
return studyDiffs;
858886
},
859887

888+
// didStudyChange takes around 0.5ms
860889
didStudyChange: function() {
861890
const studyDiffs = this.__getStudyDiffs();
862891
return Boolean(Object.keys(studyDiffs.delta).length);

services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ qx.Class.define("osparc.navigation.NavigationBar", {
112112
converter: s => s ? "visible" : "excluded"
113113
});
114114

115+
this.getChildControl("saving-study-icon");
116+
115117
// center-items
116118
this.getChildControl("read-only-info");
117119

@@ -202,6 +204,16 @@ qx.Class.define("osparc.navigation.NavigationBar", {
202204
control.addListener("openLogger", () => this.fireEvent("openLogger"));
203205
this.getChildControl("left-items").add(control);
204206
break;
207+
case "saving-study-icon":
208+
control = new qx.ui.basic.Atom().set({
209+
icon: "@FontAwesome5Solid/cloud-upload-alt/14",
210+
label: this.tr("Saving..."),
211+
font: "text-12",
212+
opacity: 0.8,
213+
visibility: "excluded",
214+
});
215+
this.getChildControl("left-items").add(control);
216+
break;
205217
case "read-only-info": {
206218
control = new qx.ui.basic.Atom().set({
207219
label: this.tr("Read only"),
@@ -337,13 +349,18 @@ qx.Class.define("osparc.navigation.NavigationBar", {
337349
},
338350

339351
__applyStudy: function(study) {
352+
const savingStudyIcon = this.getChildControl("saving-study-icon");
340353
const readOnlyInfo = this.getChildControl("read-only-info")
341354
if (study) {
342355
this.getChildControl("study-title-options").setStudy(study);
356+
study.bind("savePending", readOnlyInfo, "visibility", {
357+
converter: value => value && ["workbench", "pipeline"].includes(study.getUi().getMode()) ? "visible" : "excluded"
358+
});
343359
study.bind("readOnly", readOnlyInfo, "visibility", {
344360
converter: value => value ? "visible" : "excluded"
345361
});
346362
} else {
363+
savingStudyIcon.exclude();
347364
readOnlyInfo.exclude();
348365
}
349366
},

services/static-webserver/client/source/class/osparc/study/Conversations.js

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ qx.Class.define("osparc.study.Conversations", {
2727

2828
this._setLayout(new qx.ui.layout.VBox());
2929

30-
this.__conversations = [];
30+
this.__conversationsPages = [];
3131
this.__openConversationId = openConversationId;
3232

3333
this.set({
@@ -126,17 +126,17 @@ qx.Class.define("osparc.study.Conversations", {
126126
const eventHandler = message => {
127127
if (message) {
128128
const conversationId = message["conversationId"];
129-
const conversation = this.__getConversation(conversationId);
130-
if (conversation) {
129+
const conversationPage = this.__getConversationPage(conversationId);
130+
if (conversationPage) {
131131
switch (eventName) {
132132
case "conversation:message:created":
133-
conversation.addMessage(message);
133+
conversationPage.addMessage(message);
134134
break;
135135
case "conversation:message:updated":
136-
conversation.updateMessage(message);
136+
conversationPage.updateMessage(message);
137137
break;
138138
case "conversation:message:deleted":
139-
conversation.deleteMessage(message);
139+
conversationPage.deleteMessage(message);
140140
break;
141141
}
142142
}
@@ -147,8 +147,8 @@ qx.Class.define("osparc.study.Conversations", {
147147
});
148148
},
149149

150-
__getConversation: function(conversationId) {
151-
return this.__conversations.find(conversation => conversation.getConversationId() === conversationId);
150+
__getConversationPage: function(conversationId) {
151+
return this.__conversationsPages.find(conversation => conversation.getConversationId() === conversationId);
152152
},
153153

154154
__applyStudyData: function(studyData) {
@@ -206,15 +206,15 @@ qx.Class.define("osparc.study.Conversations", {
206206
__addConversationPage: function(conversationData) {
207207
// ignore it if it was already there
208208
const conversationId = conversationData["conversationId"];
209-
const conversation = this.__getConversation(conversationId);
210-
if (conversation) {
209+
const conversationPageFound = this.__getConversationPage(conversationId);
210+
if (conversationPageFound) {
211211
return null;
212212
}
213213

214214
const conversationPage = this.__createConversationPage(conversationData);
215215
this.__addToPages(conversationPage);
216216

217-
this.__conversations.push(conversationPage);
217+
this.__conversationsPages.push(conversationPage);
218218

219219
return conversationPage;
220220
},
@@ -234,10 +234,10 @@ qx.Class.define("osparc.study.Conversations", {
234234
enabled: osparc.data.model.Study.canIWrite(studyData["accessRights"]),
235235
});
236236
newConversationButton.addListener("execute", () => {
237-
osparc.store.Conversations.getInstance().addConversation(studyData["uuid"], "new " + (this.__conversations.length + 1))
237+
osparc.store.Conversations.getInstance().addConversation(studyData["uuid"], "new " + (this.__conversationsPages.length + 1))
238238
.then(conversationDt => {
239239
this.__addConversationPage(conversationDt);
240-
const newConversationPage = this.__getConversation(conversationDt["conversationId"]);
240+
const newConversationPage = this.__getConversationPage(conversationDt["conversationId"]);
241241
if (newConversationPage) {
242242
conversationsLayout.setSelection([newConversationPage]);
243243
}
@@ -251,11 +251,13 @@ qx.Class.define("osparc.study.Conversations", {
251251
},
252252

253253
__removeConversationPage: function(conversationId, changeSelection = false) {
254-
const conversation = this.__getConversation(conversationId);
255-
if (conversation) {
254+
const conversationPage = this.__getConversationPage(conversationId);
255+
if (conversationPage) {
256256
const conversationsLayout = this.getChildControl("conversations-layout");
257-
conversationsLayout.remove(conversation);
258-
this.__conversations = this.__conversations.filter(c => c !== conversation);
257+
if (conversationsLayout.indexOf(conversationPage) > -1) {
258+
conversationsLayout.remove(conversationPage);
259+
}
260+
this.__conversationsPages = this.__conversationsPages.filter(c => c !== conversationPage);
259261
const conversationPages = conversationsLayout.getSelectables();
260262
if (conversationPages.length) {
261263
if (changeSelection) {
@@ -272,9 +274,9 @@ qx.Class.define("osparc.study.Conversations", {
272274
// it can only be renamed, not updated
273275
__updateConversationName: function(conversationData) {
274276
const conversationId = conversationData["conversationId"];
275-
const conversation = this.__getConversation(conversationId);
276-
if (conversation) {
277-
conversation.renameConversation(conversationData["name"]);
277+
const conversationPage = this.__getConversationPage(conversationId);
278+
if (conversationPage) {
279+
conversationPage.renameConversation(conversationData["name"]);
278280
}
279281
},
280282

0 commit comments

Comments
 (0)