Commit 6491a54f by Mac Stephens

Add version to login and nav, handle database outages gracefully, and align…

Add version to login and nav, handle database outages gracefully, and align emiMobile client startup/error handling with webCharms
parent f751bb00
...@@ -211,11 +211,13 @@ type ...@@ -211,11 +211,13 @@ type
procedure UniAlerter1Event(Sender: TDAAlerter; const EventName, procedure UniAlerter1Event(Sender: TDAAlerter; const EventName,
Message: string); Message: string);
private private
{ Private declarations } { Private declarations }
public public
CADUpdate: Boolean; CADUpdate: Boolean;
function HandleUniqueFilenames(const category: string): string; function HandleUniqueFilenames(const category: string): string;
function BadgeCounts(const BaseQuery: TUniQuery): Integer; function BadgeCounts(const BaseQuery: TUniQuery): Integer;
function EnsureConnected: Boolean;
end; end;
var var
...@@ -240,7 +242,18 @@ begin ...@@ -240,7 +242,18 @@ begin
ucENTCAD.Password := IniEntries.DatabasePassword; ucENTCAD.Password := IniEntries.DatabasePassword;
ucENTCAD.LoginPrompt := False; ucENTCAD.LoginPrompt := False;
EnsureConnected;
end;
function TApiDatabaseModule.EnsureConnected: Boolean;
begin
Result := False;
try
if not ucENTCAD.Connected then if not ucENTCAD.Connected then
begin
Logger.Log(2, 'Connecting to PostgreSQL API database...');
ucENTCAD.Connect; ucENTCAD.Connect;
ucENTCAD.ExecSQL('set search_path to lems, avl, entcad, public'); ucENTCAD.ExecSQL('set search_path to lems, avl, entcad, public');
...@@ -249,6 +262,15 @@ begin ...@@ -249,6 +262,15 @@ begin
Logger.Log(1, 'Starting PostgreSQL disupdate listener'); Logger.Log(1, 'Starting PostgreSQL disupdate listener');
UniAlerter1.Start; UniAlerter1.Start;
Logger.Log(1, 'PostgreSQL disupdate listener started'); Logger.Log(1, 'PostgreSQL disupdate listener started');
CADUpdate := True;
end;
Result := True;
except
on E: Exception do
Logger.Log(1, 'PostgreSQL API database unavailable: ' + E.Message);
end;
end; end;
procedure TApiDatabaseModule.uqComplaintListCalcFields(DataSet: TDataSet); procedure TApiDatabaseModule.uqComplaintListCalcFields(DataSet: TDataSet);
......
...@@ -14,9 +14,11 @@ type ...@@ -14,9 +14,11 @@ type
strict private strict private
ApiDB: TApiDatabaseModule; ApiDB: TApiDatabaseModule;
private private
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
public public
constructor Create;
destructor Destroy; override;
function GetBadgeCounts: TJSONObject; function GetBadgeCounts: TJSONObject;
function GetComplaintList: TJSONObject; function GetComplaintList: TJSONObject;
function GetUnitList: TJSONObject; function GetUnitList: TJSONObject;
...@@ -37,21 +39,35 @@ implementation ...@@ -37,21 +39,35 @@ implementation
uses uses
uLibrary; uLibrary;
procedure TApiService.AfterConstruction;
constructor TApiService.Create;
begin begin
inherited; Logger.Log(3, 'TApiService.Create');
inherited Create;
ApiDB := TApiDatabaseModule.Create(nil); ApiDB := TApiDatabaseModule.Create(nil);
if not ApiDB.ucENTCAD.Connected then
begin
Logger.Log(1, 'Unable to connect to API database');
raise EXDataHttpException.Create(
500,
'Unable to connect to the database. Please contact EM Systems support.'
);
end;
Logger.Log(3, 'ApiDatabaseModule created'); Logger.Log(3, 'ApiDatabaseModule created');
end; end;
procedure TApiService.BeforeDestruction; destructor TApiService.Destroy;
begin begin
ApiDB.Free; ApiDB.Free;
inherited;
Logger.Log(3, 'ApiDatabaseModule destroyed'); Logger.Log(3, 'ApiDatabaseModule destroyed');
inherited Destroy;
end; end;
function TApiService.GetBadgeCounts: TJSONObject; function TApiService.GetBadgeCounts: TJSONObject;
begin begin
Logger.Log(3, '---TApiService.GetBadgeCounts initiated'); Logger.Log(3, '---TApiService.GetBadgeCounts initiated');
......
...@@ -55,10 +55,7 @@ begin ...@@ -55,10 +55,7 @@ begin
ucLemsOCSO.Connect; ucLemsOCSO.Connect;
except except
on E: Exception do on E: Exception do
begin
Logger.Log(2, Format('Failed to connect to auth database: %s', [E.Message])); Logger.Log(2, Format('Failed to connect to auth database: %s', [E.Message]));
raise;
end;
end; end;
end; end;
......
...@@ -21,12 +21,13 @@ type ...@@ -21,12 +21,13 @@ type
userBadge: string; userBadge: string;
userId: string; userId: string;
userPersonnelId: string; userPersonnelId: string;
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
function VerifyVersion(ClientVersion: string): TJSONObject; function VerifyVersion(ClientVersion: string): TJSONObject;
function CheckUser(const User, Password, Agency: string): Integer; function CheckUser(const User, Password, Agency: string): Integer;
function Decrypt(inStr, keyStr: AnsiString): AnsiString; function Decrypt(inStr, keyStr: AnsiString): AnsiString;
public public
constructor Create;
destructor Destroy; override;
function Login(const User, Password, Agency: string): string; function Login(const User, Password, Agency: string): string;
function GetAgencieslist(): TAgenciesList; function GetAgencieslist(): TAgenciesList;
function GetAgencyConfiglist: TAgencyConfigList; function GetAgencyConfiglist: TAgencyConfigList;
...@@ -46,20 +47,31 @@ uses ...@@ -46,20 +47,31 @@ uses
{ TAuthService } { TAuthService }
procedure TAuthService.AfterConstruction;
constructor TAuthService.Create;
begin begin
inherited; Logger.Log(3, 'TAuthService.Create');
inherited Create;
authDB := TAuthDatabase.Create(nil); authDB := TAuthDatabase.Create(nil);
if not authDB.ucLemsOCSO.Connected then
begin
Logger.Log(1, 'Unable to connect to auth database');
raise EXDataHttpException.Create(500, 'Unable to connect to the database. Please contact EM Systems support.');
end;
Logger.Log(3, 'AuthDatabase created'); Logger.Log(3, 'AuthDatabase created');
end; end;
procedure TAuthService.BeforeDestruction; destructor TAuthService.Destroy;
begin begin
authDB.Free; authDB.Free;
inherited;
Logger.Log(3, 'AuthDatabase destroyed'); Logger.Log(3, 'AuthDatabase destroyed');
inherited Destroy;
end; end;
function TAuthService.GetAgenciesList: TAgenciesList; function TAuthService.GetAgenciesList: TAgenciesList;
var var
agency: TAgencyItem; agency: TAgencyItem;
......
...@@ -2,7 +2,7 @@ object FMain: TFMain ...@@ -2,7 +2,7 @@ object FMain: TFMain
Left = 0 Left = 0
Top = 0 Top = 0
Caption = 'emiMobileServer' Caption = 'emiMobileServer'
ClientHeight = 615 ClientHeight = 773
ClientWidth = 778 ClientWidth = 778
Color = clBtnFace Color = clBtnFace
Font.Charset = DEFAULT_CHARSET Font.Charset = DEFAULT_CHARSET
...@@ -13,28 +13,30 @@ object FMain: TFMain ...@@ -13,28 +13,30 @@ object FMain: TFMain
OnClose = FormClose OnClose = FormClose
DesignSize = ( DesignSize = (
778 778
615) 773)
TextHeight = 13 TextHeight = 13
object pgcMain: TPageControl object pgcMain: TPageControl
Left = 0 Left = 0
Top = 40 Top = 40
Width = 778 Width = 778
Height = 575 Height = 733
ActivePage = tabConnectedClients ActivePage = tabServerLog
Align = alBottom Align = alBottom
Anchors = [akLeft, akTop, akRight, akBottom] Anchors = [akLeft, akTop, akRight, akBottom]
TabOrder = 3 TabOrder = 3
ExplicitHeight = 575
object tabServerLog: TTabSheet object tabServerLog: TTabSheet
Caption = 'Server Log' Caption = 'Server Log'
object memoInfo: TMemo object memoInfo: TMemo
Left = 0 Left = 0
Top = 0 Top = 0
Width = 770 Width = 770
Height = 547 Height = 705
Align = alClient Align = alClient
ScrollBars = ssVertical ScrollBars = ssVertical
TabOrder = 0 TabOrder = 0
WordWrap = False WordWrap = False
ExplicitHeight = 547
end end
end end
object tabConnectedClients: TTabSheet object tabConnectedClients: TTabSheet
...@@ -44,7 +46,7 @@ object FMain: TFMain ...@@ -44,7 +46,7 @@ object FMain: TFMain
Left = 0 Left = 0
Top = 0 Top = 0
Width = 770 Width = 770
Height = 487 Height = 645
Align = alClient Align = alClient
DataSource = dsConnectedClients DataSource = dsConnectedClients
Options = [dgTitles, dgIndicator, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgRowSelect, dgConfirmDelete, dgCancelOnExit, dgTitleClick, dgTitleHotTrack] Options = [dgTitles, dgIndicator, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgRowSelect, dgConfirmDelete, dgCancelOnExit, dgTitleClick, dgTitleHotTrack]
...@@ -75,13 +77,14 @@ object FMain: TFMain ...@@ -75,13 +77,14 @@ object FMain: TFMain
end end
object pnlConnectedClientsActions: TPanel object pnlConnectedClientsActions: TPanel
Left = 0 Left = 0
Top = 487 Top = 645
Width = 770 Width = 770
Height = 60 Height = 60
Align = alBottom Align = alBottom
Caption = 'pnlConnectedClientsActions' Caption = 'pnlConnectedClientsActions'
ShowCaption = False ShowCaption = False
TabOrder = 1 TabOrder = 1
ExplicitTop = 487
object btnDisconnectClient: TButton object btnDisconnectClient: TButton
Left = 5 Left = 5
Top = 18 Top = 18
......
...@@ -71,6 +71,9 @@ end; ...@@ -71,6 +71,9 @@ end;
procedure TWsDataModel.TimerFire(Sender: TObject); procedure TWsDataModel.TimerFire(Sender: TObject);
begin begin
if not FDb.ucENTCAD.Connected then
Exit;
if not FDb.CADUpdate then if not FDb.CADUpdate then
Exit; Exit;
...@@ -80,12 +83,13 @@ end; ...@@ -80,12 +83,13 @@ end;
procedure TWsDataModel.BroadcastAll; procedure TWsDataModel.BroadcastAll;
begin begin
Logger.Log(3, 'WsDataModel: broadcasting all'); Logger.Log(3, 'WsDataModel: BroadcastAll initiated');
try FBroadcast(BuildBadgeCountsJson); except on E: Exception do Logger.Log(2, 'WsDataModel BADGE_COUNTS error: ' + E.Message); end; try FBroadcast(BuildBadgeCountsJson); except on E: Exception do Logger.Log(2, 'WsDataModel BADGE_COUNTS error: ' + E.Message); end;
try FBroadcast(BuildUnitMapJson); except on E: Exception do Logger.Log(2, 'WsDataModel UNIT_MAP error: ' + E.Message); end; try FBroadcast(BuildUnitMapJson); except on E: Exception do Logger.Log(2, 'WsDataModel UNIT_MAP error: ' + E.Message); end;
try FBroadcast(BuildComplaintMapJson); except on E: Exception do Logger.Log(2, 'WsDataModel COMPLAINT_MAP error: ' + E.Message); end; try FBroadcast(BuildComplaintMapJson); except on E: Exception do Logger.Log(2, 'WsDataModel COMPLAINT_MAP error: ' + E.Message); end;
try FBroadcast(BuildUnitListJson); except on E: Exception do Logger.Log(2, 'WsDataModel UNIT_LIST error: ' + E.Message); end; try FBroadcast(BuildUnitListJson); except on E: Exception do Logger.Log(2, 'WsDataModel UNIT_LIST error: ' + E.Message); end;
try FBroadcast(BuildComplaintListJson); except on E: Exception do Logger.Log(2, 'WsDataModel COMPLAINT_LIST error: ' + E.Message); end; try FBroadcast(BuildComplaintListJson); except on E: Exception do Logger.Log(2, 'WsDataModel COMPLAINT_LIST error: ' + E.Message); end;
Logger.Log(3, 'WsDataModel: BroadcastAll end');
end; end;
function TWsDataModel.BuildBadgeCountsJson: string; function TWsDataModel.BuildBadgeCountsJson: string;
......
[Settings] [Settings]
LogFileNum=110 LogFileNum=144
webClientVersion=9.4.0 webClientVersion=0.9.4.1
[Database] [Database]
Server=192.168.91.136 --Server=192.168.91.136
Server=192.168.102.10
--Server=192.168.56.129 --Server=192.168.56.129
--Port=5432 Port=5432
--Port=5433 --Port=5433
Database=lems_wcso Database=lems_wcso
Username=postgres Username=postgres
Password=postgreSQL --Password=postgreSQL
--Password=emsys01 Password=emsys01
--Postgre!SQL --Postgre!SQL
{ {
"url": "http://localhost:2001/emsys/emiMobile/", "url": "http://localhost:2009/emiMobile/",
"jwtTokenSecret": "super_secret0123super_secret4567", "jwtTokenSecret": "super_secret0123super_secret4567",
"adminPassword": "whatisthisusedfor?", "adminPassword": "whatisthisusedfor?",
"webAppFolder": "static", "webAppFolder": "static",
......
...@@ -108,8 +108,9 @@ ...@@ -108,8 +108,9 @@
<VerInfo_MajorVer>0</VerInfo_MajorVer> <VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_MinorVer>9</VerInfo_MinorVer> <VerInfo_MinorVer>9</VerInfo_MinorVer>
<VerInfo_Release>4</VerInfo_Release> <VerInfo_Release>4</VerInfo_Release>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.9.4.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.2.0;Comments=</VerInfo_Keys> <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.9.4.1;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.2.0;Comments=</VerInfo_Keys>
<DCC_UnitSearchPath>C:\RADTOOLS\FastMM4;$(DCC_UnitSearchPath)</DCC_UnitSearchPath> <DCC_UnitSearchPath>C:\RADTOOLS\FastMM4;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<VerInfo_Build>1</VerInfo_Build>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win64)'!=''"> <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode> <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
......
...@@ -11,7 +11,6 @@ type ...@@ -11,7 +11,6 @@ type
TSuccessProc = reference to procedure; TSuccessProc = reference to procedure;
TLogoutProc = reference to procedure(AMessage: string = ''); TLogoutProc = reference to procedure(AMessage: string = '');
TUnauthorizedAccessProc = reference to procedure(AMessage: string); TUnauthorizedAccessProc = reference to procedure(AMessage: string);
TVersionCheckCallback = reference to procedure(Success: Boolean; ErrorMessage: string);
TListProc = reference to procedure; TListProc = reference to procedure;
TSelectProc = reference to procedure(AParam: string); TSelectProc = reference to procedure(AParam: string);
......
...@@ -4,7 +4,7 @@ interface ...@@ -4,7 +4,7 @@ interface
uses uses
System.SysUtils, System.Classes, WEBLib.Modules, XData.Web.Connection, System.SysUtils, System.Classes, WEBLib.Modules, XData.Web.Connection,
App.Types, App.Config, XData.Web.Client; XData.Web.Client, App.Types, App.Config;
type type
TDMConnection = class(TWebDataModule) TDMConnection = class(TWebDataModule)
...@@ -18,12 +18,12 @@ type ...@@ -18,12 +18,12 @@ type
private private
FUnauthorizedAccessProc: TUnauthorizedAccessProc; FUnauthorizedAccessProc: TUnauthorizedAccessProc;
FWsUrl: string; FWsUrl: string;
procedure VerifyVersion(SuccessProc: TSuccessProc);
public public
property WsUrl: string read FWsUrl; property WsUrl: string read FWsUrl;
const clientVersion = '0.9.4.1'; const clientVersion = '0.9.4.1';
procedure InitApp(SuccessProc: TSuccessProc; procedure InitApp(SuccessProc: TSuccessProc;
UnauthorizedAccessProc: TUnauthorizedAccessProc); UnauthorizedAccessProc: TUnauthorizedAccessProc);
procedure SetClientConfig(Callback: TVersionCheckCallback);
end; end;
var var
...@@ -57,7 +57,8 @@ procedure TDMConnection.ApiConnectionResponse( ...@@ -57,7 +57,8 @@ procedure TDMConnection.ApiConnectionResponse(
Args: TXDataWebConnectionResponse); Args: TXDataWebConnectionResponse);
begin begin
if Args.Response.StatusCode = 401 then if Args.Response.StatusCode = 401 then
FUnauthorizedAccessProc(Format('%d: %s',[Args.Response.StatusCode, Args.Response.ContentAsText])); FUnauthorizedAccessProc(Format('%d: %s',
[Args.Response.StatusCode, Args.Response.ContentAsText]));
end; end;
procedure TDMConnection.AuthConnectionError(Error: TXDataWebConnectionError); procedure TDMConnection.AuthConnectionError(Error: TXDataWebConnectionError);
...@@ -79,7 +80,14 @@ procedure TDMConnection.InitApp(SuccessProc: TSuccessProc; ...@@ -79,7 +80,14 @@ procedure TDMConnection.InitApp(SuccessProc: TSuccessProc;
if Config.WsUrl <> '' then if Config.WsUrl <> '' then
FWsUrl := Config.WsUrl; FWsUrl := Config.WsUrl;
AuthConnection.Open(SuccessProc); console.log('InitApp: opening AuthConnection');
AuthConnection.Open(
procedure
begin
console.log('InitApp: AuthConnection opened');
VerifyVersion(SuccessProc);
end);
end; end;
begin begin
...@@ -87,9 +95,9 @@ begin ...@@ -87,9 +95,9 @@ begin
LoadConfig(@ConfigLoaded); LoadConfig(@ConfigLoaded);
end; end;
procedure TDMConnection.SetClientConfig(Callback: TVersionCheckCallback); procedure TDMConnection.VerifyVersion(SuccessProc: TSuccessProc);
begin begin
console.log('VerifyVersion: calling server');
XDataWebClient1.Connection := AuthConnection; XDataWebClient1.Connection := AuthConnection;
XDataWebClient1.RawInvoke('IAuthService.VerifyVersion', [clientVersion], XDataWebClient1.RawInvoke('IAuthService.VerifyVersion', [clientVersion],
...@@ -98,17 +106,23 @@ begin ...@@ -98,17 +106,23 @@ begin
jsonResult: TJSObject; jsonResult: TJSObject;
error: string; error: string;
begin begin
console.log('VerifyVersion: response received');
jsonResult := TJSObject(Response.Result); jsonResult := TJSObject(Response.Result);
if jsonResult.HasOwnProperty('error') then if Assigned(jsonResult) and jsonResult.HasOwnProperty('error') then
error := string(jsonResult['error']) error := string(jsonResult['error'])
else else
error := ''; error := '';
if error <> '' then if error <> '' then
Callback(False, error) TFViewErrorPage.Display(error)
else else
Callback(True, ''); SuccessProc;
end,
procedure(Error: TXDataClientError)
begin
console.log('VerifyVersion ERROR: ' + Error.ErrorMessage);
TFViewErrorPage.Display('Unable to connect to the database.');
end); end);
end; end;
......
<div class="container"> <div class="container">
<br /> <div class="row justify-content-center mt-5">
<div class="col-12 col-sm-10 col-md-8 col-lg-6">
<div class="card shadow-sm border-danger">
<div class="panel panel-red"> <div id="view.errorpage.title"
<div id="view.errorpage.title" class="panel-heading"> class="card-header bg-danger text-white fw-semibold">
Error Page Error
</div> </div>
<div id="view.errorpage.message" class="panel-body"> <div class="card-body">
<div id="view.errorpage.message"
class="text-danger">
Message Message
</div> </div>
</div>
<div class="card-footer bg-light text-end">
<a href="."
class="btn btn-outline-danger btn-sm">
Reload web application
</a>
</div>
<div class="panel-footer"> </div>
<a href=".">Reload web application</a>
</div> </div>
</div> </div>
</div> </div>
...@@ -52,8 +52,9 @@ ...@@ -52,8 +52,9 @@
Login Login
</button> </button>
</div> </div>
<div class="card-footer text-muted small"> <div class="card-footer text-muted small d-flex justify-content-between">
Please use your lems username &amp; password to login. <span>Please use your lems username &amp; password to login.</span>
<span id="view.login.version" class="opacity-75"></span>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -4,7 +4,7 @@ interface ...@@ -4,7 +4,7 @@ interface
uses uses
System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Controls, WEBLib.Forms, WEBLib.Dialogs, System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Controls, WEBLib.Forms, WEBLib.Dialogs,
Vcl.Controls, Vcl.StdCtrls, WEBLib.StdCtrls, WEBLib.JSON, Vcl.Controls, Vcl.StdCtrls, WEBLib.StdCtrls, WEBLib.JSON, Web,
JS, XData.Web.Connection, WEBLib.ExtCtrls, JS, XData.Web.Connection, WEBLib.ExtCtrls,
App.Types, ConnectionModule, XData.Web.Client; App.Types, ConnectionModule, XData.Web.Client;
...@@ -65,8 +65,12 @@ end; ...@@ -65,8 +65,12 @@ end;
procedure TFViewLogin.WebFormCreate(Sender: TObject); procedure TFViewLogin.WebFormCreate(Sender: TObject);
var
el: TJSElement;
begin begin
// lblAppTitle.Caption := 'EM Systems - webCharms App ver 0.9.2.22'; el := Document.getElementById('view.login.version');
if Assigned(el) then
TJSHtmlElement(el).innerText := 'v' + TDMConnection.clientVersion;
GetAgencyConfigList(); GetAgencyConfigList();
if FMessage <> '' then if FMessage <> '' then
ShowNotification(FMessage) ShowNotification(FMessage)
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
<div class="d-flex align-items-center gap-2 ms-auto"> <div class="d-flex align-items-center gap-2 ms-auto">
<span id="view.main.lblconnection" class="navbar-text text-light small"></span> <span id="view.main.lblconnection" class="navbar-text text-light small"></span>
<span id="view.main.version" class="navbar-text text-light small opacity-75"></span>
<button id="btn_logout" type="button" class="btn btn-outline-light btn-sm">Logout</button> <button id="btn_logout" type="button" class="btn btn-outline-light btn-sm">Logout</button>
</div> </div>
</div> </div>
......
...@@ -121,9 +121,15 @@ const ...@@ -121,9 +121,15 @@ const
procedure TFViewMain.WebFormCreate(Sender: TObject); procedure TFViewMain.WebFormCreate(Sender: TObject);
var var
userName: string; userName: string;
el: TJSElement;
begin begin
userName := JS.toString(AuthService.TokenPayload.Properties['user_name']); userName := JS.toString(AuthService.TokenPayload.Properties['user_name']);
lblUsername.Caption := ' ' + userName.ToLower + ' '; lblUsername.Caption := ' ' + userName.ToLower + ' ';
el := Document.getElementById('view.main.version');
if Assigned(el) then
TJSHtmlElement(el).innerText := 'v' + TDMConnection.clientVersion;
FChildForm := nil; FChildForm := nil;
FDetailsForm := nil; FDetailsForm := nil;
FArchiveForm := nil; FArchiveForm := nil;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment