go to post Timothy Leavitt · Jan 15, 2020 1. Suppose $TLevel > (tInitTLevel + 1). That means that someone else's transaction was left open. You can't always guarantee that the code you're calling will behave by matching tstart with tcommit or trollback 1, but you can account for the possibility of your dependency misbehaving in your own transaction cleanup. Agreed on never using argumentless trollback. 2. Great point - updated accordingly.
go to post Timothy Leavitt · Dec 16, 2019 I think the answers so far have missed the point. The number of arguments itself is variable. This is handy for things like building a complex SQL statement and set of arguments to pass to %SQL.Statement:%Execute, for example. The data structure here is an integer-subscripted array with the top node set to the number of elements. (The top node is what's missing in the example above). Subscripts can be missing to leave the argument at that position undefined. Here's a simple example: Class DC.Demo.VarArgs { ClassMethod Driver() { Do ..PrintN(1,2,3) Write !! For i=1:1:4 { Set arg($i(arg)) = i } Kill arg(3) ZWrite arg Write ! Do ..PrintN(arg...) } ClassMethod PrintN(pArgs...) { For i=1:1:$Get(pArgs) { Write $Get(pArgs(i),"<undefined>"),! } } } Output is: d ##class(DC.Demo.VarArgs).Driver()123arg=4arg(1)=1arg(2)=2arg(4)=412<undefined>4
go to post Timothy Leavitt · Dec 16, 2019 For bootstrap-table, I think the examples on their site are probably more useful than anything I could dig up. https://examples.bootstrap-table.com/#welcomes/large-data.html shows pretty good performance for a large dataset. Tabulator looks nice too though. In any case it would probably be cleanest to load data via REST rather than rendering everything in the page in an HTML table and then using a library to make the table pretty.
go to post Timothy Leavitt · Dec 12, 2019 Another option rather than having two versions of the whole codebase could be having a wrapper module around webterminal (i.e., another module that depends on webterminal) with hooks in webterminal to allow that wrapper to turn off projection-based installation-related features.
go to post Timothy Leavitt · Dec 12, 2019 From the pros/cons, it seems the objectives are: Maintain compatibility with normal installation (without ZPM) Make side effects from installation/uninstallation auditable by putting them in module.xml I'd suggest as one approach to accomplish both objectives: Suppress the projection side effects when running in a package manager installation/uninstallation context (either by checking $STACK or using some trickier under-the-hood things with singletons from the package manager - regardless, be sure to unit test this behavior!). Add "Resource Processor" classes (specified in module.xml with Preload="true" and not included in normal WebTerminal XML exports used for non-ZPM installation) - that is, classes extending %ZPM.PackageManager.Developer.Processor.Abstract and overriding the appropriate methods - to handle your custom installation things. You can then use these in your module manifest, provided that such inversion of control still works without bootstrapping issues following changes made in https://github.com/intersystems-community/zpm. Generally-useful things like creating a %All namespace should probably be pushed back to zpm itself.
go to post Timothy Leavitt · Nov 21, 2019 This is nifty! Note, you can make the extent manager happy by using: Class DC.Demo.SometimesPersistent Extends %Persistent { Property Foo As %String; ClassMethod Demo() { New %storage,%fooD,%fooI,%fooS Set obj = ##class(DC.Demo.SometimesPersistent).%New() Set obj.Foo = "bar" Set %storage = "%foo" Write !,obj.%Save() Kill obj Set obj = ..%OpenId(1) w ! zw obj zw %fooD } Storage Default { <Data name="SometimesPersistentDefaultData"> <Value name="1"> <Value>%%CLASSNAME</Value> </Value> <Value name="2"> <Value>Foo</Value> </Value> </Data> <DataLocation>@($Get(%storage,"^DC.Demo.SometimesPersistent")_"D")</DataLocation> <DefaultData>SometimesPersistentDefaultData</DefaultData> <IdLocation>@($Get(%storage,"^DC.Demo.SometimesPersistent")_"D")</IdLocation> <IndexLocation>@($Get(%storage,"^DC.Demo.SometimesPersistent")_"I")</IndexLocation> <StreamLocation>@($Get(%storage,"^DC.Demo.SometimesPersistent")_"S")</StreamLocation> <Type>%Library.CacheStorage</Type> } }
go to post Timothy Leavitt · Nov 5, 2019 %EXTERNAL and %INTERNAL may also be useful, to force a particular format independent of the mode the query is running in. See: https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=RSQL_externalhttps://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=RSQL_internal
go to post Timothy Leavitt · Oct 21, 2019 Hi Steve, We (Application Services - internal applications @ InterSystems) use %UnitTest with some extensions. We have a base Unit Test case that has a "run this test" helper method (among other things), a wrapper around %UnitTest.Manager that makes it easier to run all the tests without deleting them (and with some other features optionally enabled, like test coverage measurement - see a video of my 2018 Global Summit presentation on this here). Our wrapper also loads all of the unit tests before running any, which allows unit tests to extend classes within the unit test root in different packages from their own. I agree with @Eduard Lebedyuk that %UnitTest meets our needs well aside from the lack of parallelization. A parallel %UnitTest runner would be an interesting project indeed... We routinely run unit tests via Jenkins CI, report test results in the jUnit format, and also report on code coverage (Cobertura-style) and a complexity/coverage scatter plot. For automated UI testing, Selenium/Cucumber has worked well for older Zen/CSP UIs. True unit testing of newer UIs (e.g,. Jasmine and Karma for Angular) is handy too.
go to post Timothy Leavitt · Oct 18, 2019 Disclaimer: I know more about what John is doing than is covered in the post. It looks like, for the prebuilt themes, Angular Material itself uses Bazel (see introduction at https://angular.io/guide/bazel). The relevant bits are here: https://github.com/angular/components/blob/master/src/material/prebuilt-themes/BUILD.bazelhttps://github.com/angular/components/blob/master/src/material/core/BUILD.bazelhttps://github.com/angular/components/blob/master/src/material/BUILD.bazel I think that's probably the place to start, in terms of Angular 8 best practices.
go to post Timothy Leavitt · Sep 5, 2019 Other answers are good. I'll also add, if you're running from Terminal, you can go to File > Logging... and have all the output logged to a file. (This works for other things that produce output too, not just CompileAll.)
go to post Timothy Leavitt · Sep 5, 2019 Fun fact, you can also order by the column by number.In this case:select top 5 Description,Category,* from Cinema.Film order by 2
go to post Timothy Leavitt · Sep 4, 2019 With correct web server configuration to route everything through the CSPGateway, the above example should handle URLs for other resources like that without issue (as long as the content served by the dashboard server has relative links to those endpoints, not absolute) - that's the point of the <base> element.In my sample use case, it also handles several requests for images and other assets.
go to post Timothy Leavitt · Sep 4, 2019 I don't think it's totally stupid. We're looking at doing something similar with another technology (JReport).Here's a code sample to help you get started - just change the port / page / filters / permission checks appropriately. Class Demo.CSPProxy Extends %CSP.Page { Parameter HOST = "127.0.0.1"; Parameter PORT = 8888; Parameter PAGE = "jinfonet/runReport.jsp"; /// Event handler for <b>PreHTTP</b> event: this is invoked before /// the HTTP headers for a CSP page have been sent. All changes to the /// <class>%CSP.Response</class> class, such as adding cookies, HTTP headers, /// setting the content type etc. must be made from within the OnPreHTTP() method. /// Also changes to the state of the CSP application such as changing /// %session.EndSession or %session.AppTimeout must be made within the OnPreHTTP() method. /// It is prefered that changes to %session.Preserve are also made in the OnPreHTTP() method /// as this is more efficient, although it is supported in any section of the page. /// Return <b>0</b> to prevent <method>OnPage</method> from being called. ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ] { Set request = ##class(%Net.HttpRequest).%New() Set request.Server = ..#HOST Set request.Port = ..#PORT // TODO: Add other stuff here, like authentication. Set page = $Piece(%request.CgiEnvs("REQUEST_URI"),"/"_$classname()_".cls/",2) If (page = "") { Set %base = $classname()_".cls/"_$Piece(..#PAGE,"/",1,*-1)_"/" // TODO: add query parameters from %request to the URL requested below. $$$ThrowOnError(request.Get(..#PAGE)) } Else { Set fullPage = "http://"_..#HOST_":"_..#PORT_"/"_page Do ##class(%Net.URLParser).Parse(fullPage,.parts) // TODO: Better way of checking the requested resource. If $Piece($Piece(parts("path"),"/",*),".",2) = "jsp" { Set %response.Status = ##class(%CSP.REST).#HTTP403FORBIDDEN Quit 0 } $$$ThrowOnError(request.Send(%request.Method,page)) } Set %data = request.HttpResponse.Data // TODO: Do any other headers matter? Set %response.Status = request.HttpResponse.StatusCode Set %response.ContentType = request.HttpResponse.ContentType Quit 1 } /// Event handler for <b>PAGE</b> event: this is invoked in order to /// generate the content of a csp page. ClassMethod OnPage() As %Status [ ServerOnly = 1 ] { If (%response.ContentType [ "html") && $Data(%base) { &html<<base href="#(..EscapeHTML(%base))#">> Do %data.OutputToDevice() } Else { Do %data.OutputToDevice() } Quit $$$OK } }
go to post Timothy Leavitt · Apr 1, 2019 A few weird things with custom login pages:CSPSystem needs read permission on the DB containing them. (You'll need to close CSPGateway connections after making this change so that it can reconnect with the right privileges.)It's specified with the ".cls" extension in the web application configuration, not just the classname.
go to post Timothy Leavitt · Mar 12, 2019 In my experience, code coverage measurement is useful even in development. It helps identify areas that are untested as you're writing tests.
go to post Timothy Leavitt · Mar 8, 2019 Hi Robert,Access rights are part of my concern. You can connect using an SSL/TLS configuration without having read permission on %DB_CACHESYS (or the IRIS equivalent).
go to post Timothy Leavitt · Jan 15, 2019 You should check the SQLCODE from running that statement. If SQLCODE is 100 (no record exists with the specified key), KeyID may not be defined.See: https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GSQL_esql#GSQL_esql_hvars
go to post Timothy Leavitt · Jan 14, 2019 This sounds like it could be an issue with caching (at the browser level rather than at the CSPGateway level, given that the page loads just fine in a different browser). Perhaps try clearing the cache in the Android browser then reloading the page?
go to post Timothy Leavitt · Jan 3, 2019 Generally speaking, I'd design this as a relationship to a set of "roles" that can be added or removed. (What if the person ceases to be a Doctor?) Methods of the person would dispatch to the roles.