diff --git a/services/static-webserver/client/source/class/osparc/data/Permissions.js b/services/static-webserver/client/source/class/osparc/data/Permissions.js
index 44d00471160..5c53b4da76d 100644
--- a/services/static-webserver/client/source/class/osparc/data/Permissions.js
+++ b/services/static-webserver/client/source/class/osparc/data/Permissions.js
@@ -138,7 +138,6 @@ qx.Class.define("osparc.data.Permissions", {
"study.nodestree.uuid.read",
"study.filestree.uuid.read",
"study.logger.debug.read",
- "statics.read"
],
"product_owner": [
"user.invitation.generate",
diff --git a/services/static-webserver/client/source/class/osparc/desktop/preferences/Preferences.js b/services/static-webserver/client/source/class/osparc/desktop/preferences/Preferences.js
index 876019a22c6..d04b96ceeea 100644
--- a/services/static-webserver/client/source/class/osparc/desktop/preferences/Preferences.js
+++ b/services/static-webserver/client/source/class/osparc/desktop/preferences/Preferences.js
@@ -32,9 +32,6 @@ qx.Class.define("osparc.desktop.preferences.Preferences", {
if (osparc.product.Utils.showClusters()) {
this.__addClustersPage();
}
- if (osparc.data.Permissions.getInstance().canDo("statics.read")) {
- this.__addTestersPage();
- }
},
members: {
@@ -85,12 +82,5 @@ qx.Class.define("osparc.desktop.preferences.Preferences", {
.catch(err => console.error(err));
}
},
-
- __addTestersPage: function() {
- const title = this.tr("Tester");
- const iconSrc = "@FontAwesome5Solid/user-md/24";
- const testerPage = new osparc.desktop.preferences.pages.TesterPage();
- this.addTab(title, iconSrc, testerPage);
- }
}
});
diff --git a/services/static-webserver/client/source/class/osparc/desktop/preferences/pages/TesterPage.js b/services/static-webserver/client/source/class/osparc/desktop/preferences/pages/TesterPage.js
deleted file mode 100644
index c886995c744..00000000000
--- a/services/static-webserver/client/source/class/osparc/desktop/preferences/pages/TesterPage.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/* ************************************************************************
-
- osparc - the simcore frontend
-
- https://osparc.io
-
- Copyright:
- 2020 IT'IS Foundation, https://itis.swiss
-
- License:
- MIT: https://opensource.org/licenses/MIT
-
- Authors:
- * Odei Maiz (odeimaiz)
-
-************************************************************************ */
-
-/**
- * Tester Misc in preferences dialog
- */
-
-qx.Class.define("osparc.desktop.preferences.pages.TesterPage", {
- extend: qx.ui.core.Widget,
-
- construct: function() {
- this.base(arguments);
-
- this._setLayout(new qx.ui.layout.VBox(15));
-
- const container = new qx.ui.container.Composite(new qx.ui.layout.VBox(10));
-
- const statics = this.__createStaticsLayout();
- container.add(statics);
-
- const localStorage = this.__createLocalStorageLayout();
- container.add(localStorage);
-
- const scroll = new qx.ui.container.Scroll(container);
- this._add(scroll, {
- flex: 1
- });
- },
-
- members: {
- __createStaticsLayout: function() {
- // layout
- const box = osparc.ui.window.TabbedView.createSectionBox(this.tr("Statics"));
-
- const label = osparc.ui.window.TabbedView.createHelpLabel(this.tr(
- "This is a list of the 'statics' resources"
- ));
- box.add(label);
-
- const statics = osparc.store.Store.getInstance().get("statics");
- const form = new qx.ui.form.Form();
- for (let [key, value] of Object.entries(statics)) {
- const textField = new qx.ui.form.TextField().set({
- value: typeof value === "object" ? JSON.stringify(value) : value.toString(),
- readOnly: true
- });
- form.add(textField, key, null, key);
- }
- box.add(new qx.ui.form.renderer.Single(form));
-
- return box;
- },
-
- __createLocalStorageLayout: function() {
- // layout
- const box = osparc.ui.window.TabbedView.createSectionBox(this.tr("Local Storage"));
-
- const items = {
- ...window.localStorage
- };
- const form = new qx.ui.form.Form();
- for (let [key, value] of Object.entries(items)) {
- const textField = new qx.ui.form.TextField().set({
- value: typeof value === "object" ? JSON.stringify(value) : value.toString(),
- readOnly: true
- });
- form.add(textField, key, null, key);
- }
- box.add(new qx.ui.form.renderer.Single(form));
-
- return box;
- }
- }
-});
diff --git a/services/static-webserver/client/source/class/osparc/file/FolderViewer.js b/services/static-webserver/client/source/class/osparc/file/FolderViewer.js
index 23c1d5e57e8..26fb4433bf3 100644
--- a/services/static-webserver/client/source/class/osparc/file/FolderViewer.js
+++ b/services/static-webserver/client/source/class/osparc/file/FolderViewer.js
@@ -201,24 +201,6 @@ qx.Class.define("osparc.file.FolderViewer", {
return control || this.base(arguments, id);
},
- __getEmptyEntry: function() {
- const items = [];
- if (this.getMode() === "list") {
- items.push([
- "",
- this.tr("Empty folder"),
- "",
- "",
- ""
- ]);
- } else if (this.getMode() === "icons") {
- items.push(this.self().getItemButton().set({
- label: this.tr("Empty folder")
- }));
- }
- return items;
- },
-
__convertEntries: function(content) {
const items = [];
if (this.getMode() === "list") {
diff --git a/services/static-webserver/client/source/class/osparc/navigation/UserMenu.js b/services/static-webserver/client/source/class/osparc/navigation/UserMenu.js
index b18f0a4d7b3..8a736ef7d40 100644
--- a/services/static-webserver/client/source/class/osparc/navigation/UserMenu.js
+++ b/services/static-webserver/client/source/class/osparc/navigation/UserMenu.js
@@ -61,6 +61,11 @@ qx.Class.define("osparc.navigation.UserMenu", {
control.addListener("execute", () => osparc.po.POCenterWindow.openWindow(), this);
this.add(control);
break;
+ case "tester-center":
+ control = new qx.ui.menu.Button(this.tr("Tester Center"));
+ control.addListener("execute", () => osparc.tester.TesterCenterWindow.openWindow(), this);
+ this.add(control);
+ break;
case "billing-center":
control = new qx.ui.menu.Button(this.tr("Billing Center"));
osparc.utils.Utils.setIdToWidget(control, "userMenuBillingCenterBtn");
@@ -157,6 +162,9 @@ qx.Class.define("osparc.navigation.UserMenu", {
if (osparc.data.Permissions.getInstance().isProductOwner()) {
this.getChildControl("po-center");
}
+ if (osparc.data.Permissions.getInstance().isTester()) {
+ this.getChildControl("tester-center");
+ }
if (osparc.desktop.credits.Utils.areWalletsEnabled()) {
this.getChildControl("billing-center");
}
diff --git a/services/static-webserver/client/source/class/osparc/tester/Statics.js b/services/static-webserver/client/source/class/osparc/tester/Statics.js
new file mode 100644
index 00000000000..b6655075e9f
--- /dev/null
+++ b/services/static-webserver/client/source/class/osparc/tester/Statics.js
@@ -0,0 +1,75 @@
+/* ************************************************************************
+
+ osparc - the simcore frontend
+
+ https://osparc.io
+
+ Copyright:
+ 2024 IT'IS Foundation, https://itis.swiss
+
+ License:
+ MIT: https://opensource.org/licenses/MIT
+
+ Authors:
+ * Odei Maiz (odeimaiz)
+
+************************************************************************ */
+
+qx.Class.define("osparc.tester.Statics", {
+ extend: osparc.po.BaseView,
+
+ members: {
+ _createChildControlImpl: function(id) {
+ let control;
+ switch (id) {
+ case "statics-container":
+ control = osparc.ui.window.TabbedView.createSectionBox(this.tr("Statics"));
+ this._add(control, {
+ flex: 1
+ });
+ break;
+ case "statics-content": {
+ const statics = osparc.store.Store.getInstance().get("statics");
+ const form = new qx.ui.form.Form();
+ for (let [key, value] of Object.entries(statics)) {
+ const textField = new qx.ui.form.TextField().set({
+ value: typeof value === "object" ? JSON.stringify(value) : value.toString(),
+ readOnly: true
+ });
+ form.add(textField, key, null, key);
+ }
+ const renderer = new qx.ui.form.renderer.Single(form);
+ control = new qx.ui.container.Scroll(renderer);
+ this.getChildControl("statics-container").add(control);
+ break;
+ }
+ case "local-storage-container":
+ control = osparc.ui.window.TabbedView.createSectionBox(this.tr("Local Storage"));
+ this._add(control);
+ break;
+ case "local-storage-content": {
+ const items = {
+ ...window.localStorage
+ };
+ const form = new qx.ui.form.Form();
+ for (let [key, value] of Object.entries(items)) {
+ const textField = new qx.ui.form.TextField().set({
+ value: typeof value === "object" ? JSON.stringify(value) : value.toString(),
+ readOnly: true
+ });
+ form.add(textField, key, null, key);
+ }
+ control = new qx.ui.form.renderer.Single(form);
+ this.getChildControl("local-storage-container").add(control);
+ break;
+ }
+ }
+ return control || this.base(arguments, id);
+ },
+
+ _buildLayout: function() {
+ this.getChildControl("statics-content");
+ this.getChildControl("local-storage-content");
+ },
+ }
+});
diff --git a/services/static-webserver/client/source/class/osparc/tester/TesterCenter.js b/services/static-webserver/client/source/class/osparc/tester/TesterCenter.js
new file mode 100644
index 00000000000..b456afebb32
--- /dev/null
+++ b/services/static-webserver/client/source/class/osparc/tester/TesterCenter.js
@@ -0,0 +1,48 @@
+/* ************************************************************************
+
+ osparc - the simcore frontend
+
+ https://osparc.io
+
+ Copyright:
+ 2024 IT'IS Foundation, https://itis.swiss
+
+ License:
+ MIT: https://opensource.org/licenses/MIT
+
+ Authors:
+ * Odei Maiz (odeimaiz)
+
+************************************************************************ */
+
+qx.Class.define("osparc.tester.TesterCenter", {
+ extend: osparc.ui.window.TabbedView,
+
+ construct: function() {
+ this.base(arguments);
+
+ const miniProfile = osparc.desktop.account.MyAccount.createMiniProfileView().set({
+ paddingRight: 10
+ });
+ this.addWidgetOnTopOfTheTabs(miniProfile);
+
+ this.__addSocketMessagesPage();
+ this.__addStaticsPage();
+ },
+
+ members: {
+ __addSocketMessagesPage: function() {
+ const title = this.tr("Socket Messages");
+ const iconSrc = "@FontAwesome5Solid/exchange-alt/22";
+ const maintenance = new osparc.tester.WebSocketMessages();
+ this.addTab(title, iconSrc, maintenance);
+ },
+
+ __addStaticsPage: function() {
+ const title = this.tr("Statics");
+ const iconSrc = "@FontAwesome5Solid/wrench/22";
+ const maintenance = new osparc.tester.Statics();
+ this.addTab(title, iconSrc, maintenance);
+ },
+ }
+});
diff --git a/services/static-webserver/client/source/class/osparc/tester/TesterCenterWindow.js b/services/static-webserver/client/source/class/osparc/tester/TesterCenterWindow.js
new file mode 100644
index 00000000000..9b2a99c330d
--- /dev/null
+++ b/services/static-webserver/client/source/class/osparc/tester/TesterCenterWindow.js
@@ -0,0 +1,43 @@
+/* ************************************************************************
+
+ osparc - the simcore frontend
+
+ https://osparc.io
+
+ Copyright:
+ 2024 IT'IS Foundation, https://itis.swiss
+
+ License:
+ MIT: https://opensource.org/licenses/MIT
+
+ Authors:
+ * Odei Maiz (odeimaiz)
+
+************************************************************************ */
+
+qx.Class.define("osparc.tester.TesterCenterWindow", {
+ extend: osparc.ui.window.TabbedWindow,
+
+ construct: function() {
+ this.base(arguments, "tester-center", this.tr("Tester Center"));
+
+ const width = 800;
+ const maxHeight = 800;
+ this.set({
+ width,
+ maxHeight,
+ });
+
+ const testerCenter = new osparc.tester.TesterCenter();
+ this._setTabbedView(testerCenter);
+ },
+
+ statics: {
+ openWindow: function() {
+ const accountWindow = new osparc.tester.TesterCenterWindow();
+ accountWindow.center();
+ accountWindow.open();
+ return accountWindow;
+ }
+ }
+});
diff --git a/services/static-webserver/client/source/class/osparc/tester/WebSocketMessages.js b/services/static-webserver/client/source/class/osparc/tester/WebSocketMessages.js
new file mode 100644
index 00000000000..0872301459f
--- /dev/null
+++ b/services/static-webserver/client/source/class/osparc/tester/WebSocketMessages.js
@@ -0,0 +1,138 @@
+/* ************************************************************************
+
+ osparc - the simcore frontend
+
+ https://osparc.io
+
+ Copyright:
+ 2024 IT'IS Foundation, https://itis.swiss
+
+ License:
+ MIT: https://opensource.org/licenses/MIT
+
+ Authors:
+ * Odei Maiz (odeimaiz)
+
+************************************************************************ */
+
+qx.Class.define("osparc.tester.WebSocketMessages", {
+ extend: osparc.po.BaseView,
+ construct: function() {
+ this.base(arguments);
+ },
+
+ members: {
+ _createChildControlImpl: function(id) {
+ let control;
+ switch (id) {
+ case "filter-message": {
+ control = new qx.ui.form.TextField().set({
+ liveUpdate : true,
+ placeholder: this.tr("Search in Message"),
+ });
+ this._add(control);
+ break;
+ }
+ case "messages-table": {
+ const tableModel = new qx.ui.table.model.Filtered();
+ tableModel.setColumns([
+ this.tr("Date"),
+ this.tr("Channel"),
+ this.tr("Message"),
+ ]);
+ const custom = {
+ tableColumnModel: function(obj) {
+ return new qx.ui.table.columnmodel.Resize(obj);
+ }
+ };
+ control = new qx.ui.table.Table(tableModel, custom).set({
+ selectable: true,
+ statusBarVisible: false,
+ showCellFocusIndicator: false,
+ forceLineHeight: false
+ });
+ control.getTableColumnModel().setDataCellRenderer(
+ 1,
+ new qx.ui.table.cellrenderer.String().set({
+ defaultCellStyle: "user-select: text"
+ })
+ );
+ control.getTableColumnModel().setDataCellRenderer(
+ 0,
+ new qx.ui.table.cellrenderer.String().set({
+ defaultCellStyle: "user-select: text"
+ })
+ );
+ control.getTableColumnModel().setDataCellRenderer(
+ 2,
+ new osparc.ui.table.cellrenderer.Html().set({
+ defaultCellStyle: "user-select: text; text-wrap: wrap"
+ })
+ );
+ control.setColumnWidth(0, 80);
+ control.setColumnWidth(1, 150);
+
+ control.setDataRowRenderer(new osparc.ui.table.rowrenderer.ExpandSelection(control));
+ this._add(control, {
+ flex: 1
+ });
+ break;
+ }
+ case "json-viewer":
+ control = new osparc.ui.basic.JsonTreeWidget();
+ this._add(control);
+ break;
+ }
+ return control || this.base(arguments, id);
+ },
+
+ _buildLayout: function() {
+ const filterMessage = this.getChildControl("filter-message");
+ const table = this.getChildControl("messages-table");
+ const jsonViewer = this.getChildControl("json-viewer");
+
+ const model = table.getTableModel();
+ filterMessage.addListener("changeValue", e => {
+ const value = e.getData();
+ model.resetHiddenRows();
+ model.addNotRegex(value, "Message", true);
+ model.applyFilters();
+ });
+ table.addListener("cellTap", e => {
+ const selectedRow = e.getRow();
+ const rowData = table.getTableModel().getRowData(selectedRow);
+ jsonViewer.setJson(JSON.parse(rowData[2]));
+ }, this);
+
+ this.__populateTable();
+ },
+
+ __populateTable: function() {
+ const socket = osparc.wrapper.WebSocket.getInstance();
+ const messagesObj = socket.getCachedMessages();
+ const messagesArray = [];
+ for (const channel in messagesObj) {
+ messagesObj[channel].forEach(msg => {
+ messagesArray.push({
+ date: msg.date,
+ channel,
+ message: msg.message,
+ });
+ });
+ }
+ messagesArray.sort((a, b) => {
+ return new Date(b.date) - new Date(a.date); // newest first
+ });
+ const datas = [];
+ messagesArray.forEach(entry => {
+ const data = [
+ new Date(entry.date).toLocaleTimeString(),
+ entry.channel,
+ JSON.stringify(entry.message),
+ ];
+ datas.push(data);
+ });
+ this.getChildControl("messages-table").getTableModel().setData(datas);
+ }
+ }
+});
diff --git a/services/static-webserver/client/source/class/osparc/ui/basic/JsonTreeWidget.js b/services/static-webserver/client/source/class/osparc/ui/basic/JsonTreeWidget.js
index 24453fe0bf8..60f5a55e5b1 100644
--- a/services/static-webserver/client/source/class/osparc/ui/basic/JsonTreeWidget.js
+++ b/services/static-webserver/client/source/class/osparc/ui/basic/JsonTreeWidget.js
@@ -36,11 +36,21 @@ qx.Class.define("osparc.ui.basic.JsonTreeWidget", {
* @param data {Object} Json object to be displayed by JsonTreeViewer
*/
construct: function(data) {
- const prettyJson = JSON.stringify(data, null, " ").replace(/\n/ig, "
");
- this.base(arguments, prettyJson);
+ this.base(arguments);
this.set({
rich: true,
selectable: true
});
+
+ if (data) {
+ this.setJson(data);
+ }
+ },
+
+ members: {
+ setJson(data) {
+ const prettyJson = JSON.stringify(data, null, " ").replace(/\n/ig, "
");
+ this.setValue(prettyJson);
+ }
}
});
diff --git a/services/static-webserver/client/source/class/osparc/widget/logger/LoggerView.js b/services/static-webserver/client/source/class/osparc/widget/logger/LoggerView.js
index e77ff8c6840..7eb6bbb4081 100644
--- a/services/static-webserver/client/source/class/osparc/widget/logger/LoggerView.js
+++ b/services/static-webserver/client/source/class/osparc/widget/logger/LoggerView.js
@@ -21,7 +21,7 @@
* It consists of:
* - a toolbar containing:
* - clear button
- * - filter as you type textfiled
+ * - filter as you type textfield
* - some log type filtering buttons
* - log messages table
*
diff --git a/services/static-webserver/client/source/class/osparc/wrapper/WebSocket.js b/services/static-webserver/client/source/class/osparc/wrapper/WebSocket.js
index 3a300c433b9..081d790c01d 100644
--- a/services/static-webserver/client/source/class/osparc/wrapper/WebSocket.js
+++ b/services/static-webserver/client/source/class/osparc/wrapper/WebSocket.js
@@ -134,11 +134,13 @@ qx.Class.define("osparc.wrapper.WebSocket", {
this.setNamespace(namespace);
}
this.__name = [];
+ this.__cache = {};
},
members: {
// The name store an array of events
__name: null,
+ __cache: null,
/**
* Trying to using socket.io to connect and plug every event from socket.io to qooxdoo one
@@ -234,7 +236,7 @@ qx.Class.define("osparc.wrapper.WebSocket", {
* Connect and event from socket.io like qooxdoo event
*
* @param {string} name The event name to watch
- * @param {function} fn The function wich will catch event response
+ * @param {function} fn The function which will catch event response
* @param {mixed} that A link to this
* @returns {void}
*/
@@ -247,6 +249,21 @@ qx.Class.define("osparc.wrapper.WebSocket", {
} else {
socket.on(name, fn);
}
+
+ // add a duplicated slot listener to keep the messages cached
+ socket.on(name, message => {
+ if (!(name in this.__cache)) {
+ this.__cache[name] = [];
+ }
+ const info = {
+ date: new Date(),
+ message: message ? message : "",
+ }
+ this.__cache[name].unshift(info);
+ if (this.__cache[name].length > 20) {
+ this.__cache[name].length = 20;
+ }
+ }, this);
}
},
@@ -265,7 +282,11 @@ qx.Class.define("osparc.wrapper.WebSocket", {
index = this.__name.indexOf(name);
}
}
- }
+ },
+
+ getCachedMessages: function() {
+ return this.__cache;
+ },
},
/**
@@ -281,6 +302,7 @@ qx.Class.define("osparc.wrapper.WebSocket", {
}
}
this.__name = null;
+ this.__cache = null;
this.removeAllBindings();