diff --git a/release.notes b/release.notes index cf75e05cf..cf42a22bc 100644 --- a/release.notes +++ b/release.notes @@ -1,5 +1,6 @@ -[v4r3-pre11] +[v4r3-pre12] +NEW: (#501) add VMDIRAC application CHANGE: (#502) remove Desktop view FIX: (#500) move run_in_executor part to asyncGen decorated method FIX: (#499) Create the directory in /WebApp/StaticResourceLinkDir if it doesn't already exist @@ -29,6 +30,12 @@ CHANGE: (#467) rename README.md to README.rst FIX: (#466) fix selector of pilot stats FIX: (#465) return empty result instead error for no host request +[v4r2p5] + +CHANGE: (#506) change datetime field behavior in selector, use Time field +CHANGE: (#505) get hosts from DB for SystemAdministrator +NEW: (#503) declare downtime for the application + [v4r2p4] FIX: (#495) copy SettingsPanel.js to desktop folder diff --git a/src/WebAppDIRAC/Lib/Conf.py b/src/WebAppDIRAC/Lib/Conf.py index 375c2d5c1..8ffb19e58 100644 --- a/src/WebAppDIRAC/Lib/Conf.py +++ b/src/WebAppDIRAC/Lib/Conf.py @@ -3,9 +3,9 @@ import uuid import tempfile import tornado.process + from DIRAC import gConfig from DIRAC.Core.Security import Locations, X509Chain, X509CRL -from DIRAC.Core.Utilities.Decorators import deprecated __RCSID__ = "$Id$" @@ -253,11 +253,6 @@ def getIcon(): return getCSValue("Icon", "/static/core/img/icons/system/favicon.ico") -@deprecated("Please, use SSLProtocol instead.") -def SSLProrocol(): - return SSLProtocol() - - def SSLProtocol(): """ Get ssl protocol diff --git a/src/WebAppDIRAC/Lib/SessionData.py b/src/WebAppDIRAC/Lib/SessionData.py index 92e149fe6..25e00666e 100644 --- a/src/WebAppDIRAC/Lib/SessionData.py +++ b/src/WebAppDIRAC/Lib/SessionData.py @@ -9,7 +9,7 @@ from DIRAC.Core.DISET.AuthManager import AuthManager from DIRAC.Core.DISET.ThreadConfig import ThreadConfig from DIRAC.ConfigurationSystem.Client.Helpers import Registry -from DIRAC.ConfigurationSystem.Client.Helpers import CSGlobals +from DIRAC.Core.Utilities.Extensions import extensionsByPriority from WebAppDIRAC.Lib import Conf @@ -36,7 +36,7 @@ def setHandlers(cls, handlers): cls.__handlers[handler.LOCATION.strip("/")] = handler # Calculate extensions # TODO: Remove use of deprecated function - cls.__extensions = CSGlobals.getInstalledExtensions() + cls.__extensions = extensionsByPriority() for ext in ['DIRAC', 'WebAppDIRAC']: if ext in cls.__extensions: cls.__extensions.append(cls.__extensions.pop(cls.__extensions.index(ext))) diff --git a/src/WebAppDIRAC/WebApp/handler/SystemAdministrationHandler.py b/src/WebAppDIRAC/WebApp/handler/SystemAdministrationHandler.py index 51594f1ba..87aeded38 100644 --- a/src/WebAppDIRAC/WebApp/handler/SystemAdministrationHandler.py +++ b/src/WebAppDIRAC/WebApp/handler/SystemAdministrationHandler.py @@ -5,9 +5,8 @@ import datetime from DIRAC import gConfig, gLogger -from DIRAC.Core.DISET.RPCClient import RPCClient from DIRAC.Core.Utilities.List import uniqueElements -import DIRAC.ConfigurationSystem.Client.Helpers.Registry as Registry +from DIRAC.FrameworkSystem.Client.MonitoringClient import gMonitor from DIRAC.FrameworkSystem.Client.NotificationClient import NotificationClient from DIRAC.FrameworkSystem.Client.SystemAdministratorClient import SystemAdministratorClient from DIRAC.FrameworkSystem.Client.ComponentMonitoringClient import ComponentMonitoringClient @@ -592,7 +591,7 @@ def web_getSelectionData(self): setup = self.getUserSetup().split('-')[-1] hosts = [] - result = Registry.getHosts() + result = ComponentMonitoringClient().getHosts() if result['OK']: hosts = [[i] for i in result['Value']] data['Hosts'] = hosts @@ -637,13 +636,11 @@ def web_getSelectionData(self): @asyncGen def web_ComponentLocation(self): - rpcClient = RPCClient("Framework/Monitoring") - _setup = self.getUserSetup() setup = _setup.split('-')[-1] hosts = [] - result = Registry.getHosts() + result = ComponentMonitoringClient().getHosts() if result['OK']: hosts = result['Value'] @@ -702,7 +699,7 @@ def web_ComponentLocation(self): condDict = {'Setup': _setup} gLogger.debug("condDict" + str(condDict)) - retVal = rpcClient.getComponentsStatus(condDict) + retVal = gMonitor.getComponentsStatus(condDict) today = datetime.datetime.today() if retVal['OK']: diff --git a/src/WebAppDIRAC/WebApp/static/core/js/core/App.js b/src/WebAppDIRAC/WebApp/static/core/js/core/App.js index 0eacce57d..451bc68e7 100755 --- a/src/WebAppDIRAC/WebApp/static/core/js/core/App.js +++ b/src/WebAppDIRAC/WebApp/static/core/js/core/App.js @@ -242,6 +242,55 @@ Ext.define("Ext.dirac.core.App", { return sAppName in this.validApplications; }, + /** + * Function to get all application settings + * + * @param {String} + * sAppName The class name of the application + * @return {} + */ + getApplicationSettings: function(sAppName) { + if (sAppName in GLOBAL.APP.configData.configuration) { + return GLOBAL.APP.configData.configuration[sAppName]; + } else { + return {}; + } + }, + + /** + * Function that check application downtime settings + * + * @param {String} + * sAppName The class name of the application + * @return {} + */ + applicationInDowntime: function(sAppName) { + if (this.isValidApplication(sAppName)) { + var now = Date.now(); + var app = this.validApplications[sAppName]; + var downtime = this.getApplicationSettings(app).Downtime; + + if (downtime) { + downtime.message = downtime.message || "Sorry, " + app + " application is in downtime"; + downtime.message += "\n\n From: " + downtime.start; + downtime.message += "\n To: " + downtime.end; + + // Check time + /* The string format should be: YYYY-MM-DDTHH:mm:ss.sssZ, where: + + YYYY-MM-DD – is the date: year-month-day. + The character "T" is used as the delimiter. + HH:mm:ss.sss – is the time: hours, minutes, seconds and milliseconds. + The optional 'Z' part denotes the time zone in the format +-hh:mm. A single letter Z would mean UTC+0. + Shorter variants are also possible, like YYYY-MM-DDTHH:mm, YYYY-MM-DD or YYYY-MM or even YYYY. + */ + return !downtime.end ? {} : (!downtime.start || now > Date.parse(downtime.start)) && now < Date.parse(downtime.end) ? downtime : {}; + } else { + return {}; + } + } + }, + /** * Function that is used to get the title of an application * diff --git a/src/WebAppDIRAC/WebApp/static/core/js/utils/DiracTimeSearchPanel.js b/src/WebAppDIRAC/WebApp/static/core/js/utils/DiracTimeSearchPanel.js index 773433355..0f9a1d558 100644 --- a/src/WebAppDIRAC/WebApp/static/core/js/utils/DiracTimeSearchPanel.js +++ b/src/WebAppDIRAC/WebApp/static/core/js/utils/DiracTimeSearchPanel.js @@ -12,8 +12,7 @@ Ext.define("Ext.dirac.utils.DiracTimeSearchPanel", { layout: "anchor", anchor: "100%", /************************************************************************* - * @property{It is the time stamp widget which contains a list with Last - * hour, Last Day...} + * @property{It is the time stamp widget which contains a list with Last hour, Last Day...} */ cmbTimeSpan: null, /** @@ -33,14 +32,12 @@ Ext.define("Ext.dirac.utils.DiracTimeSearchPanel", { calenTo: null, /** * - * @property{cmbTimeTo} is a combo box used to select the time in a given - * day. + * @property{cmbTimeTo} is a combo box used to select the time in a given day. */ cmbTimeTo: null, /** * - * @property{timeSearchPanelHidden} is a boolean which is true when the - * time search panel is hidden... + * @property{timeSearchPanelHidden} is a boolean which is true when the time search panel is hidden... */ timeSearchPanelHidden: null, getStateData: function() { @@ -57,10 +54,8 @@ Ext.define("Ext.dirac.utils.DiracTimeSearchPanel", { }, loadState: function(data) { var me = this; - if (data.timeSearchPanelHidden) { - if (!data.timeSearchPanelHidden) me.show(); - else me.hide(); - } + + data.timeSearchPanelHidden ? me.hide : me.show(); // END - For the time span searching sub-panel if (data.cmbTimeSpan) { @@ -96,47 +91,98 @@ Ext.define("Ext.dirac.utils.DiracTimeSearchPanel", { [5, "Manual Selection"] ] }), + emptyText: "For all time?", + editable: false, displayField: "text", valueField: "value", - anchor: "100%" + anchor: "100%", + onChange: function(newVal) { + if (newVal == 5) { + me.fromDate.items.forEach(e => e.show()); + me.toDate.items.forEach(e => e.show()); + } else { + me.fromDate.items.forEach(e => e.hide()); + me.toDate.items.forEach(e => e.hide()); + me.resetDate.items.forEach(e => e.hide()); + } + } }); - var oTimeData = []; - for (var i = 0; i < 24; i++) { - oTimeData.push([(i.toString().length == 1 ? "0" + i.toString() : i.toString()) + ":00"]); - oTimeData.push([(i.toString().length == 1 ? "0" + i.toString() : i.toString()) + ":30"]); - } - me.calenFrom = new Ext.create("Ext.form.field.Date", { - width: 100, - format: "Y-m-d" + labelAlign: "top", + fieldLabel: "From", + flex: 3, + format: "Y-m-d", + hidden: true, + onChange: function(newVal) { + if (newVal) { + me.resetDate.items.forEach(e => e.show()); + } + } }); - me.cmbTimeFrom = new Ext.create("Ext.form.field.ComboBox", { - width: 70, - store: new Ext.data.ArrayStore({ - fields: ["value"], - data: oTimeData - }), + me.cmbTimeFrom = new Ext.create("Ext.form.field.Time", { + format: "H:i", + flex: 2, + increment: 30, margin: "0 0 0 10", - displayField: "value" + hidden: true, + onChange: function(newVal) { + if (!me.calenFrom.getValue()) { + me.calenFrom.setValue(new Date()); + } + } }); + me.fromDate = { + xtype: "panel", + layout: { + type: "hbox", + align: "bottom" + }, + border: false, + margin: "0 0 5 0", + items: [me.calenFrom, me.cmbTimeFrom] + }; + me.calenTo = new Ext.create("Ext.form.field.Date", { - width: 100, - format: "Y-m-d" + labelAlign: "top", + fieldLabel: "To", + labelStyle: "width:20px", + flex: 3, + format: "Y-m-d", + hidden: true, + onChange: function(newVal) { + if (newVal) { + me.resetDate.items.forEach(e => e.show()); + } + } }); - me.cmbTimeTo = new Ext.create("Ext.form.field.ComboBox", { - width: 70, - store: new Ext.data.ArrayStore({ - fields: ["value"], - data: oTimeData - }), + me.cmbTimeTo = new Ext.create("Ext.form.field.Time", { + format: "H:i", + flex: 2, + increment: 30, margin: "0 0 0 10", - displayField: "value" + hidden: true, + onChange: function(newVal) { + if (!me.calenTo.getValue()) { + me.calenTo.setValue(new Date()); + } + } }); + me.toDate = { + xtype: "panel", + layout: { + type: "hbox", + align: "bottom" + }, + border: false, + margin: "0 0 5 0", + items: [me.calenTo, me.cmbTimeTo] + }; + me.btnResetTimePanel = new Ext.Button({ text: "Reset Time Panel", margin: 3, @@ -146,48 +192,24 @@ Ext.define("Ext.dirac.utils.DiracTimeSearchPanel", { me.cmbTimeFrom.setValue(null); me.calenTo.setRawValue(""); me.calenFrom.setRawValue(""); - me.cmbTimeSpan.setValue(null); + me.btnResetTimePanel.hide(); }, scope: me, - defaultAlign: "c" + hidden: true }); + + me.resetDate = { + xtype: "toolbar", + layout: { + type: "hbox", + pack: "center" + }, + border: false, + items: [me.btnResetTimePanel] + }; + Ext.apply(me, { - dockedItems: [ - { - xtype: "toolbar", - dock: "bottom", - items: [me.btnResetTimePanel], - layout: { - type: "hbox", - pack: "center" - } - } - ], - items: [ - me.cmbTimeSpan, - { - xtype: "tbtext", - text: "From:", - padding: "3 0 3 0" - }, - { - xtype: "panel", - layout: "column", - border: false, - items: [me.calenFrom, me.cmbTimeFrom] - }, - { - xtype: "tbtext", - text: "To:", - padding: "3 0 3 0" - }, - { - xtype: "panel", - layout: "column", - border: false, - items: [me.calenTo, me.cmbTimeTo] - } - ] + items: [me.cmbTimeSpan, me.fromDate, me.toDate, me.resetDate] }); me.callParent(arguments); }, @@ -235,9 +257,9 @@ Ext.define("Ext.dirac.utils.DiracTimeSearchPanel", { // Collect data for filtration data["startDate"] = sStartDate; - data["startTime"] = sStartTime; + data["startTime"] = sStartTime ? sStartTime.getHours() + ":" + sStartTime.getMinutes() : sStartTime; data["endDate"] = sEndDate; - data["endTime"] = sEndTime; + data["endTime"] = sEndTime ? sEndTime.getHours() + ":" + sEndTime.getMinutes() : sEndTime; return data; } }); diff --git a/src/WebAppDIRAC/WebApp/static/core/js/views/tabs/Main.js b/src/WebAppDIRAC/WebApp/static/core/js/views/tabs/Main.js index 31b4c44d9..2459914d9 100644 --- a/src/WebAppDIRAC/WebApp/static/core/js/views/tabs/Main.js +++ b/src/WebAppDIRAC/WebApp/static/core/js/views/tabs/Main.js @@ -806,6 +806,13 @@ Ext.define("Ext.dirac.views.tabs.Main", { */ createWindow: function(loadedObjectType, moduleName, setupData, oTab, cbFunction) { var me = this; + + // Do not create new window if the application in downtime + var downtime = GLOBAL.APP.applicationInDowntime(moduleName); + if (downtime.message) { + return GLOBAL.APP.CF.alert(downtime.message, "info"); + } + Ext.get("app-dirac-loading").show(); if (loadedObjectType == "app") { diff --git a/src/WebAppDIRAC/__init__.py b/src/WebAppDIRAC/__init__.py index 4926b8945..0fd9cfd09 100644 --- a/src/WebAppDIRAC/__init__.py +++ b/src/WebAppDIRAC/__init__.py @@ -25,7 +25,7 @@ majorVersion = 4 minorVersion = 3 patchLevel = 0 - preVersion = 11 + preVersion = 12 version = "v%sr%s" % (majorVersion, minorVersion) buildVersion = "v%dr%d" % (majorVersion, minorVersion)