Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
emT3web
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Mac Stephens
emT3web
Commits
4a314fa8
Commit
4a314fa8
authored
Apr 13, 2026
by
Mac Stephens
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
v0.8.5 fixes Deployed 0.8.8
parent
071af034
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1079 additions
and
288 deletions
+1079
-288
ConnectionModule.pas
emT3Web/ConnectionModule.pas
+1
-1
Utils.pas
emT3Web/Utils.pas
+18
-0
View.TaskItems.pas
emT3Web/View.TaskItems.pas
+192
-189
app.css
emT3Web/css/app.css
+152
-1
emT3web.dpr
emT3Web/emT3web.dpr
+2
-1
emT3web.dproj
emT3Web/emT3web.dproj
+5
-4
uDropdownHelpers.pas
emT3Web/uDropdownHelpers.pas
+184
-0
uNameOffCanvas.pas
emT3Web/uNameOffCanvas.pas
+7
-5
Api.Database.dfm
emT3XDataServer/Source/Api.Database.dfm
+168
-15
Api.Database.pas
emT3XDataServer/Source/Api.Database.pas
+7
-1
Api.Service.pas
emT3XDataServer/Source/Api.Service.pas
+21
-2
Api.ServiceImpl.pas
emT3XDataServer/Source/Api.ServiceImpl.pas
+318
-65
emT3XDataServer.ini
emT3XDataServer/bin/emT3XDataServer.ini
+2
-2
emT3XDataServer.dproj
emT3XDataServer/emT3XDataServer.dproj
+2
-2
No files found.
emT3Web/ConnectionModule.pas
View file @
4a314fa8
...
...
@@ -20,7 +20,7 @@ type
FUnauthorizedAccessProc
:
TUnauthorizedAccessProc
;
public
const
clientVersion
=
'0.8.
7
'
;
const
clientVersion
=
'0.8.
8
'
;
procedure
InitApp
(
SuccessProc
:
TSuccessProc
;
UnauthorizedAccessProc
:
TUnauthorizedAccessProc
);
procedure
SetClientConfig
(
Callback
:
TVersionCheckCallback
);
...
...
emT3Web/Utils.pas
View file @
4a314fa8
...
...
@@ -14,6 +14,7 @@ procedure ShowToast(const MessageText: string; const ToastType: string = 'succes
procedure
ShowConfirmationModal
(
msg
,
leftLabel
,
rightLabel
:
string
;
ConfirmProc
:
TProc
<
Boolean
>);
procedure
ShowNotificationModal
(
msg
:
string
);
procedure
ShowAppDialog
(
const
Msg
:
string
;
const
Title
:
string
=
'emT3 web app'
;
ReloadOnClose
:
Boolean
=
False
;
ButtonText
:
string
=
'Close'
);
function
NormalizeDateValue
(
const
Value
:
string
):
string
;
implementation
...
...
@@ -281,5 +282,22 @@ begin
end
;
function
NormalizeDateValue
(
const
Value
:
string
):
string
;
var
normalizedValue
:
string
;
begin
normalizedValue
:=
Trim
(
Value
);
if
(
normalizedValue
=
''
)
or
SameText
(
normalizedValue
,
'1899-12-30'
)
or
SameText
(
normalizedValue
,
'12/30/1899'
)
or
SameText
(
normalizedValue
,
'1899-12-30T00:00:00'
)
or
SameText
(
normalizedValue
,
'1899-12-30 00:00:00'
)
then
Result
:=
''
else
Result
:=
normalizedValue
;
end
;
end
.
emT3Web/View.TaskItems.pas
View file @
4a314fa8
...
...
@@ -5,7 +5,7 @@ interface
uses
System
.
SysUtils
,
System
.
Classes
,
JS
,
Web
,
WEBLib
.
Graphics
,
WEBLib
.
Controls
,
WEBLib
.
Forms
,
WEBLib
.
Dialogs
,
WEBLib
.
ExtCtrls
,
uName
Manager
,
WEBLib
.
ExtCtrls
,
uName
OffCanvas
,
uDropdownHelpers
,
XData
.
Web
.
Client
,
XData
.
Web
.
Dataset
,
Utils
,
Data
.
DB
,
XData
.
Web
.
JsonDataset
,
Vcl
.
Controls
,
Vcl
.
StdCtrls
,
WEBLib
.
StdCtrls
;
...
...
@@ -60,16 +60,12 @@ type
function
HtmlEncode
(
const
s
:
string
):
string
;
procedure
SetTotalRowsLabel
(
ARowCount
:
Integer
);
procedure
SetTaskLabel
(
const
ATitle
:
string
);
[
async
]
procedure
Save
Row
(
AIndex
:
Integer
);
[
async
]
procedure
Save
Field
(
AIndex
:
Integer
;
const
AFieldName
:
string
);
procedure
EditorBlur
(
Event
:
TJSEvent
);
[
async
]
function
AddTaskRow
:
Boolean
;
[
async
]
function
DeleteTaskRow
:
Boolean
;
function
ExtractOptionNames
(
const
SourceArray
:
TJSArray
):
TJSArray
;
function
GetOptionsForField
(
const
AFieldName
:
string
):
TJSArray
;
procedure
FocusTrigger
(
const
ATriggerId
:
string
);
procedure
DropdownItemClick
(
Event
:
TJSEvent
);
procedure
DropdownEditClick
(
Event
:
TJSEvent
);
function
ExtractCodeDescs
(
const
SourceArray
:
TJSArray
):
TJSArray
;
[
async
]
procedure
MoveTaskRow
(
AIndex
:
Integer
;
const
newItemNum
:
Integer
);
procedure
ApplyPendingFocus
;
procedure
RowClick
(
Event
:
TJSEvent
);
...
...
@@ -81,15 +77,15 @@ type
[
async
]
function
AddAssignedName
(
const
AName
:
string
):
TJSArray
;
[
async
]
function
RenameAssignedName
(
const
AOldName
,
ANewName
:
string
):
TJSArray
;
[
async
]
function
DeleteAssignedName
(
const
AName
:
string
):
TJSArray
;
function
ExtractAssignedOptionNames
(
const
ResponseResult
:
TJSObject
):
TJSArray
;
[
async
]
function
AddReportedName
(
const
AName
:
string
):
TJSArray
;
[
async
]
function
RenameReportedName
(
const
AOldName
,
ANewName
:
string
):
TJSArray
;
[
async
]
function
DeleteReportedName
(
const
AName
:
string
):
TJSArray
;
[
async
]
function
AddApplicationName
(
const
AName
:
string
):
TJSArray
;
[
async
]
function
RenameApplicationName
(
const
AOldName
,
ANewName
:
string
):
TJSArray
;
[
async
]
function
DeleteApplicationName
(
const
AName
:
string
):
TJSArray
;
function
ExtractApplicationOptionNames
(
const
ResponseResult
:
TJSObject
):
TJSArray
;
[
async
]
procedure
HandleAddManagedName
(
const
AFieldName
:
string
;
const
ARowIndex
:
Integer
;
const
ANewName
:
string
);
[
async
]
procedure
HandleRenameManagedName
(
const
AFieldName
,
AOldName
,
ANewName
:
string
);
[
async
]
procedure
HandleDeleteManagedName
(
const
AFieldName
,
AName
:
string
);
function
FindOptionIgnoreCase
(
const
AItems
:
TJSArray
;
const
AName
:
string
):
string
;
public
end
;
...
...
@@ -118,11 +114,11 @@ begin
FNameManager
:=
TNameManager
.
Create
(
function
(
const
AFieldName
:
string
):
TJSArray
begin
Result
:=
GetOptionsForField
(
AFieldName
);
Result
:=
uDropdownHelpers
.
GetOptionsForField
(
AFieldName
,
FApplicationOptions
,
FReportedByOptions
,
FAssignedToOptions
);
end
,
procedure
(
const
ATriggerId
:
string
)
begin
FocusTrigger
(
ATriggerId
);
uDropdownHelpers
.
FocusTrigger
(
ATriggerId
);
end
,
procedure
(
const
AFieldName
:
string
;
const
ARowIndex
:
Integer
;
const
ANewName
:
string
)
begin
...
...
@@ -259,7 +255,7 @@ begin
xdwdsTasks
.
Post
;
el
.
setAttribute
(
'data-unsaved-data'
,
'1'
);
Save
Row
(
idx
);
Save
Field
(
idx
,
fieldName
);
end
;
...
...
@@ -630,13 +626,11 @@ var
Result
:=
'<td class="align-top wrap-cell">'
+
s
+
'</td>'
;
end
;
function
TextInput
(
const
FieldName
,
Value
:
string
;
const
AIdx
:
Integer
;
const
MinWidth
:
Integer
=
0
):
string
;
function
TextInput
(
const
FieldName
,
Value
:
string
;
const
AIdx
:
Integer
):
string
;
var
w
:
string
;
begin
w
:=
''
;
if
MinWidth
>
0
then
w
:=
' style="min-width: '
+
IntToStr
(
MinWidth
)
+
'px;"'
;
Result
:=
'<input class="form-control form-control-sm cell-input task-editor w-100" '
+
...
...
@@ -662,18 +656,19 @@ var
'value="'
+
IntToStr
(
Value
)
+
'">'
;
end
;
function
DateInput
(
const
FieldName
,
Value
:
string
;
const
AIdx
:
Integer
;
const
MinWidth
:
Integer
=
0
):
string
;
function
DateInput
(
const
FieldName
,
Value
:
string
;
const
AIdx
:
Integer
):
string
;
var
w
:
string
;
dateValue
:
string
;
begin
w
:=
''
;
if
MinWidth
>
0
then
w
:=
' style="min-width: '
+
IntToStr
(
MinWidth
)
+
'px;"'
;
dateValue
:=
Utils
.
NormalizeDateValue
(
Value
)
;
Result
:=
'<input type="date" class="form-control form-control-sm cell-input task-editor w-100" '
+
'data-idx="'
+
IntToStr
(
AIdx
)
+
'" data-field="'
+
FieldName
+
'" '
+
'value="'
+
HtmlEncode
(
Value
)
+
'"'
+
w
+
'>'
;
'value="'
+
HtmlEncode
(
date
Value
)
+
'"'
+
w
+
'>'
;
end
;
function
SelectList
(
const
FieldName
,
Current
:
string
;
const
AIdx
:
Integer
;
const
Items
:
TJSArray
;
const
AllowEdit
:
Boolean
):
string
;
...
...
@@ -681,13 +676,21 @@ var
i
:
Integer
;
itemText
:
string
;
triggerId
:
string
;
buttonClass
:
string
;
begin
triggerId
:=
'task_dd_'
+
FieldName
+
'_'
+
IntToStr
(
AIdx
);
buttonClass
:=
'btn btn-sm border w-100 d-flex justify-content-between align-items-center text-start task-dd-toggle '
;
if
SameText
(
FieldName
,
'status'
)
then
buttonClass
:=
buttonClass
+
GetTaskStatusClass
(
Current
)
else
buttonClass
:=
buttonClass
+
'btn-light'
;
Result
:=
'<div class="dropdown w-100">'
+
'<button id="'
+
triggerId
+
'" class="btn btn-sm btn-light border w-100 d-flex justify-content-between align-items-center text-start task-dd-toggle" '
+
'type="button" data-bs-toggle="dropdown" aria-expanded="false">'
+
'<button id="'
+
triggerId
+
'" class="'
+
buttonClass
+
'" '
+
'type="button" data-bs-toggle="dropdown" aria-expanded="false" '
+
'data-idx="'
+
IntToStr
(
AIdx
)
+
'" data-field="'
+
FieldName
+
'">'
+
'<span class="task-dd-label text-truncate">'
+
HtmlEncode
(
Current
)
+
'</span>'
+
'<span class="dropdown-toggle dropdown-toggle-split border-0 ms-2"></span>'
+
'</button>'
+
...
...
@@ -728,31 +731,6 @@ var
'</div>'
;
end
;
function
StatusSelect
(
const
Current
:
string
;
const
AIdx
:
Integer
):
string
;
var
i
:
Integer
;
statusText
:
string
;
sel
:
string
;
begin
Result
:=
'<select class="form-select form-select-sm task-select" data-idx="'
+
IntToStr
(
AIdx
)
+
'" data-field="status">'
;
Result
:=
Result
+
'<option value=""></option>'
;
//Note: This adds the blank option on top
if
Assigned
(
FStatusOptions
)
then
for
i
:=
0
to
FStatusOptions
.
length
-
1
do
begin
statusText
:=
string
(
FStatusOptions
[
i
]);
sel
:=
''
;
if
SameText
(
Current
,
statusText
)
then
sel
:=
' selected'
;
Result
:=
Result
+
'<option value="'
+
HtmlEncode
(
statusText
)
+
'"'
+
sel
+
'>'
+
HtmlEncode
(
statusText
)
+
'</option>'
;
end
;
Result
:=
Result
+
'</select>'
;
end
;
begin
host
:=
TJSHTMLElement
(
document
.
getElementById
(
'tasks_table_host'
));
if
not
Assigned
(
host
)
then
...
...
@@ -761,12 +739,12 @@ begin
html
:=
'<div class="tasks-vscroll">'
+
'<div class="tasks-hscroll">'
+
'<table class="table table-sm table-bordered align-middle mb-0
" style="min-width: 1700px
;">'
+
'<table class="table table-sm table-bordered align-middle mb-0
tasks-table" style="min-width: 1700px; table-layout: fixed
;">'
+
'<colgroup>'
+
'<col style="width:40px">'
+
// Item Num
'<col style="width:200px">'
+
// App
'<col style="width:90px">'
+
// Version
'<col style="width:1
2
0px">'
+
// Date
'<col style="width:1
4
0px">'
+
// Date
'<col style="width:120px">'
+
// Reported
'<col style="width:120px">'
+
// Assigned
'<col style="width:195px">'
+
// Status
...
...
@@ -797,13 +775,13 @@ begin
'<tr class="task-row-selectable" data-task-item-id="'
+
IntToStr
(
xdwdsTaskstaskItemId
.
AsInteger
)
+
'" data-task-id="'
+
xdwdsTaskstaskId
.
AsString
+
'" data-item-num="'
+
IntToStr
(
xdwdsTasksitemNum
.
AsInteger
)
+
'">'
+
TdNowrap
(
ItemNumInput
(
xdwdsTasksitemNum
.
AsInteger
,
rowIdx
))
+
TdNowrap
(
SelectList
(
'application'
,
xdwdsTasksapplication
.
AsString
,
rowIdx
,
FApplicationOptions
,
True
))
+
TdNowrap
(
TextInput
(
'version'
,
xdwdsTasksversion
.
AsString
,
rowIdx
,
80
))
+
TdNowrap
(
DateInput
(
'taskDate'
,
xdwdsTaskstaskDate
.
AsString
,
rowIdx
,
110
))
+
TdNowrap
(
SelectList
(
'reportedBy'
,
xdwdsTasksreportedBy
.
AsString
,
rowIdx
,
FReportedByOptions
,
Fals
e
))
+
TdNowrap
(
TextInput
(
'version'
,
xdwdsTasksversion
.
AsString
,
rowIdx
))
+
TdNowrap
(
DateInput
(
'taskDate'
,
xdwdsTaskstaskDate
.
AsString
,
rowIdx
))
+
TdNowrap
(
SelectList
(
'reportedBy'
,
xdwdsTasksreportedBy
.
AsString
,
rowIdx
,
FReportedByOptions
,
Tru
e
))
+
TdNowrap
(
SelectList
(
'assignedTo'
,
xdwdsTasksassignedTo
.
AsString
,
rowIdx
,
FAssignedToOptions
,
True
))
+
TdNowrap
(
S
tatusSelect
(
xdwdsTasksstatus
.
AsString
,
rowIdx
))
+
TdNowrap
(
DateInput
(
'statusDate'
,
xdwdsTasksstatusDate
.
AsString
,
rowIdx
,
110
))
+
TdNowrap
(
TextInput
(
'formSection'
,
xdwdsTasksformSection
.
AsString
,
rowIdx
,
160
))
+
TdNowrap
(
S
electList
(
'status'
,
xdwdsTasksstatus
.
AsString
,
rowIdx
,
FStatusOptions
,
False
))
+
TdNowrap
(
DateInput
(
'statusDate'
,
xdwdsTasksstatusDate
.
AsString
,
rowIdx
))
+
TdNowrap
(
TextInput
(
'formSection'
,
xdwdsTasksformSection
.
AsString
,
rowIdx
))
+
TdWrap
(
TextArea
(
'issue'
,
xdwdsTasksissue
.
AsString
,
rowIdx
))
+
TdWrap
(
TextArea
(
'notes'
,
xdwdsTasksnotes
.
AsString
,
rowIdx
))
+
'</tr>'
;
...
...
@@ -830,12 +808,16 @@ begin
(
function
()
{
const host = document.getElementById('tasks_table_host');
if(!host) return;
const table = host.querySelector('table');
if(!table) return;
const ths = table.querySelectorAll('thead th');
ths.forEach(th => {
const cols = table.querySelectorAll('colgroup col');
ths.forEach((th, index) => {
th.classList.add('th-resize');
if(th.querySelector('.th-resize-handle')) return;
if
(th.querySelector('.th-resize-handle')) return;
const handle = document.createElement('div');
handle.className = 'th-resize-handle';
...
...
@@ -843,17 +825,27 @@ begin
handle.addEventListener('mousedown', function(e){
e.preventDefault();
e.stopPropagation();
const startX = e.clientX;
const startW = th.getBoundingClientRect().width;
function onMove(ev){
const w = Math.max(40, startW + (ev.clientX - startX));
const w = Math.max(20, startW + (ev.clientX - startX));
th.style.width = w + 'px';
th.style.minWidth = '0';
if (cols && cols[index]) {
cols[index].style.width = w + 'px';
}
}
function
onUp
()
{
document.removeEventListener('mousemove', onMove);
document.removeEventListener('mouseup', onUp);
}
document
.
addEventListener
(
'mousemove'
,
onMove
);
document
.
addEventListener
(
'mouseup'
,
onUp
);
});
...
...
@@ -896,7 +888,7 @@ begin
end
;
console
.
log
(
'EditorBlur: SAVE idx='
+
IntToStr
(
idx
)
+
' field='
+
fieldName
);
Save
Row
(
idx
);
Save
Field
(
idx
,
fieldName
);
end
;
...
...
@@ -941,14 +933,13 @@ begin
end
;
[
async
]
procedure
TFTaskItems
.
Save
Row
(
AIndex
:
Integer
);
[
async
]
procedure
TFTaskItems
.
Save
Field
(
AIndex
:
Integer
;
const
AFieldName
:
string
);
const
// Note: Use this to manipulate saving to the server or not for testing
ENABLE_SERVER_SAVE
=
True
;
var
response
:
TXDataClientResponse
;
payload
:
TJSObject
;
payloadJson
:
string
;
fieldValue
:
string
;
begin
if
not
xdwdsTasks
.
Active
then
Exit
;
...
...
@@ -957,35 +948,47 @@ begin
if
xdwdsTasks
.
Eof
then
Exit
;
payload
:=
TJSObject
.
new
;
fieldValue
:=
''
;
if
SameText
(
AFieldName
,
'application'
)
then
fieldValue
:=
xdwdsTasksapplication
.
AsString
else
if
SameText
(
AFieldName
,
'version'
)
then
fieldValue
:=
xdwdsTasksversion
.
AsString
else
if
SameText
(
AFieldName
,
'taskDate'
)
then
fieldValue
:=
xdwdsTaskstaskDate
.
AsString
else
if
SameText
(
AFieldName
,
'reportedBy'
)
then
fieldValue
:=
xdwdsTasksreportedBy
.
AsString
else
if
SameText
(
AFieldName
,
'assignedTo'
)
then
fieldValue
:=
xdwdsTasksassignedTo
.
AsString
else
if
SameText
(
AFieldName
,
'status'
)
then
fieldValue
:=
xdwdsTasksstatus
.
AsString
else
if
SameText
(
AFieldName
,
'statusDate'
)
then
fieldValue
:=
xdwdsTasksstatusDate
.
AsString
else
if
SameText
(
AFieldName
,
'formSection'
)
then
fieldValue
:=
xdwdsTasksformSection
.
AsString
else
if
SameText
(
AFieldName
,
'issue'
)
then
fieldValue
:=
xdwdsTasksissue
.
AsString
else
if
SameText
(
AFieldName
,
'notes'
)
then
fieldValue
:=
xdwdsTasksnotes
.
AsString
else
Exit
;
payload
:=
TJSObject
.
new
;
payload
[
'taskItemId'
]
:=
xdwdsTaskstaskItemId
.
AsInteger
;
payload
[
'taskId'
]
:=
xdwdsTaskstaskId
.
AsString
;
payload
[
'application'
]
:=
xdwdsTasksapplication
.
AsString
;
payload
[
'version'
]
:=
xdwdsTasksversion
.
AsString
;
payload
[
'taskDate'
]
:=
xdwdsTaskstaskDate
.
AsString
;
payload
[
'reportedBy'
]
:=
xdwdsTasksreportedBy
.
AsString
;
payload
[
'assignedTo'
]
:=
xdwdsTasksassignedTo
.
AsString
;
payload
[
'status'
]
:=
xdwdsTasksstatus
.
AsString
;
payload
[
'statusDate'
]
:=
xdwdsTasksstatusDate
.
AsString
;
payload
[
'formSection'
]
:=
xdwdsTasksformSection
.
AsString
;
payload
[
'issue'
]
:=
xdwdsTasksissue
.
AsString
;
payload
[
'notes'
]
:=
xdwdsTasksnotes
.
AsString
;
payloadJson
:=
string
(
TJSJSON
.
stringify
(
payload
));
console
.
log
(
'SaveRow: idx='
+
IntToStr
(
AIndex
)
+
' payload='
+
payloadJson
);
payload
[
'fieldName'
]
:=
AFieldName
;
payload
[
'value'
]
:=
fieldValue
;
console
.
log
(
'SaveField: idx='
+
IntToStr
(
AIndex
)
+
' field='
+
AFieldName
+
' value='
+
fieldValue
);
if
not
ENABLE_SERVER_SAVE
then
Exit
;
try
response
:=
await
(
xdwcTasks
.
RawInvokeAsync
(
'IApiService.SaveTask
Row
'
,
[
payload
]));
console
.
log
(
'Save
Row
: response='
+
string
(
TJSJSON
.
stringify
(
response
.
Result
)));
response
:=
await
(
xdwcTasks
.
RawInvokeAsync
(
'IApiService.SaveTask
ItemField
'
,
[
payload
]));
console
.
log
(
'Save
Field
: response='
+
string
(
TJSJSON
.
stringify
(
response
.
Result
)));
except
on
E
:
EXDataClientRequestException
do
begin
console
.
log
(
'Save
Row
ERROR: '
+
E
.
ErrorResult
.
ErrorMessage
);
console
.
log
(
'Save
Field
ERROR: '
+
E
.
ErrorResult
.
ErrorMessage
);
Utils
.
ShowErrorModal
(
E
.
ErrorResult
.
ErrorMessage
);
end
;
end
;
...
...
@@ -1017,75 +1020,14 @@ begin
end
;
end
;
function
TFTaskItems
.
ExtractOptionNames
(
const
SourceArray
:
TJSArray
):
TJSArray
;
var
i
:
Integer
;
optionObj
:
TJSObject
;
begin
Result
:=
TJSArray
.
new
;
if
not
Assigned
(
SourceArray
)
then
Exit
;
for
i
:=
0
to
SourceArray
.
length
-
1
do
begin
optionObj
:=
TJSObject
(
SourceArray
[
i
]);
if
Assigned
(
optionObj
)
then
Result
.
push
(
string
(
optionObj
[
'name'
]));
end
;
end
;
function
TFTaskItems
.
ExtractCodeDescs
(
const
SourceArray
:
TJSArray
):
TJSArray
;
var
i
:
Integer
;
optionObj
:
TJSObject
;
begin
Result
:=
TJSArray
.
new
;
if
not
Assigned
(
SourceArray
)
then
Exit
;
for
i
:=
0
to
SourceArray
.
length
-
1
do
begin
optionObj
:=
TJSObject
(
SourceArray
[
i
]);
if
Assigned
(
optionObj
)
then
Result
.
push
(
string
(
optionObj
[
'codeDesc'
]));
end
;
end
;
function
TFTaskItems
.
GetOptionsForField
(
const
AFieldName
:
string
):
TJSArray
;
begin
if
SameText
(
AFieldName
,
'application'
)
then
Result
:=
FApplicationOptions
else
if
SameText
(
AFieldName
,
'reportedBy'
)
then
Result
:=
FReportedByOptions
else
if
SameText
(
AFieldName
,
'assignedTo'
)
then
Result
:=
FAssignedToOptions
else
Result
:=
nil
;
end
;
procedure
TFTaskItems
.
FocusTrigger
(
const
ATriggerId
:
string
);
var
el
:
TJSHTMLElement
;
begin
if
ATriggerId
=
''
then
Exit
;
el
:=
TJSHTMLElement
(
document
.
getElementById
(
ATriggerId
));
if
Assigned
(
el
)
then
el
.
focus
;
end
;
procedure
TFTaskItems
.
DropdownItemClick
(
Event
:
TJSEvent
);
var
el
:
TJSHTMLElement
;
idx
:
Integer
;
idxStr
,
fieldName
,
newVal
,
triggerId
:
string
;
btn
:
TJSHTMLElement
;
labelEl
:
TJSHTMLElement
;
begin
if
not
xdwdsTasks
.
Active
then
Exit
;
...
...
@@ -1113,18 +1055,19 @@ begin
if
triggerId
<>
''
then
begin
asm
var
btn
=
document
.
getElementById
(
triggerId
);
if
(
btn
)
{
var labelEl = btn.querySelector('.task-dd-label');
if (labelEl) {
labelEl.textContent = newVal;
}
}
btn
:=
TJSHTMLElement
(
document
.
getElementById
(
triggerId
));
if
Assigned
(
btn
)
then
begin
labelEl
:=
TJSHTMLElement
(
btn
.
querySelector
(
'.task-dd-label'
));
if
Assigned
(
labelEl
)
then
labelEl
.
textContent
:=
newVal
;
if
SameText
(
fieldName
,
'status'
)
then
ApplyTaskStatusClass
(
btn
,
newVal
);
end
;
end
;
Save
Row
(
idx
);
Save
Field
(
idx
,
fieldName
);
end
;
...
...
@@ -1147,7 +1090,7 @@ begin
if
(
idx
<
0
)
or
(
fieldName
=
''
)
then
Exit
;
if
not
(
SameText
(
fieldName
,
'assignedTo'
)
or
SameText
(
fieldName
,
'application'
))
then
if
not
(
SameText
(
fieldName
,
'assignedTo'
)
or
SameText
(
fieldName
,
'application'
)
or
SameText
(
fieldName
,
'reportedBy'
)
)
then
Exit
;
FNameManager
.
OpenManager
(
fieldName
,
idx
,
triggerId
);
...
...
@@ -1209,10 +1152,13 @@ begin
FSelectedTaskId
:=
StrToIntDef
(
taskIdStr
,
0
);
btnDeleteRow
.
Enabled
:=
FSelectedTaskItemId
>
0
;
ApplySelectedRowState
;
asm
rowEl
.
scrollIntoView
(
{ behavior: 'auto', block: 'nearest', inline: 'nearest' }
);
end
;
end
;
asm
el
.
scrollIntoView
(
{ behavior: 'auto', block: 'nearest', inline: 'nearest' }
);
el
.
focus
();
end
;
end
;
...
...
@@ -1244,40 +1190,6 @@ begin
end
;
function
TFTaskItems
.
ExtractApplicationOptionNames
(
const
ResponseResult
:
TJSObject
):
TJSArray
;
begin
if
not
Assigned
(
ResponseResult
)
then
Exit
(
TJSArray
.
new
);
Result
:=
ExtractOptionNames
(
TJSArray
(
ResponseResult
[
'applicationOptions'
]));
end
;
function
TFTaskItems
.
ExtractAssignedOptionNames
(
const
ResponseResult
:
TJSObject
):
TJSArray
;
begin
if
not
Assigned
(
ResponseResult
)
then
Exit
(
TJSArray
.
new
);
Result
:=
ExtractOptionNames
(
TJSArray
(
ResponseResult
[
'assignedToOptions'
]));
end
;
function
TFTaskItems
.
FindOptionIgnoreCase
(
const
AItems
:
TJSArray
;
const
AName
:
string
):
string
;
var
i
:
Integer
;
itemText
:
string
;
begin
Result
:=
''
;
if
not
Assigned
(
AItems
)
then
Exit
;
for
i
:=
0
to
AItems
.
length
-
1
do
begin
itemText
:=
string
(
AItems
[
i
]);
if
SameText
(
itemText
,
Trim
(
AName
))
then
Exit
(
itemText
);
end
;
end
;
[
async
]
function
TFTaskItems
.
AddAssignedName
(
const
AName
:
string
):
TJSArray
;
var
response
:
TXDataClientResponse
;
...
...
@@ -1366,6 +1278,8 @@ begin
newOptions
:=
await
(
AddApplicationName
(
ANewName
))
else
if
SameText
(
AFieldName
,
'assignedTo'
)
then
newOptions
:=
await
(
AddAssignedName
(
ANewName
))
else
if
SameText
(
AFieldName
,
'reportedBy'
)
then
newOptions
:=
await
(
AddReportedName
(
ANewName
))
else
Exit
;
...
...
@@ -1374,6 +1288,8 @@ begin
if
SameText
(
AFieldName
,
'application'
)
then
FApplicationOptions
:=
newOptions
else
if
SameText
(
AFieldName
,
'reportedBy'
)
then
FReportedByOptions
:=
newOptions
else
FAssignedToOptions
:=
newOptions
;
...
...
@@ -1393,7 +1309,7 @@ begin
xdwdsTasks
.
Post
;
RenderTable
;
await
(
Save
Row
(
ARowIndex
));
await
(
Save
Field
(
ARowIndex
,
AFieldName
));
end
;
[
async
]
procedure
TFTaskItems
.
HandleRenameManagedName
(
const
AFieldName
,
AOldName
,
ANewName
:
string
);
...
...
@@ -1404,6 +1320,8 @@ begin
newOptions
:=
await
(
RenameApplicationName
(
AOldName
,
ANewName
))
else
if
SameText
(
AFieldName
,
'assignedTo'
)
then
newOptions
:=
await
(
RenameAssignedName
(
AOldName
,
ANewName
))
else
if
SameText
(
AFieldName
,
'reportedBy'
)
then
newOptions
:=
await
(
RenameReportedName
(
AOldName
,
ANewName
))
else
Exit
;
...
...
@@ -1412,6 +1330,8 @@ begin
if
SameText
(
AFieldName
,
'application'
)
then
FApplicationOptions
:=
newOptions
else
if
SameText
(
AFieldName
,
'reportedBy'
)
then
FReportedByOptions
:=
newOptions
else
FAssignedToOptions
:=
newOptions
;
...
...
@@ -1427,6 +1347,8 @@ begin
newOptions
:=
await
(
DeleteApplicationName
(
AName
))
else
if
SameText
(
AFieldName
,
'assignedTo'
)
then
newOptions
:=
await
(
DeleteAssignedName
(
AName
))
else
if
SameText
(
AFieldName
,
'reportedBy'
)
then
newOptions
:=
await
(
DeleteReportedName
(
AName
))
else
Exit
;
...
...
@@ -1435,6 +1357,8 @@ begin
if
SameText
(
AFieldName
,
'application'
)
then
FApplicationOptions
:=
newOptions
else
if
SameText
(
AFieldName
,
'reportedBy'
)
then
FReportedByOptions
:=
newOptions
else
FAssignedToOptions
:=
newOptions
;
...
...
@@ -1521,6 +1445,85 @@ begin
end
;
[
async
]
function
TFTaskItems
.
AddReportedName
(
const
AName
:
string
):
TJSArray
;
var
response
:
TXDataClientResponse
;
resultObj
:
TJSObject
;
begin
Result
:=
nil
;
try
response
:=
await
(
xdwcTasks
.
RawInvokeAsync
(
'IApiService.AddReportedName'
,
[
FTaskId
,
Trim
(
AName
)]
));
resultObj
:=
TJSObject
(
response
.
Result
);
Result
:=
ExtractReportedOptionNames
(
resultObj
);
FReportedByOptions
:=
Result
;
except
on
E
:
EXDataClientRequestException
do
begin
console
.
log
(
'AddReportedName ERROR: '
+
E
.
ErrorResult
.
ErrorMessage
);
Utils
.
ShowErrorModal
(
E
.
ErrorResult
.
ErrorMessage
);
Exit
;
end
;
end
;
end
;
[
async
]
function
TFTaskItems
.
RenameReportedName
(
const
AOldName
,
ANewName
:
string
):
TJSArray
;
var
response
:
TXDataClientResponse
;
resultObj
:
TJSObject
;
begin
Result
:=
nil
;
try
response
:=
await
(
xdwcTasks
.
RawInvokeAsync
(
'IApiService.RenameReportedName'
,
[
FTaskId
,
Trim
(
AOldName
),
Trim
(
ANewName
)]
));
resultObj
:=
TJSObject
(
response
.
Result
);
Result
:=
ExtractReportedOptionNames
(
resultObj
);
FReportedByOptions
:=
Result
;
except
on
E
:
EXDataClientRequestException
do
begin
console
.
log
(
'RenameReportedName ERROR: '
+
E
.
ErrorResult
.
ErrorMessage
);
Utils
.
ShowErrorModal
(
E
.
ErrorResult
.
ErrorMessage
);
Exit
;
end
;
end
;
end
;
[
async
]
function
TFTaskItems
.
DeleteReportedName
(
const
AName
:
string
):
TJSArray
;
var
response
:
TXDataClientResponse
;
resultObj
:
TJSObject
;
begin
Result
:=
nil
;
try
response
:=
await
(
xdwcTasks
.
RawInvokeAsync
(
'IApiService.DeleteReportedName'
,
[
FTaskId
,
Trim
(
AName
)]
));
resultObj
:=
TJSObject
(
response
.
Result
);
Result
:=
ExtractReportedOptionNames
(
resultObj
);
FReportedByOptions
:=
Result
;
except
on
E
:
EXDataClientRequestException
do
begin
console
.
log
(
'DeleteReportedName ERROR: '
+
E
.
ErrorResult
.
ErrorMessage
);
Utils
.
ShowErrorModal
(
E
.
ErrorResult
.
ErrorMessage
);
Exit
;
end
;
end
;
end
;
end
.
...
...
emT3Web/css/app.css
View file @
4a314fa8
...
...
@@ -62,6 +62,9 @@ input[data-field="itemNum"] {
top
:
0
;
z-index
:
2
;
background
:
var
(
--bs-body-bg
);
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
.tasks-vscroll
thead
th
.th-resize
{
...
...
@@ -86,7 +89,155 @@ span.card {
user-select
:
none
;
}
.
test-test
{}
.tasks-table
{
table-layout
:
fixed
;
}
.tasks-table
th
{
overflow
:
hidden
;
}
.tasks-table
td
{
overflow
:
visible
;
}
.nowrap-cell
,
.wrap-cell
{
overflow
:
visible
;
}
.tasks-table
.dropdown
,
.task-dd-toggle
,
.task-dd-label
,
.cell-input
,
.cell-textarea
{
min-width
:
0
;
}
.dropdown-menu
{
z-index
:
1055
;
}
.task-dd-toggle.status-cannot-duplicate
{
--bs-btn-color
:
#41464b
;
--bs-btn-bg
:
#e2e3e5
;
--bs-btn-border-color
:
#c4c8cb
;
--bs-btn-hover-color
:
#41464b
;
--bs-btn-hover-bg
:
#d3d4d5
;
--bs-btn-hover-border-color
:
#b9bcc0
;
--bs-btn-active-color
:
#41464b
;
--bs-btn-active-bg
:
#c6c7c8
;
--bs-btn-active-border-color
:
#b9bcc0
;
}
.task-dd-toggle.status-cannot-test
{
--bs-btn-color
:
#842029
;
--bs-btn-bg
:
#f8d7da
;
--bs-btn-border-color
:
#f1aeb5
;
--bs-btn-hover-color
:
#842029
;
--bs-btn-hover-bg
:
#f1c2c7
;
--bs-btn-hover-border-color
:
#ea9ca6
;
--bs-btn-active-color
:
#842029
;
--bs-btn-active-bg
:
#eaadb5
;
--bs-btn-active-border-color
:
#e68592
;
}
.task-dd-toggle.status-future-enhancement
{
--bs-btn-color
:
#055160
;
--bs-btn-bg
:
#cff4fc
;
--bs-btn-border-color
:
#9eeaf9
;
--bs-btn-hover-color
:
#055160
;
--bs-btn-hover-bg
:
#b6effb
;
--bs-btn-hover-border-color
:
#86e5f8
;
--bs-btn-active-color
:
#055160
;
--bs-btn-active-bg
:
#9eeaf9
;
--bs-btn-active-border-color
:
#74dff6
;
}
.task-dd-toggle.status-fixed-verified
{
--bs-btn-color
:
#0f5132
;
--bs-btn-bg
:
#d1e7dd
;
--bs-btn-border-color
:
#a3cfbb
;
--bs-btn-hover-color
:
#0f5132
;
--bs-btn-hover-bg
:
#badbcc
;
--bs-btn-hover-border-color
:
#8fc5a9
;
--bs-btn-active-color
:
#0f5132
;
--bs-btn-active-bg
:
#a3cfbb
;
--bs-btn-active-border-color
:
#7db89d
;
}
.task-dd-toggle.status-fixed
{
--bs-btn-color
:
#146c43
;
--bs-btn-bg
:
#d1e7dd
;
--bs-btn-border-color
:
#a3cfbb
;
--bs-btn-hover-color
:
#146c43
;
--bs-btn-hover-bg
:
#badbcc
;
--bs-btn-hover-border-color
:
#8fc5a9
;
--bs-btn-active-color
:
#146c43
;
--bs-btn-active-bg
:
#a3cfbb
;
--bs-btn-active-border-color
:
#7db89d
;
}
.task-dd-toggle.status-investigating
{
--bs-btn-color
:
#664d03
;
--bs-btn-bg
:
#fff3cd
;
--bs-btn-border-color
:
#ffe69c
;
--bs-btn-hover-color
:
#664d03
;
--bs-btn-hover-bg
:
#ffecb5
;
--bs-btn-hover-border-color
:
#ffdf7e
;
--bs-btn-active-color
:
#664d03
;
--bs-btn-active-bg
:
#ffe69c
;
--bs-btn-active-border-color
:
#ffd966
;
}
.task-dd-toggle.status-not-fixed
{
--bs-btn-color
:
#842029
;
--bs-btn-bg
:
#f8d7da
;
--bs-btn-border-color
:
#f1aeb5
;
--bs-btn-hover-color
:
#842029
;
--bs-btn-hover-bg
:
#f1c2c7
;
--bs-btn-hover-border-color
:
#ea9ca6
;
--bs-btn-active-color
:
#842029
;
--bs-btn-active-bg
:
#eaadb5
;
--bs-btn-active-border-color
:
#e68592
;
}
.task-dd-toggle.status-non-issue
{
--bs-btn-color
:
#432874
;
--bs-btn-bg
:
#e2d9f3
;
--bs-btn-border-color
:
#cbbbe8
;
--bs-btn-hover-color
:
#432874
;
--bs-btn-hover-bg
:
#d6caee
;
--bs-btn-hover-border-color
:
#bea9e2
;
--bs-btn-active-color
:
#432874
;
--bs-btn-active-bg
:
#cbbbe8
;
--bs-btn-active-border-color
:
#b89ddd
;
}
.task-dd-toggle.status-possibly-a-problem
{
--bs-btn-color
:
#7a3e00
;
--bs-btn-bg
:
#ffe5d0
;
--bs-btn-border-color
:
#f7c79d
;
--bs-btn-hover-color
:
#7a3e00
;
--bs-btn-hover-bg
:
#ffd7b8
;
--bs-btn-hover-border-color
:
#f2ba88
;
--bs-btn-active-color
:
#7a3e00
;
--bs-btn-active-bg
:
#f7c79d
;
--bs-btn-active-border-color
:
#eeaf69
;
}
.task-dd-toggle.status-default
{
--bs-btn-color
:
#212529
;
--bs-btn-bg
:
#f8f9fa
;
--bs-btn-border-color
:
#dee2e6
;
--bs-btn-hover-color
:
#212529
;
--bs-btn-hover-bg
:
#e9ecef
;
--bs-btn-hover-border-color
:
#ced4da
;
--bs-btn-active-color
:
#212529
;
--bs-btn-active-bg
:
#dee2e6
;
--bs-btn-active-border-color
:
#ced4da
;
}
emT3Web/emT3web.dpr
View file @
4a314fa8
...
...
@@ -12,7 +12,8 @@ uses
View.Main in 'View.Main.pas' {FViewMain: TWebForm} {*.html},
Utils in 'Utils.pas',
View.TaskItems in 'View.TaskItems.pas' {FTaskItems: TWebForm} {*.html},
uNameManager in 'uNameManager.pas';
uNameOffCanvas in 'uNameOffCanvas.pas',
uDropdownHelpers in 'uDropdownHelpers.pas';
{$R *.res}
...
...
emT3Web/emT3web.dproj
View file @
4a314fa8
...
...
@@ -94,12 +94,12 @@
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.8.
7
.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.8.0;Comments=;LastCompiledTime=2018/08/27 15:18:29</VerInfo_Keys>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.8.
8
.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.8.0;Comments=;LastCompiledTime=2018/08/27 15:18:29</VerInfo_Keys>
<AppDPIAwarenessMode>PerMonitor</AppDPIAwarenessMode>
<VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_MinorVer>8</VerInfo_MinorVer>
<VerInfo_Release>
7
</VerInfo_Release>
<TMSWebBrowser>
1
</TMSWebBrowser>
<VerInfo_Release>
8
</VerInfo_Release>
<TMSWebBrowser>
5
</TMSWebBrowser>
<TMSUseJSDebugger>2</TMSUseJSDebugger>
<TMSWebSingleInstance>1</TMSWebSingleInstance>
<TMSWebOutputPath>..\emT3XDataServer\bin\static</TMSWebOutputPath>
...
...
@@ -142,7 +142,8 @@
<FormType>dfm</FormType>
<DesignClass>TWebForm</DesignClass>
</DCCReference>
<DCCReference Include="uNameManager.pas"/>
<DCCReference Include="uNameOffCanvas.pas"/>
<DCCReference Include="uDropdownHelpers.pas"/>
<None Include="index.html"/>
<None Include="css\app.css"/>
<None Include="config\config.json"/>
...
...
emT3Web/uDropdownHelpers.pas
0 → 100644
View file @
4a314fa8
unit
uDropdownHelpers
;
interface
uses
System
.
SysUtils
,
System
.
Classes
,
JS
,
Web
,
WEBLib
.
Graphics
,
WEBLib
.
Controls
,
WEBLib
.
Forms
,
WEBLib
.
Dialogs
;
function
GetTaskStatusClass
(
const
AStatus
:
string
):
string
;
procedure
ClearTaskStatusClasses
(
const
AElement
:
TJSHTMLElement
);
procedure
ApplyTaskStatusClass
(
const
AElement
:
TJSHTMLElement
;
const
AStatus
:
string
);
function
ExtractOptionNames
(
const
SourceArray
:
TJSArray
):
TJSArray
;
function
ExtractCodeDescs
(
const
SourceArray
:
TJSArray
):
TJSArray
;
function
ExtractAssignedOptionNames
(
const
ResponseResult
:
TJSObject
):
TJSArray
;
function
ExtractReportedOptionNames
(
const
ResponseResult
:
TJSObject
):
TJSArray
;
function
ExtractApplicationOptionNames
(
const
ResponseResult
:
TJSObject
):
TJSArray
;
function
FindOptionIgnoreCase
(
const
AItems
:
TJSArray
;
const
AName
:
string
):
string
;
function
GetOptionsForField
(
const
AFieldName
:
string
;
const
AApplicationOptions
,
AReportedByOptions
,
AAssignedToOptions
:
TJSArray
):
TJSArray
;
procedure
FocusTrigger
(
const
ATriggerId
:
string
);
implementation
function
GetTaskStatusClass
(
const
AStatus
:
string
):
string
;
var
statusText
:
string
;
begin
statusText
:=
Trim
(
AStatus
);
if
SameText
(
statusText
,
'Cannot Duplicate'
)
then
Result
:=
'status-cannot-duplicate'
else
if
SameText
(
statusText
,
'Cannot Test'
)
then
Result
:=
'status-cannot-test'
else
if
SameText
(
statusText
,
'Future Enhancement'
)
then
Result
:=
'status-future-enhancement'
else
if
SameText
(
statusText
,
'Fixed - Verified'
)
then
Result
:=
'status-fixed-verified'
else
if
SameText
(
statusText
,
'Fixed'
)
then
Result
:=
'status-fixed'
else
if
SameText
(
statusText
,
'Investigating'
)
then
Result
:=
'status-investigating'
else
if
SameText
(
statusText
,
'Not Fixed'
)
then
Result
:=
'status-not-fixed'
else
if
SameText
(
statusText
,
'Non-Issue'
)
then
Result
:=
'status-non-issue'
else
if
SameText
(
statusText
,
'Possibly a Problem'
)
then
Result
:=
'status-possibly-a-problem'
else
Result
:=
'status-default'
;
end
;
procedure
ClearTaskStatusClasses
(
const
AElement
:
TJSHTMLElement
);
begin
if
not
Assigned
(
AElement
)
then
Exit
;
AElement
.
classList
.
remove
(
'status-cannot-duplicate'
);
AElement
.
classList
.
remove
(
'status-cannot-test'
);
AElement
.
classList
.
remove
(
'status-future-enhancement'
);
AElement
.
classList
.
remove
(
'status-fixed-verified'
);
AElement
.
classList
.
remove
(
'status-fixed'
);
AElement
.
classList
.
remove
(
'status-investigating'
);
AElement
.
classList
.
remove
(
'status-not-fixed'
);
AElement
.
classList
.
remove
(
'status-non-issue'
);
AElement
.
classList
.
remove
(
'status-possibly-a-problem'
);
AElement
.
classList
.
remove
(
'status-default'
);
end
;
procedure
ApplyTaskStatusClass
(
const
AElement
:
TJSHTMLElement
;
const
AStatus
:
string
);
begin
if
not
Assigned
(
AElement
)
then
Exit
;
ClearTaskStatusClasses
(
AElement
);
AElement
.
classList
.
add
(
GetTaskStatusClass
(
AStatus
));
end
;
function
ExtractOptionNames
(
const
SourceArray
:
TJSArray
):
TJSArray
;
var
i
:
Integer
;
optionObj
:
TJSObject
;
begin
Result
:=
TJSArray
.
new
;
if
not
Assigned
(
SourceArray
)
then
Exit
;
for
i
:=
0
to
SourceArray
.
length
-
1
do
begin
optionObj
:=
TJSObject
(
SourceArray
[
i
]);
if
Assigned
(
optionObj
)
then
Result
.
push
(
string
(
optionObj
[
'name'
]));
end
;
end
;
function
ExtractCodeDescs
(
const
SourceArray
:
TJSArray
):
TJSArray
;
var
i
:
Integer
;
optionObj
:
TJSObject
;
begin
Result
:=
TJSArray
.
new
;
if
not
Assigned
(
SourceArray
)
then
Exit
;
for
i
:=
0
to
SourceArray
.
length
-
1
do
begin
optionObj
:=
TJSObject
(
SourceArray
[
i
]);
if
Assigned
(
optionObj
)
then
Result
.
push
(
string
(
optionObj
[
'codeDesc'
]));
end
;
end
;
function
ExtractAssignedOptionNames
(
const
ResponseResult
:
TJSObject
):
TJSArray
;
begin
if
not
Assigned
(
ResponseResult
)
then
Exit
(
TJSArray
.
new
);
Result
:=
ExtractOptionNames
(
TJSArray
(
ResponseResult
[
'assignedToOptions'
]));
end
;
function
ExtractReportedOptionNames
(
const
ResponseResult
:
TJSObject
):
TJSArray
;
begin
if
not
Assigned
(
ResponseResult
)
then
Exit
(
TJSArray
.
new
);
Result
:=
ExtractOptionNames
(
TJSArray
(
ResponseResult
[
'reportedByOptions'
]));
end
;
function
ExtractApplicationOptionNames
(
const
ResponseResult
:
TJSObject
):
TJSArray
;
begin
if
not
Assigned
(
ResponseResult
)
then
Exit
(
TJSArray
.
new
);
Result
:=
ExtractOptionNames
(
TJSArray
(
ResponseResult
[
'applicationOptions'
]));
end
;
function
FindOptionIgnoreCase
(
const
AItems
:
TJSArray
;
const
AName
:
string
):
string
;
var
i
:
Integer
;
itemText
:
string
;
begin
Result
:=
''
;
if
not
Assigned
(
AItems
)
then
Exit
;
for
i
:=
0
to
AItems
.
length
-
1
do
begin
itemText
:=
string
(
AItems
[
i
]);
if
SameText
(
itemText
,
Trim
(
AName
))
then
Exit
(
itemText
);
end
;
end
;
function
GetOptionsForField
(
const
AFieldName
:
string
;
const
AApplicationOptions
,
AReportedByOptions
,
AAssignedToOptions
:
TJSArray
):
TJSArray
;
begin
if
SameText
(
AFieldName
,
'application'
)
then
Result
:=
AApplicationOptions
else
if
SameText
(
AFieldName
,
'reportedBy'
)
then
Result
:=
AReportedByOptions
else
if
SameText
(
AFieldName
,
'assignedTo'
)
then
Result
:=
AAssignedToOptions
else
Result
:=
nil
;
end
;
procedure
FocusTrigger
(
const
ATriggerId
:
string
);
var
el
:
TJSHTMLElement
;
begin
if
ATriggerId
=
''
then
Exit
;
el
:=
TJSHTMLElement
(
document
.
getElementById
(
ATriggerId
));
if
Assigned
(
el
)
then
el
.
focus
;
end
;
end
.
emT3Web/uName
Manager
.pas
→
emT3Web/uName
OffCanvas
.pas
View file @
4a314fa8
unit
uName
Manager
;
unit
uName
OffCanvas
;
interface
...
...
@@ -257,7 +257,7 @@ begin
Exit
;
end
;
if
not
(
SameText
(
FCurrentField
,
'assignedTo'
)
or
SameText
(
FCurrentField
,
'application'
))
then
if
not
(
SameText
(
FCurrentField
,
'assignedTo'
)
or
SameText
(
FCurrentField
,
'application'
)
or
SameText
(
FCurrentField
,
'reportedBy'
)
)
then
Exit
;
if
FCurrentEditName
<>
''
then
...
...
@@ -356,7 +356,7 @@ begin
Event
.
preventDefault
;
Event
.
stopPropagation
;
if
not
(
SameText
(
FCurrentField
,
'assignedTo'
)
or
SameText
(
FCurrentField
,
'application'
))
then
if
not
(
SameText
(
FCurrentField
,
'assignedTo'
)
or
SameText
(
FCurrentField
,
'application'
)
or
SameText
(
FCurrentField
,
'reportedBy'
)
)
then
Exit
;
el
:=
TJSHTMLElement
(
Event
.
currentTarget
);
...
...
@@ -383,7 +383,7 @@ begin
Event
.
preventDefault
;
Event
.
stopPropagation
;
if
not
(
SameText
(
FCurrentField
,
'assignedTo'
)
or
SameText
(
FCurrentField
,
'application'
))
then
if
not
(
SameText
(
FCurrentField
,
'assignedTo'
)
or
SameText
(
FCurrentField
,
'application'
)
or
SameText
(
FCurrentField
,
'reportedBy'
)
)
then
Exit
;
el
:=
TJSHTMLElement
(
Event
.
currentTarget
);
...
...
@@ -401,7 +401,7 @@ procedure TNameManager.OpenManager(const AFieldName: string; const ARowIndex: In
var
titleEl
:
TJSHTMLElement
;
begin
if
not
(
SameText
(
AFieldName
,
'assignedTo'
)
or
SameText
(
AFieldName
,
'application'
))
then
if
not
(
SameText
(
AFieldName
,
'assignedTo'
)
or
SameText
(
AFieldName
,
'application'
)
or
SameText
(
AFieldName
,
'reportedBy'
)
)
then
Exit
;
FCurrentField
:=
AFieldName
;
...
...
@@ -414,6 +414,8 @@ begin
begin
if
SameText
(
AFieldName
,
'application'
)
then
titleEl
.
innerHTML
:=
'Manage Application'
else
if
SameText
(
AFieldName
,
'reportedBy'
)
then
titleEl
.
innerHTML
:=
'Manage Reported By'
else
titleEl
.
innerHTML
:=
'Manage Assigned To'
;
end
;
...
...
emT3XDataServer/Source/Api.Database.dfm
View file @
4a314fa8
object ApiDatabase: TApiDatabase
OnCreate = DataModuleCreate
Height = 475
Width =
803
Width =
996
object ucETaskApi: TUniConnection
AutoCommit = False
ProviderName = 'MySQL'
...
...
@@ -236,17 +236,17 @@ object ApiDatabase: TApiDatabase
'values ('
' :TASK_ID,'
' :ITEM_NUM,'
'
'#39#39'
,'
'
'#39#39'
,'
'
curdate()
,'
'
curdate()
,'
'
'#39#39'
,'
'
'#39#39'
,'
'
'#39#39'
,'
'
'#39#39'
,'
'
'#39#39'
,'
'
'#39#39'
,'
'
'#39#39
'
null
,'
'
null
,'
'
null
,'
'
null
,'
'
null
,'
'
null
,'
'
null
,'
'
null
,'
'
null
,'
'
null
,'
'
null'
')')
Left = 536
Top = 282
...
...
@@ -580,7 +580,8 @@ object ApiDatabase: TApiDatabase
object uqProjectReportedUsers: TUniQuery
Connection = ucETaskApi
SQL.Strings = (
'select distinct'
'select'
' min(tiu.TASK_ITEM_USER_ID) as TASK_ITEM_USER_ID,'
' tiu.NAME'
'from task_item_user tiu'
'join tasks project_tasks'
...
...
@@ -589,6 +590,7 @@ object ApiDatabase: TApiDatabase
' on target_task.PROJECT_ID = project_tasks.PROJECT_ID'
'where target_task.TASK_ID = :TASK_ID'
' and tiu.USER_TYPE = '#39'Reported'#39
'group by tiu.NAME'
'order by tiu.NAME')
Left = 58
Top = 256
...
...
@@ -598,6 +600,11 @@ object ApiDatabase: TApiDatabase
Name = 'TASK_ID'
Value = nil
end>
object uqProjectReportedUsersTASK_ITEM_USER_ID: TStringField
FieldName = 'TASK_ITEM_USER_ID'
ReadOnly = True
Size = 50
end
object uqProjectReportedUsersNAME: TStringField
FieldName = 'NAME'
Required = True
...
...
@@ -758,7 +765,7 @@ object ApiDatabase: TApiDatabase
Connection = ucETaskApi
SQL.Strings = (
'update task_items'
'set ASSIGNED_TO =
'#39#39
'set ASSIGNED_TO =
null'
'where TASK_ID = :TASK_ID'
' and lower(ASSIGNED_TO) = lower(:NAME)')
Left = 388
...
...
@@ -914,7 +921,7 @@ object ApiDatabase: TApiDatabase
'update task_items ti'
'join tasks t'
' on t.TASK_ID = ti.TASK_ID'
'set ti.APPLICATION =
'#39#39
'set ti.APPLICATION =
null'
'where t.PROJECT_ID = :PROJECT_ID'
' and lower(ti.APPLICATION) = lower(:NAME)')
Left = 696
...
...
@@ -931,4 +938,150 @@ object ApiDatabase: TApiDatabase
Value = nil
end>
end
object uqReportedInsert: TUniQuery
Connection = ucETaskApi
SQL.Strings = (
'insert into task_item_user ('
' TASK_ITEM_USER_ID,'
' TASK_ID,'
' USER_TYPE,'
' NAME'
')'
'values ('
' :TASK_ITEM_USER_ID,'
' :TASK_ID,'
' '#39'Reported'#39','
' :NAME'
')')
Left = 858
Top = 32
ParamData = <
item
DataType = ftUnknown
Name = 'TASK_ITEM_USER_ID'
Value = nil
end
item
DataType = ftUnknown
Name = 'TASK_ID'
Value = nil
end
item
DataType = ftUnknown
Name = 'NAME'
Value = nil
end>
end
object uqReportedRename: TUniQuery
Connection = ucETaskApi
SQL.Strings = (
'update task_item_user tiu'
'join tasks t'
' on t.TASK_ID = tiu.TASK_ID'
'join tasks target_task'
' on target_task.PROJECT_ID = t.PROJECT_ID'
'set tiu.NAME = :NEW_NAME'
'where target_task.TASK_ID = :TASK_ID'
' and tiu.USER_TYPE = '#39'Reported'#39
' and tiu.TASK_ITEM_USER_ID = :TASK_ITEM_USER_ID')
Left = 858
Top = 88
ParamData = <
item
DataType = ftUnknown
Name = 'NEW_NAME'
Value = nil
end
item
DataType = ftUnknown
Name = 'TASK_ID'
Value = nil
end
item
DataType = ftUnknown
Name = 'TASK_ITEM_USER_ID'
Value = nil
end>
end
object uqReportedDelete: TUniQuery
Connection = ucETaskApi
SQL.Strings = (
'delete tiu'
'from task_item_user tiu'
'join tasks t'
' on t.TASK_ID = tiu.TASK_ID'
'join tasks target_task'
' on target_task.PROJECT_ID = t.PROJECT_ID'
'where target_task.TASK_ID = :TASK_ID'
' and tiu.USER_TYPE = '#39'Reported'#39
' and tiu.TASK_ITEM_USER_ID = :TASK_ITEM_USER_ID')
Left = 858
Top = 144
ParamData = <
item
DataType = ftUnknown
Name = 'TASK_ID'
Value = nil
end
item
DataType = ftUnknown
Name = 'TASK_ITEM_USER_ID'
Value = nil
end>
end
object uqBlankTaskItemReportedBy: TUniQuery
Connection = ucETaskApi
SQL.Strings = (
'update task_items ti'
'join tasks t'
' on t.TASK_ID = ti.TASK_ID'
'join tasks target_task'
' on target_task.PROJECT_ID = t.PROJECT_ID'
'set ti.REPORTED_BY = null'
'where target_task.TASK_ID = :TASK_ID'
' and lower(ti.REPORTED_BY) = lower(:NAME)')
Left = 860
Top = 264
ParamData = <
item
DataType = ftUnknown
Name = 'TASK_ID'
Value = nil
end
item
DataType = ftUnknown
Name = 'NAME'
Value = nil
end>
end
object uqRenameTaskItemReportedBy: TUniQuery
Connection = ucETaskApi
SQL.Strings = (
'update task_items ti'
'join tasks t'
' on t.TASK_ID = ti.TASK_ID'
'join tasks target_task'
' on target_task.PROJECT_ID = t.PROJECT_ID'
'set ti.REPORTED_BY = :NEW_NAME'
'where target_task.TASK_ID = :TASK_ID'
' and lower(ti.REPORTED_BY) = lower(:OLD_NAME)')
Left = 858
Top = 202
ParamData = <
item
DataType = ftUnknown
Name = 'NEW_NAME'
Value = nil
end
item
DataType = ftUnknown
Name = 'TASK_ID'
Value = nil
end
item
DataType = ftUnknown
Name = 'OLD_NAME'
Value = nil
end>
end
end
emT3XDataServer/Source/Api.Database.pas
View file @
4a314fa8
...
...
@@ -68,7 +68,6 @@ type
uqAssignedDelete
:
TUniQuery
;
uqRenameAssignedTo
:
TUniQuery
;
uqBlankAssignedTo
:
TUniQuery
;
uqProjectReportedUsersNAME
:
TStringField
;
uqTaskAssignedUsersTASK_ITEM_USER_ID
:
TStringField
;
uqTaskAssignedUsersTASK_ID
:
TStringField
;
uqTaskAssignedUsersUSER_TYPE
:
TStringField
;
...
...
@@ -82,6 +81,13 @@ type
uqProjectApplicationsTASK_ITEM_APPLICATION_ID
:
TIntegerField
;
uqProjectApplicationsPROJECT_ID
:
TStringField
;
uqProjectApplicationsNAME
:
TStringField
;
uqReportedInsert
:
TUniQuery
;
uqReportedRename
:
TUniQuery
;
uqReportedDelete
:
TUniQuery
;
uqBlankTaskItemReportedBy
:
TUniQuery
;
uqRenameTaskItemReportedBy
:
TUniQuery
;
uqProjectReportedUsersTASK_ITEM_USER_ID
:
TStringField
;
uqProjectReportedUsersNAME
:
TStringField
;
procedure
DataModuleCreate
(
Sender
:
TObject
);
procedure
uqUsersCalcFields
(
DataSet
:
TDataSet
);
private
...
...
emT3XDataServer/Source/Api.Service.pas
View file @
4a314fa8
...
...
@@ -76,6 +76,7 @@ type
TTaskUserOptionsResponse
=
class
public
assignedToOptions
:
TList
<
TTaskUserOption
>;
reportedByOptions
:
TList
<
TTaskUserOption
>;
constructor
Create
;
destructor
Destroy
;
override
;
end
;
...
...
@@ -105,21 +106,37 @@ type
notes
:
string
;
end
;
TTaskItemFieldSave
=
class
public
taskItemId
:
Integer
;
fieldName
:
string
;
value
:
string
;
end
;
type
[
ServiceContract
,
Model
(
API_MODEL
)]
IApiService
=
interface
(
IInvokable
)
[
'{0EFB33D7-8C4C-4F3C-9BC3-8B4D444B5F69}'
]
function
GetTaskItems
(
taskId
:
string
):
TTaskItemsResponse
;
[
HttpPost
]
function
AddTaskRow
(
taskId
:
string
;
insertAfterItemNum
:
Integer
):
Boolean
;
[
HttpPost
]
function
SaveTaskRow
(
Item
:
TTaskRowSave
):
Boolean
;
[
HttpPost
]
function
AddAssignedName
(
taskId
:
string
;
name
:
string
):
TTaskUserOptionsResponse
;
[
HttpPost
]
function
RenameAssignedName
(
taskId
:
string
;
oldName
:
string
;
newName
:
string
):
TTaskUserOptionsResponse
;
[
HttpPost
]
function
DeleteAssignedName
(
taskId
:
string
;
name
:
string
):
TTaskUserOptionsResponse
;
[
HttpPost
]
function
AddReportedName
(
taskId
:
string
;
name
:
string
):
TTaskUserOptionsResponse
;
[
HttpPost
]
function
RenameReportedName
(
taskId
:
string
;
oldName
:
string
;
newName
:
string
):
TTaskUserOptionsResponse
;
[
HttpPost
]
function
DeleteReportedName
(
taskId
:
string
;
name
:
string
):
TTaskUserOptionsResponse
;
[
HttpPost
]
function
AddApplicationName
(
taskId
:
string
;
name
:
string
):
TTaskApplicationOptionsResponse
;
[
HttpPost
]
function
RenameApplicationName
(
taskId
:
string
;
oldName
:
string
;
newName
:
string
):
TTaskApplicationOptionsResponse
;
[
HttpPost
]
function
DeleteApplicationName
(
taskId
:
string
;
name
:
string
):
TTaskApplicationOptionsResponse
;
procedure
MoveTaskRow
(
const
taskId
:
Integer
;
const
taskItemId
:
Integer
;
const
newItemNum
:
Integer
);
function
DeleteTaskRow
(
const
taskId
:
Integer
;
const
taskItemId
:
Integer
):
Boolean
;
function
SaveTaskItemField
(
const
Item
:
TTaskItemFieldSave
):
Boolean
;
end
;
implementation
...
...
@@ -148,11 +165,13 @@ constructor TTaskUserOptionsResponse.Create;
begin
inherited
;
assignedToOptions
:=
TList
<
TTaskUserOption
>.
Create
;
reportedByOptions
:=
TList
<
TTaskUserOption
>.
Create
;
end
;
destructor
TTaskUserOptionsResponse
.
Destroy
;
begin
assignedToOptions
.
Free
;
assignedToOptions
:=
TList
<
TTaskUserOption
>.
Create
;
reportedByOptions
:=
TList
<
TTaskUserOption
>.
Create
;
inherited
;
end
;
...
...
emT3XDataServer/Source/Api.ServiceImpl.pas
View file @
4a314fa8
...
...
@@ -3,14 +3,10 @@ unit Api.ServiceImpl;
interface
uses
XData
.
Server
.
Module
,
XData
.
Service
.
Common
,
System
.
Variants
,
System
.
DateUtils
,
Api
.
Service
,
Api
.
Database
,
Common
.
Logging
,
System
.
SysUtils
,
JSON
,
System
.
IniFiles
;
XData
.
Server
.
Module
,
XData
.
Service
.
Common
,
System
.
Variants
,
System
.
DateUtils
,
Uni
,
Api
.
Service
,
Api
.
Database
,
Common
.
Logging
,
System
.
SysUtils
,
JSON
,
System
.
IniFiles
,
DBAccess
;
type
[
ServiceImplementation
]
...
...
@@ -23,7 +19,6 @@ type
function
FindAssignedOptionId
(
const
taskId
,
name
:
string
):
string
;
function
FindAssignedOptionName
(
const
taskId
,
name
:
string
):
string
;
function
AddTaskRow
(
taskId
:
string
;
insertAfterItemNum
:
Integer
):
Boolean
;
function
SaveTaskRow
(
Item
:
TTaskRowSave
):
Boolean
;
function
BuildAssignedOptionsResponse
(
const
taskId
:
string
):
TTaskUserOptionsResponse
;
function
AddAssignedName
(
taskId
:
string
;
name
:
string
):
TTaskUserOptionsResponse
;
function
RenameAssignedName
(
taskId
:
string
;
oldName
:
string
;
newName
:
string
):
TTaskUserOptionsResponse
;
...
...
@@ -37,6 +32,13 @@ type
function
AddApplicationName
(
taskId
:
string
;
name
:
string
):
TTaskApplicationOptionsResponse
;
function
RenameApplicationName
(
taskId
:
string
;
oldName
:
string
;
newName
:
string
):
TTaskApplicationOptionsResponse
;
function
DeleteApplicationName
(
taskId
:
string
;
name
:
string
):
TTaskApplicationOptionsResponse
;
function
SaveTaskItemField
(
const
Item
:
TTaskItemFieldSave
):
Boolean
;
function
FindReportedOptionId
(
const
taskId
,
name
:
string
):
string
;
function
FindReportedOptionName
(
const
taskId
,
name
:
string
):
string
;
function
BuildReportedOptionsResponse
(
const
taskId
:
string
):
TTaskUserOptionsResponse
;
function
AddReportedName
(
taskId
:
string
;
name
:
string
):
TTaskUserOptionsResponse
;
function
RenameReportedName
(
taskId
:
string
;
oldName
:
string
;
newName
:
string
):
TTaskUserOptionsResponse
;
function
DeleteReportedName
(
taskId
:
string
;
name
:
string
):
TTaskUserOptionsResponse
;
public
procedure
AfterConstruction
;
override
;
procedure
BeforeDestruction
;
override
;
...
...
@@ -366,6 +368,116 @@ begin
end
;
function
TApiService
.
SaveTaskItemField
(
const
Item
:
TTaskItemFieldSave
):
Boolean
;
var
uqSaveField
:
TUniQuery
;
columnName
:
string
;
d
:
TDateTime
;
function
MapFieldNameToColumn
(
const
AFieldName
:
string
):
string
;
begin
Result
:=
''
;
if
SameText
(
AFieldName
,
'application'
)
then
Result
:=
'APPLICATION'
else
if
SameText
(
AFieldName
,
'version'
)
then
Result
:=
'APP_VERSION'
else
if
SameText
(
AFieldName
,
'taskDate'
)
then
Result
:=
'TASK_DATE'
else
if
SameText
(
AFieldName
,
'reportedBy'
)
then
Result
:=
'REPORTED_BY'
else
if
SameText
(
AFieldName
,
'assignedTo'
)
then
Result
:=
'ASSIGNED_TO'
else
if
SameText
(
AFieldName
,
'status'
)
then
Result
:=
'STATUS'
else
if
SameText
(
AFieldName
,
'statusDate'
)
then
Result
:=
'STATUS_DATE'
else
if
SameText
(
AFieldName
,
'formSection'
)
then
Result
:=
'FORM_SECTION'
else
if
SameText
(
AFieldName
,
'issue'
)
then
Result
:=
'ISSUE'
else
if
SameText
(
AFieldName
,
'notes'
)
then
Result
:=
'NOTES'
else
if
SameText
(
AFieldName
,
'fixedVersion'
)
then
Result
:=
'FIXED_VERSION'
;
end
;
function
IsDateField
(
const
AFieldName
:
string
):
Boolean
;
begin
Result
:=
SameText
(
AFieldName
,
'taskDate'
)
or
SameText
(
AFieldName
,
'statusDate'
);
end
;
function
ParseDateOrZero
(
const
S
:
string
;
out
ADate
:
TDateTime
):
Boolean
;
var
y
,
m
,
dInt
:
Word
;
begin
Result
:=
False
;
ADate
:=
0
;
if
Length
(
Trim
(
S
))
<>
10
then
Exit
;
y
:=
StrToIntDef
(
Copy
(
S
,
1
,
4
),
0
);
m
:=
StrToIntDef
(
Copy
(
S
,
6
,
2
),
0
);
dInt
:=
StrToIntDef
(
Copy
(
S
,
9
,
2
),
0
);
if
(
y
>
0
)
and
(
m
>
0
)
and
(
dInt
>
0
)
then
begin
try
ADate
:=
EncodeDate
(
y
,
m
,
dInt
);
Result
:=
True
;
except
Result
:=
False
;
end
;
end
;
end
;
begin
Result
:=
False
;
if
not
Assigned
(
Item
)
then
raise
Exception
.
Create
(
'SaveTaskItemField: Item is nil.'
);
if
Item
.
taskItemId
<=
0
then
raise
Exception
.
Create
(
'SaveTaskItemField: Invalid taskItemId.'
);
columnName
:=
MapFieldNameToColumn
(
Item
.
fieldName
);
if
columnName
=
''
then
raise
Exception
.
Create
(
'SaveTaskItemField: Invalid field name: '
+
Item
.
fieldName
);
uqSaveField
:=
TUniQuery
.
Create
(
nil
);
try
uqSaveField
.
Connection
:=
apiDB
.
ucETaskApi
;
uqSaveField
.
SQL
.
Text
:=
'update task_items '
+
'set '
+
columnName
+
' = :'
+
columnName
+
' '
+
'where TASK_ITEM_ID = :TASK_ITEM_ID'
;
uqSaveField
.
ParamByName
(
'TASK_ITEM_ID'
).
AsInteger
:=
Item
.
taskItemId
;
if
IsDateField
(
Item
.
fieldName
)
then
begin
if
ParseDateOrZero
(
Item
.
value
,
d
)
then
uqSaveField
.
ParamByName
(
columnName
).
AsDateTime
:=
d
else
uqSaveField
.
ParamByName
(
columnName
).
Clear
;
end
else
begin
if
Trim
(
Item
.
value
)
=
''
then
uqSaveField
.
ParamByName
(
columnName
).
Clear
else
uqSaveField
.
ParamByName
(
columnName
).
AsString
:=
Item
.
value
;
end
;
uqSaveField
.
ExecSQL
;
Result
:=
True
;
finally
uqSaveField
.
Free
;
end
;
end
;
function
TApiService
.
BuildTaskNumber
:
string
;
procedure
AddPart
(
const
value
:
string
);
...
...
@@ -409,62 +521,6 @@ begin
end
;
function
TApiService
.
SaveTaskRow
(
Item
:
TTaskRowSave
):
Boolean
;
function
ParseDateOrZero
(
const
S
:
string
;
out
D
:
TDateTime
):
Boolean
;
begin
Result
:=
Trim
(
S
)
<>
''
;
if
Result
then
D
:=
ISO8601ToDate
(
S
,
False
);
end
;
var
d
:
TDateTime
;
begin
Logger
.
Log
(
4
,
Format
(
'ApiService.SaveTaskRow - TASK_ITEM_ID="%d"'
,
[
Item
.
taskItemId
]));
try
apiDB
.
uqSaveTaskRow
.
Close
;
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'TASK_ITEM_ID'
).
AsInteger
:=
Item
.
taskItemId
;
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'APPLICATION'
).
AsString
:=
Item
.
application
;
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'APP_VERSION'
).
AsString
:=
Item
.
version
;
if
ParseDateOrZero
(
Item
.
taskDate
,
d
)
then
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'TASK_DATE'
).
AsDateTime
:=
d
else
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'TASK_DATE'
).
Clear
;
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'REPORTED_BY'
).
AsString
:=
Item
.
reportedBy
;
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'ASSIGNED_TO'
).
AsString
:=
Item
.
assignedTo
;
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'STATUS'
).
AsString
:=
Item
.
status
;
if
ParseDateOrZero
(
Item
.
statusDate
,
d
)
then
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'STATUS_DATE'
).
AsDateTime
:=
d
else
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'STATUS_DATE'
).
AsDateTime
:=
Date
;
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'FIXED_VERSION'
).
AsString
:=
Item
.
fixedVersion
;
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'FORM_SECTION'
).
AsString
:=
Item
.
formSection
;
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'ISSUE'
).
AsString
:=
Item
.
issue
;
apiDB
.
uqSaveTaskRow
.
ParamByName
(
'NOTES'
).
AsString
:=
Item
.
notes
;
apiDB
.
uqSaveTaskRow
.
ExecSQL
;
Result
:=
True
;
Logger
.
Log
(
4
,
'ApiService.SaveTaskRow - OK'
);
except
on
E
:
Exception
do
begin
Logger
.
Log
(
2
,
'ApiService.SaveTaskRow - ERROR: '
+
E
.
Message
);
raise
;
end
;
end
;
end
;
function
TApiService
.
DeleteTaskRow
(
const
taskId
:
Integer
;
const
taskItemId
:
Integer
):
Boolean
;
var
oldItemNum
:
Integer
;
...
...
@@ -934,6 +990,203 @@ begin
Result
:=
BuildApplicationOptionsResponse
(
taskId
);
end
;
function
TApiService
.
FindReportedOptionId
(
const
taskId
,
name
:
string
):
string
;
begin
Result
:=
''
;
apiDB
.
uqProjectReportedUsers
.
Close
;
apiDB
.
uqProjectReportedUsers
.
ParamByName
(
'TASK_ID'
).
AsString
:=
taskId
;
apiDB
.
uqProjectReportedUsers
.
Open
;
while
not
apiDB
.
uqProjectReportedUsers
.
Eof
do
begin
if
SameText
(
Trim
(
apiDB
.
uqProjectReportedUsersNAME
.
AsString
),
Trim
(
name
))
then
begin
Result
:=
apiDB
.
uqProjectReportedUsersTASK_ITEM_USER_ID
.
AsString
;
Exit
;
end
;
apiDB
.
uqProjectReportedUsers
.
Next
;
end
;
end
;
function
TApiService
.
FindReportedOptionName
(
const
taskId
,
name
:
string
):
string
;
begin
Result
:=
''
;
apiDB
.
uqProjectReportedUsers
.
Close
;
apiDB
.
uqProjectReportedUsers
.
ParamByName
(
'TASK_ID'
).
AsString
:=
taskId
;
apiDB
.
uqProjectReportedUsers
.
Open
;
while
not
apiDB
.
uqProjectReportedUsers
.
Eof
do
begin
if
SameText
(
Trim
(
apiDB
.
uqProjectReportedUsersNAME
.
AsString
),
Trim
(
name
))
then
begin
Result
:=
apiDB
.
uqProjectReportedUsersNAME
.
AsString
;
Exit
;
end
;
apiDB
.
uqProjectReportedUsers
.
Next
;
end
;
end
;
function
TApiService
.
BuildReportedOptionsResponse
(
const
taskId
:
string
):
TTaskUserOptionsResponse
;
var
taskUserOption
:
TTaskUserOption
;
begin
Result
:=
TTaskUserOptionsResponse
.
Create
;
TXDataOperationContext
.
Current
.
Handler
.
ManagedObjects
.
Add
(
Result
);
apiDB
.
uqProjectReportedUsers
.
Close
;
apiDB
.
uqProjectReportedUsers
.
ParamByName
(
'TASK_ID'
).
AsString
:=
taskId
;
apiDB
.
uqProjectReportedUsers
.
Open
;
while
not
apiDB
.
uqProjectReportedUsers
.
Eof
do
begin
taskUserOption
:=
TTaskUserOption
.
Create
;
TXDataOperationContext
.
Current
.
Handler
.
ManagedObjects
.
Add
(
taskUserOption
);
taskUserOption
.
name
:=
apiDB
.
uqProjectReportedUsersNAME
.
AsString
;
Result
.
reportedByOptions
.
Add
(
taskUserOption
);
apiDB
.
uqProjectReportedUsers
.
Next
;
end
;
end
;
function
TApiService
.
AddReportedName
(
taskId
:
string
;
name
:
string
):
TTaskUserOptionsResponse
;
var
newName
:
string
;
existingName
:
string
;
newGuid
:
TGuid
;
begin
newName
:=
Trim
(
name
);
if
newName
=
''
then
raise
Exception
.
Create
(
'Reported name cannot be blank.'
);
existingName
:=
FindReportedOptionName
(
taskId
,
newName
);
if
existingName
=
''
then
begin
CreateGUID
(
newGuid
);
apiDB
.
uqReportedInsert
.
Connection
.
StartTransaction
;
try
apiDB
.
uqReportedInsert
.
Close
;
apiDB
.
uqReportedInsert
.
ParamByName
(
'TASK_ITEM_USER_ID'
).
AsString
:=
GuidToString
(
newGuid
);
apiDB
.
uqReportedInsert
.
ParamByName
(
'TASK_ID'
).
AsString
:=
taskId
;
apiDB
.
uqReportedInsert
.
ParamByName
(
'NAME'
).
AsString
:=
newName
;
apiDB
.
uqReportedInsert
.
ExecSQL
;
apiDB
.
uqReportedInsert
.
Connection
.
Commit
;
except
on
E
:
Exception
do
begin
if
apiDB
.
uqReportedInsert
.
Connection
.
InTransaction
then
apiDB
.
uqReportedInsert
.
Connection
.
Rollback
;
raise
;
end
;
end
;
end
;
Result
:=
BuildReportedOptionsResponse
(
taskId
);
end
;
function
TApiService
.
RenameReportedName
(
taskId
:
string
;
oldName
:
string
;
newName
:
string
):
TTaskUserOptionsResponse
;
var
oldReportedId
:
string
;
existingReportedId
:
string
;
trimmedOldName
:
string
;
trimmedNewName
:
string
;
begin
trimmedOldName
:=
Trim
(
oldName
);
trimmedNewName
:=
Trim
(
newName
);
if
trimmedOldName
=
''
then
raise
Exception
.
Create
(
'Old reported name cannot be blank.'
);
if
trimmedNewName
=
''
then
raise
Exception
.
Create
(
'New reported name cannot be blank.'
);
oldReportedId
:=
FindReportedOptionId
(
taskId
,
trimmedOldName
);
if
oldReportedId
=
''
then
raise
Exception
.
Create
(
'Reported name not found.'
);
existingReportedId
:=
FindReportedOptionId
(
taskId
,
trimmedNewName
);
apiDB
.
uqReportedRename
.
Connection
.
StartTransaction
;
try
apiDB
.
uqRenameTaskItemReportedBy
.
Close
;
apiDB
.
uqRenameTaskItemReportedBy
.
ParamByName
(
'TASK_ID'
).
AsString
:=
taskId
;
apiDB
.
uqRenameTaskItemReportedBy
.
ParamByName
(
'OLD_NAME'
).
AsString
:=
trimmedOldName
;
apiDB
.
uqRenameTaskItemReportedBy
.
ParamByName
(
'NEW_NAME'
).
AsString
:=
trimmedNewName
;
apiDB
.
uqRenameTaskItemReportedBy
.
ExecSQL
;
if
(
existingReportedId
<>
''
)
and
(
not
SameText
(
existingReportedId
,
oldReportedId
))
then
begin
apiDB
.
uqReportedDelete
.
Close
;
apiDB
.
uqReportedDelete
.
ParamByName
(
'TASK_ITEM_USER_ID'
).
AsString
:=
oldReportedId
;
apiDB
.
uqReportedDelete
.
ParamByName
(
'TASK_ID'
).
AsString
:=
taskId
;
apiDB
.
uqReportedDelete
.
ExecSQL
;
end
else
begin
apiDB
.
uqReportedRename
.
Close
;
apiDB
.
uqReportedRename
.
ParamByName
(
'TASK_ITEM_USER_ID'
).
AsString
:=
oldReportedId
;
apiDB
.
uqReportedRename
.
ParamByName
(
'TASK_ID'
).
AsString
:=
taskId
;
apiDB
.
uqReportedRename
.
ParamByName
(
'NEW_NAME'
).
AsString
:=
trimmedNewName
;
apiDB
.
uqReportedRename
.
ExecSQL
;
end
;
apiDB
.
uqReportedRename
.
Connection
.
Commit
;
except
on
E
:
Exception
do
begin
if
apiDB
.
uqReportedRename
.
Connection
.
InTransaction
then
apiDB
.
uqReportedRename
.
Connection
.
Rollback
;
raise
;
end
;
end
;
Result
:=
BuildReportedOptionsResponse
(
taskId
);
end
;
function
TApiService
.
DeleteReportedName
(
taskId
:
string
;
name
:
string
):
TTaskUserOptionsResponse
;
var
reportedId
:
string
;
reportedName
:
string
;
begin
reportedId
:=
FindReportedOptionId
(
taskId
,
name
);
reportedName
:=
FindReportedOptionName
(
taskId
,
name
);
if
reportedId
=
''
then
raise
Exception
.
Create
(
'Reported name not found.'
);
apiDB
.
uqReportedDelete
.
Connection
.
StartTransaction
;
try
apiDB
.
uqBlankTaskItemReportedBy
.
Close
;
apiDB
.
uqBlankTaskItemReportedBy
.
ParamByName
(
'TASK_ID'
).
AsString
:=
taskId
;
apiDB
.
uqBlankTaskItemReportedBy
.
ParamByName
(
'NAME'
).
AsString
:=
reportedName
;
apiDB
.
uqBlankTaskItemReportedBy
.
ExecSQL
;
apiDB
.
uqReportedDelete
.
Close
;
apiDB
.
uqReportedDelete
.
ParamByName
(
'TASK_ITEM_USER_ID'
).
AsString
:=
reportedId
;
apiDB
.
uqReportedDelete
.
ParamByName
(
'TASK_ID'
).
AsString
:=
taskId
;
apiDB
.
uqReportedDelete
.
ExecSQL
;
apiDB
.
uqReportedDelete
.
Connection
.
Commit
;
except
on
E
:
Exception
do
begin
if
apiDB
.
uqReportedDelete
.
Connection
.
InTransaction
then
apiDB
.
uqReportedDelete
.
Connection
.
Rollback
;
raise
;
end
;
end
;
Result
:=
BuildReportedOptionsResponse
(
taskId
);
end
;
initialization
RegisterServiceType
(
TypeInfo
(
IApiService
));
RegisterServiceType
(
TApiService
);
...
...
emT3XDataServer/bin/emT3XDataServer.ini
View file @
4a314fa8
[Settings]
MemoLogLevel
=
4
FileLogLevel
=
4
webClientVersion
=
0.8.
7
LogFileNum
=
1
55
webClientVersion
=
0.8.
8
LogFileNum
=
1
60
[Database]
Server
=
192.168.102.131
...
...
emT3XDataServer/emT3XDataServer.dproj
View file @
4a314fa8
...
...
@@ -114,10 +114,10 @@
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_ExeOutput>.\bin</DCC_ExeOutput>
<DCC_UnitSearchPath>C:\RADTOOLS\FastMM4;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<VerInfo_Keys>CompanyName=EM Systems;FileDescription=$(MSBuildProjectName);FileVersion=0.8.
7
.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.11;Comments=</VerInfo_Keys>
<VerInfo_Keys>CompanyName=EM Systems;FileDescription=$(MSBuildProjectName);FileVersion=0.8.
8
.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.11;Comments=</VerInfo_Keys>
<VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_MinorVer>8</VerInfo_MinorVer>
<VerInfo_Release>
7
</VerInfo_Release>
<VerInfo_Release>
8
</VerInfo_Release>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment