diff --git a/.gitignore b/.gitignore index 3d73590..906cac3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ sc-list.txt +.vscode/settings.json diff --git a/MDX2JSON/AbstractREST.cls b/MDX2JSON/AbstractREST.cls index f13c873..c9be0b7 100644 --- a/MDX2JSON/AbstractREST.cls +++ b/MDX2JSON/AbstractREST.cls @@ -28,7 +28,7 @@ ClassMethod OnPreDispatch(pUrl As %String, pMethod As %String, ByRef pContinue A Set st = ..ConvertRequestBody() If $$$ISERR(st) { - Do ..Http500(st) + #; Do ..Http500(st) Set pContinue = $$$NO Quit st } @@ -37,9 +37,9 @@ ClassMethod OnPreDispatch(pUrl As %String, pMethod As %String, ByRef pContinue A Set Namespace = %request.Get("Namespace", $namespace) Set st = ..CheckNamespace(.Namespace) If $$$ISERR(st) { - Do ..Http500(st) + #; Do ..Http500(st) Set pContinue = $$$NO - Quit + Quit st } #; Dispatch @@ -114,22 +114,6 @@ ClassMethod Login(skipheader As %Boolean = 1) As %Status Return $$$OK } -/// Issue an '500' error and give some indication as to what occurred.
-/// pStatus - %status, not %Exception.AbstractException. -ClassMethod Http500(pStatus As %Exception.AbstractException) As %Status -{ - // we are expecting status - #; Set the response Http status - Set %response.Status="500 Internal Server Error" - - #; Skip duplicate calls - Quit:$isObject(pStatus) $$$OK - - #; Return a helpful error string - Write "{""Error"":"_$$$ZENJSSTR($System.Status.GetErrorText(pStatus,%session.Language))_"}" - - Quit $$$OK -} /// Returns info about MDX2JSON package mapping ClassMethod GetMappings() As %ArrayOfObjects diff --git a/MDX2JSON/Dashboard.cls b/MDX2JSON/Dashboard.cls index 20f8156..1a9139f 100644 --- a/MDX2JSON/Dashboard.cls +++ b/MDX2JSON/Dashboard.cls @@ -96,6 +96,42 @@ ClassMethod WidgetsToProxyObject(Dashboard As %DeepSee.Dashboard.Definition, Out return st } + +/// A very specific method of displaying the data type for cube measures. +/// Serves for the convenience of front-end development of the filter widget. +/// The return is something like this %DeepSee.Time.DayMonthYear +ClassMethod GetCubeMeasuresDataType(Widget, Number, CubeName, Output DataType As %String) As %Status +{ + + set st = $$$OK + set dataSource = $piece(Widget.dataSource, ".", *) // get dataSource type + try{ + if ((dataSource '= "kpi") && (dataSource '= "")){ + if ($FIND(Widget.controls.GetAt(Number).targetProperty, "[") && $FIND(Widget.controls.GetAt(Number).targetProperty, ".")){ + set tMeasure = $TRANSLATE(Widget.controls.GetAt(Number).targetProperty, "[]", "") + + set st = ##class(%DeepSee.Utils).%GetDimensionInfo(CubeName,tMeasure,.pDimNo,.pHierNo,.pLevelNo) // get positional info about dimension + + Set tMbrInfo = $G($$$DeepSeeMetaGLVN("cubes",$$$UPPER(CubeName),"mbr#",pDimNo,pHierNo,pLevelNo)) + set DataType = $LG(tMbrInfo,6) // get data type + if '($FIND(DataType, "%")){ // if DataType return cube fact search for dataType in "star" + Set tMbrInfo = $G($$$DeepSeeMetaGLVN("cubes", $$$UPPER(CubeName), "star", DataType, "prop", $LG(tMbrInfo,7), "type")) + set DataType = tMbrInfo + } + }else{ + + set DataType = "" + } + }else{ + + set DataType = "" + } + }catch ex { + set st = ex.AsStatus() + } + return st +} + /// Converts relevant parts of %DeepSee.Dashboard.Widget object into %ZEN.proxyObject. ClassMethod WidgetToProxyObject(Widget As %DeepSee.Dashboard.Widget, CubeName As %String) As %ZEN.proxyObject [ Internal ] { @@ -108,13 +144,14 @@ ClassMethod WidgetToProxyObject(Widget As %DeepSee.Dashboard.Widget, CubeName As // Linked widgets processing set mdx = "" set basemdx = "" - set obj.Link = Widget.dataLink + set obj.dataLink = Widget.dataLink } // datasource is a kpi if $piece(Widget.dataSource, ".", *) = "kpi" { set kpiClass = ##class(%DeepSee.Utils).%GetKPIClass(Widget.dataSource) set obj.kpitype = $classmethod(kpiClass, "%GetSourceType") + set obj.kpiclass = kpiClass // showing kpi class for implementing context menu button for kpi } @@ -253,6 +290,13 @@ ClassMethod WidgetControlToProxyObject(Widget As %DeepSee.Dashboard.Widget, Numb set obj.label = ##class(%DeepSee.UserPortal.Utils).%ResolveText(obj.label) set obj.source = Widget.name + set st = ..GetCubeMeasuresDataType(Widget,Number,CubeName,.fDataType) + + if (st = $$$OK) + { + set obj.targetPropertyDataType = fDataType + } + set:(obj.target="") obj.target = Widget.name if ($e(obj.value)="@") { diff --git a/MDX2JSON/REST.cls b/MDX2JSON/REST.cls index d478171..a39dae3 100644 --- a/MDX2JSON/REST.cls +++ b/MDX2JSON/REST.cls @@ -49,6 +49,7 @@ XData UrlMap + @@ -60,11 +61,16 @@ XData UrlMap + + + + + @@ -85,7 +91,6 @@ XData UrlMap - @@ -114,7 +119,7 @@ ClassMethod Test() As %Status set obj.Status = "OK" set obj.Embed = $g(^MDX2JSON.Embed, $g(^%MDX2JSON.Embed, "")) set obj.User = $Username - set obj.Version = "3.2.5" + set obj.Version = "3.2.38" set obj.Parent = ##class(MDX2JSON.Tests).#LastCommit set obj.ParentTS = ##class(MDX2JSON.Tests).#LastCommitTS set obj.DefaultApp = $System.CSP.GetDefaultApp($Namespace) @@ -132,6 +137,63 @@ ClassMethod Test() As %Status return $$$OK } +ClassMethod deleteWidget() As %Status +{ + set name = $$$R("key") + set dashboardData = $$$R("Dashboard") + + return ##class(MDX2JSON.Utils).DeleteWidget(name,dashboardData) +} + +ClassMethod saveWidget() As %Status +{ + set key = $$$R("key") + set widgetData= $$$R("WidgetData") + set dashboardData = $$$R("Dashboard") + + return ##class(MDX2JSON.Utils).AddWidget(widgetData,dashboardData,key) +} + + +/// Get all data sources including "pivot", "kpi", "worksheets","metrics" +ClassMethod GetListDataSources(Source) As %Status +{ + + set Source = $ZCONVERT($ZCONVERT(Source ,"I","URL") ,"I","UTF8") + + if (Source = "pivot") + { + Set tSC = ##class(%DeepSee.Utils).%GetPivotListArray(.tParms,.pMetaData,.pData) + + } + elseif (Source = "kpi") + { + Set tSC = ##class(%DeepSee.Utils).%GetKPIListArray(.tParms,.pMetaData,.pData) + + } + elseif (Source = "worksheets") + { + Set tSC = ##class(%DeepSee.Utils).%GetWorksheetListArray(.tParms,.pMetaData,.pData) + + } + elseif (Source = "metrics") + { + Set tSC = ##class(%DeepSee.Utils).%GetMetricListArray(.tParms,.pMetaData,.pData) + + } + + quit:$$$ISERR(tSC) tSC + + Set tSC = ##class(%DeepSee.REST.v1.DataServer).%CreateObjectFromArray(.pData,pMetaData,.tSourceObj) + + quit:$$$ISERR(tSC) tSC + + do tSourceObj.%ToJSON() + + quit tSC +} + + ClassMethod GetDataSource() As %Status { return ##class(MDX2JSON.Utils).GetDataSource($$$R("DataSource")) @@ -220,6 +282,41 @@ ClassMethod WriteFiltersForDataSource() As %Status return st } +///Execute requests from kpi +ClassMethod KPIExecute() As %Status +{ + try{ + set KPI = $$$R("KPI") + set Drillthrough = $$$R("Drillthrough") + + + if (Drillthrough = 1){ + set SortOrder = $$$R("SortOrder") + + if %request.Content.FILTERS + { + set Filters = $$$R("FILTERS") + + }else{ + set Filters = $$$R("Filters") + } + + set SortColumn = $$$R("SortColumn") + set pSelection = SortColumn _ "," _ SortOrder + + set st = ##class(MDX2JSON.Utils).WriteDrillthroughJSONKPI(KPI, Filters, pSelection) + } + else { + set st = ##class(%DeepSee.REST.v1.DataServer).WriteJSONfromKPI(KPI) + } + + }catch ex { + set st=ex.AsStatus() + } + + return st +} + /// Wrapper for ##class(MDX2JSON.Utils).WriteJSONPfromMDX(pMDX)
/// Converts incoming request object and calls abovementioned method. ClassMethod WriteJSONfromMDX() As %Status @@ -324,12 +421,20 @@ ClassMethod WritePivotVariablesForCube(Cube As %String) As %Status ClassMethod WriteAddons() As %Status { #dim sc As %Status = $$$OK - - set app = "/dsw" + + set currentApp = $ZConvert($Get(%request.CgiEnvs("SCRIPT_NAME"), ""), "L") + set prefix = $piece(currentApp, "/mdx2json", 1) + set app = prefix _ "/dsw" set path = $system.CSP.GetFileName(app _ "/") set path = ##class(%File).NormalizeDirectory(path) set path = ##class(%File).SubDirectoryName(path, "addons", $$$YES) set url = app _ "/addons/" + + // Check if path exists + if '##class(%File).Exists(path) { + set sc = $$$ERROR($$$GeneralError, "Addons directory does not exist: "_path_". Probably different prefixes for MDX2JSON and DSW applications.") + quit sc + } #dim rs As %SQL.ClassQueryResultSet = ##class(%File).FileSetFunc(path, "*.js") @@ -350,12 +455,20 @@ ClassMethod WriteThemes() As %Status { #dim sc As %Status = $$$OK - set app = "/dsw" + set currentApp = $ZConvert($Get(%request.CgiEnvs("SCRIPT_NAME"), ""), "L") + set prefix = $piece(currentApp, "/mdx2json", 1) + set app = prefix _ "/dsw" set path = $system.CSP.GetFileName(app _ "/") set path = ##class(%File).NormalizeDirectory(path) set path = ##class(%File).SubDirectoryName(path, "themes", $$$YES) set url = app _ "/themes/" + // Check if path exists + if '##class(%File).Exists(path) { + set sc = $$$ERROR($$$GeneralError, "Themes directory does not exist: "_path_". Probably different prefixes for MDX2JSON and DSW applications.") + quit sc + } + #dim rs As %SQL.ClassQueryResultSet = ##class(%File).FileSetFunc(path, "*.css") set list = $$$NewDynDTList @@ -377,4 +490,4 @@ ClassMethod WriteJSONfromKPI() As %Status [ CodeMode = objectgenerator ] do %code.Write(base) } -} +} \ No newline at end of file diff --git a/MDX2JSON/ResultSet.cls b/MDX2JSON/ResultSet.cls index 7f7db4b..210c64f 100644 --- a/MDX2JSON/ResultSet.cls +++ b/MDX2JSON/ResultSet.cls @@ -35,7 +35,7 @@ Method ToProxyObject(Output pStatus As %Status) As %ZEN.proxyObject try { set obj.Info = ..InfoToProxyObject() // basic info about cube and query quit:obj.Info.percentDone<100 - + set obj.Cols = ..AxesToListOfObjects() // all axes set obj.Data = ..DataToListOfDataTypes() // array of all cells, left-to-right, up-to-down } catch ex { @@ -79,7 +79,7 @@ Method InfoToProxyObject() As %ZEN.proxyObject set info.numericGroupSeparator = ##class(%SYS.NLS.Format).GetFormatItem("NumericGroupSeparator") set info.numericGroupSize = ##class(%SYS.NLS.Format).GetFormatItem("NumericGroupSize") set info.decimalSeparator = ##class(%SYS.NLS.Format).GetFormatItem("DecimalSeparator") - + return info } @@ -130,7 +130,7 @@ Method ProcessOneAxisCell(CubeIndex, AxisKey, CubeName, QueryKey, AxisNumber, No set cell.vis = $LG(tNode,2) // visibility helper - does not help (apperently it shows if the cell is the lowest level) // now we process cell children, if any exist - if ($D($$$DeepSeeAxisGLVN(CubeIndex, AxisKey, "axes", Node, "ch")) = 10) { + if ($D($$$DeepSeeAxisGLVN(CubeIndex, AxisKey, "axes", Node, "ch")) = 10) && ($LG(tNode, 1)'="agg") { set cell.children = $$$NewDynObjList set key = $O($$$DeepSeeAxisGLVN(CubeIndex, AxisKey, "axes", Node, "ch", "")) while (key'="") { @@ -154,23 +154,23 @@ Method ProcessOneAxisCell(CubeIndex, AxisKey, CubeName, QueryKey, AxisNumber, No if (..IsCellNull(cell, AxisNumber, Node)=1) { return cell.children } - + try { set cell.path = ##class(%DeepSee.Query.Engine).%GetSpecForAxisNode(CubeName, QueryKey, AxisNumber, Node) // MDX cell path set:$e(cell.path)="(" cell.path = $e(cell.path, 2, *-1) // removing redundant parentheses } catch ex { set cell.path = "path too long" } - + set cell.format = $LG(tNode,12) // format for numbers, eg: $## ###.## set cell.total = $LG(tNode,8) //COUNT,AVG function set cell.type = $LG(tNode,1) // mbr,cmbr,lit,exp set cell.valueID = $LG(tNode,6) // id in mdx dimension for mbr, path for cmbr set cell.title = $LG(tNode,23) - + set cell.headerStyle = $LG(tNode,19) set cell.cellStyle = $LG(tNode,18) - + set info = $LG(tNode,18) if info'="" { // extract aggregation information, leave the rest as css set summaryposition = $f(info,"summary") @@ -181,7 +181,7 @@ Method ProcessOneAxisCell(CubeIndex, AxisKey, CubeName, QueryKey, AxisNumber, No } set cell.style = info // css } - + set tDimNo = $LG(tNode,9) set tHierNo = $LG(tNode,10) set tLevelNo = $LG(tNode,11) @@ -190,7 +190,7 @@ Method ProcessOneAxisCell(CubeIndex, AxisKey, CubeName, QueryKey, AxisNumber, No do ##class(%DeepSee.Utils).%GetDimensionCaption(CubeName,tDimNo, tHierNo,tLevelNo, .tAxisCaption) set cell.dimension = tCaption // cube dimension taken from the name of the axes. if (cell.dimension = "") {set cell.dimension = tCaption} // hack for assigne dimension property in case of empty dimension - + set:$$$Debug cell.visible = '..IsCellNull(cell,AxisNumber,Node) set:$$$Debug cell.node = Node diff --git a/MDX2JSON/Utils.cls b/MDX2JSON/Utils.cls index 806010d..835322d 100644 --- a/MDX2JSON/Utils.cls +++ b/MDX2JSON/Utils.cls @@ -53,21 +53,65 @@ ClassMethod ExecuteResultSet(RS As MDX2JSON.ResultSet, QueryKey As %String = "", quit Status } +ClassMethod QuerySet(MDX) As %Status +{ + set ^Query($I(^Query), "%dsQuery") = MDX +} + /// Automatic processing of MDX query and outputting resulting JSON.
/// MDX - String containing MDX query.
ClassMethod WriteJSONfromMDX(MDX As %String, Timeout As %Integer = 0) As %Status { + Set tSC = $$$OK #dim RS As MDX2JSON.ResultSet - set RS = ..GetResultSet(MDX, .st) - return:$$$ISERR(st) st + + set RS = ..GetResultSet(MDX, .tSC) + set cube = ##class(%DeepSee.Utils).%IsCubeCompound(RS.%Cube) // check if cube is compound type + return:$$$ISERR(tSC) tSC + + if cube // if cube is compound then we prepare it using %ZEN.Auxiliary.jsonMDXProvider + { + Set tProvider = ##class(%ZEN.Auxiliary.jsonMDXProvider).%New() + Set tProvider.mdxQuery = MDX + Set tWait = %session.AppTimeout - $S(%session.AppTimeout>2:2,1:0) // Send something back jst before the appTimeout is reached + Set tSC = ##class(%DeepSee.REST.v1.DataServer).%WaitForProviderResults(tProvider,tWait) - set st = ..ExecuteResultSet(RS, , Timeout) - return:$$$ISERR(st) st + set tSC = ..ExecuteResultSet(RS, ,Timeout) + return:$$$ISERR(tSC) tSC - set obj = RS.ToProxyObject(.st) - return:$$$ISERR(st) st - $$$DynObjToJSON(obj) + set obj = RS.ToProxyObject(.tSC) + return:$$$ISERR(tSC) tSC + + set %dsQuery = MDX + + // initiate an RS object to a global variable %dsResultSet + set %dsResultSet = RS + + set %dsCubeName = RS.%Cube + + // check if audit global hold something and execute it + try {xecute ^DeepSee.AuditQueryCode} catch {} + + $$$DynObjToJSON(obj) + }else{ // if cube is not compound execute the query in usual way + + set tSC = ..ExecuteResultSet(RS, ,Timeout) + return:$$$ISERR(tSC) tSC + + set obj = RS.ToProxyObject(.tSC) + return:$$$ISERR(tSC) tSC + + set %dsQuery = MDX + set %dsResultSet = RS + + // check if audit global hold something and execute it + try {xecute ^DeepSee.AuditQueryCode} catch {} + + $$$DynObjToJSON(obj) + } + + return $$$OK } @@ -89,6 +133,92 @@ ClassMethod WriteJSONfromQuery(CubeKey As %String, QueryKey As %String, Timeout return $$$OK } +/// Execute SQL query taken from KPI and extract column values by name of column +/// Output array with list of values like so pValue(n) = $LB(sNameList(i)...) +ClassMethod GetSQLValues(pSQL, Output pValues As %String, Output tResultSet As %SQL.Statement) As %Status +{ + + set st = $$$OK + Set tResultSet = ##class(%SQL.Statement).%ExecDirect(,pSQL) + set tCount = 0 + + while tResultSet.%Next() + { + set lValue = "" + for i=1:1:tResultSet.%GetMetadata().columnCount + { + set sNameList(i) = tResultSet.%GetMetadata().columns.GetAt(i).label + set lValue = lValue _ $lb(tResultSet.%Get(sNameList(i))) // append next column to the list + } + + Set tCount = tCount + 1 + set pValues(tCount) = lValue + } + return st +} + +/// This method provides listing execution for KPI. +/// tKPI as a name of KPI class. pFilters not yet implemented +/// as a pSelection. Thats for future use. +ClassMethod WriteDrillthroughJSONKPI(tKPI As %String, pFilters As %String, pSelection As %String) As %Status +{ + + Set st = $$$OK + + Set tKpiClassName = ##class(%DeepSee.Utils).%GetKPIClass(tKPI,.tSC) // get name of a kpi from REST + set kpitype = $classmethod(tKpiClassName, "%GetSourceType") + + if (kpitype="sql") { + set pSQL = $classmethod(tKpiClassName,"%OnGetListingSQL",pFilters,pSelection) // invoke corresponding method from given kpi and get sql query + set values = ..GetSQLValues(pSQL, .pValue, .tResultSet) + + for i=1:1:tResultSet.%GetMetadata().columnCount + { + set pList(i) = tResultSet.%GetMetadata().columns.GetAt(i).label + set pList(i, "columnNo") = i + Set tKpiPropIdx = $O(pList(""),1,tProperty) + Set tKpiPropList = "" + While (tKpiPropIdx'="") { + Set tKpiPropList = tKpiPropList _ $LB(tProperty) + Set tKpiPropArray(tKpiPropIdx) = $LB(tProperty,$G(pList(tKpiPropIdx,"name")),$G(pList(tKpiPropIdx,"columnNo"))) + Set tKpiPropIdx = $O(pList(tKpiPropIdx),1,tProperty) + + } + + } + Set tKpiSC = $classmethod(tKpiClassName,"%GetKPIValueArray",tKpiClassName,,.tKpiPropList,.tFilters) + + Set tSC = ##class(%DeepSee.REST.v1.DataServer).%CreateObjectFromArray(.pValue,tKpiPropList,.tValueObj) + If $$$ISERR(tSC) Quit + + Set tSC = ##class(%DeepSee.REST.v1.DataServer).%CreateObjectFromArray(.tKpiPropArray,$LB("name","caption","columnNo"),.tPropObj) + If $$$ISERR(tSC) + + // Use consistent objects for normalized return + Set tProvider = ##class(%ZEN.Auxiliary.jsonMDXProvider).%New() + Set tInfoObj = tProvider.%ConstructNewDynamicObject() + Set tResultObj = tProvider.%ConstructNewDynamicObject() + + Set:$IsObject(tPropObj.children) tResultObj.Properties = tPropObj.children + Set:$IsObject(tValueObj.children) tResultObj.Series = tValueObj.children + + Set tInfoObj.Error = tProvider.%StatusToDynamicObject(tKpiSC) + Set tInfoObj.KpiName = tKpiClassName + + Set tKpiObj = tProvider.%ConstructNewDynamicObject() + Set tKpiObj.Info = tInfoObj + Set tKpiObj.Result = tResultObj + + Set tSC = tProvider.%ObjectToJSON(tKpiObj) + + }else{ + + quit $$$ERROR($$$GeneralError, "KPI type " _ kpitype _ " not supported") + } + + return st +} + /// Automatic processing of MDX query and outputting resulting JSONP.
/// pMDX - String containing MDX query.
ClassMethod WriteJSONPfromMDX(pMDX As %String) As %Status @@ -128,7 +258,25 @@ ClassMethod WriteDrillthroughJSON(pMDX As %String) As %Status return:$$$ISERR(st) st set SQL = RS.%GetListingSQL() - do ##class(%ZEN.Auxiliary.altJSONSQLProvider).%WriteJSONFromSQL(,SQL,,$$$MaxCacheInt) + + set rs = ##class(%SQL.Statement).%ExecDirect(, SQL) + set list = [] + + while rs.%Next() { + set row = {} + for i=1:1:rs.%ResultColumnCount { + set colName = rs.%GetMetadata().columns.GetAt(i).colName + set colValue = rs.%GetData(i) + do row.%Set(colName, colValue) + } + do list.%Push(row) + } + + set result = { + "children": (list) + } + + do result.%ToJSON(.stream) return $$$OK } @@ -202,8 +350,8 @@ ClassMethod GetDataSource(pDataSource As %String) set st = $$$OK try { - - if ($FIND(pDataSource, ".pivot") = ($LENGTH(pDataSource) + 1)) { + + if ($FIND(pDataSource, ".pivot") = ($LENGTH(pDataSource) + 1) && pDataSource '="") { set st = ..OpenPivotByName(pDataSource, .dataSource) return:($$$ISERR(st)) st @@ -215,6 +363,7 @@ ClassMethod GetDataSource(pDataSource As %String) set st = ##class(%ZEN.Auxiliary.jsonProvider).%ObjectToJSON(dataSource, .out) } + } catch ex { set st = ex.AsStatus() @@ -302,12 +451,19 @@ ClassMethod GetWidgetsList(pDashName As %String) As %Status ClassMethod GetDashboard(pDashName As %String) As %Status { try { + set st = ##class(MDX2JSON.DashboardFilters).OpenDashboardByName(pDashName, .dash) return:($$$ISERR(st)) st set st = ##class(MDX2JSON.DashboardFilters).WidgetsToProxyObject(dash, .widgetlist) return:($$$ISERR(st)) st w "" // weird hack required for 15.3 + + set %dsDashboard = pDashName + + // check if audit global hold something and execute it + try {xecute ^DeepSee.AuditCode} catch {} + $$$DynObjToJSON(widgetlist) } catch ex { set st = ex.AsStatus() @@ -316,6 +472,42 @@ ClassMethod GetDashboard(pDashName As %String) As %Status return st } +/// the method initiate the audit for %dsDashboard +ClassMethod SetAuditCode() As %Status +{ + set ^DeepSee.AuditCode = "Do ##class(MDX2JSON.Utils).SetAuditDash()" + + quit $$$OK +} + +/// the method initiate the audit for %dsQueryText, %dsCubeName, %dsResultSet +ClassMethod SetAuditQueryCode() As %Status +{ + set ^DeepSee.AuditQueryCode = "Do ##class(MDX2JSON.Utils).SetAuditQuery()" + + quit $$$OK +} + +/// zw ^AuditLogDash to get the dashboard audit dashboard readings +ClassMethod SetAuditDash() As %Status +{ + set ^AuditLogDash($INCREMENT(^AuditLogDash),"%dsDashoard") = %dsDashboard + + quit $$$OK +} + +/// zw ^AuditLogQuery to get the query audit readings +/// zw ^AuditLogCube to get the cube audit readings +/// zw ^AuditLogRS to get the RS audit readings +ClassMethod SetAuditQuery() As %Status +{ + set ^AuditLogQuery($INCREMENT(^AuditLogQuery),"%dsQueryText") = %dsQueryText + set ^AuditLogCube($INCREMENT(^AuditLogQuery),"%dsCubeName") = %dsCubeName + set ^AuditLogRS($INCREMENT(^AuditLogRS),"%dsResultSet") = %dsResultSet + + quit $$$OK +} + /// Get format defaults. ClassMethod GetFormat() As %Status { @@ -450,4 +642,162 @@ ClassMethod CreateAddonClass(Class As %Dictionary.CacheClassname) As %Status quit classObj.%Save() } +/// Add new widgets and edit existing ones directly from DeepSeeWeb +/// it takes widget name(key) as unique identifier as string, dashboard name as string +/// and object with parameters as zen.proxyObject +ClassMethod AddWidget(sWidget As %String, sDashboard As %String, key As %String) As %Status +{ + set st = $$$OK + set dExist=##class(%DeepSee.Dashboard.Utils).%DashboardExists(sDashboard) + + // Check if dashboard exists + If (dExist '= 1) + { + Quit $$$ERROR($$$GeneralError,"Dashboard " _ sDashboard _ " does not exists") + } + Set tDash=##class(%DeepSee.Dashboard.Utils).%OpenDashboard(sDashboard, .st) + + // Check if widget with name is exists + set isExists = 0 + for i=1:1:tDash.widgets.Count() + { + if (tDash.widgets.GetAt(i).name = sWidget.name) + { + set isExists = 1 + } + } + + // Adding new widget + if ($LENGTH(key) = 0) { // if key received empty then we expect new widget if not then else logic is working + // Check if we trying to create widget with exists name + if (isExists = 1) { + return $$$ERROR($$$GeneralError,"Widget " _ sWidget.name _ " already exists") + } + + set tWidgets = ##class(%DeepSee.Dashboard.Widget).%New() + set st = ..UpdateWidget(tWidgets, sWidget) + + if (st = $$$OK) // checking for errors in UpdateWidget + { + $$$Insert(tDash.widgets, tWidgets) + do tDash.%Save() + } + + } else { + // Edit exists widget + for i=1:1:tDash.widgets.Count() + { + + set dWidgets = tDash.widgets.GetAt(i) + + // Check if we trying to change widget name with exists one + if ((dWidgets.name '= key) && (dWidgets.name = sWidget.name)) { + return $$$ERROR($$$GeneralError,"Widget " _ sWidget.name _ " already exists") + + } + + if (dWidgets.name = key) + { + set changed = dWidgets + } + } + if (changed '= "") { + set st = ..UpdateWidget(changed, sWidget) + if (st = $$$OK) // checking for errors in UpdateWidget + { + do tDash.%Save() + } + } + } + + return st +} + +/// This method remove widget from dashboard directly from DeepSeeWeb +/// it takes widget name as unique identifier and dashboard name +ClassMethod DeleteWidget(wName As %String, sDashboard As %String) As %Status +{ + set st = $$$OK + + set dExist=##class(%DeepSee.Dashboard.Utils).%DashboardExists(sDashboard) + + // Check if dashboard exists + If (dExist '= 1) + { + Quit $$$ERROR($$$GeneralError,"Dashboard " _ sDashboard _ " does not exists") + } + Set tDash=##class(%DeepSee.Dashboard.Utils).%OpenDashboard(sDashboard, .st) + + // Check if widget with name is exists + set isExists = 0 + for i=1:1:tDash.widgets.Count() + { + if (tDash.widgets.GetAt(i).name = wName) + { + set isExists = 1 + } + } + + if (isExists = 1) + { + for i=1:1:tDash.widgets.Count() + { + if (tDash.widgets.GetAt(i).name = wName) + { + do tDash.widgets.RemoveAt(i) + do tDash.%Save() + } + } + }else + { + quit $$$ERROR($$$GeneralError,"Widget " _ wName _ " is not exists") + + } + + return st } + +/// the collection of necessary parameters for building widget +ClassMethod UpdateWidget(widgetToUpdate As %DeepSee.Dashboard.Widget, data As %ZEN.proxyObject) As %Status +{ + set st = $$$OK + + set widgetToUpdate.name = data.name + set widgetToUpdate.title = data.title + if (data.dataSource = "") + { + quit $$$ERROR($$$GeneralError,"Parameter DataSource is not set") + }else + { + set widgetToUpdate.dataSource = data.dataSource + } + + set widgetToUpdate.dataLink = data.dataLink + + if (data.type = "pivot") + { + set widgetToUpdate.type = "pivot" + set widgetToUpdate.subtype = "pivot" + } + elseif (data.type '= "pivot") + { + set widgetToUpdate.type = "pivot" + set widgetToUpdate.subtype = data.type + } + + if (data.displayInfo '= "") { + set widgetToUpdate.top = data.displayInfo.top + set widgetToUpdate.left = data.displayInfo.left + set widgetToUpdate.width = data.displayInfo.width + set widgetToUpdate.height = data.displayInfo.height + set widgetToUpdate.homeColL = data.displayInfo.topCol + set widgetToUpdate.homeRowL = data.displayInfo.leftRow + set widgetToUpdate.colSpanL = data.displayInfo.colWidth + set widgetToUpdate.rowSpanL = data.displayInfo.rowHeight + } + + return st +} + +} + diff --git a/module.xml b/module.xml index 73b27b1..421185b 100644 --- a/module.xml +++ b/module.xml @@ -2,7 +2,7 @@ MDX2JSON - 3.2.18 + 3.2.50 RESTful web api for MDX to JSON transformation (plus JSONP and XML/A) for InterSystems IRIS. Also provides information about DeepSee objects. module ./