Skip to content

Commit 1c9adea

Browse files
committed
Jobs table
1 parent da498a0 commit 1c9adea

File tree

2 files changed

+270
-0
lines changed

2 files changed

+270
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2025 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
19+
qx.Class.define("osparc.jobs.JobsTable", {
20+
extend: qx.ui.table.Table,
21+
22+
construct: function(walletId, filters) {
23+
this.base(arguments);
24+
25+
const model = new osparc.desktop.credits.JobsTableModel(walletId, filters);
26+
this.setTableModel(model);
27+
28+
this.set({
29+
statusBarVisible: false,
30+
headerCellHeight: 26,
31+
rowHeight: 26,
32+
});
33+
34+
const columnModel = this.getTableColumnModel();
35+
columnModel.setColumnVisible(this.self().COLS.CHECKOUT_ID.column, false);
36+
columnModel.setColumnVisible(this.self().COLS.ITEM_ID.column, false);
37+
38+
Object.values(this.self().COLS).forEach(col => columnModel.setColumnWidth(col.column, col.width));
39+
},
40+
41+
statics: {
42+
COLS: {
43+
CHECKOUT_ID: {
44+
id: "checkoutId",
45+
column: 0,
46+
label: qx.locale.Manager.tr("CheckoutId"),
47+
width: 150
48+
},
49+
ITEM_ID: {
50+
id: "itemId",
51+
column: 1,
52+
label: qx.locale.Manager.tr("ItemId"),
53+
width: 150
54+
},
55+
ITEM_LABEL: {
56+
id: "itemLabel",
57+
column: 2,
58+
label: qx.locale.Manager.tr("Name"),
59+
width: 150
60+
},
61+
START: {
62+
id: "start",
63+
column: 3,
64+
label: qx.locale.Manager.tr("Start"),
65+
width: 150
66+
},
67+
DURATION: {
68+
id: "duration",
69+
column: 4,
70+
label: qx.locale.Manager.tr("Duration"),
71+
width: 150
72+
},
73+
SEATS: {
74+
id: "seats",
75+
column: 5,
76+
label: qx.locale.Manager.tr("Seats"),
77+
width: 50
78+
},
79+
USER: {
80+
id: "user",
81+
column: 6,
82+
label: qx.locale.Manager.tr("User"),
83+
width: 150
84+
},
85+
}
86+
}
87+
});
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2025 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
19+
qx.Class.define("osparc.jobs.JobsTableModel", {
20+
extend: qx.ui.table.model.Remote,
21+
22+
construct(walletId, filters) {
23+
this.base(arguments);
24+
25+
const checkoutsCols = osparc.jobs.JobsTable.COLS;
26+
const colLabels = Object.values(checkoutsCols).map(col => col.label);
27+
const colIDs = Object.values(checkoutsCols).map(col => col.id);
28+
29+
this.setColumns(colLabels, colIDs);
30+
this.setWalletId(walletId);
31+
if (filters) {
32+
this.setFilters(filters);
33+
}
34+
this.setSortColumnIndexWithoutSortingData(checkoutsCols.START.column);
35+
this.setSortAscendingWithoutSortingData(false);
36+
this.setColumnSortable(checkoutsCols.DURATION.column, false);
37+
},
38+
39+
properties: {
40+
walletId: {
41+
check: "Number",
42+
nullable: true
43+
},
44+
45+
filters: {
46+
check: "Object",
47+
init: null
48+
},
49+
50+
isFetching: {
51+
check: "Boolean",
52+
init: false,
53+
event: "changeFetching"
54+
},
55+
56+
orderBy: {
57+
check: "Object",
58+
init: {
59+
field: "startAt",
60+
direction: "desc"
61+
}
62+
},
63+
},
64+
65+
statics: {
66+
SERVER_MAX_LIMIT: 49,
67+
COLUMN_ID_TO_DB_COLUMN_MAP: {
68+
0: "startAt",
69+
},
70+
},
71+
72+
members: {
73+
// overridden
74+
sortByColumn(columnIndex, ascending) {
75+
this.setOrderBy({
76+
field: this.self().COLUMN_ID_TO_DB_COLUMN_MAP[columnIndex],
77+
direction: ascending ? "asc" : "desc"
78+
})
79+
this.base(arguments, columnIndex, ascending);
80+
},
81+
82+
// overridden
83+
_loadRowCount() {
84+
const walletId = this.getWalletId();
85+
const urlParams = {
86+
offset: 0,
87+
limit: 1,
88+
filters: this.getFilters() ?
89+
JSON.stringify({
90+
"startAt": this.getFilters()
91+
}) :
92+
null,
93+
orderBy: JSON.stringify(this.getOrderBy()),
94+
};
95+
const options = {
96+
resolveWResponse: true
97+
};
98+
osparc.store.LicensedItems.getInstance().getCheckedOutLicensedItems(walletId, urlParams, options)
99+
.then(resp => this._onRowCountLoaded(resp["_meta"].total))
100+
.catch(() => this._onRowCountLoaded(null));
101+
},
102+
103+
// overridden
104+
_loadRowData(firstRow, qxLastRow) {
105+
this.setIsFetching(true);
106+
107+
const lastRow = Math.min(qxLastRow, this._rowCount - 1);
108+
// Returns a request promise with given offset and limit
109+
const getFetchPromise = (offset, limit=this.self().SERVER_MAX_LIMIT) => {
110+
const walletId = this.getWalletId();
111+
const urlParams = {
112+
limit,
113+
offset,
114+
filters: this.getFilters() ?
115+
JSON.stringify({
116+
"started_at": this.getFilters()
117+
}) :
118+
null,
119+
orderBy: JSON.stringify(this.getOrderBy())
120+
};
121+
const licensedItemsStore = osparc.store.LicensedItems.getInstance();
122+
return Promise.all([
123+
licensedItemsStore.getLicensedItems(),
124+
licensedItemsStore.getCheckedOutLicensedItems(walletId, urlParams),
125+
])
126+
.then(values => {
127+
const licensedItems = values[0];
128+
const checkoutsItems = values[1];
129+
130+
const data = [];
131+
const checkoutsCols = osparc.desktop.credits.JobsTable.COLS;
132+
checkoutsItems.forEach(checkoutsItem => {
133+
const licensedItemId = checkoutsItem["licensedItemId"];
134+
const licensedItem = licensedItems[licensedItemId];
135+
let start = "";
136+
let duration = "";
137+
if (checkoutsItem["startedAt"]) {
138+
start = osparc.utils.Utils.formatDateAndTime(new Date(checkoutsItem["startedAt"]));
139+
if (checkoutsItem["stoppedAt"]) {
140+
duration = osparc.utils.Utils.formatMsToHHMMSS(new Date(checkoutsItem["stoppedAt"]) - new Date(checkoutsItem["startedAt"]));
141+
}
142+
}
143+
data.push({
144+
[checkoutsCols.CHECKOUT_ID.id]: checkoutsItem["licensedItemCheckoutId"],
145+
[checkoutsCols.ITEM_ID.id]: licensedItemId,
146+
[checkoutsCols.ITEM_LABEL.id]: licensedItem ? licensedItem.getDisplayName() : "unknown model",
147+
[checkoutsCols.START.id]: start,
148+
[checkoutsCols.DURATION.id]: duration,
149+
[checkoutsCols.SEATS.id]: checkoutsItem["numOfSeats"],
150+
[checkoutsCols.USER.id]: checkoutsItem["userEmail"],
151+
});
152+
});
153+
return data;
154+
});
155+
};
156+
157+
// Divides the model row request into several server requests to comply with the number of rows server limit
158+
const reqLimit = lastRow - firstRow + 1; // Number of requested rows
159+
const nRequests = Math.ceil(reqLimit / this.self().SERVER_MAX_LIMIT);
160+
if (nRequests > 1) {
161+
const requests = [];
162+
for (let i=firstRow; i <= lastRow; i += this.self().SERVER_MAX_LIMIT) {
163+
requests.push(getFetchPromise(i, i > lastRow - this.self().SERVER_MAX_LIMIT + 1 ? reqLimit % this.self().SERVER_MAX_LIMIT : this.self().SERVER_MAX_LIMIT))
164+
}
165+
Promise.all(requests)
166+
.then(responses => this._onRowDataLoaded(responses.flat()))
167+
.catch(err => {
168+
console.error(err);
169+
this._onRowDataLoaded(null);
170+
})
171+
.finally(() => this.setIsFetching(false));
172+
} else {
173+
getFetchPromise(firstRow, reqLimit)
174+
.then(data => this._onRowDataLoaded(data))
175+
.catch(err => {
176+
console.error(err)
177+
this._onRowDataLoaded(null);
178+
})
179+
.finally(() => this.setIsFetching(false));
180+
}
181+
}
182+
}
183+
})

0 commit comments

Comments
 (0)