Commit f952c2be by Mac Stephens

Switched complaint map to Leaflet popups, updated the popups to match current…

Switched complaint map to Leaflet popups, updated the popups to match current app. Fixed details click wiring, and tightened popup/list card layout & CSS.
parent 1f94b0a6
object ApiDatabaseModule: TApiDatabaseModule
Height = 491
Width = 640
object ucEnvoy: TUniConnection
ProviderName = 'PostgreSQL'
SpecificOptions.Strings = (
'PostgreSQL.Schema=envoy')
LoginPrompt = False
Left = 35
Top = 29
end
object PostgreSQLUniProvider1: TPostgreSQLUniProvider
Left = 180
Top = 30
end
object UniQuery1: TUniQuery
Connection = ucEnvoy
SQL.Strings = (
'')
Left = 351
Top = 34
end
object OracleUniProvider1: TOracleUniProvider
Left = 182
Top = 98
......@@ -632,7 +613,8 @@ object ApiDatabaseModule: TApiDatabaseModule
' ).sdo_point.y'
' END AS LAT,'
''
' cdc.CODE_DESC AS DISPATCH_CODE_DESC'
' cdc.CODE_DESC AS DISPATCH_CODE_DESC,'
' ca.ADDRESS AS ADDRESS'
'FROM COMPLAINT_ACTIVE ca'
'JOIN COMPLAINT_TIMES ct'
' ON ct.COMPLAINTID = ca.COMPLAINTID'
......@@ -675,6 +657,10 @@ object ApiDatabaseModule: TApiDatabaseModule
ReadOnly = True
Size = 50
end
object uqMapComplaintsADDRESS: TStringField
FieldName = 'ADDRESS'
Size = 64
end
object uqMapComplaintspriorityKey: TStringField
FieldKind = fkCalculated
FieldName = 'priorityKey'
......@@ -711,4 +697,54 @@ object ApiDatabaseModule: TApiDatabaseModule
ReadOnly = True
end
end
object uqMapComplaintUnitsList: TUniQuery
Connection = ucENTCAD
SQL.Strings = (
'SELECT'
' ca.COMPLAINTID,'
' ca.UNITID,'
' ca.UNITNAME,'
' ca.DATEDISPATCHED,'
' ca.DATERESPONDED,'
' ca.DATEARRIVED,'
' ca.DATECLEARED,'
' ca.LOCATION'
'FROM CFS_ACTIVE ca'
'WHERE ca.COMPLAINTID IN ('
' SELECT c.COMPLAINTID'
' FROM COMPLAINT_ACTIVE c'
' WHERE c.XCOORD IS NOT NULL'
' AND c.YCOORD IS NOT NULL'
')'
'ORDER BY ca.COMPLAINTID, ca.DATEDISPATCHED;')
Active = True
Left = 470
Top = 242
object uqMapComplaintUnitsListCOMPLAINTID: TFloatField
FieldName = 'COMPLAINTID'
end
object uqMapComplaintUnitsListUNITID: TFloatField
FieldName = 'UNITID'
end
object uqMapComplaintUnitsListUNITNAME: TStringField
FieldName = 'UNITNAME'
Size = 10
end
object uqMapComplaintUnitsListDATEDISPATCHED: TDateTimeField
FieldName = 'DATEDISPATCHED'
end
object uqMapComplaintUnitsListDATERESPONDED: TDateTimeField
FieldName = 'DATERESPONDED'
end
object uqMapComplaintUnitsListDATEARRIVED: TDateTimeField
FieldName = 'DATEARRIVED'
end
object uqMapComplaintUnitsListDATECLEARED: TDateTimeField
FieldName = 'DATECLEARED'
end
object uqMapComplaintUnitsListLOCATION: TStringField
FieldName = 'LOCATION'
Size = 30
end
end
end
......@@ -9,9 +9,6 @@ uses
type
TApiDatabaseModule = class(TDataModule)
ucEnvoy: TUniConnection;
PostgreSQLUniProvider1: TPostgreSQLUniProvider;
UniQuery1: TUniQuery;
OracleUniProvider1: TOracleUniProvider;
uqBooking: TUniQuery;
uqMapUnits: TUniQuery;
......@@ -121,6 +118,16 @@ type
uqComplaintDetailsDATERESPONDED: TDateTimeField;
uqComplaintDetailsDATEARRIVED: TDateTimeField;
uqComplaintDetailsDATECLEARED: TDateTimeField;
uqMapComplaintUnitsList: TUniQuery;
uqMapComplaintUnitsListCOMPLAINTID: TFloatField;
uqMapComplaintUnitsListUNITID: TFloatField;
uqMapComplaintUnitsListUNITNAME: TStringField;
uqMapComplaintUnitsListDATEDISPATCHED: TDateTimeField;
uqMapComplaintUnitsListDATERESPONDED: TDateTimeField;
uqMapComplaintUnitsListDATEARRIVED: TDateTimeField;
uqMapComplaintUnitsListDATECLEARED: TDateTimeField;
uqMapComplaintUnitsListLOCATION: TStringField;
uqMapComplaintsADDRESS: TStringField;
procedure uqComplaintListCalcFields(DataSet: TDataSet);
procedure uqMapComplaintsCalcFields(DataSet: TDataSet);
private
......@@ -129,7 +136,6 @@ type
function DerivePriorityKeyFromPriorityString(const priorityString: string): string;
function HandleUniqueFilenames(const category: string): string;
function BadgeCounts(const BaseQuery: TUniQuery): Integer;
class procedure ExecSQL(const SQL: string);
end;
var
......@@ -141,19 +147,6 @@ implementation
{$R *.dfm}
class procedure TApiDatabaseModule.ExecSQL(const SQL: string);
var
DB: TApiDatabaseModule;
begin
DB := TApiDatabaseModule.Create(nil);
try
DB.UniQuery1.SQL.Text := SQL;
DB.UniQuery1.ExecSQL;
finally
DB.Free;
end;
end;
procedure TApiDatabaseModule.uqComplaintListCalcFields(DataSet: TDataSet);
var
raw: string;
......
......@@ -57,7 +57,6 @@ begin
begin
Open;
try
// NOTE: your TUniQuery exposes fields named COMPLAINTS and UNITS
Result.AddPair('BadgeComplaints', TJSONNumber.Create(FieldByName('COMPLAINTS').AsInteger));
Result.AddPair('BadgeUnits', TJSONNumber.Create(FieldByName('UNITS').AsInteger));
finally
......@@ -80,60 +79,115 @@ var
data: TJSONArray;
emitted: Integer;
item: TJSONObject;
UnitsByComplaintMap: TObjectDictionary<string,TJSONArray>;
complaintId: string;
unitArray: TJSONArray;
unitStatus: string;
latestUpdate: TDateTime;
unitObj: TJSONObject;
begin
Logger.Log(3, '---TApiService.GetComplaintMap initiated');
Logger.Log(3,'---TApiService.GetComplaintMap initiated');
Result := TJSONObject.Create;
Result:=TJSONObject.Create;
TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
data := TJSONArray.Create;
data:=TJSONArray.Create;
UnitsByComplaintMap:=TObjectDictionary<string,TJSONArray>.Create([doOwnsValues]);
try
emitted := 0;
with ApiDB.uqMapComplaints do
begin
Open;
First;
while not Eof do
ApiDB.uqMapComplaintUnitsList.Open;
while not ApiDB.uqMapComplaintUnitsList.Eof do
begin
if ApiDB.uqMapComplaintsLAT.IsNull or ApiDB.uqMapComplaintsLNG.IsNull then
complaintId:=ApiDB.uqMapComplaintUnitsListCOMPLAINTID.AsString;
if not UnitsByComplaintMap.TryGetValue(complaintId,unitArray) then
begin
Next;
Continue;
unitArray:=TJSONArray.Create;
UnitsByComplaintMap.Add(complaintId,unitArray);
end;
item := TJSONObject.Create;
unitStatus:='Dispatched';
if not ApiDB.uqMapComplaintUnitsListDATECLEARED.IsNull then
unitStatus:='Cleared'
else if not ApiDB.uqMapComplaintUnitsListDATEARRIVED.IsNull then
unitStatus:='On Scene'
else if not ApiDB.uqMapComplaintUnitsListDATERESPONDED.IsNull then
unitStatus:='Enroute';
latestUpdate:=0;
if not ApiDB.uqMapComplaintUnitsListDATEDISPATCHED.IsNull then
latestUpdate:=ApiDB.uqMapComplaintUnitsListDATEDISPATCHED.AsDateTime;
if (not ApiDB.uqMapComplaintUnitsListDATERESPONDED.IsNull) and
(ApiDB.uqMapComplaintUnitsListDATERESPONDED.AsDateTime>latestUpdate) then
latestUpdate:=ApiDB.uqMapComplaintUnitsListDATERESPONDED.AsDateTime;
if (not ApiDB.uqMapComplaintUnitsListDATEARRIVED.IsNull) and
(ApiDB.uqMapComplaintUnitsListDATEARRIVED.AsDateTime>latestUpdate) then
latestUpdate:=ApiDB.uqMapComplaintUnitsListDATEARRIVED.AsDateTime;
if (not ApiDB.uqMapComplaintUnitsListDATECLEARED.IsNull) and
(ApiDB.uqMapComplaintUnitsListDATECLEARED.AsDateTime>latestUpdate) then
latestUpdate:=ApiDB.uqMapComplaintUnitsListDATECLEARED.AsDateTime;
unitObj:=TJSONObject.Create;
unitObj.AddPair('Unit',ApiDB.uqMapComplaintUnitsListUNITNAME.AsString);
unitObj.AddPair('Status',unitStatus);
if latestUpdate<>0 then
unitObj.AddPair('Updated',FormatDateTime('yyyy-mm-dd hh:nn:ss',latestUpdate))
else
unitObj.AddPair('Updated','');
item.AddPair('ComplaintId', ApiDB.uqMapComplaintsCOMPLAINTID.AsString);
item.AddPair('DispatchDistrict', ApiDB.uqMapComplaintsDISPATCHDISTRICT.AsString);
item.AddPair('DispatchCodeDesc', ApiDB.uqMapComplaintsDISPATCH_CODE_DESC.AsString);
unitArray.AddElement(unitObj);
ApiDB.uqMapComplaintUnitsList.Next;
end;
item.AddPair('DispatchCodeCategory', ApiDB.uqMapComplaintsDISPATCHCODECATEGORY.AsString);
item.AddPair('Priority', ApiDB.uqMapComplaintsPRIORITY.AsString);
item.AddPair('priorityKey', ApiDB.uqMapComplaints.FieldByName('priorityKey').AsString);
item.AddPair('pngName', ApiDB.uqMapComplaints.FieldByName('pngName').AsString);
try
emitted:=0;
ApiDB.uqMapComplaints.Open;
while not ApiDB.uqMapComplaints.Eof do
begin
item:=TJSONObject.Create;
item.AddPair('ComplaintId',ApiDB.uqMapComplaintsCOMPLAINTID.AsString);
item.AddPair('DispatchDistrict',ApiDB.uqMapComplaintsDISPATCHDISTRICT.AsString);
item.AddPair('DispatchCodeDesc',ApiDB.uqMapComplaintsDISPATCH_CODE_DESC.AsString);
item.AddPair('DispatchCodeCategory',ApiDB.uqMapComplaintsDISPATCHCODECATEGORY.AsString);
item.AddPair('Priority',ApiDB.uqMapComplaintsPRIORITY.AsString);
item.AddPair('priorityKey',ApiDB.uqMapComplaintspriorityKey.AsString);
item.AddPair('pngName',ApiDB.uqMapComplaintspngName.AsString);
item.AddPair('Address',ApiDB.uqMapComplaintsADDRESS.AsString);
complaintId:=ApiDB.uqMapComplaintsCOMPLAINTID.AsString;
if UnitsByComplaintMap.TryGetValue(complaintId,unitArray) then
item.AddPair('Units',TJSONArray(unitArray.Clone))
else
item.AddPair('Units',TJSONArray.Create);
item.AddPair('Lat', TJSONNumber.Create(ApiDB.uqMapComplaintsLAT.AsFloat));
item.AddPair('Lng', TJSONNumber.Create(ApiDB.uqMapComplaintsLNG.AsFloat));
item.AddPair('Lat',TJSONNumber.Create(ApiDB.uqMapComplaintsLAT.AsFloat));
item.AddPair('Lng',TJSONNumber.Create(ApiDB.uqMapComplaintsLNG.AsFloat));
data.AddElement(item);
Inc(emitted);
Next;
end;
ApiDB.uqMapComplaints.Next;
end;
Result.AddPair('count', TJSONNumber.Create(data.Count));
Result.AddPair('returned', TJSONNumber.Create(emitted));
Result.AddPair('data', data);
Result.AddPair('count',TJSONNumber.Create(data.Count));
Result.AddPair('returned',TJSONNumber.Create(emitted));
Result.AddPair('data',data);
Logger.Log(3,'---TApiService.GetComplaintMap End (returned='+emitted.ToString+')');
except
data.Free;
Logger.Log(3, '---TApiService.GetComplaintMap End (error)');
raise EXDataHttpException.Create(500, 'Failed to load complaint map');
on E: Exception do
begin
FreeAndNil(data);
Logger.Log(1,'GetComplaintMap error: '+E.Message);
raise EXDataHttpException.Create(500,'Failed to load complaint map');
end;
end;
finally
UnitsByComplaintMap.Free;
end;
Logger.Log(3, '---TApiService.GetComplaintMap End');
end;
function TApiService.GetUnitMap: TJSONObject;
var
data: TJSONArray;
......@@ -211,7 +265,6 @@ begin
var item := TJSONObject.Create;
// Add a section header only when the district changes
var curDistrict := ApiDB.uqComplaintListDISPATCHDISTRICT.AsString;
if not SameText(curDistrict, lastDistrict) then
item.AddPair('DistrictHeader', curDistrict);
......@@ -220,11 +273,9 @@ begin
var districtSector := ApiDB.uqComplaintListDISTRICT_DESC.AsString + ApiDB.uqComplaintListSECTOR_DESC.AsString;
item.AddPair('DistrictSector', districtSector);
// existing color hex
var colorVal := ApiDB.uqComplaintListPRIORITY_COLOR.AsInteger;
item.AddPair('PriorityColor', '#' + IntToHex(colorVal and $FFFFFF, 6));
// Text is white only for the deep blue (255 = $0000FF), black otherwise
if (colorVal and $FFFFFF) = $0000FF then
item.AddPair('PriorityTextColor', '#FFFFFF')
else
......
......@@ -51,10 +51,6 @@ object AuthDatabase: TAuthDatabase
Left = 249
Top = 45
end
object PostgreSQLUniProvider1: TPostgreSQLUniProvider
Left = 276
Top = 156
end
object OracleUniProvider1: TOracleUniProvider
Left = 94
Top = 152
......@@ -78,7 +74,7 @@ object AuthDatabase: TAuthDatabase
end
object uqBooking: TUniQuery
Connection = ucBooking
Left = 98
Top = 44
Left = 88
Top = 48
end
end
......@@ -10,7 +10,6 @@ type
TAuthDatabase = class(TDataModule)
uq: TUniQuery;
uqMisc: TUniQuery;
PostgreSQLUniProvider1: TPostgreSQLUniProvider;
uquser_id: TLargeintField;
uqusername: TStringField;
uqpassword: TMemoField;
......@@ -70,21 +69,6 @@ begin
end;
end;
Logger.Log(1, '');
Logger.Log(1, 'Loading Twilio settings...');
var twilioSID := iniFile.ReadString('Twilio', 'AccountSID', '');
if twilioSID.IsEmpty then
Logger.Log(1, 'Twilio->AccountSID: Entry not found')
else
Logger.Log(1, 'Twilio->AccountSID Found');
var twilioAuth := iniFile.ReadString('Twilio', 'AuthHeader', '');
if twilioAuth.IsEmpty then
Logger.Log(1, 'Twilio->AuthHeader: Entry not found')
else
Logger.Log(1, 'Twilio->AuthHeader Found');
finally
iniFile.Free;
end;
......
......@@ -15,30 +15,11 @@ type
FFileLogLevelFromIni: Boolean;
FLogFileNum: Integer;
FLogFileNumFromIni: Boolean;
FEmailPolling: Boolean;
FEmailPollingFromIni: Boolean;
FEmailPollingInterval: Integer;
FEmailPollingIntervalFromIni: Boolean;
FWebClientVersion: string;
FWebClientVersionFromIni: Boolean;
FTwilioUpdateTime: Integer;
FTwilioUpdateTimeFromIni: Boolean;
// [Database]
FDatabaseServer: string;
FDatabaseServerFromIni: Boolean;
FDatabaseName: string;
FDatabaseNameFromIni: Boolean;
FDatabaseUsername: string;
FDatabaseUsernameFromIni: Boolean;
FDatabasePassword: string;
FDatabasePasswordFromIni: Boolean;
// [Twilio]
FTwilioSID: string;
FTwilioSIDFromIni: Boolean;
FTwilioAuthHeader: string;
FTwilioAuthHeaderFromIni: Boolean;
public
constructor Create;
......@@ -49,30 +30,12 @@ type
property FileLogLevelFromIni: Boolean read FFileLogLevelFromIni;
property LogFileNum: Integer read FLogFileNum;
property LogFileNumFromIni: Boolean read FLogFileNumFromIni;
property EmailPolling: Boolean read FEmailPolling;
property EmailPollingFromIni: Boolean read FEmailPollingFromIni;
property EmailPollingInterval: Integer read FEmailPollingInterval;
property EmailPollingIntervalFromIni: Boolean read FEmailPollingIntervalFromIni;
property WebClientVersion: string read FWebClientVersion;
property WebClientVersionFromIni: Boolean read FWebClientVersionFromIni;
property TwilioUpdateTime: Integer read FTwilioUpdateTime;
property TwilioUpdateTimeFromIni: Boolean read FTwilioUpdateTimeFromIni;
// [Database]
property DatabaseServer: string read FDatabaseServer;
property DatabaseServerFromIni: Boolean read FDatabaseServerFromIni;
property DatabaseName: string read FDatabaseName;
property DatabaseNameFromIni: Boolean read FDatabaseNameFromIni;
property DatabaseUsername: string read FDatabaseUsername;
property DatabaseUsernameFromIni: Boolean read FDatabaseUsernameFromIni;
property DatabasePassword: string read FDatabasePassword;
property DatabasePasswordFromIni: Boolean read FDatabasePasswordFromIni;
// [Twilio]
property TwilioSID: string read FTwilioSID;
property TwilioSIDFromIni: Boolean read FTwilioSIDFromIni;
property TwilioAuthHeader: string read FTwilioAuthHeader;
property TwilioAuthHeaderFromIni: Boolean read FTwilioAuthHeaderFromIni;
end;
procedure LoadIniEntries;
......@@ -107,37 +70,11 @@ begin
FLogFileNum := iniFile.ReadInteger('Settings', 'LogFileNum', 0);
FLogFileNumFromIni := iniFile.ValueExists('Settings', 'LogFileNum');
FEmailPolling := iniFile.ReadBool('Settings', 'EmailPolling', False);
FEmailPollingFromIni := iniFile.ValueExists('Settings', 'EmailPolling');
FEmailPollingInterval := iniFile.ReadInteger('Settings', 'EmailPollingInterval', 1);
FEmailPollingIntervalFromIni := iniFile.ValueExists('Settings', 'EmailPollingInterval');
FWebClientVersion := iniFile.ReadString('Settings', 'webClientVersion', '');
FWebClientVersionFromIni := iniFile.ValueExists('Settings', 'webClientVersion');
FTwilioUpdateTime := iniFile.ReadInteger('Settings', 'TwilioUpdateTime', 0);
FTwilioUpdateTimeFromIni := iniFile.ValueExists('Settings', 'TwilioUpdateTime');
// [Database]
FDatabaseServer := iniFile.ReadString('Database', 'Server', 'localhost');
FDatabaseServerFromIni := iniFile.ValueExists('Database', 'Server');
FDatabaseName := iniFile.ReadString('Database', 'Database', 'envoy_db');
FDatabaseNameFromIni := iniFile.ValueExists('Database', 'Database');
FDatabaseUsername := iniFile.ReadString('Database', 'Username', 'postgres');
FDatabaseUsernameFromIni := iniFile.ValueExists('Database', 'Username');
FDatabasePassword := iniFile.ReadString('Database', 'Password', '');
FDatabasePasswordFromIni := iniFile.ValueExists('Database', 'Password');
// [Twilio]
FTwilioSID := iniFile.ReadString('Twilio', 'AccountSID', '');
FTwilioSIDFromIni := iniFile.ValueExists('Twilio', 'AccountSID');
FTwilioAuthHeader := iniFile.ReadString('Twilio', 'AuthHeader', '');
FTwilioAuthHeaderFromIni := iniFile.ValueExists('Twilio', 'AuthHeader');
finally
iniFile.Free;
end;
......
object FData: TFData
Left = 0
Top = 0
ActiveControl = DBAdvGrid1
Caption = 'FData'
ClientHeight = 522
ClientWidth = 1002
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
OnCreate = FormCreate
OnDestroy = FormDestroy
TextHeight = 15
object lblStartDate: TLabel
Left = 0
Top = 8
Width = 51
Height = 15
Alignment = taRightJustify
Caption = 'Start Date'
end
object lblLocation: TLabel
Left = 0
Top = 40
Width = 46
Height = 15
Caption = 'Location'
end
object Label1: TLabel
Left = 190
Top = 9
Width = 47
Height = 15
Caption = 'End Date'
end
object lblHash: TLabel
Left = 644
Top = 232
Width = 3
Height = 15
end
object lblHash2: TLabel
Left = 644
Top = 278
Width = 3
Height = 15
end
object btnFind: TButton
Left = 398
Top = 9
Width = 75
Height = 25
Caption = 'Find'
TabOrder = 0
OnClick = btnFindClick
end
object Memo1: TMemo
Left = 0
Top = 433
Width = 1002
Height = 89
Align = alBottom
Lines.Strings = (
'Memo1')
TabOrder = 1
end
object btnGetCalls: TButton
Left = 398
Top = 40
Width = 75
Height = 25
Caption = 'Get Calls'
TabOrder = 2
OnClick = btnGetCallsClick
end
object txtPhoneNum: TAdvEdit
Left = 243
Top = 41
Width = 121
Height = 23
EmptyTextStyle = []
FlatLineColor = 11250603
FocusColor = clWindow
FocusFontColor = 3881787
LabelFont.Charset = DEFAULT_CHARSET
LabelFont.Color = clWindowText
LabelFont.Height = -12
LabelFont.Name = 'Segoe UI'
LabelFont.Style = []
Lookup.Font.Charset = DEFAULT_CHARSET
Lookup.Font.Color = clWindowText
Lookup.Font.Height = -11
Lookup.Font.Name = 'Segoe UI'
Lookup.Font.Style = []
Lookup.Separator = ';'
Color = clWindow
TabOrder = 3
Text = ''
Visible = True
Version = '4.0.6.1'
end
object DBAdvGrid1: TDBAdvGrid
Left = 6
Top = 84
Width = 632
Height = 154
ColCount = 25
DrawingStyle = gdsClassic
FixedColor = clWhite
RowCount = 2
FixedRows = 1
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goColSizing, goFixedRowDefAlign]
TabOrder = 4
ActiveCellFont.Charset = DEFAULT_CHARSET
ActiveCellFont.Color = 4474440
ActiveCellFont.Height = -12
ActiveCellFont.Name = 'Segoe UI'
ActiveCellFont.Style = [fsBold]
ActiveCellColor = 11565130
ActiveCellColorTo = 11565130
BorderColor = 11250603
ControlLook.FixedGradientFrom = clWhite
ControlLook.FixedGradientTo = clWhite
ControlLook.FixedGradientHoverFrom = clGray
ControlLook.FixedGradientHoverTo = clWhite
ControlLook.FixedGradientHoverMirrorFrom = clWhite
ControlLook.FixedGradientHoverMirrorTo = clWhite
ControlLook.FixedGradientHoverBorder = 11645361
ControlLook.FixedGradientDownFrom = clWhite
ControlLook.FixedGradientDownTo = clWhite
ControlLook.FixedGradientDownMirrorFrom = clWhite
ControlLook.FixedGradientDownMirrorTo = clWhite
ControlLook.FixedGradientDownBorder = 11250603
ControlLook.DropDownHeader.Font.Charset = DEFAULT_CHARSET
ControlLook.DropDownHeader.Font.Color = clWindowText
ControlLook.DropDownHeader.Font.Height = -11
ControlLook.DropDownHeader.Font.Name = 'Segoe UI'
ControlLook.DropDownHeader.Font.Style = []
ControlLook.DropDownHeader.Visible = True
ControlLook.DropDownHeader.Buttons = <>
ControlLook.DropDownFooter.Font.Charset = DEFAULT_CHARSET
ControlLook.DropDownFooter.Font.Color = clWindowText
ControlLook.DropDownFooter.Font.Height = -11
ControlLook.DropDownFooter.Font.Name = 'Segoe UI'
ControlLook.DropDownFooter.Font.Style = []
ControlLook.DropDownFooter.Visible = True
ControlLook.DropDownFooter.Buttons = <>
ControlLook.ToggleSwitch.BackgroundBorderWidth = 1.000000000000000000
ControlLook.ToggleSwitch.ButtonBorderWidth = 1.000000000000000000
ControlLook.ToggleSwitch.CaptionFont.Charset = DEFAULT_CHARSET
ControlLook.ToggleSwitch.CaptionFont.Color = clWindowText
ControlLook.ToggleSwitch.CaptionFont.Height = -12
ControlLook.ToggleSwitch.CaptionFont.Name = 'Segoe UI'
ControlLook.ToggleSwitch.CaptionFont.Style = []
ControlLook.ToggleSwitch.Shadow = False
Filter = <>
FilterDropDown.Font.Charset = DEFAULT_CHARSET
FilterDropDown.Font.Color = clWindowText
FilterDropDown.Font.Height = -12
FilterDropDown.Font.Name = 'Segoe UI'
FilterDropDown.Font.Style = []
FilterDropDown.TextChecked = 'Checked'
FilterDropDown.TextUnChecked = 'Unchecked'
FilterDropDownClear = '(All)'
FilterEdit.TypeNames.Strings = (
'Starts with'
'Ends with'
'Contains'
'Not contains'
'Equal'
'Not equal'
'Larger than'
'Smaller than'
'Clear')
FixedColWidth = 20
FixedRowHeight = 22
FixedFont.Charset = DEFAULT_CHARSET
FixedFont.Color = clWindowText
FixedFont.Height = -11
FixedFont.Name = 'Segoe UI'
FixedFont.Style = [fsBold]
FloatFormat = '%.2f'
HoverButtons.Buttons = <>
HTMLSettings.ImageFolder = 'images'
HTMLSettings.ImageBaseName = 'img'
Look = glCustom
PrintSettings.DateFormat = 'dd/mm/yyyy'
PrintSettings.Font.Charset = DEFAULT_CHARSET
PrintSettings.Font.Color = clWindowText
PrintSettings.Font.Height = -12
PrintSettings.Font.Name = 'Segoe UI'
PrintSettings.Font.Style = []
PrintSettings.FixedFont.Charset = DEFAULT_CHARSET
PrintSettings.FixedFont.Color = clWindowText
PrintSettings.FixedFont.Height = -12
PrintSettings.FixedFont.Name = 'Segoe UI'
PrintSettings.FixedFont.Style = []
PrintSettings.HeaderFont.Charset = DEFAULT_CHARSET
PrintSettings.HeaderFont.Color = clWindowText
PrintSettings.HeaderFont.Height = -12
PrintSettings.HeaderFont.Name = 'Segoe UI'
PrintSettings.HeaderFont.Style = []
PrintSettings.FooterFont.Charset = DEFAULT_CHARSET
PrintSettings.FooterFont.Color = clWindowText
PrintSettings.FooterFont.Height = -12
PrintSettings.FooterFont.Name = 'Segoe UI'
PrintSettings.FooterFont.Style = []
PrintSettings.PageNumSep = '/'
SearchFooter.ColorTo = clNone
SearchFooter.FindNextCaption = 'Find &next'
SearchFooter.FindPrevCaption = 'Find &previous'
SearchFooter.Font.Charset = DEFAULT_CHARSET
SearchFooter.Font.Color = clWindowText
SearchFooter.Font.Height = -12
SearchFooter.Font.Name = 'Segoe UI'
SearchFooter.Font.Style = []
SearchFooter.HighLightCaption = 'Highlight'
SearchFooter.HintClose = 'Close'
SearchFooter.HintFindNext = 'Find next occurrence'
SearchFooter.HintFindPrev = 'Find previous occurrence'
SearchFooter.HintHighlight = 'Highlight occurrences'
SearchFooter.MatchCaseCaption = 'Match case'
SearchFooter.ResultFormat = '(%d of %d)'
SelectionColor = 13744549
SelectionTextColor = clWindowText
SortSettings.HeaderColor = clWhite
SortSettings.HeaderColorTo = clWhite
SortSettings.HeaderMirrorColor = clWhite
SortSettings.HeaderMirrorColorTo = clWhite
Version = '2.8.3.7'
AutoCreateColumns = True
AutoRemoveColumns = True
Columns = <
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 20
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'date_updated'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 84
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'price_unit'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'parent_call_sid'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 89
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'caller_name'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 75
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'duration'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 57
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'annotation'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 70
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'answered_by'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 80
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'sid'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 27
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'queue_time'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 74
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'price'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 38
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'api_version'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 71
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'status'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 43
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'direction'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 59
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'start_time'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'date_created'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 79
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'from_formatted'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 96
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'group_sid'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'trunk_sid'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 60
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'uri'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 26
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'account_sid'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 75
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'end_time'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 61
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'to_formatted'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 81
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'phone_number_sid'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 113
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'forwarded_from'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 97
end>
DataSource = dsCalls
InvalidPicture.Data = {
055449636F6E0000010001002020200000000000A81000001600000028000000
2000000040000000010020000000000000100000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000006A6A6B256A6A6B606A6A6B946A6A6BC06A6A6BE1
6A6A6BF86A6A6BF86A6A6BE16A6A6BC06A6A6B946A6A6B606A6A6B2500000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000006A6A6B407575769E787879F19F9F9FF6C0C0C0FDDADADAFFEDEDEEFF
FBFBFBFFFBFBFBFFEDEDEEFFDADADAFFC0C0C0FD9F9F9FF6787879F17575769E
6A6A6B4000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000006A6A6B22
7C7C7C98888889F0BDBDBDFCE9E9EBFED9D9E9FEB5B5DDFE8B8BCDFE595AB7FF
3739A8FF2B2CA4FF4A49B1FF7171C1FFA1A2D7FFD3D3E8FFEAEAEBFEBEBEBFFC
888889F07C7C7C986A6A6B220000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000006A6A6B43838383D8
B7B7B8FAECECEFFEC0C0DFFF7977C4FF2221A0FF12129BFF1010A4FF0C0CA8FF
0A0AACFF0A0AB4FF0A0AB9FF0D0DBEFF0F0FB1FF1111A6FF5656B8FFAEADDCFF
ECECEFFEB7B7B8FA838383D86A6A6B4300000000000000000000000000000000
00000000000000000000000000000000000000006A6A6B4E878788EAD3D3D3FE
CACAE8FF4443B0FF171799FF11119CFF0C0C98FF0B0B9BFF0B0BA0FF0A0AA6FF
0909ACFF0909B2FF0808BAFF0707BFFF0B09C8FF0D0DCEFF1111CCFF1010AFFF
4A49B2FFCFCFEBFFD3D3D3FE878788EA6A6A6B4E000000000000000000000000
000000000000000000000000000000006A6A6B43878788EAE1E1E1FFA8A8DAFF
2323A0FF15159CFF0D0D92FF0C0C95FF0C0C99FF0B0B9EFF0B0BA0FF0A0AA6FF
0909ACFF0909B2FF0808B8FF0808BCFF0808C3FF0C0CC9FF0C0CD0FF0D0DD6FF
1313CFFF2222A9FFAFAFDEFFE1E1E1FF878788EA6A6A6B430000000000000000
0000000000000000000000006A6A6B22838383D8D3D3D3FEA8A8D9FF2020A4FF
13139BFF0C0C92FF0C0C95FF0C0C97FF0C0C99FF0B0B9EFF0B0BA0FF0A0AA4FF
0A0AA9FF0909B0FF0808B4FF0808BBFF0707C0FF0A0AC6FF0909CCFF0C0CD3FF
0D0DD8FF1313D3FF1A1AA8FFAEADDEFFD4D4D4FE838383D86A6A6B2200000000
0000000000000000000000007C7C7C98B7B7B8FACACAE8FF2524A3FF13139FFF
0C0C97FF0C0C95FF0C0C95FF0C0C91FF0C0C95FF0B0B9EFF0B0BA0FF0A0AA4FF
0A0AA8FF0909ADFF0909B2FF0808B8FF0808BCFF0707C0FF0808BCFF0707C5FF
0C0CD3FF0D0DD7FF1212D1FF2020A7FFCDCDEBFFB8B8B9FA7C7C7C9800000000
00000000000000006A6A6B40888889F0ECECEFFE4545B1FF1616A4FF0B0B9BFF
0C0C99FF0C0C96FF3333A2FFB9B9D0FF393A9BFF0C0C95FF0B0BA1FF0A0AA4FF
0A0AA7FF0A0AABFF0909B0FF0808B4FF0808B7FF2F2FC2FFAEAEE2FF4B4BBFFF
0707BEFF0B0BD1FF0C0CD3FF1413CCFF4848B1FFECECEFFE888889F06A6A6B40
00000000000000007575769EBFBFBFFD9B9BD5FF1C1CA6FF0C0CA1FF0B0B9FFF
0B0B9AFF3535A7FFB5B5BEFFE6E6DFFFEDEDEFFF3C3C9CFF0C0C97FF0A0AA4FF
0A0AA6FF0A0AA9FF0909ADFF0909B0FF2626B5FFCECEDEFFFFFFFBFFEEEEF1FF
4848BAFF0808BCFF0A0ACDFF0B0BCEFF1111ABFFBEC0E0FFBFC0BFFD7575769E
000000006A6A6B25787879F1E3E3E5FE4646B2FF1414A8FF0A0AA4FF0B0BA0FF
2121A9FFBDBDCAFFD0D0C8FFC5C5C5FFE3E3E1FFEDEDEFFF3E3E9EFF0C0C98FF
0A0AA6FF0A0AA8FF0A0AA9FF2B2BB0FFC0C0CDFFEAEAE2FFEBEBEBFFFEFEF8FF
EDEDEEFF2828BDFF0707C4FF0809C7FF0F0FC4FF8788CBFFEBEBECFE79797AF1
6A6A6B256A6A6B609D9E9DF6D6D7E4FF3A3AB3FF1212ADFF0A0AA8FF0A0AA4FF
1313AAFFABABCFFFD6D6CBFFCACACAFFC6C6C6FFE4E4E0FFEEEEEFFF3F3FA0FF
0C0C99FF0A0AA6FF2828ABFFB2B2BFFFD8D8CEFFD6D6D8FFE0E0E0FFF6F5EDFF
D1D1EDFF1E1CC0FF0707BEFF0707BFFF0707C0FF2120AAFFD3D5E9FE9FA0A0F6
6A6A6B606A6A6B94BDBDBDFBBABBDCFF3A39B7FF2F2FB8FF0909ADFF0A0AA9FF
0A0AA6FF1515ACFFADADCFFFD6D6CBFFCBCBCAFFC6C6C6FFE4E4E1FFEEEEEFFF
3838A1FF2222A2FFACABB8FFC8C8C0FFC7C7C8FFCDCDCDFFE1E1D9FFC8CAE1FF
2424BCFF0808B4FF0808B9FF0808BAFF0808BBFF0F0EABFFA1A2D5FEC0C0C0FC
6A6A6B946A6A6BC0D9D8D7FE9999D1FF3838BBFF3636BCFF2C2CB7FF0909ADFF
0A0AA9FF0A0AA4FF1C1CAFFFB1B1CFFFD6D6CBFFCCCCCBFFC7C7C7FFE4E4E1FF
ECECEEFFACACB7FFC2C2BCFFBEBEBFFFC0C0C0FFCFCFC6FFC1C1D5FF2727B8FF
0909ACFF0909B2FF0909B2FF0909B4FF0808B4FF0E0EB5FF6E6EBFFFD9D9D9FE
6A6A6BC06A6A6BE1EBEAEBFF7D7CC7FF3838BFFF3434BEFF3536BEFF2A2AB8FF
0909B0FF0909ACFF0A0AA8FF1C1CB1FFB2B2D0FFD7D7CCFFCBCBCBFFC7C7C8FF
C8C8C3FFC6C6C3FFBFBFC1FFBDBDBDFFC5C5BCFFB8B8CEFF2929B5FF0A0AA8FF
0909ACFF0909ADFF0909AFFF0909AFFF0909AFFF0C0CB0FF4747AFFFECECEDFF
6A6A6BE16A6A6BF8F9F9F9FF6666C1FF3838C4FF3535C2FF3434C0FF3535BEFF
3030BCFF1313B4FF0909ADFF0A0AA8FF1E1EB3FFAAAAD0FFD3D3CDFFCCCCCCFF
C8C8C8FFC3C3C3FFC2C2C1FFC4C4BFFFB2B2CBFF2B2BB4FF0A0AA4FF0A0AA8FF
0A0AA8FF0A0AA9FF0A0AA9FF0A0AA9FF0A0AA9FF0B0BA9FF3131A6FFFAFAFAFF
6A6A6BF86A6A6BF8FBFBFBFF5959BEFF3B3BCAFF3A3AC8FF3737C4FF3535C2FF
3636C0FF3636BEFF2323B8FF0909B1FF0A0AA7FF4949BEFFD6D6D4FFD3D3D1FF
CDCDCDFFC8C8C8FFC4C4C3FFEDEDEDFF5F5FB3FF0C0C98FF0A0AA7FF0A0AA6FF
0A0AA6FF0A0AA6FF0A0AA4FF0A0AA6FF0A0AA4FF0B0BA4FF2D2DA6FFFBFBFBFF
6A6A6BF86A6A6BE1EDEDEEFF7F80CBFF4041CCFF3C3CCAFF3A3AC8FF383AC8FF
3838C4FF3636C2FF3939C0FF2123B7FF4A4AC2FFCBCBDEFFE0E0DCFFD6D6D6FF
D2D2D3FFCDCDCEFFC9C9C9FFE2E2E1FFF1F1F2FF4242A3FF0C0C99FF0A0AA4FF
0A0AA4FF0A0AA4FF0B0BA3FF0B0BA3FF0B0BA1FF0E0EA1FF4443B0FFEDEDEEFF
6A6A6BE16A6A6BC0DADADAFF9C9BD5FE4949CDFF3E3DD0FF3C3DCEFF3C3CCAFF
3A3AC8FF3B39C7FF2828BDFF5C5CCCFFE5E5EDFFF4F4EDFFE5E5E6FFDEDEDEFF
DCDCD9FFD9D9D3FFCDCDCDFFC8C8C8FFE5E5E1FFF1F1F3FF3F3FA0FF0C0C99FF
0A0AA4FF0B0BA1FF0B0BA0FF0B0BA0FF0B0B9FFF1313A2FF6B6BC0FFDADADAFF
6A6A6BC06A6A6B94C0C0C0FDBDBAE1FE5655CFFF4141D4FF3F3FD2FF3F3FCEFF
3D3DCCFF2C2AC3FF5E5ED3FFEBEBF6FFFFFFFAFFF1F1F1FFEDEDEEFFF0F0E9FF
D2D2E6FFBDBDD6FFDADAD3FFCFCFCFFFC9C9CAFFE5E5E2FFF1F1F3FF3A3AA0FF
0C0C98FF0B0BA3FF0B0B9FFF0B0B9EFF0B0B9EFF1C1CA4FF9C9CD3FFC1C1C1FD
6A6A6B946A6A6B609F9F9FF6DAD9EAFF6B6BCFFF4444D7FF4143D6FF4242D3FF
3434CDFF6464DBFFEFEFFFFFFFFFFFFFFCFCFCFFF6F6F6FFFCFCF4FFE2E1F0FF
5050CCFF4040C1FFC3C3DBFFE1E1D8FFD4D4D5FFCFCFCFFFE8E8E5FFF2F2F4FF
4040A2FF0C0C99FF0F0FA2FF0F0FA0FF0F0F9DFF302FA9FFD1D1E8FEA0A0A0F6
6A6A6B606A6A6B25787879F1E9E9EBFEA7A7DAFF6060DBFF4547DBFF3C3CD6FF
5857DEFFF2F2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8E8F8FF5B5BD4FF
2828BDFF2A2BBDFF4949C5FFC3C3DBFFE4E4DAFFD5D5D5FFCECED0FFE8E8E5FF
F4F4F4FF4949AFFF2121A6FF2A2AA6FF2C2BA9FF5557B8FFEAEAECFE787879F1
6A6A6B25000000007575769EBEBEBEFDC9CAE6FF7A79DBFF4C4CDFFF4141DBFF
5757E0FFEAEAFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8E7FFFF5B5BD7FF2E2EC6FF
3E3EC9FF3A3AC5FF2C2EC1FF4A49C8FFC2C2DDFFE3E3DAFFD5D5D4FFDADAD3FF
CACBD9FF4747BBFF2525ADFF2C2BACFF3332AEFFA5A4D8FFBFBFBFFD7575769E
00000000000000006A6A6B40888889F0ECECEFFE9696D6FF7B7BE3FF4D4BE0FF
4141DBFF5F5FE6FFE7E7FFFFFFFFFFFFE9E9FFFF5A5ADCFF3333CAFF4242CFFF
4040CBFF3D3DC9FF3D3EC8FF3030C2FF4848C9FFC0C0DDFFECEEDEFFD0D0E0FF
5554C7FF2828B3FF3232B4FF3434B1FF5453B7FFECECEFFE888889F06A6A6B40
0000000000000000000000007C7C7C98B7B7B8FAD0D0ECFF8F8FDBFF6868E3FF
4E4EE2FF3E40DBFF6565E9FFB2B2F7FF6565E4FF393BD2FF4646D7FF4343D4FF
4343D1FF4242CFFF4040CBFF3F3FCAFF3333C4FF4E4ECBFF9E9EE2FF5C5BCFFF
292ABAFF3636BCFF3938B8FF3F3EB1FFCBCBE9FFB7B7B8FA7C7C7C9800000000
0000000000000000000000006A6A6B22838383D8D3D3D3FEB5B5E2FF9E9EE4FF
6766E2FF4E50E6FF4646E0FF3D3DDAFF4444DCFF4B4BDCFF4848DBFF4847D9FF
4646D5FF4443D3FF4343D1FF4242CFFF4143CDFF3A3AC8FF312FC5FF3535C3FF
3C3CC3FF3D3DBEFF403FB5FFACACDCFFD3D3D3FE838383D86A6A6B2200000000
000000000000000000000000000000006A6A6B43878788EAE1E1E1FFB5B5E2FF
A7A6E4FF7877E5FF5151E5FF4F4FE4FF4E4EE2FF4D4DE0FF4C4CDEFF4B4BDCFF
4949DBFF4848D7FF4747D5FF4545D3FF4545D1FF4343CFFF4242CCFF3F3FCBFF
4343C2FF4645B6FFADADDCFFE1E1E1FF878788EA6A6A6B430000000000000000
00000000000000000000000000000000000000006A6A6B4E878788EAD3D3D3FE
D0D0ECFFAAA9DFFFA2A2ECFF6565E3FF5151E6FF4F4FE4FF4F4DE4FF4D4DE0FF
4D4DDFFF4D4DDCFF4C49DBFF4A4AD8FF4749D6FF4747D4FF4949CBFF4B4BC3FF
8E8ED0FFCDCCE8FFD3D3D3FE878788EA6A6A6B4E000000000000000000000000
0000000000000000000000000000000000000000000000006A6A6B43838383D8
B7B7B8FAECECEFFEC3C2E5FFADAEE1FF9E9DE8FF6F6FE0FF5C5CE1FF5452E2FF
5051E1FF4F4FDFFF4F4FDBFF5150D6FF5151CFFF5F5FC8FFA1A1D3FEC7C8E0FE
E4E4E7FEB7B7B8FA838383D86A6A6B4300000000000000000000000000000000
000000000000000000000000000000000000000000000000000000006A6A6B22
7C7C7C98888889F0BFBFBFFDEBEBECFED8D9EBFEBDBDE4FEA8A7DCFF9695D7FF
8886D4FF7F7DCEFF8C8BD2FFA1A2D9FFC0BEE1FED9D9EAFEEAEAECFEBFBFBFFD
888889F07C7C7C986A6A6B220000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000006A6A6B407575769E787879F19F9F9FF6C0C0C0FDDADADAFFEDEDEEFF
FBFBFBFFFBFBFBFFEDEDEEFFDADADAFFC0C0C0FD9F9F9FF6787879F17575769E
6A6A6B4000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000006A6A6B256A6A6B606A6A6B946A6A6BC06A6A6BE1
6A6A6BF86A6A6BF86A6A6BE16A6A6BC06A6A6B946A6A6B606A6A6B2500000000
0000000000000000000000000000000000000000000000000000000000000000
00000000FFC003FFFF0000FFFC00003FF800001FF000000FE0000007C0000003
C000000380000001800000010000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000080000001
80000001C0000003C0000003E0000007F000000FF800001FFC00003FFF0000FF
FFC003FF}
ShowUnicode = False
ColWidths = (
20
84
64
89
75
57
70
80
27
74
38
71
43
59
64
79
96
64
60
26
75
61
81
113
97)
RowHeights = (
22
22)
end
object DBAdvGrid2: TDBAdvGrid
Left = 0
Top = 238
Width = 631
Height = 199
ColCount = 20
DrawingStyle = gdsClassic
FixedColor = clWhite
RowCount = 2
FixedRows = 1
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goColSizing, goFixedRowDefAlign]
TabOrder = 5
ActiveCellFont.Charset = DEFAULT_CHARSET
ActiveCellFont.Color = 4474440
ActiveCellFont.Height = -12
ActiveCellFont.Name = 'Segoe UI'
ActiveCellFont.Style = [fsBold]
ActiveCellColor = 11565130
ActiveCellColorTo = 11565130
BorderColor = 11250603
ControlLook.FixedGradientFrom = clWhite
ControlLook.FixedGradientTo = clWhite
ControlLook.FixedGradientHoverFrom = clGray
ControlLook.FixedGradientHoverTo = clWhite
ControlLook.FixedGradientHoverMirrorFrom = clWhite
ControlLook.FixedGradientHoverMirrorTo = clWhite
ControlLook.FixedGradientHoverBorder = 11645361
ControlLook.FixedGradientDownFrom = clWhite
ControlLook.FixedGradientDownTo = clWhite
ControlLook.FixedGradientDownMirrorFrom = clWhite
ControlLook.FixedGradientDownMirrorTo = clWhite
ControlLook.FixedGradientDownBorder = 11250603
ControlLook.DropDownHeader.Font.Charset = DEFAULT_CHARSET
ControlLook.DropDownHeader.Font.Color = clWindowText
ControlLook.DropDownHeader.Font.Height = -11
ControlLook.DropDownHeader.Font.Name = 'Segoe UI'
ControlLook.DropDownHeader.Font.Style = []
ControlLook.DropDownHeader.Visible = True
ControlLook.DropDownHeader.Buttons = <>
ControlLook.DropDownFooter.Font.Charset = DEFAULT_CHARSET
ControlLook.DropDownFooter.Font.Color = clWindowText
ControlLook.DropDownFooter.Font.Height = -11
ControlLook.DropDownFooter.Font.Name = 'Segoe UI'
ControlLook.DropDownFooter.Font.Style = []
ControlLook.DropDownFooter.Visible = True
ControlLook.DropDownFooter.Buttons = <>
ControlLook.ToggleSwitch.BackgroundBorderWidth = 1.000000000000000000
ControlLook.ToggleSwitch.ButtonBorderWidth = 1.000000000000000000
ControlLook.ToggleSwitch.CaptionFont.Charset = DEFAULT_CHARSET
ControlLook.ToggleSwitch.CaptionFont.Color = clWindowText
ControlLook.ToggleSwitch.CaptionFont.Height = -12
ControlLook.ToggleSwitch.CaptionFont.Name = 'Segoe UI'
ControlLook.ToggleSwitch.CaptionFont.Style = []
ControlLook.ToggleSwitch.Shadow = False
Filter = <>
FilterDropDown.Font.Charset = DEFAULT_CHARSET
FilterDropDown.Font.Color = clWindowText
FilterDropDown.Font.Height = -12
FilterDropDown.Font.Name = 'Segoe UI'
FilterDropDown.Font.Style = []
FilterDropDown.TextChecked = 'Checked'
FilterDropDown.TextUnChecked = 'Unchecked'
FilterDropDownClear = '(All)'
FilterEdit.TypeNames.Strings = (
'Starts with'
'Ends with'
'Contains'
'Not contains'
'Equal'
'Not equal'
'Larger than'
'Smaller than'
'Clear')
FixedColWidth = 20
FixedRowHeight = 22
FixedFont.Charset = DEFAULT_CHARSET
FixedFont.Color = clWindowText
FixedFont.Height = -11
FixedFont.Name = 'Segoe UI'
FixedFont.Style = [fsBold]
FloatFormat = '%.2f'
HoverButtons.Buttons = <>
HTMLSettings.ImageFolder = 'images'
HTMLSettings.ImageBaseName = 'img'
Look = glCustom
PrintSettings.DateFormat = 'dd/mm/yyyy'
PrintSettings.Font.Charset = DEFAULT_CHARSET
PrintSettings.Font.Color = clWindowText
PrintSettings.Font.Height = -12
PrintSettings.Font.Name = 'Segoe UI'
PrintSettings.Font.Style = []
PrintSettings.FixedFont.Charset = DEFAULT_CHARSET
PrintSettings.FixedFont.Color = clWindowText
PrintSettings.FixedFont.Height = -12
PrintSettings.FixedFont.Name = 'Segoe UI'
PrintSettings.FixedFont.Style = []
PrintSettings.HeaderFont.Charset = DEFAULT_CHARSET
PrintSettings.HeaderFont.Color = clWindowText
PrintSettings.HeaderFont.Height = -12
PrintSettings.HeaderFont.Name = 'Segoe UI'
PrintSettings.HeaderFont.Style = []
PrintSettings.FooterFont.Charset = DEFAULT_CHARSET
PrintSettings.FooterFont.Color = clWindowText
PrintSettings.FooterFont.Height = -12
PrintSettings.FooterFont.Name = 'Segoe UI'
PrintSettings.FooterFont.Style = []
PrintSettings.PageNumSep = '/'
SearchFooter.ColorTo = clNone
SearchFooter.FindNextCaption = 'Find &next'
SearchFooter.FindPrevCaption = 'Find &previous'
SearchFooter.Font.Charset = DEFAULT_CHARSET
SearchFooter.Font.Color = clWindowText
SearchFooter.Font.Height = -12
SearchFooter.Font.Name = 'Segoe UI'
SearchFooter.Font.Style = []
SearchFooter.HighLightCaption = 'Highlight'
SearchFooter.HintClose = 'Close'
SearchFooter.HintFindNext = 'Find next occurrence'
SearchFooter.HintFindPrev = 'Find previous occurrence'
SearchFooter.HintHighlight = 'Highlight occurrences'
SearchFooter.MatchCaseCaption = 'Match case'
SearchFooter.ResultFormat = '(%d of %d)'
SelectionColor = 13744549
SelectionTextColor = clWindowText
SortSettings.HeaderColor = clWhite
SortSettings.HeaderColorTo = clWhite
SortSettings.HeaderMirrorColor = clWhite
SortSettings.HeaderMirrorColorTo = clWhite
Version = '2.8.3.7'
AutoCreateColumns = True
AutoRemoveColumns = True
Columns = <
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 20
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'account_sid'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'api_version'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'call_sid'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'conference_sid'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'date_created'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'date_updated'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'start_time'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'duration'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'sid'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'price'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'price_unit'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'status'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'channels'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'source'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'error_code'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'uri'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'encryption_details'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'media_url'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end
item
Borders = []
BorderPen.Color = clSilver
ButtonHeight = 18
CheckFalse = 'N'
CheckTrue = 'Y'
Color = clWindow
FieldName = 'transcription'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
HeaderFont.Charset = DEFAULT_CHARSET
HeaderFont.Color = 3881787
HeaderFont.Height = -12
HeaderFont.Name = 'Segoe UI'
HeaderFont.Style = []
PrintBorders = [cbTop, cbLeft, cbRight, cbBottom]
PrintFont.Charset = DEFAULT_CHARSET
PrintFont.Color = clWindowText
PrintFont.Height = -12
PrintFont.Name = 'Segoe UI'
PrintFont.Style = []
Width = 64
end>
DataSource = dsRecordings
InvalidPicture.Data = {
055449636F6E0000010001002020200000000000A81000001600000028000000
2000000040000000010020000000000000100000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000006A6A6B256A6A6B606A6A6B946A6A6BC06A6A6BE1
6A6A6BF86A6A6BF86A6A6BE16A6A6BC06A6A6B946A6A6B606A6A6B2500000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000006A6A6B407575769E787879F19F9F9FF6C0C0C0FDDADADAFFEDEDEEFF
FBFBFBFFFBFBFBFFEDEDEEFFDADADAFFC0C0C0FD9F9F9FF6787879F17575769E
6A6A6B4000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000006A6A6B22
7C7C7C98888889F0BDBDBDFCE9E9EBFED9D9E9FEB5B5DDFE8B8BCDFE595AB7FF
3739A8FF2B2CA4FF4A49B1FF7171C1FFA1A2D7FFD3D3E8FFEAEAEBFEBEBEBFFC
888889F07C7C7C986A6A6B220000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000006A6A6B43838383D8
B7B7B8FAECECEFFEC0C0DFFF7977C4FF2221A0FF12129BFF1010A4FF0C0CA8FF
0A0AACFF0A0AB4FF0A0AB9FF0D0DBEFF0F0FB1FF1111A6FF5656B8FFAEADDCFF
ECECEFFEB7B7B8FA838383D86A6A6B4300000000000000000000000000000000
00000000000000000000000000000000000000006A6A6B4E878788EAD3D3D3FE
CACAE8FF4443B0FF171799FF11119CFF0C0C98FF0B0B9BFF0B0BA0FF0A0AA6FF
0909ACFF0909B2FF0808BAFF0707BFFF0B09C8FF0D0DCEFF1111CCFF1010AFFF
4A49B2FFCFCFEBFFD3D3D3FE878788EA6A6A6B4E000000000000000000000000
000000000000000000000000000000006A6A6B43878788EAE1E1E1FFA8A8DAFF
2323A0FF15159CFF0D0D92FF0C0C95FF0C0C99FF0B0B9EFF0B0BA0FF0A0AA6FF
0909ACFF0909B2FF0808B8FF0808BCFF0808C3FF0C0CC9FF0C0CD0FF0D0DD6FF
1313CFFF2222A9FFAFAFDEFFE1E1E1FF878788EA6A6A6B430000000000000000
0000000000000000000000006A6A6B22838383D8D3D3D3FEA8A8D9FF2020A4FF
13139BFF0C0C92FF0C0C95FF0C0C97FF0C0C99FF0B0B9EFF0B0BA0FF0A0AA4FF
0A0AA9FF0909B0FF0808B4FF0808BBFF0707C0FF0A0AC6FF0909CCFF0C0CD3FF
0D0DD8FF1313D3FF1A1AA8FFAEADDEFFD4D4D4FE838383D86A6A6B2200000000
0000000000000000000000007C7C7C98B7B7B8FACACAE8FF2524A3FF13139FFF
0C0C97FF0C0C95FF0C0C95FF0C0C91FF0C0C95FF0B0B9EFF0B0BA0FF0A0AA4FF
0A0AA8FF0909ADFF0909B2FF0808B8FF0808BCFF0707C0FF0808BCFF0707C5FF
0C0CD3FF0D0DD7FF1212D1FF2020A7FFCDCDEBFFB8B8B9FA7C7C7C9800000000
00000000000000006A6A6B40888889F0ECECEFFE4545B1FF1616A4FF0B0B9BFF
0C0C99FF0C0C96FF3333A2FFB9B9D0FF393A9BFF0C0C95FF0B0BA1FF0A0AA4FF
0A0AA7FF0A0AABFF0909B0FF0808B4FF0808B7FF2F2FC2FFAEAEE2FF4B4BBFFF
0707BEFF0B0BD1FF0C0CD3FF1413CCFF4848B1FFECECEFFE888889F06A6A6B40
00000000000000007575769EBFBFBFFD9B9BD5FF1C1CA6FF0C0CA1FF0B0B9FFF
0B0B9AFF3535A7FFB5B5BEFFE6E6DFFFEDEDEFFF3C3C9CFF0C0C97FF0A0AA4FF
0A0AA6FF0A0AA9FF0909ADFF0909B0FF2626B5FFCECEDEFFFFFFFBFFEEEEF1FF
4848BAFF0808BCFF0A0ACDFF0B0BCEFF1111ABFFBEC0E0FFBFC0BFFD7575769E
000000006A6A6B25787879F1E3E3E5FE4646B2FF1414A8FF0A0AA4FF0B0BA0FF
2121A9FFBDBDCAFFD0D0C8FFC5C5C5FFE3E3E1FFEDEDEFFF3E3E9EFF0C0C98FF
0A0AA6FF0A0AA8FF0A0AA9FF2B2BB0FFC0C0CDFFEAEAE2FFEBEBEBFFFEFEF8FF
EDEDEEFF2828BDFF0707C4FF0809C7FF0F0FC4FF8788CBFFEBEBECFE79797AF1
6A6A6B256A6A6B609D9E9DF6D6D7E4FF3A3AB3FF1212ADFF0A0AA8FF0A0AA4FF
1313AAFFABABCFFFD6D6CBFFCACACAFFC6C6C6FFE4E4E0FFEEEEEFFF3F3FA0FF
0C0C99FF0A0AA6FF2828ABFFB2B2BFFFD8D8CEFFD6D6D8FFE0E0E0FFF6F5EDFF
D1D1EDFF1E1CC0FF0707BEFF0707BFFF0707C0FF2120AAFFD3D5E9FE9FA0A0F6
6A6A6B606A6A6B94BDBDBDFBBABBDCFF3A39B7FF2F2FB8FF0909ADFF0A0AA9FF
0A0AA6FF1515ACFFADADCFFFD6D6CBFFCBCBCAFFC6C6C6FFE4E4E1FFEEEEEFFF
3838A1FF2222A2FFACABB8FFC8C8C0FFC7C7C8FFCDCDCDFFE1E1D9FFC8CAE1FF
2424BCFF0808B4FF0808B9FF0808BAFF0808BBFF0F0EABFFA1A2D5FEC0C0C0FC
6A6A6B946A6A6BC0D9D8D7FE9999D1FF3838BBFF3636BCFF2C2CB7FF0909ADFF
0A0AA9FF0A0AA4FF1C1CAFFFB1B1CFFFD6D6CBFFCCCCCBFFC7C7C7FFE4E4E1FF
ECECEEFFACACB7FFC2C2BCFFBEBEBFFFC0C0C0FFCFCFC6FFC1C1D5FF2727B8FF
0909ACFF0909B2FF0909B2FF0909B4FF0808B4FF0E0EB5FF6E6EBFFFD9D9D9FE
6A6A6BC06A6A6BE1EBEAEBFF7D7CC7FF3838BFFF3434BEFF3536BEFF2A2AB8FF
0909B0FF0909ACFF0A0AA8FF1C1CB1FFB2B2D0FFD7D7CCFFCBCBCBFFC7C7C8FF
C8C8C3FFC6C6C3FFBFBFC1FFBDBDBDFFC5C5BCFFB8B8CEFF2929B5FF0A0AA8FF
0909ACFF0909ADFF0909AFFF0909AFFF0909AFFF0C0CB0FF4747AFFFECECEDFF
6A6A6BE16A6A6BF8F9F9F9FF6666C1FF3838C4FF3535C2FF3434C0FF3535BEFF
3030BCFF1313B4FF0909ADFF0A0AA8FF1E1EB3FFAAAAD0FFD3D3CDFFCCCCCCFF
C8C8C8FFC3C3C3FFC2C2C1FFC4C4BFFFB2B2CBFF2B2BB4FF0A0AA4FF0A0AA8FF
0A0AA8FF0A0AA9FF0A0AA9FF0A0AA9FF0A0AA9FF0B0BA9FF3131A6FFFAFAFAFF
6A6A6BF86A6A6BF8FBFBFBFF5959BEFF3B3BCAFF3A3AC8FF3737C4FF3535C2FF
3636C0FF3636BEFF2323B8FF0909B1FF0A0AA7FF4949BEFFD6D6D4FFD3D3D1FF
CDCDCDFFC8C8C8FFC4C4C3FFEDEDEDFF5F5FB3FF0C0C98FF0A0AA7FF0A0AA6FF
0A0AA6FF0A0AA6FF0A0AA4FF0A0AA6FF0A0AA4FF0B0BA4FF2D2DA6FFFBFBFBFF
6A6A6BF86A6A6BE1EDEDEEFF7F80CBFF4041CCFF3C3CCAFF3A3AC8FF383AC8FF
3838C4FF3636C2FF3939C0FF2123B7FF4A4AC2FFCBCBDEFFE0E0DCFFD6D6D6FF
D2D2D3FFCDCDCEFFC9C9C9FFE2E2E1FFF1F1F2FF4242A3FF0C0C99FF0A0AA4FF
0A0AA4FF0A0AA4FF0B0BA3FF0B0BA3FF0B0BA1FF0E0EA1FF4443B0FFEDEDEEFF
6A6A6BE16A6A6BC0DADADAFF9C9BD5FE4949CDFF3E3DD0FF3C3DCEFF3C3CCAFF
3A3AC8FF3B39C7FF2828BDFF5C5CCCFFE5E5EDFFF4F4EDFFE5E5E6FFDEDEDEFF
DCDCD9FFD9D9D3FFCDCDCDFFC8C8C8FFE5E5E1FFF1F1F3FF3F3FA0FF0C0C99FF
0A0AA4FF0B0BA1FF0B0BA0FF0B0BA0FF0B0B9FFF1313A2FF6B6BC0FFDADADAFF
6A6A6BC06A6A6B94C0C0C0FDBDBAE1FE5655CFFF4141D4FF3F3FD2FF3F3FCEFF
3D3DCCFF2C2AC3FF5E5ED3FFEBEBF6FFFFFFFAFFF1F1F1FFEDEDEEFFF0F0E9FF
D2D2E6FFBDBDD6FFDADAD3FFCFCFCFFFC9C9CAFFE5E5E2FFF1F1F3FF3A3AA0FF
0C0C98FF0B0BA3FF0B0B9FFF0B0B9EFF0B0B9EFF1C1CA4FF9C9CD3FFC1C1C1FD
6A6A6B946A6A6B609F9F9FF6DAD9EAFF6B6BCFFF4444D7FF4143D6FF4242D3FF
3434CDFF6464DBFFEFEFFFFFFFFFFFFFFCFCFCFFF6F6F6FFFCFCF4FFE2E1F0FF
5050CCFF4040C1FFC3C3DBFFE1E1D8FFD4D4D5FFCFCFCFFFE8E8E5FFF2F2F4FF
4040A2FF0C0C99FF0F0FA2FF0F0FA0FF0F0F9DFF302FA9FFD1D1E8FEA0A0A0F6
6A6A6B606A6A6B25787879F1E9E9EBFEA7A7DAFF6060DBFF4547DBFF3C3CD6FF
5857DEFFF2F2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8E8F8FF5B5BD4FF
2828BDFF2A2BBDFF4949C5FFC3C3DBFFE4E4DAFFD5D5D5FFCECED0FFE8E8E5FF
F4F4F4FF4949AFFF2121A6FF2A2AA6FF2C2BA9FF5557B8FFEAEAECFE787879F1
6A6A6B25000000007575769EBEBEBEFDC9CAE6FF7A79DBFF4C4CDFFF4141DBFF
5757E0FFEAEAFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8E7FFFF5B5BD7FF2E2EC6FF
3E3EC9FF3A3AC5FF2C2EC1FF4A49C8FFC2C2DDFFE3E3DAFFD5D5D4FFDADAD3FF
CACBD9FF4747BBFF2525ADFF2C2BACFF3332AEFFA5A4D8FFBFBFBFFD7575769E
00000000000000006A6A6B40888889F0ECECEFFE9696D6FF7B7BE3FF4D4BE0FF
4141DBFF5F5FE6FFE7E7FFFFFFFFFFFFE9E9FFFF5A5ADCFF3333CAFF4242CFFF
4040CBFF3D3DC9FF3D3EC8FF3030C2FF4848C9FFC0C0DDFFECEEDEFFD0D0E0FF
5554C7FF2828B3FF3232B4FF3434B1FF5453B7FFECECEFFE888889F06A6A6B40
0000000000000000000000007C7C7C98B7B7B8FAD0D0ECFF8F8FDBFF6868E3FF
4E4EE2FF3E40DBFF6565E9FFB2B2F7FF6565E4FF393BD2FF4646D7FF4343D4FF
4343D1FF4242CFFF4040CBFF3F3FCAFF3333C4FF4E4ECBFF9E9EE2FF5C5BCFFF
292ABAFF3636BCFF3938B8FF3F3EB1FFCBCBE9FFB7B7B8FA7C7C7C9800000000
0000000000000000000000006A6A6B22838383D8D3D3D3FEB5B5E2FF9E9EE4FF
6766E2FF4E50E6FF4646E0FF3D3DDAFF4444DCFF4B4BDCFF4848DBFF4847D9FF
4646D5FF4443D3FF4343D1FF4242CFFF4143CDFF3A3AC8FF312FC5FF3535C3FF
3C3CC3FF3D3DBEFF403FB5FFACACDCFFD3D3D3FE838383D86A6A6B2200000000
000000000000000000000000000000006A6A6B43878788EAE1E1E1FFB5B5E2FF
A7A6E4FF7877E5FF5151E5FF4F4FE4FF4E4EE2FF4D4DE0FF4C4CDEFF4B4BDCFF
4949DBFF4848D7FF4747D5FF4545D3FF4545D1FF4343CFFF4242CCFF3F3FCBFF
4343C2FF4645B6FFADADDCFFE1E1E1FF878788EA6A6A6B430000000000000000
00000000000000000000000000000000000000006A6A6B4E878788EAD3D3D3FE
D0D0ECFFAAA9DFFFA2A2ECFF6565E3FF5151E6FF4F4FE4FF4F4DE4FF4D4DE0FF
4D4DDFFF4D4DDCFF4C49DBFF4A4AD8FF4749D6FF4747D4FF4949CBFF4B4BC3FF
8E8ED0FFCDCCE8FFD3D3D3FE878788EA6A6A6B4E000000000000000000000000
0000000000000000000000000000000000000000000000006A6A6B43838383D8
B7B7B8FAECECEFFEC3C2E5FFADAEE1FF9E9DE8FF6F6FE0FF5C5CE1FF5452E2FF
5051E1FF4F4FDFFF4F4FDBFF5150D6FF5151CFFF5F5FC8FFA1A1D3FEC7C8E0FE
E4E4E7FEB7B7B8FA838383D86A6A6B4300000000000000000000000000000000
000000000000000000000000000000000000000000000000000000006A6A6B22
7C7C7C98888889F0BFBFBFFDEBEBECFED8D9EBFEBDBDE4FEA8A7DCFF9695D7FF
8886D4FF7F7DCEFF8C8BD2FFA1A2D9FFC0BEE1FED9D9EAFEEAEAECFEBFBFBFFD
888889F07C7C7C986A6A6B220000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000006A6A6B407575769E787879F19F9F9FF6C0C0C0FDDADADAFFEDEDEEFF
FBFBFBFFFBFBFBFFEDEDEEFFDADADAFFC0C0C0FD9F9F9FF6787879F17575769E
6A6A6B4000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000006A6A6B256A6A6B606A6A6B946A6A6BC06A6A6BE1
6A6A6BF86A6A6BF86A6A6BE16A6A6BC06A6A6B946A6A6B606A6A6B2500000000
0000000000000000000000000000000000000000000000000000000000000000
00000000FFC003FFFF0000FFFC00003FF800001FF000000FE0000007C0000003
C000000380000001800000010000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000080000001
80000001C0000003C0000003E0000007F000000FF800001FFC00003FFF0000FF
FFC003FF}
ShowUnicode = False
ColWidths = (
20
64
64
64
64
64
64
64
64
64
64
64
64
64
64
64
64
64
64
64)
RowHeights = (
22
22)
end
object wwlcStore: TwwDBLookupCombo
Left = 57
Top = 41
Width = 123
Height = 23
DropDownAlignment = taLeftJustify
Selected.Strings = (
'location'#9'30'#9'location'#9#9)
LookupTable = TwilioDataModule.uqLocations
LookupField = 'phone_number_formatted'
TabOrder = 6
AutoDropDown = False
ShowButton = True
PreciseEditRegion = False
AllowClearKey = True
OnCloseUp = wwlcStoreCloseUp
end
object dtpCallsDate1: TwwDBDateTimePicker
Left = 57
Top = 8
Width = 121
Height = 23
Epoch = 1950
ShowButton = True
TabOrder = 7
end
object FullUpdate: TButton
Left = 486
Top = 40
Width = 75
Height = 25
Caption = 'Full Update'
TabOrder = 8
OnClick = FullUpdateClick
end
object dtpCallsDate2: TwwDBDateTimePicker
Left = 243
Top = 9
Width = 121
Height = 23
Epoch = 1950
ShowButton = True
TabOrder = 9
end
object edtUsername: TEdit
Left = 696
Top = 10
Width = 121
Height = 23
TabOrder = 10
TextHint = 'Username'
end
object edtPassword: TEdit
Left = 696
Top = 39
Width = 121
Height = 23
TabOrder = 11
TextHint = 'Password'
end
object btnAddUser: TButton
Left = 866
Top = 29
Width = 75
Height = 25
Caption = 'Add User'
TabOrder = 12
OnClick = btnAddUserClick
end
object cbAdmin: TCheckBox
Left = 696
Top = 158
Width = 97
Height = 17
Caption = 'Make Admin?'
TabOrder = 13
end
object edtFullName: TEdit
Left = 696
Top = 68
Width = 121
Height = 23
TabOrder = 14
TextHint = 'Full Name'
end
object edtPhoneNumber: TEdit
Left = 696
Top = 97
Width = 121
Height = 23
TabOrder = 15
TextHint = 'Phone Number'
end
object edtEmailAddress: TEdit
Left = 696
Top = 129
Width = 121
Height = 23
TabOrder = 16
TextHint = 'Email Address'
end
object dsCalls: TDataSource
DataSet = TwilioDataModule.uqCalls
Left = 502
Top = 475
end
object dsRecordings: TDataSource
DataSet = TwilioDataModule.uqRecordings
Left = 348
Top = 472
end
object uqUsers: TUniQuery
Connection = TwilioDataModule.ucEnvoy
SQL.Strings = (
'select * from envoy.users')
Left = 669
Top = 456
object uqUsersuser_id: TLargeintField
FieldName = 'user_id'
end
object uqUsersusername: TStringField
FieldName = 'username'
Required = True
Size = 64
end
object uqUserspassword: TMemoField
FieldName = 'password'
Required = True
BlobType = ftMemo
end
object uqUsersdate_created: TStringField
FieldName = 'date_created'
Required = True
Size = 21
end
object uqUsersadmin: TBooleanField
FieldName = 'admin'
end
object uqUsersemail: TMemoField
FieldName = 'email'
BlobType = ftMemo
end
object uqUsersphone_number: TStringField
FieldName = 'phone_number'
Size = 14
end
object uqUsersfull_name: TStringField
FieldName = 'full_name'
Size = 30
end
object uqUsersactive: TBooleanField
FieldName = 'active'
end
end
end
// Uses Twilio.Data.Module for the rest api calls. Simply for testing querys.
// Visual aspect is for testing purposes only and has no affect on the client.
// Authors:
// Cameron Hayes
// Elias Serraf
// Mac ...
unit Data;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, AdvUtil, Data.DB, Vcl.Grids, AdvObj,
BaseGrid, AdvGrid, DBAdvGrid, MemDS, DBAccess, Uni, Vcl.StdCtrls, Vcl.Mask,
vcl.wwdbedit, vcl.wwdotdot, vcl.wwdbcomb, REST.Client, REST.Types, System.JSON,
System.Generics.Collections, AdvEdit, vcl.wwdblook, vcl.wwdbdatetimepicker,
System.Hash;
type
TFData = class(TForm)
dsCalls: TDataSource;
btnFind: TButton;
Memo1: TMemo;
btnGetCalls: TButton;
txtPhoneNum: TAdvEdit;
DBAdvGrid1: TDBAdvGrid;
DBAdvGrid2: TDBAdvGrid;
dsRecordings: TDataSource;
wwlcStore: TwwDBLookupCombo;
dtpCallsDate1: TwwDBDateTimePicker;
FullUpdate: TButton;
lblStartDate: TLabel;
lblLocation: TLabel;
dtpCallsDate2: TwwDBDateTimePicker;
Label1: TLabel;
edtUsername: TEdit;
edtPassword: TEdit;
lblHash: TLabel;
btnAddUser: TButton;
lblHash2: TLabel;
uqUsers: TUniQuery;
cbAdmin: TCheckBox;
uqUsersuser_id: TLargeintField;
uqUsersusername: TStringField;
uqUserspassword: TMemoField;
uqUsersdate_created: TStringField;
uqUsersadmin: TBooleanField;
edtFullName: TEdit;
edtPhoneNumber: TEdit;
edtEmailAddress: TEdit;
uqUsersemail: TMemoField;
uqUsersphone_number: TStringField;
uqUsersfull_name: TStringField;
uqUsersactive: TBooleanField;
procedure btnFindClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure btnGetCallsClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FullUpdateClick(Sender: TObject);
procedure wwlcStoreCloseUp(Sender: TObject; LookupTable,
FillTable: TDataSet; modified: Boolean);
procedure btnAddUserClick(Sender: TObject);
procedure addUser();
private
{ Private declarations }
accountSID: string;
authHeader: string;
public
{ Public declarations }
end;
var
FData: TFData;
implementation
{$R *.dfm}
uses Api.Database, Twilio.Data.Module, uLibrary;
procedure TFData.FormCreate(Sender: TObject);
begin
TwilioDataModule := TTwilioDataModule.Create(Self);
end;
procedure TFData.FormDestroy(Sender: TObject);
begin
TwilioDataModule.Free;
end;
procedure TFData.FullUpdateClick(Sender: TObject);
var
count: string;
begin
count := TwilioDataModule.FullUpdate();
Memo1.Lines.Add(count);
end;
procedure TFData.wwlcStoreCloseUp(Sender: TObject; LookupTable,
FillTable: TDataSet; modified: Boolean);
begin
if wwlcStore.Text = '' then
txtPhoneNum.Text := ''
else
txtPhoneNum.Text := wwlcStore.LookupValue;
end;
procedure TFData.btnGetCallsClick(Sender: TObject);
// Gets 50 calls and adds them to the database if they havent seen an earlier call
begin
TwilioDataModule.GetCalls(txtPhoneNum.Text, 50, 0 );
end;
procedure TFData.btnAddUserClick(Sender: TObject);
var
dateCreated: TDateTime;
hashString: string;
SQL: string;
begin
addUser();
end;
procedure TFData.addUser();
var
dateCreated: TDateTime;
hashString: string;
SQL: string;
username: string;
begin
dateCreated := now;
hashString := DateTimeToStr(dateCreated) + edtPassword.Text;
lblHash.Caption := THashSHA2.GetHashString(
hashString,
THashSHA2.TSHA2Version.SHA512).ToUpper;
lblHash2.Caption := IntToStr(length(DateTimeToStr(dateCreated)));
username := edtUsername.Text;
username := username.ToLower;
SQL := 'select * from envoy.users where username = ' + QuotedStr(username);
uqUsers.Close;
uqUsers.SQL.Text := sql;
uqUsers.Open;
if uqUsers.IsEmpty then
begin
uqUsers.Insert;
uqUsersusername.AsString := username;
uqUserspassword.AsString := THashSHA2.GetHashString(hashString,
THashSHA2.TSHA2Version.SHA512).ToUpper;
uqUsersdate_created.AsString := DateTimeToStr(dateCreated);
uqUsersadmin.AsBoolean := cbAdmin.Checked;
uqUsersphone_number.AsString := edtPhoneNumber.Text;
uqUsersemail.AsString := edtEmailAddress.Text;
uqUsersfull_name.AsString := edtFullName.Text;
uqUsers.Post;
lblHash2.Caption := 'Added';
end
else
lblHash2.Caption := 'Username already taken';
end;
procedure TFData.btnFindClick(Sender: TObject);
// Retrieves calls from a specific number from the database.
// SQL: SQL statement to retrieve calls from the database
// whereSQL: where section of the SQL that is built in the function
var
SQL: string;
whereSQL: string;
begin
//TwilioDataModule.ShowCalls(txtPhoneNum.Text);
whereSQL := 'where ';
if wwlcStore.Text <> '' then
whereSQL := whereSQL + 'to_formatted = ' + QuotedStr(txtPhoneNum.Text);
if dtpCallsDate1.Text <> '' then
if whereSQL = 'where ' then
whereSQL := whereSQL + 'date_created > ' + QuotedStr(dtpCallsDate1.Text)
else
whereSQL := whereSQL + 'AND date_created > ' + QuotedStr(dtpCallsDate1.Text);
if dtpCallsDate2.Text <> '' then
if whereSQL = 'where ' then
whereSQL := whereSQL + 'date_created <= ' + QuotedStr(dtpCallsDate2.Text)
else
whereSQL := whereSQL + 'AND date_created <= ' + QuotedStr(dtpCallsDate2.Text);
if whereSQL = 'where ' then
whereSQL := '';
SQL := 'select * from envoy.calls '+ whereSQL + ' order by date_created desc';
Memo1.Lines.Add(SQL);
doQuery(TwilioDataModule.uqCalls, SQL);
DBAdvGrid1.AutoSizeColumns(true);
end;
end.
......@@ -17,7 +17,7 @@ object FMain: TFMain
TextHeight = 13
object memoInfo: TMemo
Left = 8
Top = 40
Top = 39
Width = 744
Height = 549
Anchors = [akLeft, akTop, akRight, akBottom]
......@@ -33,22 +33,13 @@ object FMain: TFMain
TabOrder = 1
OnClick = btnApiSwaggerUIClick
end
object btnData: TButton
Left = 525
Top = 8
Width = 75
Height = 25
Caption = 'Data'
TabOrder = 2
OnClick = btnDataClick
end
object btnExit: TButton
Left = 671
Top = 8
Width = 75
Height = 25
Caption = 'Exit'
TabOrder = 3
TabOrder = 2
OnClick = btnExitClick
end
object btnAuthSwaggerUI: TButton
......@@ -57,7 +48,7 @@ object FMain: TFMain
Width = 100
Height = 25
Caption = 'Auth SwaggerUI'
TabOrder = 4
TabOrder = 3
OnClick = btnAuthSwaggerUIClick
end
object initTimer: TTimer
......
......@@ -13,20 +13,17 @@ type
TFMain = class(TForm)
memoInfo: TMemo;
btnApiSwaggerUI: TButton;
btnData: TButton;
btnExit: TButton;
initTimer: TTimer;
btnAuthSwaggerUI: TButton;
ExeInfo1: TExeInfo;
procedure btnApiSwaggerUIClick(Sender: TObject);
procedure btnDataClick(Sender: TObject);
procedure btnExitClick(Sender: TObject);
procedure ContactFormData(AText: String);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure initTimerTimer(Sender: TObject);
procedure btnAuthSwaggerUIClick(Sender: TObject);
strict private
phoneDict: TDictionary<string, string>;
procedure StartServers;
function LogValue(const LabelName: string; const Value: string; FromIni: Boolean): string;
end;
......@@ -41,7 +38,8 @@ uses
Common.Config,
Common.Ini,
Sparkle.Utils,
Data, Twilio.Data.Module, Api.Database, System.StrUtils;
Api.Database,
System.StrUtils;
{$R *.dfm}
......@@ -62,14 +60,6 @@ begin
ShellExecute(Handle, 'open', PChar(TSparkleUtils.CombineUrlFast(AuthServerModule.XDataServer.BaseUrl, 'swaggerui')), nil, nil, SW_SHOWNORMAL);
end;
procedure TFMain.btnDataClick(Sender: TObject);
begin
FData := TFData.Create(Self);
FData.ShowModal;
FData.Free;
end;
procedure TFMain.ContactFormData(AText: String);
begin
if memoInfo.CanFocus then
......@@ -90,7 +80,6 @@ end;
procedure TFMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
phoneDict.Free;
ServerConfig.Free;
IniEntries.Free;
AuthServerModule.Free;
......@@ -118,16 +107,15 @@ begin
Logger.Log(1, '--- Settings ---');
Logger.Log(1, LogValue('--Settings->LogFileNum', IniEntries.LogFileNum.ToString, IniEntries.LogFileNumFromIni));
Logger.Log(1, LogValue('--Settings->webClientVersion', IniEntries.WebClientVersion, IniEntries.WebClientVersionFromIni));
Logger.Log(1, LogValue('--Settings->TwilioUpdateTime', IniEntries.TwilioUpdateTime.ToString, IniEntries.TwilioUpdateTimeFromIni));
Logger.Log(1, '');
Logger.Log(1, '--- Database ---');
Logger.Log(1, LogValue('--Database->Server', IniEntries.DatabaseServer, IniEntries.DatabaseServerFromIni));
Logger.Log(1, LogValue('--Database->Database', IniEntries.DatabaseName, IniEntries.DatabaseNameFromIni));
Logger.Log(1, LogValue('--Database->Username', IniEntries.DatabaseUsername, IniEntries.DatabaseUsernameFromIni));
Logger.Log(1, LogValue('--Database->Password', IniEntries.DatabasePassword, IniEntries.DatabasePasswordFromIni));
Logger.Log(1, '');
// Logger.Log(1, '--- Database ---');
// Logger.Log(1, LogValue('--Database->Server', IniEntries.DatabaseServer, IniEntries.DatabaseServerFromIni));
// Logger.Log(1, LogValue('--Database->Database', IniEntries.DatabaseName, IniEntries.DatabaseNameFromIni));
// Logger.Log(1, LogValue('--Database->Username', IniEntries.DatabaseUsername, IniEntries.DatabaseUsernameFromIni));
// Logger.Log(1, LogValue('--Database->Password', IniEntries.DatabasePassword, IniEntries.DatabasePasswordFromIni));
Logger.Log(1, '');
Logger.Log(1, '--- URLs ---');
try
AuthServerModule := TAuthServerModule.Create(Self);
AuthServerModule.StartAuthServer(ServerConfig.url, AUTH_MODEL);
......
object TwilioDataModule: TTwilioDataModule
OnCreate = DataModuleCreate
OnDestroy = DataModuleDestroy
Height = 338
Width = 537
object ucEnvoy: TUniConnection
ProviderName = 'PostgreSQL'
SpecificOptions.Strings = (
'PostgreSQL.Schema=envoy')
LoginPrompt = False
Left = 65
Top = 89
end
object PostgreSQLUniProvider1: TPostgreSQLUniProvider
Left = 226
Top = 88
end
object UniQuery1: TUniQuery
Connection = ucEnvoy
SQL.Strings = (
'')
Left = 361
Top = 88
end
object uqLocations: TUniQuery
Connection = ucEnvoy
SQL.Strings = (
'select * from locations')
Left = 130
Top = 172
object uqLocationslocation: TStringField
DisplayWidth = 30
FieldName = 'location'
Required = True
Size = 30
end
object uqLocationsphone_number: TStringField
DisplayWidth = 14
FieldName = 'phone_number'
Required = True
Visible = False
Size = 14
end
object uqLocationsphone_number_formatted: TStringField
FieldName = 'phone_number_formatted'
Size = 14
end
end
object uqRecordings: TUniQuery
Connection = ucEnvoy
SQL.Strings = (
'select * from recordings')
Left = 224
Top = 174
object uqRecordingsaccount_sid: TStringField
FieldName = 'account_sid'
Size = 34
end
object uqRecordingsapi_version: TStringField
FieldName = 'api_version'
Size = 10
end
object uqRecordingscall_sid: TStringField
FieldName = 'call_sid'
Size = 34
end
object uqRecordingsconference_sid: TStringField
FieldName = 'conference_sid'
Size = 34
end
object uqRecordingsdate_created: TDateTimeField
FieldName = 'date_created'
end
object uqRecordingsdate_updated: TDateTimeField
FieldName = 'date_updated'
end
object uqRecordingsstart_time: TDateTimeField
FieldName = 'start_time'
end
object uqRecordingsduration: TStringField
FieldName = 'duration'
Size = 4
end
object uqRecordingssid: TStringField
FieldName = 'sid'
Required = True
Size = 34
end
object uqRecordingsprice: TStringField
FieldName = 'price'
Size = 8
end
object uqRecordingsprice_unit: TStringField
FieldName = 'price_unit'
Size = 3
end
object uqRecordingsstatus: TStringField
FieldName = 'status'
Size = 10
end
object uqRecordingschannels: TStringField
FieldName = 'channels'
Size = 1
end
object uqRecordingssource: TStringField
FieldName = 'source'
Size = 10
end
object uqRecordingserror_code: TStringField
FieldName = 'error_code'
Size = 5
end
object uqRecordingsuri: TStringField
FieldName = 'uri'
Size = 106
end
object uqRecordingsencryption_details: TStringField
FieldName = 'encryption_details'
Size = 30
end
object uqRecordingsmedia_url: TStringField
FieldName = 'media_url'
Size = 123
end
object uqRecordingstranscription: TMemoField
FieldName = 'transcription'
BlobType = ftMemo
end
end
object uqCalls: TUniQuery
Connection = ucEnvoy
SQL.Strings = (
'select * from calls')
Left = 323
Top = 176
object uqCallsdate_updated: TDateTimeField
FieldName = 'date_updated'
end
object uqCallsprice_unit: TStringField
FieldName = 'price_unit'
Size = 3
end
object uqCallsparent_call_sid: TStringField
FieldName = 'parent_call_sid'
Size = 34
end
object uqCallscaller_name: TStringField
FieldName = 'caller_name'
Size = 30
end
object uqCallsduration: TStringField
FieldName = 'duration'
Size = 4
end
object uqCallsannotation: TMemoField
FieldName = 'annotation'
BlobType = ftMemo
end
object uqCallsanswered_by: TStringField
FieldName = 'answered_by'
Size = 30
end
object uqCallssid: TStringField
FieldName = 'sid'
Required = True
Size = 34
end
object uqCallsqueue_time: TStringField
FieldName = 'queue_time'
Size = 4
end
object uqCallsprice: TStringField
FieldName = 'price'
Size = 8
end
object uqCallsapi_version: TStringField
FieldName = 'api_version'
Size = 10
end
object uqCallsstatus: TStringField
FieldName = 'status'
Size = 10
end
object uqCallsdirection: TStringField
FieldName = 'direction'
Size = 8
end
object uqCallsstart_time: TDateTimeField
FieldName = 'start_time'
end
object uqCallsdate_created: TDateTimeField
FieldName = 'date_created'
end
object uqCallsfrom_formatted: TStringField
FieldName = 'from_formatted'
Size = 13
end
object uqCallsgroup_sid: TStringField
FieldName = 'group_sid'
Size = 34
end
object uqCallstrunk_sid: TStringField
FieldName = 'trunk_sid'
Size = 34
end
object uqCallsuri: TStringField
FieldName = 'uri'
Size = 101
end
object uqCallsaccount_sid: TStringField
FieldName = 'account_sid'
Size = 34
end
object uqCallsend_time: TDateTimeField
FieldName = 'end_time'
end
object uqCallsto_formatted: TStringField
FieldName = 'to_formatted'
Size = 13
end
object uqCallsphone_number_sid: TStringField
FieldName = 'phone_number_sid'
Size = 34
end
object uqCallsforwarded_from: TStringField
FieldName = 'forwarded_from'
Size = 12
end
end
end
//Handles all Twilio RestAPI calls, so any file that that needs to retrieve
// info from twilio uses this file
// Authors:
// Cameron Hayes
// Elias Sarraf
unit Twilio.Data.Module;
interface
uses
System.SysUtils, System.Classes, Data.DB, MemDS, DBAccess, Uni, UniProvider,
PostgreSQLUniProvider, REST.Client, REST.Types, System.JSON, Winapi.Windows,
Winapi.Messages, System.Variants, System.Generics.Collections, System.IniFiles,
Vcl.Forms;
type
TTwilioDataModule = class(TDataModule)
ucEnvoy: TUniConnection;
PostgreSQLUniProvider1: TPostgreSQLUniProvider;
UniQuery1: TUniQuery;
uqLocations: TUniQuery;
uqLocationslocation: TStringField;
uqLocationsphone_number: TStringField;
uqRecordings: TUniQuery;
uqRecordingsaccount_sid: TStringField;
uqRecordingsapi_version: TStringField;
uqRecordingscall_sid: TStringField;
uqRecordingsconference_sid: TStringField;
uqRecordingsdate_created: TDateTimeField;
uqRecordingsdate_updated: TDateTimeField;
uqRecordingsstart_time: TDateTimeField;
uqRecordingsduration: TStringField;
uqRecordingssid: TStringField;
uqRecordingsprice: TStringField;
uqRecordingsprice_unit: TStringField;
uqRecordingsstatus: TStringField;
uqRecordingschannels: TStringField;
uqRecordingssource: TStringField;
uqRecordingserror_code: TStringField;
uqRecordingsuri: TStringField;
uqRecordingsencryption_details: TStringField;
uqRecordingsmedia_url: TStringField;
uqRecordingstranscription: TMemoField;
uqCalls: TUniQuery;
uqCallsdate_updated: TDateTimeField;
uqCallsprice_unit: TStringField;
uqCallsparent_call_sid: TStringField;
uqCallscaller_name: TStringField;
uqCallsduration: TStringField;
uqCallsannotation: TMemoField;
uqCallsanswered_by: TStringField;
uqCallssid: TStringField;
uqCallsqueue_time: TStringField;
uqCallsprice: TStringField;
uqCallsapi_version: TStringField;
uqCallsstatus: TStringField;
uqCallsdirection: TStringField;
uqCallsstart_time: TDateTimeField;
uqCallsdate_created: TDateTimeField;
uqCallsfrom_formatted: TStringField;
uqCallsgroup_sid: TStringField;
uqCallstrunk_sid: TStringField;
uqCallsuri: TStringField;
uqCallsaccount_sid: TStringField;
uqCallsend_time: TDateTimeField;
uqCallsto_formatted: TStringField;
uqCallsphone_number_sid: TStringField;
uqCallsforwarded_from: TStringField;
uqLocationsphone_number_formatted: TStringField;
procedure DataModuleCreate(Sender: TObject);
procedure DataModuleDestroy(Sender: TObject);
function GetRecordings(count: integer; offset: integer): integer;
function GetCalls(phoneNum: string; count: integer; offset: integer): integer;
procedure UpdateDB();
procedure ShowCalls(PhoneNum: string);
function GetTranscription(uri: string): string;
function toDateTime(date: string): TDateTime;
function FullUpdate(): string;
private
{ Private declarations }
accountSID: string;
authHeader: string;
public
{ Public declarations }
end;
var
TwilioDataModule: TTwilioDataModule;
implementation
uses
Common.Logging,
Common.Config;
{%CLASSGROUP 'Vcl.Controls.TControl'}
{$R *.dfm}
function TTwilioDataModule.GetCalls(phoneNum: string; count: integer; offset: integer): integer;
var
restClient: TRESTClient;
restRequest: TRESTRequest;
restResponse: TRESTResponse;
param: TRESTRequestParameter;
res: string;
sid: string;
jsValue: TJSONValue;
jsObj: TJSONObject;
jaCalls: TJSONArray;
joCall: TJSONObject;
i: integer;
uri: string;
sql: string;
addedCount: Integer;
begin
restClient := TRESTClient.Create(nil);
restClient.BaseURL := 'https://api.twilio.com';
restRequest := TRESTRequest.Create(nil);
restRequest.Client := restClient;
restResponse := TRESTResponse.Create(nil);
restRequest.Response := restResponse;
restRequest.Method := rmGET;
res := '/2010-04-01/Accounts/' + accountSID + '/Calls.json?Status=completed&To=+' + phoneNum + '&PageSize=' + IntToStr(count);
restRequest.Resource := res;
param := restRequest.Params.AddItem;
param.Name := 'Authorization';
param.Kind := pkHTTPHEADER;
param.Options := param.Options + [TRESTRequestParameterOption.poDoNotEncode];
param.Value := authHeader;
restRequest.Execute;
jsValue := restResponse.JSONValue;
jsObj := TJSONObject(jsValue);
jaCalls := TJSONArray(jsObj.GetValue('calls'));
addedCount := 0;
for i := offset to (jaCalls.Count - 1) do
begin
joCall := TJSONObject(jaCalls.Items[i]);
sql := 'select * from calls where sid = ' + QuotedStr(joCall.Get('sid').JsonValue.Value);
uqCalls.Close;
uqCalls.SQL.Text := sql;
uqCalls.Open;
if uqCalls.IsEmpty then
begin
uqCalls.Append;
uqCallsdate_updated.AsDateTime := toDateTime(joCall.Get('date_updated').JsonValue.Value);
uqCallsprice_unit.AsString := joCall.Get('price_unit').JsonValue.Value;
uqCallsparent_call_sid.AsString := joCall.Get('parent_call_sid').JsonValue.Value;
uqCallsduration.AsString := joCall.Get('duration').JsonValue.Value;
uqCallsannotation.AsString := joCall.Get('annotation').JsonValue.Value;
uqCallsanswered_by.AsString := joCall.Get('answered_by').JsonValue.Value;
uqCallssid.AsString := joCall.Get('sid').JsonValue.Value;
uqCallsqueue_time.AsString := joCall.Get('queue_time').JsonValue.Value;
uqCallsprice.AsString := joCall.Get('price').JsonValue.Value;
uqCallsdirection.AsString := joCall.Get('direction').JsonValue.Value;
uqCallsstart_time.AsDateTime := toDateTime(joCall.Get('start_time').JsonValue.Value);
uqCallsdate_created.AsDateTime := toDateTime(joCall.Get('date_created').JsonValue.Value);
uqCallsfrom_formatted.AsString := joCall.Get('from_formatted').JsonValue.Value;
uqCallsgroup_sid.AsString := joCall.Get('group_sid').JsonValue.Value;
uqCallstrunk_sid.AsString := joCall.Get('trunk_sid').JsonValue.Value;
uqCallsforwarded_from.AsString := joCall.Get('forwarded_from').JsonValue.Value;
uqCallsuri.AsString := joCall.Get('uri').JsonValue.Value;
uqCallsaccount_sid.AsString := joCall.Get('account_sid').JsonValue.Value;
uqCallsend_time.AsDateTime := toDateTime(joCall.Get('end_time').JsonValue.Value);
uqCallsto_formatted.AsString := joCall.Get('to_formatted').JsonValue.Value;
uqCallsphone_number_sid.AsString := joCall.Get('phone_number_sid').JsonValue.Value;
uqCallscaller_name.AsString := joCall.Get('caller_name').JsonValue.Value;
uqCallsapi_version.AsString := joCall.Get('api_version').JsonValue.Value;
uqCallsStatus.AsString := joCall.Get('status').JsonValue.Value;
uqCalls.Post;
Inc(addedCount);
end
else
continue;
end;
restClient.Free;
restRequest.Free;
restResponse.Free;
Result := addedCount;
end;
function TTwilioDataModule.GetRecordings(count: integer; offset: integer): integer;
var
restClient: TRESTClient;
restRequest: TRESTRequest;
restResponse: TRESTResponse;
param: TRESTRequestParameter;
jsValue: TJSONValue;
jsObj: TJSONObject;
jaRecordings: TJSONArray;
joRec: TJSONObject;
joTrans: TJSONObject;
i: integer;
sql: string;
turi: string;
addedCount: Integer;
begin
restClient := TRESTClient.Create(nil);
restClient.BaseURL := 'https://api.twilio.com';
restRequest := TRESTRequest.Create(nil);
restRequest.Client := restClient;
restResponse := TRESTResponse.Create(nil);
restRequest.Response := restResponse;
restRequest.Method := rmGET;
restRequest.Resource := '/2010-04-01/Accounts/' + accountSID + '/Recordings.json?PageSize=' + IntToStr(count);
param := restRequest.Params.AddItem;
param.Name := 'Authorization';
param.Kind := pkHTTPHEADER;
param.Options := param.Options + [TRESTRequestParameterOption.poDoNotEncode];
param.Value := authHeader;
restRequest.Execute;
jsValue := restResponse.JSONValue;
jsObj := TJSONObject(jsValue);
jaRecordings := TJSONArray(jsObj.GetValue('recordings'));
addedCount := 0;
for i := offset to jaRecordings.Count - 1 do
begin
joRec := TJSONObject(jaRecordings.Items[i]);
sql := 'select * from recordings where sid = ' + QuotedStr(joRec.Get('sid').JsonValue.Value);
uqRecordings.Close;
uqRecordings.SQL.Text := sql;
uqRecordings.Open;
if not uqRecordings.IsEmpty then
continue;
uqRecordings.Append;
uqRecordingsaccount_sid.AsString := joRec.Get('account_sid').JsonValue.Value;
uqRecordingscall_sid.AsString := joRec.Get('call_sid').JsonValue.Value;
uqRecordingsdate_created.AsDateTime := toDateTime(joRec.Get('date_created').JsonValue.Value);
uqRecordingsstatus.AsString := joRec.Get('status').JsonValue.Value;
uqRecordingsduration.AsString := joRec.Get('duration').JsonValue.Value;
uqRecordingsapi_version.AsString := joRec.Get('api_version').JsonValue.Value;
uqRecordingsconference_sid.AsString := joRec.Get('conference_sid').JsonValue.Value;
uqRecordingsdate_updated.AsDateTime := toDateTime(joRec.Get('date_updated').JsonValue.Value);
uqRecordingsstart_time.AsDateTime := toDateTime(joRec.Get('start_time').JsonValue.Value);
uqRecordingssid.AsString := joRec.Get('sid').JsonValue.Value;
uqRecordingsprice.AsString := joRec.Get('price').JsonValue.Value;
uqRecordingsprice_unit.AsString := joRec.Get('price_unit').JsonValue.Value;
uqRecordingschannels.AsString := joRec.Get('channels').JsonValue.Value;
uqRecordingssource.AsString := joRec.Get('source').JsonValue.Value;
uqRecordingserror_code.AsString := joRec.Get('error_code').JsonValue.Value;
uqRecordingsuri.AsString := joRec.Get('uri').JsonValue.Value;
uqRecordingsencryption_details.AsString := joRec.Get('encryption_details').JsonValue.Value;
uqRecordingsmedia_url.AsString := joRec.Get('media_url').JsonValue.Value;
if joRec.Get('duration').JsonValue.Value = '-1' then
begin
uqRecordingstranscription.AsString := 'Empty';
end
else
begin
joTrans := TJSONObject(joRec.Get('subresource_uris').JsonValue);
turi := joTrans.Get('transcriptions').JsonValue.Value;
uqRecordingstranscription.AsString := GetTranscription(turi);
end;
uqRecordings.Post;
Inc(addedCount);
end;
restClient.Free;
restRequest.Free;
restResponse.Free;
Result := addedCount;
end;
function TTwilioDataModule.GetTranscription(uri: string): string;
// Retrieves a JSONArray of 1 transcription then adds that one transcription
// into the database. The RestAPI call is directly linked to Recording sid so
// this is only called when the recording has an assoiciated transcription. Bulk
// adding transcriptions is currently not doable.
var
restClient: TRESTClient;
restRequest: TRESTRequest;
restResponse: TRESTResponse;
param: TRESTRequestParameter;
jsValue: TJSONValue;
jsObj: TJSONObject;
joTrans: TJSONObject;
jaTrans: TJSONArray;
i: integer;
trans_text: string;
begin
restClient := TRESTClient.Create(nil);
restClient.BaseURL := 'https://api.twilio.com';
restRequest := TRESTRequest.Create(nil);
restRequest.Client := restClient;
restResponse := TRESTResponse.Create(nil);
restRequest.Response := restResponse;
restRequest.Method := rmGET;
restRequest.Resource := uri;
param := restRequest.Params.AddItem;
param.Name := 'Authorization';
param.Kind := pkHTTPHEADER;
param.Options := param.Options + [TRESTRequestParameterOption.poDoNotEncode];
param.Value := authHeader;
restRequest.Execute;
jsValue := restResponse.JSONValue;
jsObj := TJSONObject(jsValue);
jaTrans := TJSONArray(jsObj.Get('transcriptions').JsonValue);
if jaTrans.IsEmpty then
begin
trans_text := 'Empty';
end
else
begin
joTrans := TJSONObject(jaTrans.Items[0]);
trans_text := joTrans.Get('transcription_text').JsonValue.Value;
end;
if trans_text = 'null' then
begin
trans_text := 'Empty';
end;
restClient.Free;
restRequest.Free;
restResponse.Free;
Result := trans_text;
end;
procedure TTwilioDataModule.UpdateDB();
// Updates the calls for all 4 locations and gets the 50 most recent recordings
// Activates on a timer in Main set for every 5 minutes.
// phoneDict: Dictionary containing all the locations which are linked to a
// phone number.
var
sql: string;
phoneNum: string;
begin
sql := 'select * from locations';
uqLocations.Close;
uqLocations.SQL.Text := sql;
uqLocations.Open;
GetRecordings(50, 0);
while not uqLocations.Eof do
begin
phoneNum := uqLocations.FieldByName('phone_number').AsString;
GetCalls(phoneNum, 50, 0);
uqLocations.Next;
end;
end;
function TTwilioDataModule.toDateTime(date: string): TDateTime;
// Converts the string we were given from twilio into a datetime
// date: string - formatted ddd, dd mmm yyyy hh:nn:ss+zzzz
// Returns a DateTime Object with formating specified below
var
fs: TFormatSettings;
dt: TDateTime;
dateString: String;
begin
// Removes the very first day(ddd, )
date := Copy(date, Pos(',', date) + 2, MaxInt);
// Removes the timezone(+zzzz) as it is always +0000
date := Copy(date, 1, Pos(' +', date)-1);
fs.Create;
fs.DateSeparator := ' ';
fs.TimeSeparator := ':';
fs.ShortDateFormat := 'mm/dd/yyyy';
fs.ShortTimeFormat := 'hh:nn:ss';
dt := VarToDateTime(date);
Result := dt;
end;
procedure TTwilioDataModule.ShowCalls(PhoneNum: string);
var
SQL: string;
begin
SQL := 'select * ' + ' from calls where to_formatted = '
+ QuotedStr(PhoneNum) + ' order by calls.date_created desc';
uqCalls.SQL.Text := SQL;
uqCalls.Open;
end;
procedure TTwilioDataModule.DataModuleCreate(Sender: TObject);
var
IniFile: TIniFile;
iniStr: string;
begin
IniFile := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
Logger.Log(5, 'Twilio Data Module Created');
try
iniStr := IniFile.ReadString('Database', 'Server', '');
if iniStr <> '' then
ucEnvoy.Server := iniStr;
iniStr := IniFile.ReadString('Database', 'Database', '');
if iniStr <> '' then
ucEnvoy.Database := iniStr;
iniStr := IniFile.ReadString('Database', 'Username', '');
if iniStr <> '' then
ucEnvoy.Username := iniStr;
iniStr := IniFile.ReadString('Database', 'Password', '');
if iniStr <> '' then
ucEnvoy.Password := iniStr;
// Same logic as before for Twilio...
iniStr := IniFile.ReadString('Twilio', 'AccountSID', '');
if iniStr <> '' then
accountSID := iniStr;
iniStr := IniFile.ReadString('Twilio', 'AuthHeader', '');
if iniStr <> '' then
authHeader := iniStr;
finally
IniFile.Free;
end;
uqLocations.Open;
end;
procedure TTwilioDataModule.DataModuleDestroy(Sender: TObject);
begin
Logger.Log(5, 'Twilio Data Module Destroyed');
uqLocations.Close;
end;
function TTwilioDataModule.FullUpdate: String;
var
sql, phoneNum: string;
count, offset, added: integer;
call_count, rec_count: integer;
resultString: string;
begin
call_count := 0;
rec_count := 0;
// Update calls for each location
sql := 'select * from locations';
uqLocations.Close;
uqLocations.SQL.Text := sql;
uqLocations.Open;
while not uqLocations.Eof do
begin
phoneNum := uqLocations.FieldByName('phone_number').AsString;
offset := 0;
count := 50;
repeat
added := GetCalls(phoneNum, count, offset);
if added > 0 then
Inc(call_count, added);
Inc(offset, count);
until added = 0;
uqLocations.Next;
end;
// Update recordings
offset := 0;
count := 50;
repeat
added := GetRecordings(count, offset);
if added > 0 then
Inc(rec_count, added);
Inc(offset, count);
until added = 0;
resultString := 'Added ~' + IntToStr(call_count) + ' calls to database' + sLineBreak +
'Added ~' + IntToStr(rec_count) + ' recordings to database';
Result := resultString;
end;
end.
......@@ -10,7 +10,6 @@ uses
Api.Server.Module in 'Source\Api.Server.Module.pas' {ApiServerModule: TDataModule},
Main in 'Source\Main.pas' {FMain},
Common.Logging in 'Source\Common.Logging.pas',
Data in 'Source\Data.pas' {FData},
Api.Database in 'Source\Api.Database.pas' {ApiDatabaseModule: TDataModule},
Common.Middleware.Logging in 'Source\Common.Middleware.Logging.pas',
Common.Config in 'Source\Common.Config.pas',
......@@ -21,7 +20,6 @@ uses
Api.Service in 'Source\Api.Service.pas',
Auth.ServiceImpl in 'Source\Auth.ServiceImpl.pas',
Api.ServiceImpl in 'Source\Api.ServiceImpl.pas',
Twilio.Data.Module in 'Source\Twilio.Data.Module.pas' {TwilioDataModule: TDataModule},
App.Server.Module in 'Source\App.Server.Module.pas' {AppServerModule: TDataModule},
Common.Ini in 'Source\Common.Ini.pas';
......
......@@ -141,9 +141,6 @@
<Form>FMain</Form>
</DCCReference>
<DCCReference Include="Source\Common.Logging.pas"/>
<DCCReference Include="Source\Data.pas">
<Form>FData</Form>
</DCCReference>
<DCCReference Include="Source\Api.Database.pas">
<Form>ApiDatabaseModule</Form>
<DesignClass>TDataModule</DesignClass>
......@@ -163,10 +160,6 @@
<DCCReference Include="Source\Api.Service.pas"/>
<DCCReference Include="Source\Auth.ServiceImpl.pas"/>
<DCCReference Include="Source\Api.ServiceImpl.pas"/>
<DCCReference Include="Source\Twilio.Data.Module.pas">
<Form>TwilioDataModule</Form>
<DesignClass>TDataModule</DesignClass>
</DCCReference>
<DCCReference Include="Source\App.Server.Module.pas">
<Form>AppServerModule</Form>
<DesignClass>TDataModule</DesignClass>
......
[Settings]
LogFileNum=513
LogFileNum=525
webClientVersion=0.1.0
TwilioUpdateTime=0
[Database]
Server=192.168.102.129
--Server=192.168.75.133
Database=envoy_db
Username=postgres
Password=postgreSQL
--Password=emsys01
[Twilio]
AccountSID=AC37aeef9c36a2cccbaecbadafc172b2ff
AuthHeader=Basic QUMzN2FlZWY5YzM2YTJjY2NiYWVjYmFkYWZjMTcyYjJmZjo5NzM5OTAwYTgyZmRlNjVlMzI2ODFmZjVmMmI5ZGZjZgo=
object FViewComplaintDetails: TFViewComplaintDetails
Width = 640
Height = 480
CSSLibrary = cssBootstrap
ElementFont = efCSS
object WebDBTableControl1: TWebDBTableControl
Left = 164
Top = 198
Width = 300
Height = 200
BorderColor = clSilver
ElementFont = efCSS
ElementHeaderClassName = 'thead-light'
ElementTableClassName = 'table table-striped table-bordered table-hover'
Footer.ButtonActiveElementClassName = 'btn btn-primary'
Footer.ButtonElementClassName = 'btn btn-light'
Footer.DropDownElementClassName = 'form-control'
Footer.InputElementClassName = 'form-control'
Footer.LinkActiveElementClassName = 'link-primary'
Footer.LinkElementClassName = 'link-secondary'
Footer.ListElementClassName = 'pagination'
Footer.ListItemElementClassName = 'page-item'
Footer.ListLinkElementClassName = 'page-link'
Header.ButtonActiveElementClassName = 'btn btn-primary'
Header.ButtonElementClassName = 'btn btn-light'
Header.DropDownElementClassName = 'form-control'
Header.InputElementClassName = 'form-control'
Header.LinkActiveElementClassName = 'link-primary'
Header.LinkElementClassName = 'link-secondary'
Header.ListElementClassName = 'pagination'
Header.ListItemElementClassName = 'page-item'
Header.ListLinkElementClassName = 'page-link'
Columns = <>
end
end
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>TMS Web Project</title>
<style>
</style>
</head>
<body>
</body>
</html>
\ No newline at end of file
<!-- Sticky local navbar (Complaint Details) -->
<div class="sticky-top">
<nav class="navbar navbar-dark bg-primary py-2">
<div class="container-fluid">
<div class="row w-100 g-2 align-items-stretch">
<div class="col">
<div id="cdetails_title" class="navbar-brand mb-0 h5 text-white">Complaint Details</div>
</div>
<div class="col-auto">
<button id="btn_close_complaint_details" type="button" class="btn btn-outline-light w-100 h-100">
<i class="fa fa-times me-1"></i>
<span class="d-none d-sm-inline">Close</span>
</button>
</div>
</div>
</div>
</nav>
</div>
<!-- Complaint details content -->
<div class="container-fluid mt-2 complaint-details-page">
<div class="row justify-content-center">
<div class="col-12 col-md-10 col-lg-8">
<!-- Outer card -->
<div class="card border-0 shadow-sm">
<div class="card-body p-3 bg-light">
<!-- Summary panel -->
<div class="card mb-3">
<div class="card-body py-2">
<div class="row gy-1">
<div class="col-5 col-sm-4 fw-semibold">Complaint</div>
<div class="col-7 col-sm-8" id="lbl_complaint_number"></div>
<div class="col-5 col-sm-4 fw-semibold">Priority</div>
<div class="col-7 col-sm-8" id="lbl_priority"></div>
<div class="col-5 col-sm-4 fw-semibold">Status</div>
<div class="col-7 col-sm-8" id="lbl_status"></div>
<div class="col-5 col-sm-4 fw-semibold">Dispatch Code</div>
<div class="col-7 col-sm-8" id="lbl_dispatch_code"></div>
<div class="col-5 col-sm-4 fw-semibold">Dispatch District</div>
<div class="col-7 col-sm-8" id="lbl_dispatch_district"></div>
<div class="col-5 col-sm-4 fw-semibold">Address</div>
<div class="col-7 col-sm-8" id="lbl_address"></div>
</div>
</div>
</div>
<!-- Action tabs (green buttons) -->
<div class="mb-3">
<div class="d-flex flex-wrap gap-2">
<button type="button" class="btn btn-success btn-sm px-3" id="btn_history">History</button>
<button type="button" class="btn btn-success btn-sm px-3" id="btn_warnings">Warnings</button>
<button type="button" class="btn btn-success btn-sm px-3" id="btn_contacts">Contacts</button>
<button type="button" class="btn btn-success btn-sm px-3" id="btn_cmp">CMP</button>
<button type="button" class="btn btn-success btn-sm px-3" id="btn_e911">E-911</button>
<button type="button" class="btn btn-success btn-sm px-3" id="btn_rem">REM</button>
<button type="button" class="btn btn-success btn-sm px-3" id="btn_unt">UNT</button>
</div>
</div>
<!-- Details table (thead in HTML, tbody filled by TWebDBListControl) -->
<div class="card">
<div class="card-body p-0">
<div class="table-responsive" style="max-height: 60vh; overflow-y: auto;">
<table class="table table-sm table-striped mb-0">
<thead class="table-light sticky-top">
<tr>
<th style="width: 70px;">Type</th>
<th style="width: 150px;">Timestamp</th>
<th>Remarks</th>
</tr>
</thead>
<tbody id="tbl_complaint_details"></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
......@@ -3,15 +3,18 @@ unit View.ComplaintDetails;
interface
uses
System.SysUtils, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
WEBLib.Forms, WEBLib.Dialogs;
System.SysUtils, System.Classes, JS, Web,
WEBLib.Graphics, WEBLib.Controls, WEBLib.Forms, WEBLib.Dialogs, Vcl.Controls,
WEBLib.Grids, WEBLib.DBCtrls;
type
TFViewComplaintDetails = class(TWebForm)
WebDBTableControl1: TWebDBTableControl;
private
{ Private declarations }
FComplaintId: string;
public
{ Public declarations }
class function CreateForm(AElementID, ComplaintId: string): TWebForm;
procedure InitializeForm;
end;
var
......@@ -21,4 +24,170 @@ implementation
{$R *.dfm}
class function TFViewComplaintDetails.CreateForm(AElementID, ComplaintId: string): TWebForm;
procedure AfterCreate(AForm: TObject);
begin
with TFViewComplaintDetails(AForm) do
begin
FComplaintId := ComplaintId;
InitializeForm; // kick off loading / UI binding here
end;
end;
begin
Application.CreateForm(TFViewComplaintDetails, AElementID, Result, @AfterCreate);
end;
procedure TFViewComplaintDetails.InitializeForm;
begin
// TODO:
// - call your XData endpoint with FComplaintId
// - bind fields / populate controls
// - handle spinner / errors as you do elsewhere
end;
end.
//unit View.ComplaintDetails;
//
//interface
//
//uses
// System.SysUtils, System.Classes, JS, Web,
// WEBLib.Graphics, WEBLib.Controls, WEBLib.Forms, WEBLib.Dialogs,
// WEBLib.StdCtrls, WEBLib.WebCtrls, WEBLib.ExtCtrls,
// WEBLib.DB, Data.DB,
// XData.Web.Client, XData.Web.JsonDataset, XData.Web.Dataset,
// View.Main, View.Complaints, Vcl.Controls, WEBLib.Grids, WEBLib.DBCtrls;
//
//type
// TFViewComplaintDetails = class(TWebForm)
// // Header controls (ElementID -> HTML ids in snake_case)
// btnCloseComplaintDetails: TWebButton; // ElementID = 'btn_close_complaint_details'
// lblComplaintNumber: TWebLabel; // 'lbl_complaint_number'
// lblPriority: TWebLabel; // 'lbl_priority'
// lblStatus: TWebLabel; // 'lbl_status'
// lblDispatchCode: TWebLabel; // 'lbl_dispatch_code'
// lblDispatchDistrict: TWebLabel; // 'lbl_dispatch_district'
// lblAddress: TWebLabel; // 'lbl_address'
//
// // Action buttons (optional events later)
// btnHistory: TWebButton; // 'btn_history'
// btnWarnings: TWebButton; // 'btn_warnings'
// btnContacts: TWebButton; // 'btn_contacts'
// btnCMP: TWebButton; // 'btn_cmp'
// btnE911: TWebButton; // 'btn_e911'
// btnREM: TWebButton; // 'btn_rem'
// btnUNT: TWebButton; // 'btn_unt'
//
// // Data-aware table
// tblComplaintDetails: TWebDBListControl; // ElementID = 'tbl_complaint_details'
// xdwcComplaintDetails: TXDataWebClient;
// xdwdsxComplaintDetails: TXDataWebDataSet; // (your requested name)
// wdsComplaintDetails: TWebDataSource;
//
// private
// FComplaintId: string;
//
// [async] procedure LoadHeaderAsync;
// [async] procedure LoadRowsAsync;
//
// public
// class function CreateForm(AElementID, ComplaintId: string): TWebForm;
// procedure InitializeForm;
// end;
//
//implementation
//
//{$R *.dfm}
//
//class function TFViewComplaintDetails.CreateForm(AElementID, ComplaintId: string): TWebForm;
//
// procedure AfterCreate(AForm: TObject);
// begin
// with TFViewComplaintDetails(AForm) do
// begin
// FComplaintId := ComplaintId;
// InitializeForm;
// end;
// end;
//
//begin
// Application.CreateForm(TFViewComplaintDetails, AElementID, Result, @AfterCreate);
//end;
//
//procedure TFViewComplaintDetails.InitializeForm;
//begin
// // Close button navigates back via Main (keeps host container ownership clean)
// btnCloseComplaintDetails.OnClick :=
// procedure(Sender: TObject)
// begin
// if Assigned(FViewMain) then
// begin
//// FViewMain.SetActiveNavButton('view.main.btncomplaints');
// FViewMain.ShowForm(TFViewComplaints);
// end;
// end;
//
// // Data-aware wiring (design-time also OK; keeping here for clarity)
// wdsComplaintDetails.DataSet := xdwdsxComplaintDetails;
// tblComplaintDetails.DataSource := wdsComplaintDetails;
//
// // Expecting ItemTemplate at design-time:
// // <tr><td>(%MemoType%)</td><td>(%Timestamp%)</td><td>(%Remarks%)</td></tr>
//
// // Kick off loads
// LoadHeaderAsync;
// LoadRowsAsync;
//end;
//
//[async] procedure TFViewComplaintDetails.LoadHeaderAsync;
//var
// resp: TXDataClientResponse;
// obj: TJSObject;
//begin
// try
// // TODO:Adjust endpoint and args to match your server (array param is common in XData)
// resp := await(xdwcComplaintDetails.RawInvokeAsync('IApiService.GetComplaintDetailsHeader', [FComplaintId]));
// obj := TJSObject(resp.Result);
//
// // If the server returns { data: {...} }, unwrap:
// if obj['data'] <> nil then
// obj := TJSObject(obj['data']);
//
// lblComplaintNumber.Caption := string(obj['ComplaintNumber'] ?? FComplaintId);
// lblPriority.Caption := string(obj['Priority'] ?? '');
// lblStatus.Caption := string(obj['Status'] ?? '');
// lblDispatchCode.Caption := string(obj['DispatchCodeDesc'] ?? '');
// lblDispatchDistrict.Caption := string(obj['DispatchDistrict'] ?? '');
// lblAddress.Caption := string(obj['Address'] ?? '');
// except
// on E: Exception do
// Console.Log('Header load error: ' + E.Message);
// end;
//end;
//
//[async] procedure TFViewComplaintDetails.LoadRowsAsync;
//var
// resp: TXDataClientResponse;
// root: TJSObject;
//begin
// try
// // Adjust endpoint name/params to your API
// resp := await(xdwcComplaintDetails.RawInvokeAsync('IApiService.GetComplaintDetailsRows', [FComplaintId]));
// root := TJSObject(resp.Result);
//
// // Expecting { data: [ { MemoType, Timestamp, Remarks }, ... ] }
// xdwdsxComplaintDetails.Close;
// xdwdsxComplaintDetails.SetJsonData(root['data']);
// xdwdsxComplaintDetails.Open;
// except
// on E: Exception do
// Console.Log('Rows load error: ' + E.Message);
// end;
//end;
//
//end.
......@@ -85,20 +85,19 @@ object FViewComplaints: TFViewComplaints
Style = lsListGroup
DataSource = wdsComplaints
ItemTemplate =
'<div class="list-section-header small fw-semibold bg-secondary ' +
'text-white rounded-1 px-2 mb-1"> (%DistrictHeader%)</div><div ' +
'class="card border shadow-sm" style=" --bs-card-bg: (%Priori' +
'tyColor%); --bs-card-color: (%PriorityTextColor%); "> <div ' +
'class="card-body py-2 px-3"> <div class="fw-bold text-upperca' +
'se small"> (%Priority%): (%DispatchCodeDesc%) </div> ' +
'<div class="small">(%Address%)</div> <div class="small text-o' +
'pacity-75"> (%Complaint%): (%Status%)&nbsp;&nbsp;(%District' +
'Sector%) </div> <div class="small text-opacity-75">(%DateR' +
'eported%)</div> <div class="d-flex justify-content-end mt-2' +
'"> <button type="button" class="btn btn-li' +
'ght btn-sm complaint-details-btn" data-id="(%Comp' +
'laintId%)"> Details </button> </div> </div' +
'></div>'
'<div class="list-section-header small fw-semibold bg-secondary t' +
'ext-white rounded-1 px-2 mb-1"> (%DistrictHeader%)</div><div cl' +
'ass="card border shadow-sm" style="--bs-card-bg:(%PriorityCo' +
'lor%);--bs-card-color:(%PriorityTextColor%);"> <div class="card' +
'-body py-2 px-3"> <div class="fw-bold text-uppercase small"> ' +
' (%Priority%): (%DispatchCodeDesc%) </div> <div class=' +
'"small">(%Address%)</div> <div class="small text-opacity-75 d' +
'-flex align-items-center"> <span> (%Complaint%): (%S' +
'tatus%)&nbsp;&nbsp;(%DistrictSector%) </span> <button ' +
'type="button" class="btn btn-primary btn-sm ms-auto' +
' complaint-details-btn" data-id="(%ComplaintId%)"> ' +
' Details </button> </div> <div class="small tex' +
't-opacity-75">(%DateReported%)</div> </div></div>'
ListSource = wdsComplaints
end
object xdwcComplaints: TXDataWebClient
......
<div class="sticky-top">
<!-- Local navbar (Complaints) -->
<nav class="navbar navbar-dark bg-primary py-2"><!-- removed sticky-top -->
<nav class="navbar navbar-dark bg-primary py-2">
<div class="container-fluid">
<div class="row w-100 g-2 align-items-stretch">
<div class="col">
......@@ -27,7 +27,7 @@
</nav>
<!-- Search bar under local navbar -->
<div class="bg-light border-bottom py-2"><!-- removed sticky-top -->
<div class="bg-light border-bottom py-2">
<div class="container-fluid">
<div class="input-group">
<span class="input-group-text bg-white"><i class="fa fa-search"></i></span>
......@@ -36,7 +36,7 @@
</div>
</div>
</div> <!-- /sticky-top wrapper -->
</div>
<!-- Complaints list container -->
<div class="container-fluid mt-2">
......@@ -47,7 +47,6 @@
<!-- Cards will render here -->
</div>
<!-- Entry Count Label -->
<label id="complaints_lblentries" class="mt-2 d-block"></label>
<!-- Pagination -->
......@@ -60,3 +59,4 @@
</div>
</div>
......@@ -40,11 +40,12 @@ type
procedure tmrRefreshTimer(Sender: TObject);
procedure WebFormDestroy(Sender: TObject);
private
FSelectProc: TSelectProc;
FLoading: Boolean;
[async] procedure GetComplaints;
procedure HandleListClick(e: TJSMouseEvent);
public
property OnShowDetails: TSelectProc read FSelectProc write FSelectProc;
end;
var
......@@ -72,10 +73,14 @@ begin
id := string(TJSHtmlElement(el).dataset['id']); // comes from (%ComplaintId%)
e.preventDefault;
e.stopPropagation;
if Assigned(FSelectProc) then
FSelectProc(id);
end;
end;
procedure TFViewComplaints.WebFormDestroy(Sender: TObject);
begin
Document.removeEventListener('click', @HandleListClick);
......
// Form that functions as both a way to edit or add users to the database
// Author: Cameron Hayes
unit View.EditUser;
interface
......
......@@ -52,6 +52,7 @@ type
procedure ShowForm( AFormClass: TWebFormClass );
procedure EditUser( Mode, FullName, Username, Phone, Email: string; admin, active: boolean);
procedure ShowUserForm(Info: string);
procedure ShowComplaintDetails(ComplaintId: string);
end;
var
......@@ -65,6 +66,7 @@ uses
View.UserProfile,
View.Map,
View.Complaints,
View.ComplaintDetails,
View.Units,
View.Admin,
View.Users,
......@@ -136,6 +138,13 @@ procedure TFViewMain.btnComplaintsClick(Sender: TObject);
begin
SetActiveNavButton('view.main.btncomplaints');
ShowForm(TFViewComplaints);
if (FChildForm is TFViewComplaints) then
TFViewComplaints(FChildForm).OnShowDetails :=
procedure(AComplaintId: string)
begin
ShowComplaintDetails(AComplaintId);
end;
end;
procedure TFViewMain.btnMapClick(Sender: TObject);
......@@ -186,6 +195,14 @@ begin
FChildForm := TFViewUsers.CreateForm(WebPanel1.ElementID, Info);
end;
procedure TFViewMain.ShowComplaintDetails(ComplaintId: string);
begin
if Assigned(FChildForm) then
FChildForm.Free;
FChildForm := TFViewComplaintDetails.CreateForm(WebPanel1.ElementID, ComplaintId);
end;
procedure TFViewMain.SetActiveNavButton(const btnId: string);
var
......
......@@ -26,8 +26,6 @@ type
procedure lfMapMapInitialized(Sender: TObject);
[async] procedure httpReqGeoJsonResponse(Sender: TObject; AResponse: string);
procedure lfMapPolyElementMouseEnter(Sender: TObject; AElement: TTMSFNCMapsPolyElement);
procedure lfMapPolyElementMouseLeave(Sender: TObject; AElement: TTMSFNCMapsPolyElement);
procedure lfMapCustomizeMarker(Sender: TObject;
var ACustomizeMarker: string);
procedure lfMapCustomizeCSS(Sender: TObject; var ACustomizeCSS: string);
......@@ -55,6 +53,19 @@ begin
FUnitsLoaded := False;
FComplaintsLoaded := False;
httpReqGeoJson.Execute;
{$IFNDEF WIN32}
asm
window.showComplaintDetails = function (id) {
console.log('JS bridge showComplaintDetails called, id=', id);
try {
pas['View.Main'].FViewMain.ShowComplaintDetails(id);
console.log('TFViewMain.ShowComplaintDetails finished OK');
} catch (e) {
console.log('Error in TFViewMain.ShowComplaintDetails', e);
}
};
end;
{$ENDIF}
end;
......@@ -142,24 +153,25 @@ end;
[async] procedure TFViewMap.LoadPointsAsync;
var
resp: TXDataClientResponse;
root, item: TJSObject;
data: TJSArray;
i: Integer;
root, item, uo: TJSObject;
data, units: TJSArray;
i, ui: Integer;
m: TTMSFNCMapsMarker;
lat, lng: Double;
uname, dist: string;
complaintId, codeDesc, dispatchDist: string;
pngName, iconUrl: string;
priority: string;
complaintId, codeDesc, dispatchDist, priority: string;
pngName, iconUrl, rowsHtml: string;
begin
ShowSpinner('spinner');
FUnitsLoaded := False;
FComplaintsLoaded := False;
// --- Units ---------------------------------------------------------------
try
resp := await(xdwcMap.RawInvokeAsync('IApiService.GetUnitMap', []));
root := TJSObject(resp.Result);
data := TJSArray(root['data']);
if data <> nil then
begin
lfMap.BeginUpdate;
......@@ -167,6 +179,7 @@ begin
for i := 0 to data.Length - 1 do
begin
item := TJSObject(data[i]);
lat := Double(item['Lat']);
lng := Double(item['Lng']);
uname := string(item['UnitName']);
......@@ -178,22 +191,24 @@ begin
m.Title := uname + IfThen(dist <> '', ' / ' + dist, '');
m.DataString := 'unit';
m.IconURL := CarIconForDistrict(dist);
end;
finally
lfMap.EndUpdate;
end;
end;
FUnitsLoaded := True;
except
on E: EXDataClientRequestException do
Console.Log('Units XData error: ' + E.ErrorResult.ErrorMessage);
end;
// --- Complaints ----------------------------------------------------------
try
resp := await(xdwcMap.RawInvokeAsync('IApiService.GetComplaintMap', []));
root := TJSObject(resp.Result);
data := TJSArray(root['data']);
if data <> nil then
begin
lfMap.BeginUpdate;
......@@ -201,10 +216,12 @@ begin
for i := 0 to data.Length - 1 do
begin
item := TJSObject(data[i]);
complaintId := string(item['ComplaintId']);
codeDesc := string(item['DispatchCodeDesc']);
dispatchDist := string(item['DispatchDistrict']);
priority := string(item['Priority']);
lat := Double(item['Lat']);
lng := Double(item['Lng']);
......@@ -217,34 +234,72 @@ begin
else
iconUrl := 'assets/markers/default_5-9.png';
rowsHtml := '';
units := TJSArray(item['Units']);
if Assigned(units) and (units.Length > 0) then
begin
for ui := 0 to units.Length - 1 do
begin
uo := TJSObject(units[ui]);
rowsHtml := rowsHtml +
'<tr>' +
'<td>' + string(uo['Unit']) + '</td>' +
'<td>' + string(uo['Status']) + '</td>' +
'<td>' + string(uo['Updated']) + '</td>' +
'</tr>';
end;
end
else
rowsHtml := '<tr><td colspan="3" class="text-muted">No units</td></tr>';
// Complaint Markers
m := lfMap.Markers.Add;
m.Latitude := lat;
m.Longitude := lng;
// Note: This is th HTML tooltip content: info + button
m.Title :=
'<div class="d-flex flex-column gap-1" style="min-width:180px;">' +
'<div class="d-flex flex-column gap-1 px-1 py-1" style="width:260px;">' +
'<div class="fw-semibold small">' +
'<span class="fw-bold">Complaint ID:</span> ' + complaintId +
'<span class="fw-bold">Complaint:</span> ' + complaintId +
'</div>' +
'<div class="small">' +
'<span class="fw-bold">Priority:</span> ' + priority +
'</div>' +
'<div class="small">' +
'<span class="fw-bold">Type:</span> ' + codeDesc +
'<span class="fw-bold">Dispatch Code:</span> ' + codeDesc +
'</div>' +
'<div class="small">' +
'<span class="fw-bold">District:</span> ' + dispatchDist +
'<span class="fw-bold">Dispatch District:</span> ' + dispatchDist +
'</div>' +
'<div class="small mb-1">' +
'<span class="fw-bold">Priority:</span> ' + priority +
'<span class="fw-bold">Address:</span> ' + string(item['Address']) +
'</div>' +
'<div class="d-flex justify-content-end mt-1">' +
'<table class="table table-sm table-bordered mb-1 emi-tip-table">' +
'<colgroup>' +
'<col style="width:34%">' +
'<col style="width:33%">' +
'<col style="width:33%">' +
'</colgroup>' +
'<thead class="table-light">' +
'<tr>' +
'<th>Unit</th>' +
'<th>Status</th>' +
'<th>Updated</th>' +
'</tr>' +
'</thead>' +
'<tbody>' + rowsHtml + '</tbody>' +
'</table>' +
'<div class="d-flex justify-content-end mt-0">' +
'<button type="button" class="btn btn-primary btn-sm px-2 py-1" ' +
'onclick="emiOpenComplaintDetails(''' + complaintId + ''')">' +
'onclick="window.showComplaintDetails(''' + complaintId + ''')">' +
'Details' +
'</button>' +
'</div>' +
'</div>';
// Note: DataString not used for badges anymore, but keep for future
// Note: m.DataString := 'complaint|' + complaintId;
m.IconURL := iconUrl;
end;
finally
......@@ -257,144 +312,117 @@ begin
on E: EXDataClientRequestException do
Console.Log('Complaints XData error: ' + E.ErrorResult.ErrorMessage);
end;
HideSpinner('spinner');
end;
procedure TFViewMap.lfMapCustomizeMarker(Sender: TObject; var ACustomizeMarker: string);
begin
ACustomizeMarker :=
'var m=' + MARKERVAR + ', o=m.options||{};' + #13#10 +
// Grab the HTML title and move it off the native "title" attribute
'var rawTitle = (o && o.title) ? o.title : "";' + #13#10 +
'o.tooltipHtml = rawTitle;' + #13#10 + // store our HTML here
'o.title = "";' + #13#10 + // prevent browser native tooltip
'o.tooltipHtml = rawTitle;' + #13#10 +
'o.title = "";' + #13#10 +
'var t = o.tooltipHtml || "";' + #13#10 +
'var u = (o.icon && o.icon.options && o.icon.options.iconUrl) ? o.icon.options.iconUrl : null;' + #13#10 +
'try { m.unbindTooltip(); } catch(e) {}' + #13#10 +
'if (!u) {' + #13#10 +
' m.bindTooltip(t, {' + #13#10 +
' className: "emi-tip",' + #13#10 +
' direction: "top",' + #13#10 +
' offset: [0,-28],' + #13#10 +
' sticky: true' + #13#10 +
' });' + #13#10 +
' return;' + #13#10 +
'}' + #13#10 +
// clear any old tooltip/popup bindings
'try { if (m.unbindTooltip) m.unbindTooltip(); } catch(e) {}' + #13#10 +
'try { if (m.unbindPopup) m.unbindPopup(); } catch(e) {}' + #13#10 +
// derive badgeText from the icon filename suffix: *_2.png, *_3.png, *_4.png, *_5-9.png, etc.
// Note: we derive badgeText from icon filename suffix: *_2.png, *_3.png, *_4.png, *_5-9.png, etc.
'var badgeText = "";' + #13#10 +
'try {' + #13#10 +
'if (u) {' + #13#10 +
' try {' + #13#10 +
' var file = u.split("/").pop();' + #13#10 +
' var base = file.replace(/\.[^/.]+$/, "");' + #13#10 + // strip .png
' var base = file.replace(/\.[^/.]+$/, "");' + #13#10 +
' var idx = base.lastIndexOf("_");' + #13#10 +
' if (idx >= 0 && idx < base.length - 1) {' + #13#10 +
' var suffix = base.substring(idx + 1);' + #13#10 +
' if (suffix && suffix.length > 0) {' + #13#10 +
' var ch = suffix.charAt(0);' + #13#10 +
' if (ch >= "1" && ch <= "9") {' + #13#10 +
' badgeText = ch;' + #13#10 +
' }' + #13#10 +
' if (ch >= "1" && ch <= "9") badgeText = ch;' + #13#10 +
' }' + #13#10 +
' }' + #13#10 +
'} catch(e) {}' + #13#10 +
' } catch(e) {}' + #13#10 +
'}' + #13#10 +
// map badgeText (priority) to background color
'var badgeColor = "#4b5563"; // default for 5-9' + #13#10 +
'var badgeColor = "#4b5563";' + #13#10 +
'if (badgeText === "1") badgeColor = "#bc28d9";' + #13#10 +
'else if (badgeText === "2") badgeColor = "#b91c1c";' + #13#10 +
'else if (badgeText === "3") badgeColor = "#b45309";' + #13#10 +
'else if (badgeText === "4") badgeColor = "#047857";' + #13#10 +
'// 59 remain #4b5563' + #13#10 +
'var html = ''<div class="emi-marker-wrap"><img src="'' + u + ''" class="emi-marker-img">'';' + #13#10 +
'if (badgeText) {' + #13#10 +
'if (u) {' + #13#10 +
' var html = ''<div class="emi-marker-wrap"><img src="'' + u + ''" class="emi-marker-img">'';' + #13#10 +
' if (badgeText) {' + #13#10 +
' html += ''<div class="emi-marker-badge" style="background:'' + badgeColor + '';">'' + badgeText + ''</div>'';' + #13#10 +
'}' + #13#10 +
'html += ''</div>'';' + #13#10 +
'm.setIcon(L.divIcon({' + #13#10 +
' }' + #13#10 +
' html += ''</div>'';' + #13#10 +
' m.setIcon(L.divIcon({' + #13#10 +
' html: html,' + #13#10 +
' iconSize: [32,32],' + #13#10 +
' iconAnchor: [16,32],' + #13#10 +
' popupAnchor: [0,-20],' + #13#10 +
' className: ""' + #13#10 +
'}));' + #13#10 +
// extra safety: strip native title from the DOM element if present
'try { if (m._icon) m._icon.removeAttribute("title"); } catch(e) {}' + #13#10 +
' }));' + #13#10 +
' try { if (m._icon) m._icon.removeAttribute("title"); } catch(e) {}' + #13#10 +
'}' + #13#10 +
'm.bindTooltip(t, {' + #13#10 +
'm.bindPopup(t, {' + #13#10 +
' className: "emi-tip",' + #13#10 +
' direction: "top",' + #13#10 +
' offset: [0,-28],' + #13#10 +
' sticky: true,' + #13#10 +
' interactive: true' + #13#10 +
' maxWidth: 260,' + #13#10 +
' closeButton: false,' + #13#10 +
' autoPan: true' + #13#10 +
'});';
end;
procedure TFViewMap.lfMapCustomizeCSS(Sender: TObject; var ACustomizeCSS: string);
begin
ACustomizeCSS :=
// Note: Tooltip Container
'.leaflet-tooltip.emi-tip {' + #13#10 +
' background: rgba(245,245,245,0.99);' + #13#10 +
' color: #000;' + #13#10 +
' border-radius: 8px;' + #13#10 +
' padding: 10px 12px;' + #13#10 +
' border: 1px solid rgba(0,0,0,.20);' + #13#10 +
' box-shadow: 0 4px 14px rgba(0,0,0,.25);' + #13#10 +
' pointer-events: auto;' + #13#10 +
// popup container: rounded, shadow
'.emi-tip .leaflet-popup-content-wrapper{' +
'border-radius:8px;' +
'box-shadow:0 4px 14px rgba(0,0,0,.25);' +
'}' + #13#10 +
// Note: Tooltip Arrow Colors
'.leaflet-tooltip-top.emi-tip:before { border-top-color: rgba(245,245,245,0.92); }' + #13#10 +
'.leaflet-tooltip-bottom.emi-tip:before { border-bottom-color: rgba(245,245,245,0.92); }' + #13#10 +
'.leaflet-tooltip-left.emi-tip:before { border-left-color: rgba(245,245,245,0.92); }' + #13#10 +
'.leaflet-tooltip-right.emi-tip:before { border-right-color: rgba(245,245,245,0.92); }' + #13#10 +
// Note: Marker Badge Wrap
'.emi-marker-wrap { position: relative; display: inline-block; }' + #13#10 +
'.emi-marker-img { display: block; }' + #13#10 +
'.emi-marker-badge {' + #13#10 +
' position: absolute;' + #13#10 +
' top: -4px;' + #13#10 +
' right: -4px;' + #13#10 +
' min-width: 16px;' + #13#10 +
' height: 16px;' + #13#10 +
' padding: 0 4px;' + #13#10 +
' border-radius: 999px;' + #13#10 +
' background: var(--bs-danger);' + #13#10 +
' color: #fff;' + #13#10 +
' font: 700 11px/16px system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;' + #13#10 +
' text-align: center;' + #13#10 +
' box-shadow: 0 0 0 2px #fff;' + #13#10 +
'}';
end;
// popup content: no fixed width, max 260px on normal screens
'.emi-tip .leaflet-popup-content{' +
'margin:0;' +
'padding:0;' +
'width:auto;' +
'max-width:260px;' +
'}' + #13#10 +
procedure TFViewMap.lfMapPolyElementMouseEnter(Sender: TObject; AElement: TTMSFNCMapsPolyElement);
begin
if AElement is TTMSFNCMapsPolygon then
begin
TTMSFNCMapsPolygon(AElement).StrokeWidth := 3;
TTMSFNCMapsPolygon(AElement).FillOpacity := 0.55;
end;
end;
// on very small screens, let it grow almost full width
'@media (max-width:480px){' +
'.emi-tip .leaflet-popup-content{' +
'max-width:calc(100vw - 32px);' +
'}' +
'}' + #13#10 +
// table: compact, wraps text
'.emi-tip .emi-tip-table{display:table;border-collapse:collapse;table-layout:auto;width:auto;margin:.25rem 0;}'+#13#10+
'.emi-tip .emi-tip-table thead{display:table-header-group;}'+#13#10+
'.emi-tip .emi-tip-table tbody{display:table-row-group;}'+#13#10+
'.emi-tip .emi-tip-table tr{display:table-row;}'+#13#10+
'.emi-tip .emi-tip-table th,.emi-tip .emi-tip-table td{' +
'display:table-cell;' +
'white-space:normal;' +
'word-break:break-word;' +
'padding:.125rem .25rem;' +
'font-size:11px;' +
'vertical-align:middle;' +
'}' + #13#10 +
procedure TFViewMap.lfMapPolyElementMouseLeave(Sender: TObject; AElement: TTMSFNCMapsPolyElement);
begin
if AElement is TTMSFNCMapsPolygon then
begin
TTMSFNCMapsPolygon(AElement).StrokeWidth := 2;
TTMSFNCMapsPolygon(AElement).FillOpacity := 0.42;
end;
// marker badge
'.emi-marker-wrap{position:relative;display:inline-block;}'+#13#10+
'.emi-marker-img{display:block;}'+#13#10+
'.emi-marker-badge{position:absolute;top:-4px;right:-4px;min-width:16px;height:16px;padding:0 4px;border-radius:999px;background:var(--bs-danger);color:#fff;font:700 11px/16px system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;text-align:center;box-shadow:0 0 0 2px #fff;}';
end;
end.
......@@ -39,23 +39,22 @@ object FViewUnits: TFViewUnits
Style = lsListGroup
DataSource = wdsUnits
ItemTemplate =
'<div class="list-section-header small fw-semibold bg-body-secon' +
'dary text-dark rounded-1 px-2 mb-1"> (%DistrictHeader%)</div><d' +
'iv class="card border shadow-sm position-relative"> <div class=' +
'"card-body py-2 px-3"> <!-- Unit + Status --> <div class="' +
'fw-bold text-uppercase small"> (%UnitName%)&nbsp;-&nbsp;(%S' +
'tatus%) </div> <!-- Location --> <div class="small text' +
'-body-secondary mb-1"> (%Location%) </div> <!-- Call ' +
'type --> <div class="small">(%CallType%)</div> <!-- Divide' +
'r line (we'#39'll auto-hide if no officers) --> <hr class="unit-d' +
'ivider my-1" style="width: 80px; margin-left: 0;"> <!-- Offic' +
'ers --> <div class="small officer1">(%Officer1%)</div> <di' +
'v class="small officer2">(%Officer2%)</div> </div> <!-- Floati' +
'ng details button (solid, info icon) --> <div class="position-a' +
'bsolute top-50 end-0 translate-middle-y pe-2"> <button class=' +
'"btn btn-secondary btn-sm btn-unit-details" data-unit' +
'id="(%UnitId%)"> <i class="fa fa-info"></i> </button> <' +
'/div></div>'
'<div class="list-section-header small fw-semibold bg-body-second' +
'ary text-dark rounded-1 px-2 mb-1"> (%DistrictHeader%)</div><di' +
'v class="card border shadow-sm position-relative"> <div class="' +
'card-body py-2 px-3"> <!-- Unit + Status --> <div class="f' +
'w-bold text-uppercase small"> (%UnitName%)&nbsp;-&nbsp;(%St' +
'atus%) </div> <!-- Location --> <div class="small text-' +
'body-secondary mb-1"> (%Location%) </div> <!-- Call t' +
'ype --> <div class="small">(%CallType%)</div> <!-- Divider' +
' line --> <hr class="unit-divider my-1" style="width:80px;mar' +
'gin-left:0;"> <!-- Officers --> <div class="small officer1' +
'">(%Officer1%)</div> <div class="small officer2">(%Officer2%)' +
'</div> </div> <!-- Vertically centered Details button on the r' +
'ight --> <div class="position-absolute top-50 end-0 translate-m' +
'iddle-y pe-2"> <button type="button" class="btn bt' +
'n-primary btn-sm btn-unit-details" data-unitid="(%Uni' +
'tId%)"> Details </button> </div></div>'
ListSource = wdsUnits
end
object btnRefresh: TWebButton
......
......@@ -24,60 +24,7 @@
display: table-cell
}
.table tbody tr {
transition: background-color 0.3s ease;
}
.table {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
@media (max-width: 1200px) {
.table-responsive {
display: block;
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.table thead {
display: none;
}
.table tbody, .table tr, .table td {
display: block;
width: 100%;
}
.table tr {
margin-bottom: 1rem;
}
.table td {
text-align: right;
padding-left: 50%; /* Adjust padding to accommodate the data-label */
position: relative;
}
.table td::before {
content: attr(data-label);
position: absolute;
left: 0;
width: 50%;
padding-left: 15px; /* Adjust as necessary */
font-weight: bold;
text-align: left;
}
.table td .transcript {
margin-top: 20px; /* Set top margin to 20px */
text-align: left; /* Ensure text alignment is left */
margin-left: 8px;
white-space: normal; /* Prevent text from being cut off */
}
}
.login-navbar {
......@@ -159,3 +106,5 @@ span.card {
program webEmiMobile;
{$R *.dres}
uses
Vcl.Forms,
XData.Web.Connection,
......
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{DB6F5DBF-7E4B-45DA-AFFA-6C8DF15BA740}</ProjectGuid>
<ProjectVersion>20.3</ProjectVersion>
......@@ -184,6 +184,301 @@
<None Include="index.html"/>
<None Include="css\app.css"/>
<None Include="css\spinner.css"/>
<None Include="assets\bpddistricts-updated.geojson"/>
<None Include="assets\bpddistricts.geojson"/>
<RcItem Include="assets\markers\alarm_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_1</ResourceId>
</RcItem>
<RcItem Include="assets\markers\alarm_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_2</ResourceId>
</RcItem>
<RcItem Include="assets\markers\alarm_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_3</ResourceId>
</RcItem>
<RcItem Include="assets\markers\alarm_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_4</ResourceId>
</RcItem>
<RcItem Include="assets\markers\alarm_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_5</ResourceId>
</RcItem>
<RcItem Include="assets\markers\assault_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_6</ResourceId>
</RcItem>
<RcItem Include="assets\markers\assault_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_7</ResourceId>
</RcItem>
<RcItem Include="assets\markers\assault_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_8</ResourceId>
</RcItem>
<RcItem Include="assets\markers\assault_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_9</ResourceId>
</RcItem>
<RcItem Include="assets\markers\assault_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_10</ResourceId>
</RcItem>
<RcItem Include="assets\markers\caraccident_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_11</ResourceId>
</RcItem>
<RcItem Include="assets\markers\caraccident_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_12</ResourceId>
</RcItem>
<RcItem Include="assets\markers\caraccident_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_13</ResourceId>
</RcItem>
<RcItem Include="assets\markers\caraccident_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_14</ResourceId>
</RcItem>
<RcItem Include="assets\markers\caraccident_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_15</ResourceId>
</RcItem>
<RcItem Include="assets\markers\car_A.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_16</ResourceId>
</RcItem>
<RcItem Include="assets\markers\car_B.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_17</ResourceId>
</RcItem>
<RcItem Include="assets\markers\car_C.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_18</ResourceId>
</RcItem>
<RcItem Include="assets\markers\car_D.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_19</ResourceId>
</RcItem>
<RcItem Include="assets\markers\car_default.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_20</ResourceId>
</RcItem>
<RcItem Include="assets\markers\car_E.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_21</ResourceId>
</RcItem>
<RcItem Include="assets\markers\car_X.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_22</ResourceId>
</RcItem>
<RcItem Include="assets\markers\default.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_23</ResourceId>
</RcItem>
<RcItem Include="assets\markers\default_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_24</ResourceId>
</RcItem>
<RcItem Include="assets\markers\default_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_25</ResourceId>
</RcItem>
<RcItem Include="assets\markers\default_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_26</ResourceId>
</RcItem>
<RcItem Include="assets\markers\default_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_27</ResourceId>
</RcItem>
<RcItem Include="assets\markers\default_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_28</ResourceId>
</RcItem>
<RcItem Include="assets\markers\gun_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_29</ResourceId>
</RcItem>
<RcItem Include="assets\markers\gun_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_30</ResourceId>
</RcItem>
<RcItem Include="assets\markers\gun_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_31</ResourceId>
</RcItem>
<RcItem Include="assets\markers\gun_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_32</ResourceId>
</RcItem>
<RcItem Include="assets\markers\gun_5.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_33</ResourceId>
</RcItem>
<RcItem Include="assets\markers\home_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_34</ResourceId>
</RcItem>
<RcItem Include="assets\markers\home_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_35</ResourceId>
</RcItem>
<RcItem Include="assets\markers\home_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_36</ResourceId>
</RcItem>
<RcItem Include="assets\markers\home_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_37</ResourceId>
</RcItem>
<RcItem Include="assets\markers\home_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_38</ResourceId>
</RcItem>
<RcItem Include="assets\markers\medical_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_39</ResourceId>
</RcItem>
<RcItem Include="assets\markers\medical_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_40</ResourceId>
</RcItem>
<RcItem Include="assets\markers\medical_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_41</ResourceId>
</RcItem>
<RcItem Include="assets\markers\medical_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_42</ResourceId>
</RcItem>
<RcItem Include="assets\markers\medical_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_43</ResourceId>
</RcItem>
<RcItem Include="assets\markers\narcotics_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_44</ResourceId>
</RcItem>
<RcItem Include="assets\markers\narcotics_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_45</ResourceId>
</RcItem>
<RcItem Include="assets\markers\narcotics_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_46</ResourceId>
</RcItem>
<RcItem Include="assets\markers\narcotics_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_47</ResourceId>
</RcItem>
<RcItem Include="assets\markers\narcotics_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_48</ResourceId>
</RcItem>
<RcItem Include="assets\markers\noise_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_49</ResourceId>
</RcItem>
<RcItem Include="assets\markers\noise_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_50</ResourceId>
</RcItem>
<RcItem Include="assets\markers\noise_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_51</ResourceId>
</RcItem>
<RcItem Include="assets\markers\noise_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_52</ResourceId>
</RcItem>
<RcItem Include="assets\markers\noise_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_53</ResourceId>
</RcItem>
<RcItem Include="assets\markers\robbery_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_54</ResourceId>
</RcItem>
<RcItem Include="assets\markers\robbery_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_55</ResourceId>
</RcItem>
<RcItem Include="assets\markers\robbery_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_56</ResourceId>
</RcItem>
<RcItem Include="assets\markers\robbery_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_57</ResourceId>
</RcItem>
<RcItem Include="assets\markers\robbery_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_58</ResourceId>
</RcItem>
<RcItem Include="assets\markers\school_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_59</ResourceId>
</RcItem>
<RcItem Include="assets\markers\school_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_60</ResourceId>
</RcItem>
<RcItem Include="assets\markers\school_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_61</ResourceId>
</RcItem>
<RcItem Include="assets\markers\school_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_62</ResourceId>
</RcItem>
<RcItem Include="assets\markers\school_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_63</ResourceId>
</RcItem>
<RcItem Include="assets\markers\suspicious_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_64</ResourceId>
</RcItem>
<RcItem Include="assets\markers\suspicious_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_65</ResourceId>
</RcItem>
<RcItem Include="assets\markers\suspicious_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_66</ResourceId>
</RcItem>
<RcItem Include="assets\markers\suspicious_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_67</ResourceId>
</RcItem>
<RcItem Include="assets\markers\suspicious_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_68</ResourceId>
</RcItem>
<RcItem Include="assets\markers\traffic_1.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_69</ResourceId>
</RcItem>
<RcItem Include="assets\markers\traffic_2.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_70</ResourceId>
</RcItem>
<RcItem Include="assets\markers\traffic_3.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_71</ResourceId>
</RcItem>
<RcItem Include="assets\markers\traffic_4.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_72</ResourceId>
</RcItem>
<RcItem Include="assets\markers\traffic_5-9.png">
<ResourceType>RCDATA</ResourceType>
<ResourceId>PngImage_73</ResourceId>
</RcItem>
<None Include="config\config.json"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
......@@ -220,6 +515,462 @@
</Platform>
</DeployFile>
<DeployFile LocalName="Win32\Debug\webEnvoyCalls.exe" Configuration="Debug" Class="ProjectOutput"/>
<DeployFile LocalName="assets\bpddistricts-updated.geojson" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\bpddistricts.geojson" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\alarm_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\alarm_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\alarm_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\alarm_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\alarm_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\assault_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\assault_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\assault_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\assault_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\assault_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\car_A.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\car_B.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\car_C.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\car_D.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\car_E.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\car_X.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\car_default.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\caraccident_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\caraccident_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\caraccident_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\caraccident_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\caraccident_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\default.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\default_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\default_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\default_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\default_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\default_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\gun_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\gun_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\gun_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\gun_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\gun_5.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\home_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\home_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\home_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\home_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\home_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\medical_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\medical_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\medical_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\medical_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\medical_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\narcotics_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\narcotics_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\narcotics_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\narcotics_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\narcotics_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\noise_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\noise_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\noise_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\noise_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\noise_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\robbery_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\robbery_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\robbery_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\robbery_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\robbery_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\school_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\school_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\school_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\school_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\school_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\suspicious_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\suspicious_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\suspicious_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\suspicious_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\suspicious_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\traffic_1.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\traffic_2.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\traffic_3.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\traffic_4.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="assets\markers\traffic_5-9.png" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="config\config.json" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="css\app.css" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
......
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