Skip to content

Commit 21561a6

Browse files
authored
✨ [Frontend] Feature: Pay study's debt (#7061)
1 parent c435616 commit 21561a6

File tree

17 files changed

+511
-175
lines changed

17 files changed

+511
-175
lines changed

services/static-webserver/client/source/class/osparc/dashboard/CardBase.js

Lines changed: 77 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ qx.Class.define("osparc.dashboard.CardBase", {
320320

321321
trashedAt: {
322322
check: "Date",
323-
apply: "_applyTrasehdAt",
323+
apply: "_applyTrashedAt",
324324
nullable: true
325325
},
326326

@@ -385,15 +385,15 @@ qx.Class.define("osparc.dashboard.CardBase", {
385385
apply: "__applyState"
386386
},
387387

388-
projectState: {
389-
check: ["NOT_STARTED", "STARTED", "SUCCESS", "FAILED", "UNKNOWN"],
390-
nullable: false,
391-
init: "UNKNOWN",
392-
apply: "_applyProjectState"
388+
debt: {
389+
check: "Number",
390+
nullable: true,
391+
init: 0,
392+
apply: "__applyDebt"
393393
},
394394

395395
blocked: {
396-
check: [true, "UNKNOWN_SERVICES", "IN_USE", false],
396+
check: [true, "UNKNOWN_SERVICES", "IN_USE", "IN_DEBT", false],
397397
init: false,
398398
nullable: false,
399399
apply: "__applyBlocked"
@@ -547,7 +547,7 @@ qx.Class.define("osparc.dashboard.CardBase", {
547547
throw new Error("Abstract method called!");
548548
},
549549

550-
_applyTrasehdAt: function(value, old) {
550+
_applyTrashedAt: function(value, old) {
551551
throw new Error("Abstract method called!");
552552
},
553553

@@ -633,7 +633,7 @@ qx.Class.define("osparc.dashboard.CardBase", {
633633
const unaccessibleServices = osparc.study.Utils.getInaccessibleServices(workbench)
634634
if (unaccessibleServices.length) {
635635
this.setBlocked("UNKNOWN_SERVICES");
636-
const image = "@FontAwesome5Solid/ban/";
636+
let image = "@FontAwesome5Solid/ban/";
637637
let toolTipText = this.tr("Service info missing");
638638
unaccessibleServices.forEach(unSrv => {
639639
toolTipText += "<br>" + unSrv.key + ":" + unSrv.version;
@@ -681,65 +681,75 @@ qx.Class.define("osparc.dashboard.CardBase", {
681681
},
682682

683683
__applyState: function(state) {
684-
const locked = ("locked" in state) ? state["locked"]["value"] : false;
685-
this.setBlocked(locked ? "IN_USE" : false);
686-
if (locked) {
687-
this.__showBlockedCardFromStatus(state["locked"]);
684+
let lockInUse = false;
685+
if ("locked" in state && "value" in state["locked"]) {
686+
lockInUse = state["locked"]["value"];
687+
}
688+
this.setBlocked(lockInUse ? "IN_USE" : false);
689+
if (lockInUse) {
690+
this.__showBlockedCardFromStatus("IN_USE", state["locked"]);
688691
}
689692

690-
const projectState = ("state" in state) ? state["state"]["value"] : undefined;
691-
if (projectState) {
692-
this._applyProjectState(state["state"]);
693+
const pipelineState = ("state" in state) ? state["state"]["value"] : undefined;
694+
if (pipelineState) {
695+
this.__applyPipelineState(state["state"]["value"]);
693696
}
694697
},
695698

696-
_applyProjectState: function(projectStatus) {
697-
const status = projectStatus["value"];
698-
let icon;
699-
let toolTip;
700-
let border;
701-
switch (status) {
699+
__applyDebt: function(debt) {
700+
this.setBlocked(debt ? "IN_DEBT" : false);
701+
if (debt) {
702+
this.__showBlockedCardFromStatus("IN_DEBT", debt);
703+
}
704+
},
705+
706+
// pipelineState: ["NOT_STARTED", "STARTED", "SUCCESS", "ABORTED", "FAILED", "UNKNOWN"]
707+
__applyPipelineState: function(pipelineState) {
708+
let iconSource;
709+
let toolTipText;
710+
let borderColor;
711+
switch (pipelineState) {
702712
case "STARTED":
703-
icon = "@FontAwesome5Solid/spinner/10";
704-
toolTip = this.tr("Running");
705-
border = "info";
713+
iconSource = "@FontAwesome5Solid/spinner/10";
714+
toolTipText = this.tr("Running");
715+
borderColor = "info";
706716
break;
707717
case "SUCCESS":
708-
icon = "@FontAwesome5Solid/check/10";
709-
toolTip = this.tr("Ran successfully");
710-
border = "success";
718+
iconSource = "@FontAwesome5Solid/check/10";
719+
toolTipText = this.tr("Ran successfully");
720+
borderColor = "success";
711721
break;
712722
case "ABORTED":
713-
icon = "@FontAwesome5Solid/exclamation/10";
714-
toolTip = this.tr("Run aborted");
715-
border = "warning";
723+
iconSource = "@FontAwesome5Solid/exclamation/10";
724+
toolTipText = this.tr("Run aborted");
725+
borderColor = "warning";
716726
break;
717727
case "FAILED":
718-
icon = "@FontAwesome5Solid/exclamation/10";
719-
toolTip = this.tr("Ran with error");
720-
border = "error";
728+
iconSource = "@FontAwesome5Solid/exclamation/10";
729+
toolTipText = this.tr("Ran with error");
730+
borderColor = "error";
721731
break;
732+
case "UNKNOWN":
733+
case "NOT_STARTED":
722734
default:
723-
icon = null;
724-
toolTip = null;
725-
border = null;
735+
iconSource = null;
736+
toolTipText = null;
737+
borderColor = null;
726738
break;
727739
}
728-
this.__applyProjectLabel(icon, toolTip, border);
729-
},
730740

731-
__applyProjectLabel: function(icn, toolTipText, bdr) {
732741
const border = new qx.ui.decoration.Decorator().set({
733742
radius: 10,
734743
width: 1,
735744
style: "solid",
736-
color: bdr,
737-
backgroundColor: bdr ? bdr + "-bg" : null
745+
color: borderColor,
746+
backgroundColor: borderColor ? borderColor + "-bg" : null
738747
});
748+
739749
const projectStatusLabel = this.getChildControl("project-status");
740750
projectStatusLabel.set({
741751
decorator: border,
742-
textColor: bdr,
752+
textColor: borderColor,
743753
alignX: "center",
744754
alignY: "middle",
745755
height: 17,
@@ -748,14 +758,25 @@ qx.Class.define("osparc.dashboard.CardBase", {
748758
});
749759

750760
projectStatusLabel.set({
751-
visibility: icn && toolTipText && bdr ? "visible" : "excluded",
752-
source: icn,
753-
toolTipIcon: icn,
761+
visibility: iconSource && toolTipText && borderColor ? "visible" : "excluded",
762+
source: iconSource,
763+
toolTipIcon: iconSource,
754764
toolTipText
755765
});
756766
},
757767

758-
__showBlockedCardFromStatus: function(lockedStatus) {
768+
__showBlockedCardFromStatus: function(reason, moreInfo) {
769+
switch (reason) {
770+
case "IN_USE":
771+
this.__blockedInUse(moreInfo);
772+
break;
773+
case "IN_DEBT":
774+
this.__blockedInDebt(moreInfo);
775+
break;
776+
}
777+
},
778+
779+
__blockedInUse: function(lockedStatus) {
759780
const status = lockedStatus["status"];
760781
const owner = lockedStatus["owner"];
761782
let toolTip = osparc.utils.Utils.firstsUp(owner["first_name"] || this.tr("A user"), owner["last_name"] || ""); // it will be replaced by "userName"
@@ -788,14 +809,23 @@ qx.Class.define("osparc.dashboard.CardBase", {
788809
this.__showBlockedCard(image, toolTip);
789810
},
790811

812+
__blockedInDebt: function() {
813+
const studyAlias = osparc.product.Utils.getStudyAlias({firstUpperCase: true});
814+
const toolTip = studyAlias + " " + this.tr("Embargoed<br>Credits Required");
815+
const image = "@FontAwesome5Solid/lock/";
816+
this.__showBlockedCard(image, toolTip);
817+
},
818+
791819
__showBlockedCard: function(lockImageSrc, toolTipText) {
792820
this.getChildControl("lock-status").set({
793821
opacity: 1.0,
794822
visibility: "visible"
795823
});
824+
796825
const lockImage = this.getChildControl("lock-status").getChildControl("image");
797826
lockImageSrc += this.classname.includes("Grid") ? "32" : "22";
798827
lockImage.setSource(lockImageSrc);
828+
799829
if (toolTipText) {
800830
this.set({
801831
toolTipText

services/static-webserver/client/source/class/osparc/dashboard/GridButtonItem.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ qx.Class.define("osparc.dashboard.GridButtonItem", {
188188
},
189189

190190
// overridden
191-
_applyTrasehdAt: function(value) {
191+
_applyTrashedAt: function(value) {
192192
if (value && value.getTime() !== new Date(0).getTime()) {
193193
if (this.isResourceType("study") || this.isResourceType("template")) {
194194
const dateBy = this.getChildControl("date-by");

services/static-webserver/client/source/class/osparc/dashboard/ListButtonItem.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ qx.Class.define("osparc.dashboard.ListButtonItem", {
204204
},
205205

206206
// overridden
207-
_applyTrasehdAt: function(value) {
207+
_applyTrashedAt: function(value) {
208208
if (value && value.getTime() !== new Date(0).getTime()) {
209209
if (this.isResourceType("study") || this.isResourceType("template")) {
210210
const dateBy = this.getChildControl("date-by");

services/static-webserver/client/source/class/osparc/dashboard/ResourceDetails.js

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
6767
height: this.HEIGHT,
6868
});
6969
return win;
70+
},
71+
72+
createToolbar: function() {
73+
const toolbar = new qx.ui.container.Composite(new qx.ui.layout.HBox(20).set({
74+
alignX: "right",
75+
alignY: "top"
76+
})).set({
77+
maxHeight: 40
78+
});
79+
return toolbar;
7080
}
7181
},
7282

@@ -90,32 +100,36 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
90100
__billingSettings: null,
91101
__classifiersPage: null,
92102
__qualityPage: null,
93-
__openButton: null,
94-
95-
__createToolbar: function() {
96-
const toolbar = new qx.ui.container.Composite(new qx.ui.layout.HBox(20).set({
97-
alignX: "right",
98-
alignY: "top"
99-
})).set({
100-
maxHeight: 40
101-
});
102-
return toolbar;
103-
},
104103

105104
__addOpenButton: function(page) {
106105
const resourceData = this.__resourceData;
107106

108-
const toolbar = this.__createToolbar();
107+
const toolbar = this.self().createToolbar();
109108
page.addToHeader(toolbar);
110109

110+
if (this.__resourceData["resourceType"] === "study") {
111+
const payDebtButton = new qx.ui.form.Button(this.tr("Credits required"));
112+
page.payDebtButton = payDebtButton;
113+
osparc.dashboard.resources.pages.BasePage.decorateHeaderButton(payDebtButton);
114+
payDebtButton.addListener("execute", () => this.openBillingSettings());
115+
if (this.__resourceData["resourceType"] === "study") {
116+
const studyData = this.__resourceData;
117+
payDebtButton.set({
118+
visibility: osparc.study.Utils.isInDebt(studyData) ? "visible" : "excluded"
119+
});
120+
}
121+
toolbar.add(payDebtButton);
122+
}
123+
111124
if (osparc.utils.Resources.isService(resourceData)) {
112125
const serviceVersionSelector = this.__createServiceVersionSelector();
113126
toolbar.add(serviceVersionSelector);
114127
}
115128

116-
const openButton = this.__openButton = new osparc.ui.form.FetchButton(this.tr("Open")).set({
129+
const openButton = new osparc.ui.form.FetchButton(this.tr("Open")).set({
117130
enabled: true
118131
});
132+
page.openButton = openButton;
119133
osparc.dashboard.resources.pages.BasePage.decorateHeaderButton(openButton);
120134
osparc.utils.Utils.setIdToWidget(openButton, "openResource");
121135
const store = osparc.store.Store.getInstance();
@@ -125,8 +139,7 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
125139
this.bind("showOpenButton", openButton, "visibility", {
126140
converter: show => (store.getCurrentStudy() === null && show) ? "visible" : "excluded"
127141
});
128-
129-
openButton.addListener("execute", () => this.__openTapped());
142+
openButton.addListener("execute", () => this.__openTapped(openButton));
130143

131144
if (this.__resourceData["resourceType"] === "study") {
132145
const studyData = this.__resourceData;
@@ -137,21 +150,21 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
137150
toolbar.add(openButton);
138151
},
139152

140-
__openTapped: function() {
153+
__openTapped: function(openButton) {
141154
if (this.__resourceData["resourceType"] !== "study") {
142155
// Template or Service, nothing to pre-check
143156
this.__openResource();
144157
return;
145158
}
146-
this.__openButton.setFetching(true);
159+
openButton.setFetching(true);
147160
const params = {
148161
url: {
149162
"studyId": this.__resourceData["uuid"]
150163
}
151164
};
152165
osparc.data.Resources.getOne("studies", params)
153166
.then(updatedStudyData => {
154-
this.__openButton.setFetching(false);
167+
openButton.setFetching(false);
155168
const updatableServices = osparc.metadata.ServicesInStudyUpdate.updatableNodeIds(updatedStudyData.workbench);
156169
if (updatableServices.length && osparc.data.model.Study.canIWrite(updatedStudyData["accessRights"])) {
157170
this.__confirmUpdate();
@@ -162,7 +175,7 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
162175
.catch(err => {
163176
console.error(err);
164177
osparc.FlashMessenger.logAs(err.message, "ERROR");
165-
this.__openButton.setFetching(false);
178+
openButton.setFetching(false);
166179
});
167180
},
168181

@@ -365,19 +378,27 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
365378
const resourceData = this.__resourceData;
366379
if (osparc.utils.Resources.isStudy(resourceData)) {
367380
const id = "Billing";
368-
const title = this.tr("Tier Settings");
381+
const title = this.tr("Billing Settings");
369382
const iconSrc = "@FontAwesome5Solid/cogs/22";
370383
const page = this.__billingSettings = new osparc.dashboard.resources.pages.BasePage(title, iconSrc, id);
371384
this.__addOpenButton(page);
372385

373-
if (this.__resourceData["resourceType"] === "study") {
374-
const studyData = this.__resourceData;
375-
const canBeOpened = osparc.study.Utils.canShowBillingOptions(studyData);
386+
if (resourceData["resourceType"] === "study") {
387+
const canBeOpened = osparc.study.Utils.canShowBillingOptions(resourceData);
376388
page.setEnabled(canBeOpened);
377389
}
378390

379391
const lazyLoadContent = () => {
380392
const billingSettings = new osparc.study.BillingSettings(resourceData);
393+
billingSettings.addListener("debtPayed", () => {
394+
if (resourceData["resourceType"] === "study") {
395+
page.payDebtButton.set({
396+
visibility: osparc.study.Utils.isInDebt(resourceData) ? "visible" : "excluded"
397+
});
398+
const canBeOpened = osparc.study.Utils.canBeOpened(resourceData);
399+
page.openButton.setEnabled(canBeOpened);
400+
}
401+
})
381402
const billingScroll = new qx.ui.container.Scroll(billingSettings);
382403
page.addToContent(billingScroll);
383404
}
@@ -751,7 +772,7 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
751772

752773
const publishTemplateButton = saveAsTemplate.getPublishTemplateButton();
753774
osparc.dashboard.resources.pages.BasePage.decorateHeaderButton(publishTemplateButton);
754-
const toolbar = this.__createToolbar();
775+
const toolbar = this.self().createToolbar();
755776
toolbar.add(publishTemplateButton);
756777
page.addToHeader(toolbar);
757778
page.addToContent(saveAsTemplate);

0 commit comments

Comments
 (0)