├── .babelrc
├── .gitignore
├── Dockerfile
├── archive
├── WebTerminal-0.4-stable.xml
├── WebTerminal-0.6-dev.xml
├── WebTerminal-0.6.7-stable.xml
├── WebTerminal-0.85-dev.xml
├── WebTerminal-0.89-dev.xml
├── WebTerminal-0.9-dev.xml
├── WebTerminal-0.9.1-stable.xml
├── WebTerminal-0.9.5-stable.xml
├── WebTerminal-0.9.6-stable.xml
├── WebTerminal-0.9.6.8-dev.xml
├── WebTerminal-0.9.7-stable.xml
├── WebTerminal-0.9.7.8-dev.xml
├── WebTerminal-0.9.9-stable.xml
├── WebTerminal-0.9.9.5-dev.xml
├── WebTerminal-0.9.9.7-dev.xml
├── WebTerminal-0.9.9.8-dev.xml
├── WebTerminal-2.0.0-alpha.1.xml
├── WebTerminal-2.0.0-beta.1.xml
├── WebTerminal-2.0.0-beta.2.xml
├── WebTerminal-2.0.0-beta.3.xml
├── WebTerminal-2.0.0-beta.4.xml
├── WebTerminal-2.0.0-beta.5.xml
├── WebTerminal-2.0.0-beta.6.xml
└── WebTerminal-2.0.0-beta.xml
├── build
└── cls
│ └── WebTerminal
│ ├── Analytics.cls
│ ├── Autocomplete.cls
│ ├── Common.cls
│ ├── Core.cls
│ ├── Engine.cls
│ ├── ErrorDecomposer.cls
│ ├── Handlers.cls
│ ├── Installer.cls
│ ├── Router.cls
│ ├── StaticContent.cls
│ ├── Trace.cls
│ └── Updater.cls
├── contributing.md
├── docker-compose.yml
├── docs
├── css
│ ├── content.css
│ └── main.css
├── favicon.ico
├── files
│ ├── CacheWebTerminal-v3.1.4.xml
│ ├── CacheWebTerminal-v3.1.5.xml
│ ├── CacheWebTerminal-v3.2.0.xml
│ ├── CacheWebTerminal-v3.2.2.xml
│ ├── CacheWebTerminal-v3.2.5.xml
│ ├── CacheWebTerminal-v3.2.7.xml
│ ├── CacheWebTerminal-v3.3.0.xml
│ ├── CacheWebTerminal-v3.3.1.xml
│ ├── WebTerminal-0.9.9.9-dev.xml
│ ├── WebTerminal-1.0-stable-beta.xml
│ ├── WebTerminal-2.0.0-beta.7.xml
│ ├── WebTerminal-2.0.0-beta.8.xml
│ ├── WebTerminal-3.0.0-alpha.5.xml
│ ├── WebTerminal-3.0.0-alpha.6.xml
│ ├── WebTerminal-3.1.3.xml
│ ├── WebTerminal-v4.0.0-alpha.10.xml
│ ├── WebTerminal-v4.0.0-alpha.15.xml
│ ├── WebTerminal-v4.0.0-alpha.2.xml
│ ├── WebTerminal-v4.0.0-alpha.26.xml
│ ├── WebTerminal-v4.0.0-alpha.3.xml
│ ├── WebTerminal-v4.0.0-alpha.31.xml
│ ├── WebTerminal-v4.0.0-alpha.33.xml
│ ├── WebTerminal-v4.0.0-alpha.4.xml
│ ├── WebTerminal-v4.0.0-alpha.41.xml
│ ├── WebTerminal-v4.0.0-alpha.44.xml
│ ├── WebTerminal-v4.0.0-alpha.5.xml
│ ├── WebTerminal-v4.0.0-alpha.50.xml
│ ├── WebTerminal-v4.0.0-alpha.51-broken.xml
│ ├── WebTerminal-v4.0.0-alpha.53.xml
│ ├── WebTerminal-v4.0.0-alpha.55.xml
│ ├── WebTerminal-v4.0.0-alpha.57.xml
│ ├── WebTerminal-v4.0.0-alpha.58.xml
│ ├── WebTerminal-v4.0.0-alpha.66.xml
│ ├── WebTerminal-v4.0.0-alpha.68.xml
│ ├── WebTerminal-v4.0.0-alpha.71.xml
│ ├── WebTerminal-v4.0.0-alpha.73.xml
│ ├── WebTerminal-v4.0.0-alpha.75.xml
│ ├── WebTerminal-v4.0.0-alpha.8.xml
│ ├── WebTerminal-v4.0.0-beta.1.xml
│ ├── WebTerminal-v4.0.0-beta.11.xml
│ ├── WebTerminal-v4.0.0-beta.12.xml
│ ├── WebTerminal-v4.0.0-beta.14.xml
│ ├── WebTerminal-v4.0.0-beta.16.xml
│ ├── WebTerminal-v4.0.0-beta.17.xml
│ ├── WebTerminal-v4.0.0-beta.3.xml
│ ├── WebTerminal-v4.0.0-beta.4.xml
│ ├── WebTerminal-v4.0.0-beta.5.xml
│ ├── WebTerminal-v4.0.0-beta.6.xml
│ ├── WebTerminal-v4.0.0-beta.7.xml
│ ├── WebTerminal-v4.0.0-beta.8.xml
│ ├── WebTerminal-v4.0.0.xml
│ ├── WebTerminal-v4.1.1.xml
│ ├── WebTerminal-v4.1.2.xml
│ ├── WebTerminal-v4.2.0.xml
│ ├── WebTerminal-v4.2.12.xml
│ ├── WebTerminal-v4.2.13.xml
│ ├── WebTerminal-v4.2.14.xml
│ ├── WebTerminal-v4.2.15.xml
│ ├── WebTerminal-v4.2.2.xml
│ ├── WebTerminal-v4.2.3.xml
│ ├── WebTerminal-v4.2.6.xml
│ ├── WebTerminal-v4.2.8.xml
│ ├── WebTerminal-v4.3.0.xml
│ ├── WebTerminal-v4.3.1.xml
│ ├── WebTerminal-v4.4.1.xml
│ ├── WebTerminal-v4.5.0.xml
│ ├── WebTerminal-v4.6.0.xml
│ ├── WebTerminal-v4.6.1.xml
│ ├── WebTerminal-v4.6.3.xml
│ ├── WebTerminal-v4.7.0.xml
│ ├── WebTerminal-v4.7.3.xml
│ ├── WebTerminal-v4.7.4.xml
│ ├── WebTerminal-v4.8.0.xml
│ ├── WebTerminal-v4.8.3.xml
│ ├── WebTerminal-v4.9.0.xml
│ ├── WebTerminal-v4.9.1.xml
│ ├── WebTerminal-v4.9.2.xml
│ ├── WebTerminal-v4.9.3.xml
│ ├── WebTerminal-v4.9.4.xml
│ └── WebTerminal-v4.9.5.xml
├── img
│ ├── WebTerminal Preview.png
│ ├── back.png
│ ├── fork.png
│ ├── icons
│ │ ├── docs.png
│ │ ├── download.png
│ │ ├── feedback.png
│ │ ├── images.png
│ │ ├── save.png
│ │ └── terminal.png
│ ├── logos.png
│ └── screenshoots
│ │ ├── ac.png
│ │ ├── features-config.png
│ │ ├── features-help.png
│ │ ├── features-mobile.png
│ │ ├── install-steps.png
│ │ ├── scr4.png
│ │ └── showcase-slq-mode.png
├── index.html
├── latestNightVersion
├── latestVersion
├── readme.md
└── terminal.json
├── gulpfile.babel.js
├── import.bat
├── iris.script
├── issue_template.md
├── license
├── module.xml
├── package.json
├── readme.md
└── src
├── client
├── index.html
├── js
│ ├── analytics
│ │ └── index.js
│ ├── autocomplete
│ │ ├── hint.js
│ │ ├── index.js
│ │ └── types.js
│ ├── config.js
│ ├── elements.js
│ ├── favorite.js
│ ├── index.js
│ ├── init.js
│ ├── input
│ │ ├── caret.js
│ │ ├── handlers.js
│ │ ├── history.js
│ │ ├── index.js
│ │ └── special.js
│ ├── lib.js
│ ├── localization
│ │ ├── dictionary.js
│ │ └── index.js
│ ├── network
│ │ ├── index.js
│ │ └── update.js
│ ├── output
│ │ ├── Line.js
│ │ ├── const.js
│ │ ├── esc.js
│ │ ├── escStateMachine.js
│ │ └── index.js
│ ├── parser
│ │ ├── _build.js
│ │ ├── grammar.js
│ │ ├── index.js
│ │ └── pushdownAutomaton.js
│ ├── server
│ │ ├── handlers.js
│ │ └── index.js
│ ├── settings.js
│ ├── storage.js
│ └── tracing
│ │ └── index.js
└── scss
│ ├── graphic.scss
│ ├── hintBox.scss
│ ├── index.scss
│ ├── mixins.scss
│ ├── terminal.scss
│ └── themes
│ └── cache.scss
├── cls
└── WebTerminal
│ ├── Analytics.cls
│ ├── Autocomplete.cls
│ ├── Common.cls
│ ├── Core.cls
│ ├── Engine.cls
│ ├── ErrorDecomposer.cls
│ ├── Handlers.cls
│ ├── Installer.cls
│ ├── Router.cls
│ ├── StaticContent.cls
│ ├── Trace.cls
│ └── Updater.cls
└── mac
└── WebTerminal
└── EscapeSequencesTest.mac
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015"]
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/
2 | build/
3 | node_modules/
4 | package-lock.json
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG IMAGE=intersystemsdc/iris-ml-community:latest as build
2 | FROM $IMAGE
3 |
4 | USER root
5 |
6 | WORKDIR /opt/irisapp
7 | RUN chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/irisapp
8 | USER ${ISC_PACKAGE_MGRUSER}
9 |
10 | COPY build build
11 | COPY module.xml module.xml
12 | COPY iris.script /tmp/iris.script
13 |
14 | RUN iris start IRIS \
15 | && iris session IRIS < /tmp/iris.script \
16 | && iris stop IRIS quietly
17 |
--------------------------------------------------------------------------------
/build/cls/WebTerminal/Analytics.cls:
--------------------------------------------------------------------------------
1 | /// This class includes methods which collect WebTerminal's analytics such as error and installation reports.
2 | Class WebTerminal.Analytics
3 | {
4 |
5 | /// This method sends a report about installation status, including error message if any errors happened.
6 | ClassMethod ReportInstallStatus(status As %Status = 1, type As %String = "Install") As %Status
7 | {
8 | set req = ##class(%Net.HttpRequest).%New()
9 | set req.Server = "www.google-analytics.com"
10 | do req.EntityBody.Write("v=1&tid=UA-83005064-2&cid="_##class(%SYS.System).InstanceGUID()
11 | _"&ds=web&an=WebTerminal&av="_##class(WebTerminal.Installer).#VERSION
12 | _"&t=event&aiid="_$ZCONVERT($zv, "O", "URL")_"&ec="_$ZCONVERT(type, "O", "URL")_"&ea="
13 | _$case($$$ISOK(status), 1: "Success", : "Failure")_"&el="
14 | _$ZCONVERT($System.Status.GetErrorText(status), "O", "URL"))
15 | try {
16 | return req.Post("/collect")
17 | } catch e {
18 | write "Unable to send analytics to " _ req.Server _ ", skipping analytics collection."
19 | return $$$OK
20 | }
21 | }
22 |
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/build/cls/WebTerminal/Autocomplete.cls:
--------------------------------------------------------------------------------
1 | Class WebTerminal.Autocomplete Extends Common
2 | {
3 |
4 | /// Returns a comma-delimited string of globals names in the namespace, which begin from "beginning".
5 | ClassMethod GetGlobals(namespace As %String = "%SYS", beginning As %String = "") As %String
6 | {
7 | set result = ""
8 | set pattern = beginning _ "*"
9 | new $Namespace
10 | set $Namespace = namespace
11 | set rset = ##class(%ResultSet).%New("%SYS.GlobalQuery:NameSpaceList")
12 | do rset.Execute($Namespace, pattern, 1)
13 | while (rset.Next()) {
14 | set result = result _ $case(result = "", 1:"", :",") _ rset.GetData(1)
15 | }
16 | return result
17 | }
18 |
19 | /// Returns a comma-delimited string of class names in the namespace, which begin from "beginning".
20 | ClassMethod GetClass(namespace As %String = "%SYS", beginning As %String = "") As %String
21 | {
22 | new $Namespace
23 | set $Namespace = namespace
24 | set pattern = $REPLACE(beginning, "%", "!%") _ "%"
25 | &sql(select LIST(ID) into :ids from %Dictionary.CompiledClass where ID like :pattern ESCAPE '!' and deployed <> 2)
26 | return ids
27 | }
28 |
29 | /// Returns a comma-delimited string of public class members (accessible through ##class() construction) in the class of namespace.
30 | ClassMethod GetPublicClassMembers(namespace As %String = "%SYS", className As %String = "", beginning As %String = "") As %String
31 | {
32 | new $Namespace
33 | set $Namespace = namespace
34 | set pattern = $REPLACE(beginning, "%", "!%") _ "%"
35 | &sql(select LIST(Name) into :names from %Dictionary.CompiledMethod WHERE parent=:className AND ClassMethod=1 AND Name like :pattern ESCAPE '!')
36 | return names
37 | }
38 |
39 | /// Returns a comma-delimited string of class members in the class of namespace.
40 | ClassMethod GetClassMembers(namespace As %String = "%SYS", className As %String = "", beginning As %String = "", methodsOnly = "") As %String
41 | {
42 | new $Namespace
43 | set $Namespace = namespace
44 | if $EXTRACT(beginning, 1) = "#" {
45 | set ps = ..GetParameters(namespace, className, $EXTRACT(beginning, 2, $LENGTH(beginning)))
46 | return:(ps = "") ps
47 | return "#"_$REPLACE(ps, ",", ",#")
48 | }
49 | set pattern = $REPLACE(beginning, "%", "!%") _ "%"
50 | set props = ""
51 | &sql(select LIST(Name) into :methods from %Dictionary.CompiledMethod WHERE parent=:className AND Private = 0 AND Name like :pattern ESCAPE '!')
52 | if (methodsOnly = "") {
53 | &sql(select LIST(Name) into :props from %Dictionary.CompiledProperty WHERE parent=:className AND Name like :pattern ESCAPE '!')
54 | }
55 | return $case((methods '= "") && (props '= ""), 1: methods _ "," _ props, : methods _ props)
56 | }
57 |
58 | /// Returns a comma-delimited string of class members in the class of namespace.
59 | ClassMethod GetParameters(namespace As %String = "%SYS", className As %String = "", beginning As %String = "") As %String
60 | {
61 | new $Namespace
62 | set $Namespace = namespace
63 | set pattern = $REPLACE(beginning, "%", "!%") _ "%"
64 | &sql(select LIST(Name) into :names from %Dictionary.CompiledParameter WHERE parent=:className AND Name like :pattern ESCAPE '!')
65 | return names
66 | }
67 |
68 | /// Returns a comma-delimited string of routine names in the namespace, which begin from "beginning".
69 | ClassMethod GetRoutines(namespace As %String = "%SYS", beginning As %String = "") As %String
70 | {
71 | set result = ""
72 | set pattern = beginning _ "*.*"
73 | new $Namespace
74 | set $Namespace = namespace
75 | set rset = ##class(%ResultSet).%New("%Library.Routine:RoutineList")
76 | do rset.Execute(pattern, , , $Namespace)
77 | while (rset.Next()) {
78 | set result = result _ $case(result = "", 1:"", :",") _ $PIECE(rset.GetData(1), ".", 1, *-1)
79 | }
80 | return result
81 | }
82 |
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/build/cls/WebTerminal/Common.cls:
--------------------------------------------------------------------------------
1 | Include %sySystem
2 |
3 | Class WebTerminal.Common
4 | {
5 |
6 | /// Interprocess communication cannot handle big messages at once, so they need to be split.
7 | Parameter ChunkSize = 45;
8 |
9 | /// Send the chunk of data to another process. The process need to receive the chunk with the
10 | /// appropriate function ReceiveChunk. Consider event length less than 44 characters long.
11 | ClassMethod SendChunk(pid As %Numeric, flag As %String, data As %String = "") As %Status
12 | {
13 | set pos = 1
14 | set len = $LENGTH(data) + 1 // send the last empty message if the data size = ChunkSize
15 | for {
16 | try {
17 | set st = $system.Event.Signal(
18 | pid,
19 | $LB(flag, $EXTRACT(data, pos, pos + ..#ChunkSize - 1))
20 | )
21 | } catch (e) { return $$$NOTOK }
22 | if (st '= 1) { return $$$NOTOK }
23 | set pos = pos + ..#ChunkSize
24 | if (pos > len) { quit }
25 | }
26 | return $$$OK
27 | }
28 |
29 | /// Receives the chunk of data from another process. Returns the $LISTBUILD string which contains
30 | /// flag at the first position and string at the second. This method also terminates the process
31 | /// if the parent process is gone.
32 | ClassMethod ReceiveChunk(timeout As %Numeric = -1, masterProcess = 0) As %String
33 | {
34 | set flag = ""
35 | set str = ""
36 | set status = -1
37 | for {
38 | set message = $system.Event.WaitMsg("", $Case(timeout = -1, 1: 1, :timeout))
39 | set status = $LISTGET(message, 1)
40 | set data = $LISTGET(message, 2)
41 | if (status <= 0) {
42 | if ($ZPARENT '= 0) && ('$data(^$Job($ZPARENT))) {
43 | do $system.Process.Terminate($JOB, 0)
44 | return $LISTBUILD("e", $LISTBUILD("", "Parent process "_$JOB_" is gone"), -1)
45 | }
46 | if masterProcess && ($ZCHILD '= 0) && ('$data(^$Job($ZCHILD))) {
47 | return $LISTBUILD("e", $LISTBUILD("", "Child process "_$ZCHILD_" is gone"), -1)
48 | }
49 | }
50 | if (data = "") && (timeout = 0) quit
51 | if (status <= 0) {
52 | set:(timeout = 0) timeout = 1
53 | continue
54 | }
55 | set flag = $LISTGET(data, 1)
56 | set m = $LISTGET(data, 2)
57 | set str = str _ m
58 | if (timeout = 0) set timeout = 1
59 | quit:($LENGTH(m) '= ..#ChunkSize)
60 | }
61 | return $LISTBUILD(flag, str, status)
62 | }
63 |
64 | /// Returns the contents of the proxy object to the current device in JSON format.
65 | /// This method is called when a proxy object is used in conjunction with
66 | /// the %ZEN.Auxiliary.jsonProvider component.
67 | /// format is a flags string to control output formatting options.
68 | /// The following character option codes are supported:
69 | /// 1-9 : indent with this number of spaces (4 is the default with the 'i' format specifier)
70 | /// a - output null arrays/objects
71 | /// b - line break before opening { of objects
72 | /// c - output the Caché-specific "_class" and "_id" properties (if a child property is an instance of a concrete object class)
73 | /// e - output empty object properties
74 | /// i - indent with 4 spaces unless 't' or 1-9
75 | /// l - output empty lists
76 | /// n - newline (lf)
77 | /// o - output empty arrays/objects
78 | /// q - output numeric values unquoted even when they come from a non-numeric property
79 | /// s - use strict JSON output - NOTE: special care should be taken when sending data to a browser, as using this flag
80 | /// may expose you to cross site scripting (XSS) vulnerabilities if the data is sent inside <script>
tags. Zen uses
81 | /// this technique extensively, so this flag should NOT be specified for jsonProviders in Zen pages.
82 | /// t - indent with tab character
83 | /// u - output pre-converted to UTF-8 instead of in native internal format
84 | /// w - Windows-style cr/lf newline
85 | ClassMethod GetJSONString(obj As %ZEN.proxyObject, format As %String = "aeos") As %String [ ProcedureBlock = 0 ]
86 | {
87 | set tOldIORedirected = ##class(%Device).ReDirectIO()
88 | set tOldMnemonic = ##class(%Device).GetMnemonicRoutine()
89 | set tOldIO = $io
90 | try {
91 | set str = ""
92 | use $io::("^" _ $ZNAME)
93 | do ##class(%Device).ReDirectIO(1)
94 | do ##class(%ZEN.Auxiliary.jsonProvider).%ObjectToJSON(obj,,,format)
95 | } catch ex {
96 | set str = ""
97 | }
98 | if (tOldMnemonic '= "") {
99 | use tOldIO::("^" _ tOldMnemonic)
100 | } else {
101 | use tOldIO
102 | }
103 | do ##class(%Device).ReDirectIO(tOldIORedirected)
104 | return str
105 |
106 | rchr(c)
107 | quit
108 | rstr(sz,to)
109 | quit
110 | wchr(s)
111 | do output($char(s))
112 | quit
113 | wff()
114 | do output($char(12))
115 | quit
116 | wnl()
117 | do output($char(13,10))
118 | quit
119 | wstr(s)
120 | do output(s)
121 | quit
122 | wtab(s)
123 | do output($char(9))
124 | quit
125 | output(s)
126 | set str = str _ s
127 | quit
128 | }
129 |
130 | }
131 |
132 |
--------------------------------------------------------------------------------
/build/cls/WebTerminal/Engine.cls:
--------------------------------------------------------------------------------
1 | /// Web Terminal version 4.9.5 WebSocket client.
2 | /// This class represents a connected client via WebSocket.
3 | Class WebTerminal.Engine Extends (%CSP.WebSocket, Common, Trace, Autocomplete)
4 | {
5 |
6 | /// Timeout in minutes when connection key expires.
7 | Parameter WSKEYEXPIRES = 3600;
8 |
9 | /// How long to wait for authorization key when connection established
10 | Parameter AuthorizationTimeout = 5;
11 |
12 | Property CurrentNamespace As %String;
13 |
14 | Property InitialZName As %String;
15 |
16 | Property InitialZNamespace As %String;
17 |
18 | /// The process ID of the terminal core.
19 | Property corePID As %Numeric [ InitialExpression = 0 ];
20 |
21 | /// The last known namespace in child process.
22 | Property childNamespace As %String;
23 |
24 | Property StartupRoutine As %String;
25 |
26 | /// Output flag
27 | Property echo As %Boolean [ InitialExpression = 1 ];
28 |
29 | /// flag which enables output buffering
30 | Property bufferOutput As %Boolean [ InitialExpression = 0 ];
31 |
32 | /// Used to buffer the output ("o" flag) when bufferOutput flag is set
33 | Property outputBuffer As %Stream.TmpCharacter [ InitialExpression = {##class(%Stream.TmpCharacter).%New()} ];
34 |
35 | /// Output flag
36 | Property handler As %Boolean [ InitialExpression = 0, Private ];
37 |
38 | Method GetMessage(timeout As %Integer = 86400) As %ZEN.proxyObject
39 | {
40 | #define err(%e, %s) if (%e '= $$$OK) { set obj = ##class(%ZEN.proxyObject).%New() set obj.error = %s return obj }
41 | set data = ..Read(, .st, timeout)
42 | return:((st = $$$CSPWebSocketTimeout) || (st = $$$CSPWebSocketClosed)) ""
43 | $$$err(st, "%wsReadErr: "_$System.Status.GetErrorText(st))
44 | set st = ##class(%ZEN.Auxiliary.jsonProvider).%ConvertJSONToObject(data, , .obj, 1)
45 | $$$err(st, "%wsParseErr: "_$System.Status.GetErrorText(st))
46 | return obj
47 | }
48 |
49 | /// Do not remove this method in future versions of WebTerminal, it is used by update.
50 | Method Send(handler As %String = "", data = "") As %Status
51 | {
52 | if (handler = "o") && (..bufferOutput = 1) {
53 | do ..outputBuffer.Write(data)
54 | return $$$OK
55 | }
56 | return:((handler = "o") && (..echo = 0)) $$$OK
57 | return:(handler = "o") ..Write("o"_data) // Enables 2013.2 support (no JSON)
58 | set obj = ##class(%ZEN.proxyObject).%New()
59 | set obj.h = handler
60 | if (..handler '= 0) {
61 | set obj."_cb" = ..handler
62 | }
63 | set obj.d = data
64 | return ..Write(..GetJSONString(obj))
65 | }
66 |
67 | Method OnPreServer() As %Status
68 | {
69 | set ..InitialZName = $zname
70 | set ..InitialZNamespace = $znspace
71 | quit $$$OK
72 | }
73 |
74 | Method OnPostServer() As %Status
75 | {
76 | if (..corePID '= 0) {
77 | do ..SendChunk(..corePID, "e")
78 | }
79 | quit $$$OK
80 | }
81 |
82 | ClassMethod WriteToFile(filename As %String, data As %String) As %Status
83 | {
84 | set file=##class(%File).%New(filename)
85 | do file.Open("WSN")
86 | do file.WriteLine(data)
87 | do file.Close()
88 | }
89 |
90 | Method ExecuteSQL(query As %String = "") As %Status
91 | {
92 | set tStatement = ##class(%SQL.Statement).%New()
93 | set qStatus = tStatement.%Prepare(query)
94 | if qStatus'=1 {
95 | write $System.Status.DisplayError(qStatus)
96 | } else {
97 | set rset = tStatement.%Execute()
98 | do rset.%Display()
99 | }
100 | quit $$$OK
101 | }
102 |
103 | /// This method performs the authorization and login to WebTerminal.
104 | /// It returns a list with data (see Router.Auth method), which is used then to set up the
105 | /// initial values for the client.
106 | Method RequireAuthorization() As %List
107 | {
108 | set data = ..GetMessage(..#AuthorizationTimeout)
109 | return:(data = "") $LB("%wsReadErr")
110 | return:('$IsObject(data.d)) $LB($case(data.error = "", 1: "Unresolved WS message format", :data.error))
111 | return:(data.d.key = "") $LB("Missing key")
112 |
113 | set authKey = data.d.key
114 | set key = $ORDER(^WebTerminal("AuthUser", ""))
115 | set list = ""
116 | while (key '= "") {
117 | set lb = $GET(^WebTerminal("AuthUser", key))
118 | if ((lb '= "") && (key = authKey)) {
119 | set list = lb
120 | }
121 | set time = $LISTGET(lb, 2)
122 | if (time '= "") && ($System.SQL.DATEDIFF("s", time, $h) > ..#WSKEYEXPIRES) {
123 | kill ^WebTerminal("AuthUser", key)
124 | }
125 | set key = $ORDER(^WebTerminal("AuthUser", key))
126 | }
127 |
128 | if (list = "") { // not found
129 | return $LB("Invalid key")
130 | }
131 |
132 | set username = $LISTGET(list, 1)
133 | set namespace = $LISTGET(list, 3)
134 | set ns = $Namespace
135 |
136 | znspace "%SYS"
137 | do ##class(Security.Users).Get(username, .userProps)
138 | znspace ns
139 |
140 | set namespace = $case(namespace, "":userProps("NameSpace"), :namespace)
141 |
142 | if ($get(userProps("Routine")) '= "") {
143 | set ..StartupRoutine = userProps("Routine")
144 | }
145 |
146 | if $get(userProps("Enabled")) '= 1 {
147 | return $LB("User " _ username _ " is not enabled in the system")
148 | }
149 |
150 | set $LIST(list, 3) = namespace
151 | set loginStatus = $System.Security.Login(username)
152 |
153 | if (loginStatus '= 1) {
154 | return $LB($System.Status.GetErrorText(loginStatus))
155 | }
156 |
157 | return $LB("", list)
158 | }
159 |
160 | /// See WebTerminal.Handlers
161 | Method ProcessRequest(handler As %String, data) As %Status [ Private ]
162 | {
163 | try {
164 | return $CLASSMETHOD("WebTerminal.Handlers", handler, $this, data)
165 | } catch (e) {
166 | set ..echo = 1
167 | return e.AsSystemError()
168 | }
169 | }
170 |
171 | /// Main method for every new client.
172 | Method ClientLoop() As %Status [ Private ]
173 | {
174 | job ##class(WebTerminal.Core).Loop(..StartupRoutine):($NAMESPACE):5
175 | if ($TEST '= 1) { // $TEST=0 for JOB only when timeouted
176 | do ..Send("error", "%noJob")
177 | return $$$NOTOK
178 | }
179 | set ..corePID = $ZCHILD
180 | set ..childNamespace = $NAMESPACE
181 | if (..StartupRoutine = "") {
182 | do ..Send("prompt", ..childNamespace)
183 | } else {
184 | set message = ##class(%ZEN.proxyObject).%New()
185 | set status = $CLASSMETHOD("WebTerminal.Handlers", "Execute", $this, "", 1)
186 | goto loopEnd
187 | }
188 | //try { // temp
189 | for {
190 | set message = ..GetMessage()
191 | quit:(message = "") // if client is gone, finish looping
192 | if (message.error '= "") {
193 | if (message.error '[ "ERROR #7951") { // don't try and send message if it was a WS close error
194 | set st = ..Send("error", message.error)
195 | }
196 | quit
197 | }
198 | if (message."_cb" '= "") { set ..handler = message."_cb" }
199 | set status = ..ProcessRequest(message.h, message.d)
200 | set ..handler = 0
201 | set ..echo = 1
202 | if (status '= "") && (status '= $$$OK) {
203 | set eType = $EXTRACT(status, 1, 1)
204 | do ..Send("oLocalized", $C(13,10) _ $case(eType = 0, 1: $System.Status.GetErrorText(status), :status))
205 | continue
206 | }
207 | }
208 | loopEnd
209 | //} catch (e) { do ..Send("o", $System.Status.GetErrorText(e)) } // temp
210 | return $$$OK
211 | }
212 |
213 | /// This method sends basic login info to the user. Use this method to set client variables
214 | /// during the WebTerminal initialization.
215 | /// authList See Router.Auth method.
216 | Method SendLoginInfo(authList As %List)
217 | {
218 | set obj = ##class(%ZEN.proxyObject).%New()
219 | set obj.username = $USERNAME
220 | set obj.name = $get(^WebTerminal("Name"))
221 | set obj.cleanStart = $ListGet(authList, 4)
222 | set obj.system = $SYSTEM
223 | set obj.firstLaunch = ($get(^WebTerminal("FirstLaunch"), 1) '= 0)
224 | set obj.InstanceGUID = ##class(%SYS.System).InstanceGUID()
225 | set obj.zv = $ZVersion
226 | set ^WebTerminal("FirstLaunch") = 0
227 | do ..Send("init", obj)
228 | }
229 |
230 | /// Triggered when new connection established.
231 | Method Server() As %Status
232 | {
233 | set authRes = ..RequireAuthorization()
234 | set authMessage = $ListGet(authRes, 1)
235 | if (authMessage = "") {
236 | set authList = $ListGet(authRes, 2) // see Router.Auth method
237 | set namespace = $ListGet(authList, 3)
238 | if (namespace '= "") && (namespace '= $Namespace) {
239 | try {
240 | znspace namespace
241 | } catch (e) {
242 | do ..Send("oLocalized",
243 | $Char(27) _ "[31m%unNS(" _ namespace _ ")"_ $Char(27) _ "[0m" _ $Char(13,10)
244 | )
245 | }
246 | }
247 | set ..CurrentNamespace = $Namespace
248 | do ..SendLoginInfo(authList)
249 | do ..ClientLoop()
250 | do ..Send("oLocalized", "%wsNormalClose"_$C(13,10))
251 | } else {
252 | do ..Send("oLocalized", "%wsRefuse(" _ authMessage _ ")")
253 | }
254 | do ..EndServer()
255 | set %session.EndSession = 1
256 | quit $$$OK
257 | }
258 |
259 | }
260 |
261 |
--------------------------------------------------------------------------------
/build/cls/WebTerminal/ErrorDecomposer.cls:
--------------------------------------------------------------------------------
1 | Class WebTerminal.ErrorDecomposer
2 | {
3 |
4 | Parameter LINES As %Numeric = 5;
5 |
6 | /// Takes $ZERROR function result.
7 | /// Returns either simple string or %ZEN.proxyObject representing the error details.
8 | ClassMethod DecomposeError(err As %String = "", ns As %String = "")
9 | {
10 | new $namespace
11 | if (ns '= "") {
12 | try {
13 | set $namespace = ns
14 | } catch (e) {
15 | return err
16 | }
17 | }
18 | return:($FIND(err, "<") '= 2) err
19 | set startPos = $FIND(err, ">")
20 | return:(startPos = 0) err
21 | set spacePos = $FIND(err, " ") - 1
22 | return:(spacePos = startPos) err
23 | set label = $EXTRACT(err, startPos, $case(spacePos = -1, 1:999, :spacePos-1))
24 | return:(label = "") err
25 | try {
26 | set obj = ##class(%ZEN.proxyObject).%New()
27 | set obj.zerror = err
28 | set plusPos = $FIND(label, "+")
29 | set cPos = $FIND(label, "^")
30 | if (plusPos = 0) || (cPos = 0) {
31 | set obj.source = $TEXT(@label)
32 | set obj.line = 0
33 | return obj
34 | }
35 | set line = +$EXTRACT(label, plusPos, cPos - 2)
36 | set part1 = $EXTRACT(label, 1, plusPos - 1)
37 | set part2 = $EXTRACT(label, cPos - 1, *)
38 | set range = ..#LINES \ 2
39 | set obj.source = ""
40 | set obj.line = 0
41 | for i=line-range:1:line+range {
42 | continue:(i < 1)
43 | set label = part1 _ i _ part2
44 | set text = $TEXT(@label)
45 | set:(text '= "") obj.source = obj.source _ $case(obj.source = "", 1: "", :$C(10)) _ text
46 | set:((text '= "") && (i < line)) obj.line = obj.line + 1
47 | }
48 | return obj
49 | } catch (e) {
50 | return err
51 | }
52 | return err
53 | }
54 |
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/build/cls/WebTerminal/Router.cls:
--------------------------------------------------------------------------------
1 | /// The REST interface: class that routes HTTP requests
2 | Class WebTerminal.Router Extends %CSP.REST [ CompileAfter = StaticContent ]
3 | {
4 |
5 | XData UrlMap
6 | {
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | }
16 |
17 | /// Calls StaticContent.Write method or sends not modified header. Type have to be "css" or "js"
18 | ClassMethod WriteStatic(type As %String, ContentType As %String = "") [ Private ]
19 | {
20 | #define CompileTime ##Expression("""" _ $zd($h, 11) _ ", "_ $zdt($NOW(0), 2,1) _ " GMT""")
21 | set %response.CharSet = "utf-8"
22 | set %response.ContentType = $case(type,
23 | "css": "text/css",
24 | "js": "text/javascript",
25 | "html": "text/html",
26 | : $case(ContentType="", 1:"text/plain", :ContentType)
27 | )
28 | do %response.SetHeader("Last-Modified", $$$CompileTime)
29 |
30 | if (%request.GetCgiEnv("HTTP_IF_MODIFIED_SINCE")=$$$CompileTime) {
31 | set %response.Status = "304 Not Modified"
32 | } else {
33 | do ##class(StaticContent).Write(type)
34 | }
35 | }
36 |
37 | ClassMethod Auth() As %Status
38 | {
39 | set cookie = $System.Encryption.Base64Encode(%session.Key)
40 | set ^WebTerminal("AuthUser", cookie) = $LB( // authList
41 | $Username, // username
42 | $Horolog, // granting ticket date
43 | $Get(%request.Data("ns", 1), $Get(%request.Data("NS", 1))),
44 | $Get(%request.Data("clean", 1), 0) '= 0
45 | )
46 | write "{""key"":""" _ cookie _ """}"
47 | return $$$OK
48 | }
49 |
50 | /// Method writes application CSS.
51 | ClassMethod GetCss() As %Status
52 | {
53 | do ..WriteStatic("css")
54 | return $$$OK
55 | }
56 |
57 | /// Method writes application theme.
58 | ClassMethod GetTheme(Theme As %String) As %Status
59 | {
60 | do ..WriteStatic("Theme"_$REPLACE(Theme, ".css", ""),"text/css")
61 | return $$$OK
62 | }
63 |
64 | /// Method writes application JavaScript.
65 | ClassMethod GetJs() As %Status
66 | {
67 | do ..WriteStatic("js")
68 | return $$$OK
69 | }
70 |
71 | /// Method writes application HTML.
72 | ClassMethod Index() As %Status
73 | {
74 | do ..WriteStatic("html")
75 | return $$$OK
76 | }
77 |
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/build/cls/WebTerminal/Trace.cls:
--------------------------------------------------------------------------------
1 | Class WebTerminal.Trace Extends Common
2 | {
3 |
4 | /// Property is used to store watching files/globals.
5 | Property Watches As %List;
6 |
7 | /// Watch position in file or global
8 | Property WatchesCaret As %Numeric [ MultiDimensional ];
9 |
10 | /// Checks for correct watch source and sets watch target to ..Watches
11 | /// Returns status of this operation
12 | Method Trace(name) As %Status
13 | {
14 | set s = $CHAR(0)
15 | set watches = s _ $LISTTOSTRING(..Watches, s) _ s
16 | if ($FIND(watches, s_name_s) '= 0) return 0 // if watch already defined
17 |
18 | if ($EXTRACT(name,1,1) = "^") { // watching global
19 | set g = 0
20 | try {
21 | if (($data(@name)) '= 0) set g = 1
22 | } catch { }
23 | set $ZERROR = ""
24 | if (g = 1) {
25 | set ..Watches = ..Watches _ $LISTBUILD(name)
26 | set ..WatchesCaret(name, 0) = $QUERY(@name@(""), -1) // last
27 | set ..WatchesCaret(name, 1) = "?"
28 | return 1
29 | }
30 | } else { // watch file
31 | if (##class(%File).Exists(name)) {
32 | set ..Watches = ..Watches _ $LISTBUILD(name)
33 | set file = ##class(%File).%New(name)
34 | set ..WatchesCaret(name,0) = file.Size // current watch cursor position
35 | set ..WatchesCaret(name,1) = file.DateModified
36 | return 1
37 | }
38 | }
39 |
40 | return 0
41 | }
42 |
43 | /// Removes watch from watches list
44 | /// Returns success status
45 | Method StopTracing(name) As %Status
46 | {
47 | set s = $CHAR(0)
48 | set watches = s _ $LISTTOSTRING(..Watches,s) _ s
49 | set newWatches = $REPLACE(watches, s_name_s, s)
50 | set ..Watches = $LISTFROMSTRING($EXTRACT(newWatches, 2, *-1), s)
51 | if (watches '= newWatches) {
52 | kill ..WatchesCaret(name)
53 | }
54 | return watches '= newWatches
55 | }
56 |
57 | /// Returns a list current watches
58 | Method ListWatches() As %String
59 | {
60 | set no = 0
61 | set s = "Watching: " _ $CHAR(10)
62 | while $LISTNEXT(..Watches, no, value) {
63 | set s = s_"(pos: "_..WatchesCaret(value,0)_
64 | "; mod: "_..WatchesCaret(value,1)_") "_value_$CHAR(10)
65 | }
66 | return s
67 | }
68 |
69 | /// Return null string if global hadn't been updated
70 | /// This method watches only for tail of global and detects if global still alive
71 | Method GetTraceGlobalModified(watch) As %List
72 | {
73 | set data = ""
74 | if ($data(@watch)=0) {
75 | do ..StopTracing(watch)
76 | return $lb($C(27)_"[(wrong)m[D]"_$C(27)_"[0m", $C(13, 10))
77 | }
78 | for {
79 | set query = $QUERY(@..WatchesCaret(watch,0))
80 | quit:query=""
81 | set ..WatchesCaret(watch,0) = query
82 | set data = data _ $case(data = "", 1: "", :$CHAR(13, 10)) _ @query
83 | }
84 | return $lb($C(27)_"[(special)m[M]"_$C(27)_"[0m", data)
85 | }
86 |
87 | Method GetTraceFileModified(watch) As %String
88 | {
89 | set file=##class(%File).%New(watch)
90 | set size = file.Size
91 | set modDate = file.DateModified
92 | set output = ""
93 | if (size < 0) { // file had been deleted
94 | do ..StopTracing(watch)
95 | return $lb($C(27)_"[(wrong)m[D]"_$C(27)_"[0m", $C(13, 10))
96 | }
97 |
98 | if (size > ..WatchesCaret(watch, 0)) {
99 |
100 | set stream = ##class(%Stream.FileCharacter).%New()
101 | set sc = stream.LinkToFile(watch)
102 | do stream.MoveTo(..WatchesCaret(watch, 0) + 1)
103 | set read = stream.Read(size - ..WatchesCaret(watch, 0))
104 | set output = output _ read
105 | set ..WatchesCaret(watch, 0) = size
106 | set ..WatchesCaret(watch, 1) = file.DateModified
107 | return $lb($C(27)_"[(constant)m[A]"_$C(27)_"[0m", output)
108 |
109 | } elseif ((size < ..WatchesCaret(watch, 0)) || (file.DateModified '= ..WatchesCaret(watch, 1))) {
110 |
111 | set output = output _ "Size change: " _ (size - ..WatchesCaret(watch, 0))
112 | set ..WatchesCaret(watch, 0) = size
113 | set ..WatchesCaret(watch, 1) = file.DateModified
114 | return $lb($C(27)_"[(special)m[M]"_$C(27)_"[0m", output)
115 |
116 | } // else file not changed
117 |
118 | return $lb("", "")
119 | }
120 |
121 | Method CheckTracing() As %String
122 | {
123 | set no = 0
124 | set data = ""
125 | set overall = ""
126 | set watchList = ..Watches // do not remove or simplify: ..Watches can be modified
127 | while $LISTNEXT(watchList, no, value) {
128 | set global = $EXTRACT(value, 1, 1) = "^"
129 | if global {
130 | set data = ..GetTraceGlobalModified(value)
131 | } else {
132 | set data = ..GetTraceFileModified(value)
133 | }
134 | if ($LISTGET(data, 2) '= "") {
135 | set overall = $LISTGET(data, 1) _ " " _ $C(27) _ "[2m" _ $ZDATETIME($NOW(),1,1)
136 | _ $C(27) _ "[0m " _ $C(27) _ "[(" _ $case(global, 1: "global", :"string") _ ")m"
137 | _ value _ $C(27) _ "[0m" _ $CHAR(13, 10) _ $LISTGET(data, 2) _ $CHAR(13, 10)
138 | }
139 | set data = ""
140 | }
141 | return overall
142 | }
143 |
144 | }
145 |
146 |
--------------------------------------------------------------------------------
/build/cls/WebTerminal/Updater.cls:
--------------------------------------------------------------------------------
1 | /// Web Terminal version 4.9.5 update module class.
2 | /// This class represents update mechanism for WebTerminal. Internet connection is required to
3 | /// update WebTerminal.
4 | Class WebTerminal.Updater
5 | {
6 |
7 | /// SSL configuration name used for HTTPS requests.
8 | Parameter SSLConfigName = "WebTerminalSSL";
9 |
10 | ClassMethod GetSSLConfigurationName() As %String
11 | {
12 | new $namespace
13 | zn "%SYS"
14 | if ('##class(Security.SSLConfigs).Exists(..#SSLConfigName)) {
15 | set st = ##class(Security.SSLConfigs).Create(..#SSLConfigName)
16 | return:(st '= 1) "UnableToCreateSSLConfig:"_$System.Status.GetErrorText(st)
17 | }
18 | return ..#SSLConfigName
19 | }
20 |
21 | ClassMethod WriteAndDelete(client As WebTerminal.Engine, file As %String) As %Status
22 | {
23 | if ##class(%File).Exists(file) {
24 | set stream = ##class(%Stream.FileCharacter).%New()
25 | set sc = stream.LinkToFile(file)
26 | while 'stream.AtEnd {
27 | do client.Send("o", stream.Read()_$CHAR(13, 10))
28 | }
29 | do client.Send("oLocalized", "%sUpdCleanLog("_file_")"_$CHAR(13, 10))
30 | do ##class(%File).Delete(file)
31 | } else {
32 | do client.Send("oLocalized", "%sUpdNoFile")
33 | }
34 | return $$$OK
35 | }
36 |
37 | ClassMethod Stop(client As WebTerminal.Engine, status As %Status) As %Status
38 | {
39 | if ($$$ISERR(status)) {
40 | do client.Send("oLocalized", "%sUpdErr("_$System.Status.GetErrorText(status)_")"_$C(13, 10))
41 | }
42 | return status
43 | }
44 |
45 | ClassMethod Update(client As WebTerminal.Engine, URL As %String) As %Status
46 | {
47 | do client.Send("oLocalized", "%sUpdSt"_$CHAR(13, 10))
48 | set request = ##class(%Net.HttpRequest).%New()
49 | set request.Server = $PIECE(URL, "/", 3)
50 | set request.Location = $PIECE(URL, "/", 4, *)
51 | set request.Https = 1
52 | set request.SSLConfiguration = ..GetSSLConfigurationName()
53 | do client.Send("oLocalized", "%sUpdRURL(https://"_request.Server_"/"_request.Location_")"_$CHAR(13, 10))
54 | set status = request.Get()
55 | do client.Send("oLocalized", "%sUpdGetOK"_$CHAR(13, 10))
56 | return:(status '= $$$OK) status
57 |
58 | if (request.HttpResponse.StatusCode '= 200) {
59 | do client.Send("oLocalized", "%sUpdSCode("_request.HttpResponse.StatusCode_")"_$CHAR(13, 10))
60 | return $$$ERROR($$$GeneralError, "HTTP "_request.HttpResponse.StatusCode)
61 | }
62 |
63 | do client.Send("oLocalized", "%sUpdWTF"_$CHAR(13, 10))
64 | set tempFile = ##class(%File).TempFilename("xml")
65 | set file = ##class(%File).%New(tempFile)
66 | do file.Open("NW")
67 | set data = request.HttpResponse.Data
68 | if (($IsObject(data)) && (data.%IsA("%Stream.Object"))) {
69 | while 'data.AtEnd {
70 | set chunk = data.Read(data.Size)
71 | do file.Write(chunk)
72 | }
73 | } else {
74 | do file.Write(data)
75 | }
76 | do file.Close()
77 |
78 | set backupFile = ##class(%File).TempFilename("xml")
79 | do client.Send("oLocalized", "%sUpdBack("_backupFile_")"_$CHAR(13, 10))
80 |
81 | set logFile = ##class(%File).TempFilename("txt")
82 | set io = $IO
83 |
84 | open logFile:("NW")
85 | use logFile
86 | set exportStatus = $System.OBJ.Export("WebTerminal.*.CLS", backupFile)
87 | close logFile
88 | use io
89 |
90 | do ..WriteAndDelete(client, logFile)
91 | if ($$$ISERR(exportStatus)) {
92 | do ##class(WebTerminal.Analytics).ReportInstallStatus(exportStatus, "Update")
93 | return ..Stop(client, exportStatus)
94 | }
95 | do client.Send("oLocalized", "%sUpdRemLoad"_$CHAR(13, 10))
96 |
97 | open logFile:("NW")
98 | use logFile
99 | write $C(27)_"[2m"
100 | do $System.OBJ.DeletePackage("WebTerminal")
101 | write $C(27)_"[0m", !
102 | set loadStatus = $SYSTEM.OBJ.Load(tempFile, "c")
103 |
104 | // At this moment WebTerminal's code can be broken, totally changed or deleted. Do not call
105 | // WebTerminal's methods until terminal is restored / fully updated
106 |
107 | if '$$$ISOK(loadStatus) { // roll back
108 | write !, $C(27)_"[(wrong)m==FAILED=="_$C(27)_"[0m", !,
109 | $System.Status.GetErrorText(loadStatus), !, !,
110 | $C(27)_"[(special)m==RESTORING=="_$C(27)_"[0m", !
111 | do $SYSTEM.OBJ.Load(backupFile, "c")
112 | }
113 |
114 | // end
115 |
116 | close logFile
117 | use io
118 | do ..WriteAndDelete(client, logFile)
119 |
120 | do client.Send("oLocalized", "%sUpdClean("_tempFile_")"_$CHAR(13, 10))
121 | do ##class(%File).Delete(tempFile)
122 | do client.Send("oLocalized", "%sUpdClean("_backupFile_")"_$CHAR(13, 10, 13, 10))
123 | do ##class(%File).Delete(backupFile)
124 | if '$$$ISOK(loadStatus) {
125 | do ..Stop(client, loadStatus)
126 | do client.Send("oLocalized", $CHAR(13, 10)_"%sUpdRes"_$CHAR(13, 10))
127 | }
128 | do client.Send("oLocalized", "%sUpdDone"_$CHAR(13, 10))
129 |
130 | do ##class(WebTerminal.Analytics).ReportInstallStatus(loadStatus, "Update")
131 |
132 | return $$$OK
133 | }
134 |
135 | }
136 |
137 |
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 | Contributing Guidelines
2 | =======================
3 |
4 | We are happy to see anyone who is interested in improving the WebTerminal project!
5 | All the bugs you find, issues you discover and things you report make WebTerminal project grow!
6 |
7 | Feel free to [submit](https://github.com/intersystems-ru/webterminal/issues) any questions, issues, feature requests or bug reports to this project.
8 |
9 | If You Want To Implement Something...
10 | =====================================
11 |
12 | Please, read [Contributing Guidelines](http://intersystems-ru.github.io/webterminal/#docs.5) at the project's page. This will be useful if you want to implement some features or fix something by yourself. This project is always open for pull requests!
13 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 | services:
3 | iris:
4 | build:
5 | context: .
6 | dockerfile: Dockerfile
7 | restart: always
8 | command: --check-caps false
9 | ports:
10 | - 51663:1972
11 | - 52663:52773
12 | - 53773
13 | volumes:
14 | - ./:/irisdev/app
15 |
--------------------------------------------------------------------------------
/docs/css/content.css:
--------------------------------------------------------------------------------
1 | @-webkit-keyframes rainbow {
2 | 0% {
3 | color: rgb(0, 255, 0);
4 | }
5 |
6 | 33% {
7 | color: rgb(0, 0, 255);
8 | }
9 |
10 | 66% {
11 | color: rgb(255, 0, 0);
12 | }
13 |
14 | 100% {
15 | color: rgb(0, 255, 0);
16 | }
17 | }
18 |
19 | @-moz-keyframes rainbow {
20 | 0% {
21 | color: rgb(0, 255, 0);
22 | }
23 |
24 | 33% {
25 | color: rgb(0, 0, 255);
26 | }
27 |
28 | 66% {
29 | color: rgb(255, 0, 0);
30 | }
31 |
32 | 100% {
33 | color: rgb(0, 255, 0);
34 | }
35 | }
36 |
37 | @-o-keyframes rainbow {
38 | 0% {
39 | color: rgb(0, 255, 0);
40 | }
41 |
42 | 33% {
43 | color: rgb(0, 0, 255);
44 | }
45 |
46 | 66% {
47 | color: rgb(255, 0, 0);
48 | }
49 |
50 | 100% {
51 | color: rgb(0, 255, 0);
52 | }
53 | }
54 |
55 | @keyframes rainbow {
56 | 0% {
57 | color: rgb(0, 255, 0);
58 | }
59 |
60 | 33% {
61 | color: rgb(0, 0, 255);
62 | }
63 |
64 | 66% {
65 | color: rgb(255, 0, 0);
66 | }
67 |
68 | 100% {
69 | color: rgb(0, 255, 0);
70 | }
71 | }
72 |
73 | .rainbowText {
74 | text-shadow: 1px 1px 1px #ffffff;
75 | -webkit-animation: rainbow 4s infinite linear;
76 | -moz-animation: rainbow 4s infinite linear;
77 | -o-animation: rainbow 4s infinite linear;
78 | animation: rainbow 4s infinite linear;
79 | }
80 |
81 | .imgFloatLeft {
82 | float: left;
83 | margin: 5px;
84 | }
85 |
86 | .imgFloatRight {
87 | float: right;
88 | margin: 5px;
89 | }
90 |
91 | .center {
92 | text-align: center;
93 | }
94 |
95 | .screenShoot {
96 | max-width: 60%;
97 | box-shadow: 4px 4px 6px black;
98 | margin: 15px;
99 | }
100 |
101 | .clearHL {
102 | clear: both;
103 | }
104 |
105 | .warn {
106 | color: #ff6500
107 | }
108 |
109 | .newsBlock {
110 | overflow: hidden;
111 | position: relative;
112 | background: rgba(255, 255, 255, 0.2);
113 | border-radius: 5px;
114 | padding: .3em;
115 | }
116 |
117 | .newsBlock h1 {
118 | margin: 4px;
119 | font-size: 20px;
120 | text-decoration: underline;
121 | }
122 |
123 | .newsBlock .date {
124 | float: right;
125 | font-style: italic;
126 | }
127 |
128 | .newsBlock .content {
129 | clear: both;
130 | text-indent: 2.5em;
131 | }
132 |
133 | .newsBlock ~ .newsBlock {
134 | margin-top: 10px;
135 | }
136 |
137 | #showcase > p:after {
138 | content: "";
139 | display: block;
140 | clear: both;
141 | }
142 |
143 | /* Terminal Colors */
144 |
145 |
146 | .g.m1 { /* bright */
147 | font-weight: 900;
148 | }
149 |
150 | .g.m2 { /* dim */
151 | opacity: 0.7;
152 | }
153 |
154 | .g.m3 {
155 | font-style: italic;
156 | }
157 |
158 | .g.m4 {
159 | text-decoration: underline;
160 | }
161 |
162 | .g.m5 {
163 | @include animation(blink infinite 1s);
164 | }
165 |
166 | .g.m7 {
167 | @include filter(invert(100%));
168 | }
169 |
170 | .g.m8 {
171 | opacity: 0;
172 | }
173 |
174 | .g.hint {
175 | opacity: .5;
176 | }
177 |
178 | .g.m30 {
179 | color: #000000;
180 | }
181 |
182 | .g.m31 {
183 | color: #ff0000;
184 | }
185 |
186 | .g.m32 {
187 | color: #008000;
188 | }
189 |
190 | .g.m33 {
191 | color: yellow;
192 | }
193 |
194 | .g.m34 {
195 | color: #0000ff;
196 | }
197 |
198 | .g.m35 {
199 | color: magenta;
200 | }
201 |
202 | .g.m36 {
203 | color: cyan;
204 | }
205 |
206 | .g.m37 {
207 | color: white;
208 | }
209 |
210 | .g.m40 {
211 | background-color: #000000;
212 | }
213 |
214 | .g.m41 {
215 | background-color: #ff0000;
216 | }
217 |
218 | .g.m42 {
219 | background-color: #008000;
220 | }
221 |
222 | .g.m43 {
223 | background-color: yellow;
224 | }
225 |
226 | .g.m44 {
227 | background-color: #0000ff;
228 | }
229 |
230 | .g.m45 {
231 | background-color: magenta;
232 | }
233 |
234 | .g.m46 {
235 | background-color: cyan;
236 | }
237 |
238 | .g.m47 {
239 | background-color: white;
240 | }
241 |
242 | .g.keyword {
243 | color: #4898ff;
244 | }
245 |
246 | .g.string {
247 | color: #00c700;
248 | }
249 |
250 | .g.constant {
251 | color: cyan;
252 | }
253 |
254 | .g.special {
255 | color: yellow;
256 | }
257 |
258 | .g.variable {
259 | color: lightsalmon;
260 | }
261 |
262 | .g.wrong {
263 | color: red;
264 | }
265 |
266 | .g.selected {
267 | color: white;
268 | background-color: royalblue;
269 | }
270 |
271 | .g.argument {
272 | color: magenta;
273 | }
274 |
275 | .segments {
276 | position: relative;
277 | overflow: hidden;
278 | }
279 |
280 | @media (min-width: 1200px) {
281 | .segments {
282 | column-count: 2;
283 | column-gap: 0;
284 | }
285 | .segments > .segment {
286 | break-inside: avoid;
287 | padding: 5px;
288 | }
289 | }
--------------------------------------------------------------------------------
/docs/css/main.css:
--------------------------------------------------------------------------------
1 | html {
2 | background: url("../img/back.png") black;
3 | color: white;
4 | font-family: 'PT Sans Narrow', sans-serif;
5 | font-size: 18px !important;
6 | text-shadow: 1px 1px 1px #000000;
7 | min-width: 539px;
8 | }
9 |
10 | body {
11 | position: relative;
12 | margin: 0;
13 | padding: 0 80px 180px 80px;
14 | }
15 |
16 | img {
17 | border: none;
18 | }
19 |
20 | p {
21 | text-indent: 2.5em;
22 | text-align: justify;
23 | }
24 |
25 | a {
26 | text-decoration: none;
27 | color: #fffc9e;
28 | transition: all 0.3s ease;
29 | }
30 |
31 | sup {
32 | position: relative;
33 | }
34 |
35 | a:hover {
36 | text-shadow: 0 0 5px #fff000;
37 | }
38 |
39 | .pageHeader {
40 | font-size: 50px;
41 | position: absolute;
42 | left: -60px;
43 | top: -70px;
44 | white-space: nowrap;
45 | text-shadow: 1px 1px 5px #fff063;
46 | }
47 |
48 | .pageBody {
49 | position: relative;
50 | top: 80px;
51 | overflow: visible;
52 | min-height: 520px;
53 | background: rgba(255,255,255,0.2);
54 | border-radius: 0 20px/100px;
55 | }
56 |
57 | .pageLayout, .pageLayout:target ~ #main, #main.inactive {
58 | position: relative;
59 | padding: 0;
60 | height: 0;
61 | overflow: hidden;
62 | opacity: 0;
63 | transition: all 0.3s ease;
64 | }
65 |
66 | #main, .pageLayout:target, .pageLayout.active {
67 | display: block;
68 | opacity: 1;
69 | padding: 20px 20px 20px 20px;
70 | height: auto;
71 | }
72 |
73 | .pageFooter {
74 | position: absolute;
75 | background: rgba(255,255,255,0.2);
76 | border-radius: 0 0 15px 15px;
77 | right: 0;
78 | height: 30px;
79 | bottom: -30px;
80 | padding: 0 6px 0 6px;
81 | color: #acacac;
82 | }
83 |
84 | .siteNavigator {
85 | position: absolute;
86 | list-style: none;
87 | padding: 0;
88 | margin: 0;
89 | display: block;
90 | left: -64px;
91 | width: 64px;
92 | }
93 |
94 | .siteNavigator > li {
95 | position: relative;
96 | width: 64px;
97 | height: 64px;
98 | background: rgba(255,255,255,0.2);
99 | border-radius: 15px 0 0 15px;
100 | margin-bottom: 6px;
101 | cursor: pointer;
102 | }
103 |
104 | .siteNavigator > li > a > img {
105 | position: relative;
106 | left: 10%;
107 | top: 10%;
108 | width: 80%;
109 | height: 80%;
110 | transition: all 0.1s ease;
111 | }
112 |
113 | .siteNavigator > li > a > img:hover {
114 | left: 0;
115 | top: 0;
116 | width: 100%;
117 | height: 100%;
118 | }
119 |
120 | #forkLink {
121 | position: absolute;
122 | right: 0;
123 | top: 0;
124 | display: block;
125 | z-index: 1;
126 | }
127 |
128 | table {
129 | border-collapse: collapse;
130 | box-shadow: 0 0 1px white;
131 | border-radius: 5px;
132 | }
133 |
134 | table tr:nth-child(2n) {
135 | background-color: rgba(255,255,255,0.2);
136 | }
137 |
138 | table th {
139 | background-color: rgba(255, 252, 158, 0.5);
140 | }
141 |
142 | table th:first-child {
143 | border-radius: 5px 0 0 0;
144 | }
145 |
146 | table th:last-child {
147 | border-radius: 0 5px 0 0;
148 | }
149 |
150 | table tbody tr:last-child td:first-child {
151 | border-radius: 0 0 0 5px;
152 | }
153 |
154 | table tbody tr:last-child td:last-child {
155 | border-radius: 0 0 5px 0;
156 | }
157 |
158 | table td {
159 | padding: 2px;
160 | }
161 |
162 | code {
163 | display: block;
164 | background-color: rgba(255,255,255,0.1);
165 | text-indent: 0;
166 | padding: .5em;
167 | margin: .3em 0;
168 | border-radius: 5px;
169 | overflow: auto;
170 | font-size: 12px;
171 | }
172 |
173 | code.inline {
174 | display: inline-block;
175 | margin: 0;
176 | font-size: 95%;
177 | padding: 1px;
178 | vertical-align: bottom;
179 | }
180 |
181 | code.pre {
182 | white-space: pre;
183 | font-size: 12px;
184 | }
185 |
186 | OL {
187 | counter-reset: list1;
188 | padding-left: 2.5em;
189 | }
190 | UL {
191 | padding-left: 2.5em;
192 | }
193 | OL LI {
194 | list-style-type: none;
195 | }
196 | OL LI:before {
197 | counter-increment: list1;
198 | content: counter(list1) ". ";
199 | }
200 | OL OL { counter-reset: list2; }
201 | OL OL LI:before {
202 | counter-increment: list2;
203 | content: counter(list1) "." counter(list2) ". ";
204 | }
205 | OL OL OL { counter-reset: list3; }
206 | OL OL OL LI:before {
207 | counter-increment: list3;
208 | content: counter(list1) "." counter(list2) "." counter(list3) ". ";
209 | }
210 |
211 | h1:target, h2:target, h3:target {
212 | color: #fffc9e;
213 | animation: highlight 2s ease-out;
214 | -moz-animation: highlight 2s ease-out;
215 | -o-animation: highlight 2s ease-out;
216 | -webkit-animation: highlight 2s ease-out;
217 | text-decoration: underline;
218 | }
219 |
220 | @keyframes highlight {
221 | 0% { color: inherit }
222 | 50% { color: orange; padding-left: 10px; }
223 | 100% { color: #fffc9e }
224 | }
225 |
226 | @-moz-keyframes highlight {
227 | 0% { color: inherit }
228 | 50% { color: orange; padding-left: 10px; }
229 | 100% { color: #fffc9e }
230 | }
231 |
232 | @-ms-keyframes highlight {
233 | 0% { color: inherit }
234 | 50% { color: orange; padding-left: 10px; }
235 | 100% { color: #fffc9e }
236 | }
237 |
238 | @-o-keyframes highlight {
239 | 0% { color: inherit }
240 | 50% { color: orange; padding-left: 10px; }
241 | 100% { color: #fffc9e }
242 | }
243 |
244 | @-webkit-keyframes highlight {
245 | 0% { color: inherit }
246 | 50% { color: orange; padding-left: 10px; }
247 | 100% { color: #fffc9e }
248 | }
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/favicon.ico
--------------------------------------------------------------------------------
/docs/img/WebTerminal Preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/WebTerminal Preview.png
--------------------------------------------------------------------------------
/docs/img/back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/back.png
--------------------------------------------------------------------------------
/docs/img/fork.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/fork.png
--------------------------------------------------------------------------------
/docs/img/icons/docs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/icons/docs.png
--------------------------------------------------------------------------------
/docs/img/icons/download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/icons/download.png
--------------------------------------------------------------------------------
/docs/img/icons/feedback.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/icons/feedback.png
--------------------------------------------------------------------------------
/docs/img/icons/images.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/icons/images.png
--------------------------------------------------------------------------------
/docs/img/icons/save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/icons/save.png
--------------------------------------------------------------------------------
/docs/img/icons/terminal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/icons/terminal.png
--------------------------------------------------------------------------------
/docs/img/logos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/logos.png
--------------------------------------------------------------------------------
/docs/img/screenshoots/ac.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/screenshoots/ac.png
--------------------------------------------------------------------------------
/docs/img/screenshoots/features-config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/screenshoots/features-config.png
--------------------------------------------------------------------------------
/docs/img/screenshoots/features-help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/screenshoots/features-help.png
--------------------------------------------------------------------------------
/docs/img/screenshoots/features-mobile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/screenshoots/features-mobile.png
--------------------------------------------------------------------------------
/docs/img/screenshoots/install-steps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/screenshoots/install-steps.png
--------------------------------------------------------------------------------
/docs/img/screenshoots/scr4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/screenshoots/scr4.png
--------------------------------------------------------------------------------
/docs/img/screenshoots/showcase-slq-mode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intersystems-community/webterminal/91b54afa0ef4c80d5ac2d114df55b07de72e3864/docs/img/screenshoots/showcase-slq-mode.png
--------------------------------------------------------------------------------
/docs/latestNightVersion:
--------------------------------------------------------------------------------
1 | 9999#WebTerminal-v4.0.0-beta.1
--------------------------------------------------------------------------------
/docs/latestVersion:
--------------------------------------------------------------------------------
1 | 26#WebTerminal-v4.0.0-beta.1
--------------------------------------------------------------------------------
/docs/readme.md:
--------------------------------------------------------------------------------
1 | # Caché Web Terminal Project Website's Sources
2 |
3 | This (`/docs`) directory is served by GitHub at https://intersystems-community.github.io/webterminal.
4 |
5 | You are welcome to fix all found mistakes or typos on the project's website.
6 | Do do this, fork this repository, edit corresponding files and make a pull request.
7 | Find more about contributing to WebTerminal project [here](https://intersystems-community.github.io/webterminal/#docs.5).
8 |
--------------------------------------------------------------------------------
/gulpfile.babel.js:
--------------------------------------------------------------------------------
1 | import gulp from "gulp";
2 | import pkg from "./package.json";
3 | import cssNano from "gulp-cssnano";
4 | import uglify from "gulp-uglify";
5 | import replace from "gulp-replace";
6 | import rimraf from "gulp-rimraf";
7 | import scss from "gulp-sass";
8 | import rename from "gulp-rename";
9 | import preprocess from "gulp-preprocess";
10 | import browserify from "browserify";
11 | import "babelify";
12 | import sourceStream from "vinyl-source-stream";
13 | import buffer from "vinyl-buffer";
14 | import fs from "fs";
15 | import preprocessify from "preprocessify";
16 | //import sourcemaps from "gulp-sourcemaps";
17 | import { getAutomaton } from "./src/client/js/parser/_build";
18 |
19 | let INSTALLER_CLASS_NAME = `${ pkg["packageName"] }.Installer`;
20 |
21 | let dir = __dirname,
22 | dest = `${dir}/build`,
23 | source = `${dir}/src`,
24 | context = {
25 | includeBase: dest,
26 | context: {
27 | package: pkg,
28 | compileAfter: "", // is set during "pre-cls" task.
29 | themes: "", // is set after css move task
30 | autocompleteAutomaton: [],
31 | ruleMappings: {}
32 | }
33 | },
34 | themes = []; // reassigned
35 |
36 | const sass = require('gulp-sass')(require('sass'));
37 |
38 | function themesReady () { // triggered when build is done
39 | themes = fs.readdirSync(`${ dest }/client/css/themes`);
40 | context.context.themes = themes.map(function (n) {
41 | return ', "' + n.replace(/\..*$/, "") + '": "css/themes/' + n + '"';
42 | }).join("");
43 | }
44 |
45 | gulp.task("prepare", function (cb) {
46 | let aut = [];
47 | console.log(`Compiling autocomplete and highlight rules...`);
48 | try {
49 | aut = getAutomaton();
50 | context.context.autocompleteAutomaton = JSON.stringify(aut.automaton);
51 | context.context.ruleMappings = JSON.stringify(aut.ruleMappings);
52 | } catch (e) {
53 | console.error.apply(console, e);
54 | cb(e);
55 | }
56 | console.log(`Automaton ready and has ${ aut.automaton.length } states with ${
57 | aut.automaton.reduce((a, b) =>
58 | (typeof a === "number" ? a : a.length) + (typeof b === "number" ? b : b.length))
59 | } rules.`);
60 | cb();
61 | });
62 |
63 | gulp.task("clean", gulp.series("prepare", function () {
64 | return gulp.src(dest, { read: false, allowEmpty: true })
65 | .pipe(rimraf());
66 | }));
67 |
68 | gulp.task("html", gulp.series(function () {
69 | return gulp.src(`${ source }/client/index.html`)
70 | .pipe(preprocess(context))
71 | .pipe(gulp.dest(`${ dest }/client`));
72 | }));
73 |
74 | gulp.task("scss", gulp.series(() => {
75 | return gulp.src([`${source}/client/scss/index.scss`])
76 | .pipe(preprocess(context))
77 | .pipe(sass())
78 | .pipe(cssNano({
79 | zindex: false
80 | }))
81 | .pipe(gulp.dest(`${dest}/client/css`));
82 | }));
83 |
84 | gulp.task("copy-css-themes", gulp.series(function () {
85 | return gulp.src(`${ source }/client/scss/themes/*.*`)
86 | .pipe(preprocess(context))
87 | .pipe(sass())
88 | .pipe(cssNano())
89 | .pipe(gulp.dest(`${ dest }/client/css/themes/`));
90 | }));
91 |
92 | // Need css themes directory copied to collect themes names.
93 | gulp.task("css", gulp.series("scss", "copy-css-themes", function (cb) {
94 | themesReady();
95 | cb();
96 | }));
97 |
98 | gulp.task("js", gulp.series("css", function () {
99 | let bundler = browserify({
100 | entries: `${source}/client/js/index.js`,
101 | debug: true
102 | }).transform(preprocessify, {
103 | includeExtensions: ['.js'],
104 | context: context.context
105 | });
106 | bundler.transform("babelify", { presets: ["es2015"] });
107 | return bundler.bundle()
108 | .on("error", function (err) { console.error("An error occurred during bundling:", err); })
109 | .pipe(sourceStream("index.js"))
110 | .pipe(buffer())
111 | //.pipe(sourcemaps.init({ loadMaps: true }))
112 | .pipe(uglify({
113 | output: {
114 | ascii_only: true,
115 | width: 25000,
116 | max_line_len: 15000,
117 | comments: "some"
118 | },
119 | }))
120 | .pipe(replace(/\x0b|\x1b/g, e => `\\x${ e === "\x0b" ? 0 : 1 }b`))
121 | .pipe(replace(/[\x00-\x08]/g, e => `\\x0${ e.charCodeAt(0) }`))
122 | //.pipe(sourcemaps.write())
123 | .pipe(gulp.dest(`${ dest }/client/js`));
124 | }));
125 |
126 | gulp.task("readme", gulp.series(function () {
127 | return gulp.src(`${ dir }/readme.md`)
128 | .pipe(gulp.dest(`${ dest }`));
129 | }));
130 |
131 | gulp.task("cls", gulp.series("js", "js", "html", "css", "readme", () => {
132 | return gulp.src([`${ source }/cls/**/*.cls`])
133 | .pipe(preprocess(context))
134 | .pipe(gulp.dest(`${dest}/cls`));
135 | }));
136 |
137 | gulp.task("default", gulp.series("clean", "cls"));
--------------------------------------------------------------------------------
/import.bat:
--------------------------------------------------------------------------------
1 | :: This batch script makes the Caché application deployment much faster by building, importing and
2 | :: exporting the XML the project. Replace the path below to your Caché installation and
3 | :: build & import application to Caché using only one command.
4 |
5 | :: Latest NodeJS & Caché 2016.2+ IS REQUIRED TO PROCEED
6 | @echo off
7 |
8 | :: CHANGE THIS PATH TO YOUR CACHÉ INSTALLATION PATH ON WINDOWS (folder that contains bin, CSP, mgr and other folders)
9 | set CACHE_DIR=C:\Program Files\Ensemble-2017
10 | :: NAMESPACE TO IMPORT PACKAGE TO
11 | set NAMESPACE=USER
12 | :: Other variables
13 | set BUILD_DIR=build\cls
14 | :: Export
15 | set XML_EXPORT_DIR=build
16 | set PACKAGE_NAME=WebTerminal
17 |
18 | :: Build and import application to Caché
19 | echo Building the project...
20 | npm run build && ^
21 | echo s st = $system.Status.GetErrorText($system.OBJ.ImportDir("%~dp0%BUILD_DIR%",,"ck",,1)) w "IMPORT STATUS: "_$case(st="",1:"OK",:st) halt | "%CACHE_DIR%\bin\cache.exe" -s "%CACHE_DIR%\mgr" -U %NAMESPACE% && ^
22 | echo s st = $system.Status.GetErrorText($system.OBJ.ExportPackage("%PACKAGE_NAME%", "%~dp0%XML_EXPORT_DIR%\%PACKAGE_NAME%-v"_##class(%PACKAGE_NAME%.Installer).#VERSION_".xml")) w $c(13,10)_"EXPORT STATUS: "_$case(st="",1:"OK",:st) halt | "%CACHE_DIR%\bin\cache.exe" -s "%CACHE_DIR%\mgr" -U %NAMESPACE%
--------------------------------------------------------------------------------
/iris.script:
--------------------------------------------------------------------------------
1 | zn "%SYS"
2 | Do ##class(Security.Users).UnExpireUserPasswords("*")
3 |
4 | zn "USER"
5 | zpm "load /opt/irisapp/ -v":1:1
6 | halt
7 |
--------------------------------------------------------------------------------
/issue_template.md:
--------------------------------------------------------------------------------
1 | Thank you for reaching WebTerminal project! Just a few guidelines for you:
2 |
3 | + Feel free to submit questions and feature requests!
4 | + If you are going to submit bug report, please include technical details: Caché version and a way
5 | how to reproduce the problem. Please, submit some demonstration code (when appropriate).
6 | + By using search, check if there were no such issues before.
7 | + Replace this text with your issue! Thanks!
8 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-present Nikita Savchenko (https://nikita.tk)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | webterminal
6 | 4.9.6
7 | true
8 | Web Terminal
9 | module
10 | build
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-terminal",
3 | "title": "Web Terminal",
4 | "packageName": "WebTerminal",
5 | "printableName": "Web Terminal",
6 | "description": "Web-based terminal emulator for InterSystems products.",
7 | "author": {
8 | "name": "Nikita Savchenko",
9 | "url": "https://nikita.tk"
10 | },
11 | "version": "4.9.5",
12 | "gaID": "UA-83005064-2",
13 | "releaseNumber": 26,
14 | "contributors": [
15 | {
16 | "name": "Nikita Savchenko",
17 | "email": "me@nikita.tk"
18 | },
19 | {
20 | "name": "John Murray",
21 | "email": "johnm@georgejames.com"
22 | }
23 | ],
24 | "scripts": {
25 | "build": "gulp"
26 | },
27 | "repository": {
28 | "type": "git",
29 | "url": "https://github.com/intersystems-community/webterminal.git"
30 | },
31 | "devDependencies": {
32 | "babel-core": "^6.23.1",
33 | "babel-polyfill": "^6.23.0",
34 | "babel-preset-es2015": "^6.22.0",
35 | "babelify": "^7.3.0",
36 | "browserify": "^14.1.0",
37 | "gulp": "^4.0.2",
38 | "gulp-cssnano": "^2.1.3",
39 | "gulp-minify-css": "^1.2.4",
40 | "gulp-preprocess": "^4.0.2",
41 | "gulp-rename": "^2.0.0",
42 | "gulp-replace": "^0.5.4",
43 | "gulp-rimraf": "^1.0.0",
44 | "gulp-sass": "^5.1.0",
45 | "gulp-uglify": "^3.0.2",
46 | "preprocessify": "^1.0.1",
47 | "sass": "^1.53.0",
48 | "vinyl-buffer": "^1.0.1",
49 | "vinyl-source-stream": "^2.0.0"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Web Terminal
2 |
3 | [](https://t.me/joinchat/FoZ4M0jbeW8PVp2l5tqrgg)
4 |
5 | Web-based terminal for InterSystems products. Access your database from everywhere!
6 |
7 | + Visit the [project's page](http://intersystems-community.github.io/webterminal) for more details.
8 | + **Download** the latest version from [here](http://intersystems-community.github.io/webterminal/#downloads).
9 | + Read more and discuss WebTerminal on [InterSystems Developer Community](https://community.intersystems.com/post/cach%C3%A9-webterminal-v4-release).
10 | + Read [complete documentation](http://intersystems-community.github.io/webterminal/#docs) about WebTerminal.
11 |
12 | ### Preview
13 |
14 | Syntax highlighting & intelligent autocomplete!
15 |
16 | 
17 |
18 | Embedded SQL mode!
19 |
20 | 
21 |
22 | Even more features!
23 |
24 | 
25 |
26 | ### Key Features
27 |
28 |
29 | Native browser application |
30 | Allows to access Caché terminal both from desktop and mobile devices. |
31 |
32 |
33 | Autocompletion |
34 | Type faster. Autocomplete is available for class names, variable and global names, methods, properties, etc. |
35 |
36 |
37 | Tracing |
38 | Monitor any changes in globals or files. |
39 |
40 |
41 | SQL mode |
42 | A convenient way to execute SQL queries. |
43 |
44 |
45 | Syntax highlighting |
46 | Intelligently highlighted input both for ObjectScript and SQL. |
47 |
48 |
49 | Favorites |
50 | Save commands you execute frequently. |
51 |
52 |
53 | Security |
54 | All you need is to protect /terminal/ web application, and all sessions are guaranteed to be secure. |
55 |
56 |
57 | Self-updating |
58 | WebTerminal of version 4 and higher prompts to update automatically when new version is available, so you will never miss the important update. |
59 |
60 |
61 | Explore! |
62 | Enjoy using WebTerminal! |
63 |
64 |
65 |
66 | Installation
67 | ------------
68 |
69 | Download the latest version from the project page and import downloaded XML file into any namespace. Compile imported items and the WebTerminal is ready!
70 |
71 | Usage
72 | -----
73 |
74 | After installation, you will be able to access application at `http://[host]:[port]/terminal/` (slash at the end is required).
75 | Type `/help` there to get more information.
76 |
77 | Integration and WebTerminal's API
78 | ---------------------------------
79 |
80 | To embed WebTerminal to any other web application, you can use `