Commit cb5e8ce5 by Mac Stephens

Improve TasksHTML row management, header info, and layout scrolling; add…

Improve TasksHTML row management,  header info, and layout scrolling; add insert-below-selected row behavior end-to-end; implement scroll position preservation
parent 38ccc4e0
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{F0FD637A-3831-4B55-80F8-F15510E0463F}</ProjectGuid>
<ProjectVersion>20.3</ProjectVersion>
<ProjectVersion>20.4</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<MainSource>emT3VCLDemo.cpp</MainSource>
<AppType>Application</AppType>
......@@ -254,6 +254,16 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\bin64\libc++-370.dll" Class="DependencyModule">
<Platform Name="Win64x">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile Condition="'$(DynamicRTL)'=='true'" LocalName="$(BDS)\bin64\libunwind-370.dll" Class="DependencyModule">
<Platform Name="Win64x">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile Condition="'$(UsingDelphiRTL)'=='true'" LocalName="$(BDS)\bin\borlndmm.dll" Class="DependencyModule">
<Platform Name="Win32">
<Overwrite>true</Overwrite>
......@@ -299,6 +309,21 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile Condition="'$(UsingDelphiRTL)'=='true'" LocalName="$(BDS)\binarm64ec\borlndmm.dll" Class="DependencyModule">
<Platform Name="WinARM64EC">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'!='true'" LocalName="$(BDS)\binarm64ec\cc64370.dll" Class="DependencyModule">
<Platform Name="WinARM64EC">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile Condition="'$(DynamicRTL)'=='true' And '$(Multithreaded)'=='true'" LocalName="$(BDS)\binarm64ec\cc64370mt.dll" Class="DependencyModule">
<Platform Name="WinARM64EC">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName=".\Win64x\Debug\emT3VCLDemo.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win64x">
<RemoteName>emT3VCLDemo.exe</RemoteName>
......@@ -968,6 +993,9 @@
<Platform Name="Win64x">
<Operation>1</Operation>
</Platform>
<Platform Name="WinARM64EC">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
......@@ -1042,6 +1070,10 @@
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="WinARM64EC">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_CppLogo44">
<Platform Name="Win32">
......@@ -1056,6 +1088,10 @@
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="WinARM64EC">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iOS_AppStore1024">
<Platform Name="iOSDevice64">
......@@ -1269,6 +1305,7 @@
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win64x" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="WinARM64EC" Name="$(PROJECTNAME)"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
......
......@@ -106,7 +106,7 @@ object fMain: TfMain
'MySQL.HttpTrustServerCertificate=False'
'MySQL.ProxyPort=0')
Username = 'root'
Server = '192.168.102.129'
Server = '192.168.102.131'
LoginPrompt = False
Left = 390
Top = 342
......
......@@ -10,13 +10,9 @@ procedure HideStatusMessage(const AElementId: string);
procedure ShowSpinner(SpinnerID: string);
procedure HideSpinner(SpinnerID: string);
procedure ShowErrorModal(msg: string);
function CalculateAge(DateOfBirth: TDateTime): Integer;
function FormatPhoneNumber(PhoneNumber: string): string;
procedure ApplyReportTitle(CurrentReportType: string);
procedure ShowToast(const MessageText: string; const ToastType: string = 'success');
procedure ShowConfirmationModal(msg, leftLabel, rightLabel: string; ConfirmProc: TProc<Boolean>);
procedure ShowNotificationModal(msg: string);
// function FormatDollarValue(ValueStr: string): string;
implementation
......@@ -153,28 +149,6 @@ begin
end;
// ShowConfirmationModal displays a two-button modal with custom labels.
// Params:
// - messageText: text shown in the modal body
// - leftButtonText: label for the left button (e.g., "Cancel")
// - rightButtonText: label for the right button (e.g., "Delete")
// - callback: procedure(confirmed: Boolean); confirmed = True if right button clicked
//
// Example:
// ShowConfirmationModal('Delete this?', 'Cancel', 'Delete',
// procedure(confirmed: Boolean)
// begin
// if confirmed then DeleteOrder();
// end);
// function ShowConfirmationModal(msg, leftLabel, rightLabel: string;): Boolean;
// if ShowConfirmationModal then
// doThing()
// else
// doOtherThing();
procedure ShowConfirmationModal(msg, leftLabel, rightLabel: string; ConfirmProc: TProc<Boolean>);
begin
asm
......@@ -211,49 +185,6 @@ begin
end;
function CalculateAge(DateOfBirth: TDateTime): Integer;
var
Today, BirthDate: TJSDate;
Year, Month, Day, BirthYear, BirthMonth, BirthDay: NativeInt;
DOBString: string;
begin
Today := TJSDate.New;
Year := Today.FullYear;
Month := Today.Month + 1;
Day := Today.Date;
// Formats the DateOfBirth as an ISO 8601 date string
DOBString := FormatDateTime('yyyy-mm-dd', DateOfBirth);
BirthDate := TJSDate.New(DOBString);
if BirthDate = nil then
begin
Exit(0); // Exit the function with an age of 0 if the date creation fails
end;
BirthYear := BirthDate.FullYear;
BirthMonth := BirthDate.Month + 1;
BirthDay := BirthDate.Date;
Result := Year - BirthYear;
if (Month < BirthMonth) or ((Month = BirthMonth) and (Day < BirthDay)) then
Dec(Result);
end;
function FormatPhoneNumber(PhoneNumber: string): string;
var
Digits: string;
begin
Digits := PhoneNumber.Replace('(', '').Replace(')', '').Replace('-', '').Replace(' ', '');
case Length(Digits) of
7: Result := Format('%s-%s', [Copy(Digits, 1, 3), Copy(Digits, 4, 4)]);
10: Result := Format('(%s) %s-%s', [Copy(Digits, 1, 3), Copy(Digits, 4, 3), Copy(Digits, 7, 4)]);
else
// If the number does not have 7 or 10 digits, whatever they typed is returned
Result := PhoneNumber;
end;
end;
procedure ShowToast(const MessageText: string; const ToastType: string = 'success');
var
ParsedText, ToastKind, MsgPrefix: string;
......@@ -318,35 +249,5 @@ begin
end;
procedure ApplyReportTitle(CurrentReportType: string);
var
CrimeTitleElement: TJSHTMLElement;
begin
CrimeTitleElement := TJSHTMLElement(document.getElementById('crime_title'));
if Assigned(CrimeTitleElement) then
CrimeTitleElement.innerText := CurrentReportType
else
Console.Log('Element with ID "crime_title" not found.');
end;
// Used html number input type to restrict the input instead of this function
// function FormatDollarValue(ValueStr: string): string;
// var
// i: Integer;
// begin
// Result := ''; // Initialize the result
// // Filter out any characters that are not digits or decimal point
// for i := 1 to Length(ValueStr) do
// begin
// if (Pos(ValueStr[i], '0123456789.') > 0) then
// begin
// Result := Result + ValueStr[i];
// end;
// end;
// end;
end.
......@@ -98,27 +98,9 @@ object FViewMain: TFViewMain
Role = 'null'
TabOrder = 0
end
object memoDebug: TWebMemo
Left = 45
Top = 361
Width = 471
Height = 83
ElementID = 'memo_debug'
ElementPosition = epRelative
Enabled = False
HeightPercent = 100.000000000000000000
Lines.Strings = (
'WebMemo1')
Role = 'null'
SelLength = 0
SelStart = 0
ShowFocus = False
Visible = False
WidthPercent = 100.000000000000000000
end
object xdwcMain: TXDataWebClient
Connection = DMConnection.ApiConnection
Left = 80
Top = 476
Left = 76
Top = 332
end
end
......@@ -56,16 +56,8 @@
</div>
<!-- Main Panel (where all forms display) -->
<div class="container-fluid py-3">
<div class="row">
<div id="pnl_main" class="col-12"></div>
</div>
<div class="row mt-3">
<div class="col-12">
<textarea class="form-control font-monospace" id="memo_debug" rows="4" placeholder="Debug output..."></textarea>
</div>
</div>
<div class="container-fluid py-3 d-flex flex-column overflow-hidden" style="height: calc(100vh - 57px);">
<div id="pnl_main" class="flex-grow-1 min-h-0 overflow-hidden"></div>
</div>
<!-- Spinner Modal -->
......
......@@ -17,7 +17,6 @@ type
lblLogout: TWebLinkLabel;
lblVersion: TWebLabel;
lblAppTitle: TWebLabel;
memoDebug: TWebMemo;
xdwcMain: TXDataWebClient;
procedure WebFormCreate(Sender: TObject);
procedure lblLogoutClick(Sender: TObject);
......
<div class="container-fluid p-2 d-flex flex-column h-100">
<div class="container-fluid p-2 d-flex flex-column h-100 overflow-hidden">
<div class="d-flex align-items-center justify-content-between mb-2 flex-shrink-0">
<h5 class="mb-0" id="lbl_project_name"></h5>
<div class="d-flex gap-2">
<button id="btn_add_row" class="btn btn-sm btn-outline-success">Add Row</button>
<button id="btn_delete_row" class="btn btn-sm btn-outline-danger">Delete Row</button>
<button id="btn_reload" class="btn btn-sm btn-outline-primary">Reload</button>
<div class="d-flex align-items-center gap-3">
<div id="lbl_total_rows"></div>
<div class="d-flex gap-2">
<button id="btn_add_row" class="btn btn-sm btn-success">Add Row</button>
<button id="btn_delete_row" class="btn btn-sm btn-danger">Delete Row</button>
<button id="btn_reload" class="btn btn-sm btn-primary">Reload</button>
</div>
</div>
</div>
<div id="tasks_table_host" class="flex-grow-1 min-vh-0 overflow-auto"></div>
<div id="tasks_table_host" class="flex-grow-1 min-h-0 overflow-auto"></div>
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasNameManager" aria-labelledby="nm_title">
<div class="offcanvas-header">
......@@ -34,6 +39,3 @@
</div>
</div>
</div>
......@@ -43,6 +43,8 @@ type
FPendingFocusField: string;
FSelectedTaskItemId: Integer;
FSelectedTaskId: Integer;
FPendingScrollTop: Integer;
FPendingScrollLeft: Integer;
FPendingFocusItemNum: Integer;
FPendingFocusTaskField: string;
FNameManager: TNameManager;
......@@ -55,6 +57,7 @@ type
procedure EnableAutoGrowTextAreas;
procedure GotoRowIndex(AIndex: Integer);
function HtmlEncode(const s: string): string;
procedure SetTotalRowsLabel(ARowCount: Integer);
procedure SetTaskLabel(const ATitle: string);
[async] procedure SaveRow(AIndex: Integer);
procedure EditorBlur(Event: TJSEvent);
......@@ -72,6 +75,8 @@ type
procedure ApplySelectedRowState;
procedure ApplyPendingDeleteFocus;
procedure EditorKeyDown(Event: TJSEvent);
procedure CaptureTableScroll;
procedure RestoreTableScroll;
public
end;
......@@ -322,7 +327,10 @@ begin
Utils.ShowSpinner('spinner');
try
if await(AddTaskRow) then
begin
CaptureTableScroll;
LoadTasks(FTaskId);
end;
finally
Utils.HideSpinner('spinner');
end;
......@@ -362,6 +370,7 @@ begin
FPendingFocusItemNum := deletedItemNum;
FPendingFocusTaskField := 'application';
CaptureTableScroll;
LoadTasks(FTaskId);
end;
finally
......@@ -407,6 +416,9 @@ end;
[async] function TFTasksHTML.AddTaskRow: Boolean;
var
response: TXDataClientResponse;
insertAfterItemNum: Integer;
newItemNum: Integer;
maxItemNum: Integer;
begin
Result := False;
......@@ -416,11 +428,38 @@ begin
Exit;
end;
insertAfterItemNum := 0;
maxItemNum := 0;
if xdwdsTasks.Active then
begin
xdwdsTasks.First;
while not xdwdsTasks.Eof do
begin
if xdwdsTasksitemNum.AsInteger > maxItemNum then
maxItemNum := xdwdsTasksitemNum.AsInteger;
if xdwdsTaskstaskItemId.AsInteger = FSelectedTaskItemId then
insertAfterItemNum := xdwdsTasksitemNum.AsInteger;
xdwdsTasks.Next;
end;
end;
if insertAfterItemNum > 0 then
newItemNum := insertAfterItemNum + 1
else
newItemNum := maxItemNum + 1;
try
response := await(xdwcTasks.RawInvokeAsync(
'IApiService.AddTaskRow', [FTaskId]
'IApiService.AddTaskRow', [FTaskId, insertAfterItemNum]
));
console.log('AddTaskRow response=' + string(TJSJSON.stringify(response.Result)));
FPendingFocusItemNum := newItemNum;
FPendingFocusTaskField := 'application';
Result := True;
except
on E: EXDataClientRequestException do
......@@ -460,6 +499,16 @@ begin
end;
procedure TFTasksHTML.SetTotalRowsLabel(ARowCount: Integer);
var
el: TJSHTMLElement;
begin
el := TJSHTMLElement(document.getElementById('lbl_total_rows'));
if Assigned(el) then
el.innerText := 'Total Rows: ' + IntToStr(ARowCount);
end;
procedure TFTasksHTML.SetTaskLabel(const ATitle: string);
var
el: TJSHTMLElement;
......@@ -476,6 +525,7 @@ var
resultObj, taskObj: TJSObject;
itemsArray: TJSArray;
titleText: string;
rowCount: Integer;
begin
console.log('IApiService.GetTaskItems called with task_id: ' + ATaskId);
console.log('Load Tasks Fired');
......@@ -506,6 +556,9 @@ begin
SetTaskLabel(titleText);
rowCount := StrToIntDef(string(resultObj['count']), 0);
SetTotalRowsLabel(rowCount);
FReportedByOptions := ExtractOptionNames(TJSArray(resultObj['reportedByOptions']));
FAssignedToOptions := ExtractOptionNames(TJSArray(resultObj['assignedToOptions']));
FStatusOptions := ExtractCodeDescs(TJSArray(resultObj['statusOptions']));
......@@ -682,19 +735,19 @@ begin
html :=
'<div class="tasks-vscroll">' +
'<div class="tasks-hscroll">' +
'<table class="table table-sm align-middle mb-0" style="min-width: 2000px;">' +
'<table class="table table-sm table-bordered align-middle mb-0" style="min-width: 2000px;">' +
'<colgroup>' +
'<col style="width:40px">' +
'<col style="width:240px">' +
'<col style="width:90px">' +
'<col style="width:120px">' +
'<col style="width:120px">' +
'<col style="width:120px">' +
'<col style="width:140px">' +
'<col style="width:140px">' +
'<col style="width:160px">' +
'<col style="width:520px">' +
'<col style="width:520px">' +
'<col style="width:40px">' + // Item Num
'<col style="width:200px">' + // App
'<col style="width:90px">' + // Version
'<col style="width:120px">' + // Date
'<col style="width:120px">' + // Reported
'<col style="width:120px">' + // Assigned
'<col style="width:195px">' + // Status
'<col style="width:140px">' + // Status Date
'<col style="width:160px">' + // Form
'<col style="width:520px">' + // Issue
'<col style="width:520px">' + // Notes
'</colgroup>' +
'<thead><tr>' +
ThBlank +
......@@ -739,6 +792,7 @@ begin
BindTableEditors;
EnableAutoGrowTextAreas;
EnableColumnResize;
RestoreTableScroll;
ApplyPendingFocus;
ApplyPendingDeleteFocus;
end;
......@@ -848,6 +902,7 @@ begin
FPendingFocusTaskItemId := movedTaskItemId;
FPendingFocusField := 'application';
CaptureTableScroll;
LoadTasks(FTaskId);
except
on E: EXDataClientRequestException do
......@@ -1097,7 +1152,10 @@ end;
procedure TFTasksHTML.ApplyPendingDeleteFocus;
var
el: TJSHTMLElement;
rowEl: TJSHTMLElement;
selector: string;
taskItemIdStr: string;
taskIdStr: string;
begin
if (FPendingFocusItemNum <= 0) or (FPendingFocusTaskField = '') then
Exit;
......@@ -1109,6 +1167,19 @@ begin
el := TJSHTMLElement(document.querySelector(selector));
if Assigned(el) then
begin
rowEl := TJSHTMLElement(el.closest('tr'));
if Assigned(rowEl) then
begin
taskItemIdStr := string(rowEl.getAttribute('data-task-item-id'));
taskIdStr := string(rowEl.getAttribute('data-task-id'));
FSelectedTaskItemId := StrToIntDef(taskItemIdStr, 0);
FSelectedTaskId := StrToIntDef(taskIdStr, 0);
btnDeleteRow.Enabled := FSelectedTaskItemId > 0;
ApplySelectedRowState;
end;
asm
el.scrollIntoView({ behavior: 'auto', block: 'nearest', inline: 'nearest' });
el.focus();
......@@ -1119,6 +1190,28 @@ begin
FPendingFocusTaskField := '';
end;
procedure TFTasksHTML.CaptureTableScroll;
begin
asm
const vscroll = document.querySelector('.tasks-vscroll');
const hscroll = document.querySelector('.tasks-hscroll');
this.FPendingScrollTop = vscroll ? vscroll.scrollTop : 0;
this.FPendingScrollLeft = hscroll ? hscroll.scrollLeft : 0;
end;
end;
procedure TFTasksHTML.RestoreTableScroll;
begin
asm
const vscroll = document.querySelector('.tasks-vscroll');
const hscroll = document.querySelector('.tasks-hscroll');
if (vscroll) vscroll.scrollTop = this.FPendingScrollTop || 0;
if (hscroll) hscroll.scrollLeft = this.FPendingScrollLeft || 0;
end;
end;
......
......@@ -53,7 +53,7 @@ input[data-field="itemNum"] {
}
.tasks-vscroll {
max-height: calc(100vh - 260px);
height: 100%;
overflow: auto;
}
......@@ -68,5 +68,9 @@ input[data-field="itemNum"] {
z-index: 3;
}
span.card {
border: none;
}
......@@ -99,11 +99,11 @@
<VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_MinorVer>9</VerInfo_MinorVer>
<VerInfo_Release>8</VerInfo_Release>
<TMSURLParams>?user_id=1019&amp;task_id=4000&amp;url_code=123456</TMSURLParams>
<TMSWebBrowser>1</TMSWebBrowser>
<TMSWebOutputPath>..\emT3XDataServer\bin\static</TMSWebOutputPath>
<TMSWebSingleInstance>1</TMSWebSingleInstance>
<TMSURLParams>?user_id=1019&amp;task_id=4000&amp;url_code=123456</TMSURLParams>
<TMSUseJSDebugger>2</TMSUseJSDebugger>
<TMSWebOutputPath>..\emT3XDataServer\bin\static</TMSWebOutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
......@@ -170,7 +170,12 @@
<Source>
<Source Name="MainSource">emT3WebApp.dpr</Source>
</Source>
<Excluded_Packages/>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k370.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp370.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k370.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp370.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="5">
<DeployFile LocalName="Win32\Debug\emT3WebApp.exe" Configuration="Debug" Class="ProjectOutput">
......
......@@ -23,8 +23,8 @@ object ApiDatabase: TApiDatabase
SQL.Strings = (
'SELECT USER_ID, NAME, STATUS from users ORDER BY NAME')
OnCalcFields = uqUsersCalcFields
Left = 414
Top = 40
Left = 408
Top = 20
object uqUsersUSER_ID: TIntegerField
FieldName = 'USER_ID'
Required = True
......@@ -239,11 +239,7 @@ object ApiDatabase: TApiDatabase
')'
'values ('
' :TASK_ID,'
' ('
' select coalesce(max(ti.ITEM_NUM), 0) + 1'
' from task_items ti'
' where ti.TASK_ID = :TASK_ID'
' ),'
' :ITEM_NUM,'
' '#39#39','
' '#39#39','
' curdate(),'
......@@ -263,6 +259,11 @@ object ApiDatabase: TApiDatabase
DataType = ftUnknown
Name = 'TASK_ID'
Value = nil
end
item
DataType = ftUnknown
Name = 'ITEM_NUM'
Value = nil
end>
end
object uqTaskHeader: TUniQuery
......@@ -604,4 +605,25 @@ object ApiDatabase: TApiDatabase
Value = nil
end>
end
object uqShiftTaskRowsForInsert: TUniQuery
Connection = ucETaskApi
SQL.Strings = (
'update task_items'
'set ITEM_NUM = ITEM_NUM + 1'
'where TASK_ID = :TASK_ID'
' and ITEM_NUM > :INSERT_AFTER_ITEM_NUM')
Left = 408
Top = 80
ParamData = <
item
DataType = ftUnknown
Name = 'TASK_ID'
Value = nil
end
item
DataType = ftUnknown
Name = 'INSERT_AFTER_ITEM_NUM'
Value = nil
end>
end
end
......@@ -66,6 +66,7 @@ type
uqGetTaskRowPositionTASK_ITEM_ID: TIntegerField;
uqDeleteTaskRow: TUniQuery;
uqShiftTaskRowsAfterDelete: TUniQuery;
uqShiftTaskRowsForInsert: TUniQuery;
procedure DataModuleCreate(Sender: TObject);
procedure uqUsersCalcFields(DataSet: TDataSet);
private
......
......@@ -92,7 +92,7 @@ type
IApiService = interface(IInvokable)
['{0EFB33D7-8C4C-4F3C-9BC3-8B4D444B5F69}']
function GetTaskItems(taskId: string): TTaskItemsResponse;
[HttpPost] function AddTaskRow(taskId: string): Boolean;
[HttpPost] function AddTaskRow(taskId: string; insertAfterItemNum: Integer): Boolean;
[HttpPost] function SaveTaskRow(Item: TTaskRowSave): Boolean;
function TestApi(messageText: string): TJSONObject;
procedure MoveTaskRow(const taskId: Integer; const taskItemId: Integer; const newItemNum: Integer);
......
......@@ -20,7 +20,7 @@ type
private
function BuildTaskNumber: string;
function BuildTaskTitle(const taskNumber, projectName, subject: string): string;
function AddTaskRow(taskId: string): Boolean;
function AddTaskRow(taskId: string; insertAfterItemNum: Integer): Boolean;
function SaveTaskRow(Item: TTaskRowSave): Boolean;
function TestApi(messageText: string): TJSONObject;
function GetWebClientVersion: string;
......@@ -177,20 +177,51 @@ begin
end;
function TApiService.AddTaskRow(taskId: string): Boolean;
function TApiService.AddTaskRow(taskId: string; insertAfterItemNum: Integer): Boolean;
var
newItemNum: Integer;
maxItemNum: Integer;
begin
Logger.Log(4, Format('ApiService.AddTaskRow - TASK_ID="%s"', [taskId]));
Logger.Log(4, Format('ApiService.AddTaskRow - TASK_ID="%s" INSERT_AFTER_ITEM_NUM="%d"', [taskId, insertAfterItemNum]));
apiDB.uqGetTaskMaxItemNum.Close;
apiDB.uqGetTaskMaxItemNum.ParamByName('TASK_ID').AsString := taskId;
apiDB.uqGetTaskMaxItemNum.Open;
maxItemNum := apiDB.uqGetTaskMaxItemNumMAX_ITEM_NUM.AsInteger;
if insertAfterItemNum < 0 then
insertAfterItemNum := 0;
if insertAfterItemNum > maxItemNum then
insertAfterItemNum := maxItemNum;
newItemNum := insertAfterItemNum + 1;
apiDB.uqAddTaskRow.Connection.StartTransaction;
try
if insertAfterItemNum > 0 then
begin
apiDB.uqShiftTaskRowsForInsert.Close;
apiDB.uqShiftTaskRowsForInsert.ParamByName('TASK_ID').AsString := taskId;
apiDB.uqShiftTaskRowsForInsert.ParamByName('INSERT_AFTER_ITEM_NUM').AsInteger := insertAfterItemNum;
apiDB.uqShiftTaskRowsForInsert.ExecSQL;
end;
apiDB.uqAddTaskRow.Close;
apiDB.uqAddTaskRow.ParamByName('TASK_ID').AsString := taskId;
apiDB.uqAddTaskRow.ParamByName('ITEM_NUM').AsInteger := newItemNum;
apiDB.uqAddTaskRow.ExecSQL;
apiDB.uqAddTaskRow.Connection.Commit;
Result := True;
Logger.Log(4, 'ApiService.AddTaskRow - OK');
Logger.Log(4, Format('ApiService.AddTaskRow - OK TASK_ID="%s" ITEM_NUM="%d"', [taskId, newItemNum]));
except
on E: Exception do
begin
if apiDB.uqAddTaskRow.Connection.InTransaction then
apiDB.uqAddTaskRow.Connection.Rollback;
Logger.Log(2, 'ApiService.AddTaskRow - ERROR: ' + E.Message);
raise;
end;
......
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