Bug #10915
ugly dialogs
100%
History
#1 Updated by Greg Shah 8 months ago
- File hotel_gui_embedded_mode_guests_tab_browser_hyperlinks_open_prompt.png added
- version_reported set to trunk 16287
I've asked for our dialogs to be sized without a lot of unnecessary space.
Somehow, we still have dialogs loading which are very ugly. It makes the system look unpolished/unfinished.

This one can be reached via Hotel GUI embedded mode, on the Guests tab, if you click on the room num browse cell hyperlink. You might have to try multiple times to get the prompt.
In this task, PLEASE, PLEASE, PLEASE find and fix all of these dialogs.
#2 Updated by Sergey Ivanovskiy 8 months ago
This should depend on css I did not remember details. At some moment I did some changes in dialog css but they were probably not used because the client was rewritten slightly. Although why this dialog should be there?
#4 Updated by Sergey Ivanovskiy 8 months ago
- Status changed from New to WIP
Created 10915a. The current dialog called open popup dialog does not block user mouse and key events to be sent to the java web client because the global p2j.dialog is not assigned to the open popup dialog. This adds a mess into user actions and the functionality becomes not working properly. The dialog dimensions should be fitted to its content dynamically through the proper css styles.
#5 Updated by Sergey Ivanovskiy 8 months ago
- vendor_id deleted (
GCD) - Assignee changed from Sergey Ivanovskiy to Eric Faulhaber
I observed that two documents were downloaded when clicking on the first column of the Guest screen.
#6 Updated by Eugenie Lyzenko 8 months ago
- File dialog_fixed.jpg added
The fix for dialog size can be in p2j.js
...
function ModalDialog (id, container, text, tooltip, hidden)
{
var overlayId = getOverlayId(id);
...
//fill text content
setTextContent(text);
dialog.appendChild(contentDiv);
dialog.tabIndex = 1;
dialog.className = "dialog centered";
+ dialog.style.height = "50px";
...
The improved screen:

I have not changes p2j.client.css justto use in anoher dialogs. But we can do this fix common for every one of this.
#7 Updated by Sergey Ivanovskiy 8 months ago
- Assignee changed from Eric Faulhaber to Sergey Ivanovskiy
#8 Updated by Sergey Ivanovskiy 8 months ago
Yes, we can set the absolute height in pixels within this method createOpenPopupDialog but it is also possible to change css in order that all dialogs adapt its height depending on its content.
#9 Updated by Sergey Ivanovskiy 8 months ago
- % Done changed from 0 to 100
- Status changed from WIP to Review
Please review the committed revision 16291(10915a).
#11 Updated by Hynek Cihlar 8 months ago
The changes look fine, but the dialog is still pretty ugly :-). Why don't we use a Dojo dialog here? We already use it in other places.
#12 Updated by Sergey Ivanovskiy 8 months ago
- reviewer deleted (
Hynek Cihlar)
Hynek Cihlar wrote:
The changes look fine, but the dialog is still pretty ugly :-). Why don't we use a Dojo dialog here? We already use it in other places.
Please post references where Dojo dialog are used. The design of the dialog is not my deal. I have no skills to make it better. I can perform only constructive requirements dynamic height and so on.
#13 Updated by Hynek Cihlar 8 months ago
Sergey Ivanovskiy wrote:
I can perform only constructive requirements dynamic height and so on.
Don't worry, I cannot do it any better either :-). That is why I think it makes sense to use Dojo.
Just search for dijit/Dialog.
#14 Updated by Sergey Ivanovskiy 8 months ago
- reviewer Hynek Cihlar added
Hynek, it is not used in the web client but only in p2j.perf_tests.js although I did not remember but there was an issue when I tried to use this dialog with upload/download files dialog.
#15 Updated by Sergey Ivanovskiy 8 months ago
The styles can be used to add border and other elements if there are needed. So it needs to have a template of look and feel.
#16 Updated by Hynek Cihlar 8 months ago
Sergey Ivanovskiy wrote:
Hynek, it is not used in the web client but only in
p2j.perf_tests.jsalthough I did not remember but there was an issue when I tried to use this dialog with upload/download files dialog.
It is also used in the log stack dialog and report server.
#17 Updated by Hynek Cihlar 8 months ago
Sergey Ivanovskiy wrote:
The styles can be used to add border and other elements if there are needed. So it needs to have a template of look and feel.
Yes, this can be certainly done. But why do we need different look from the other modal dialogs?
#18 Updated by Sergey Ivanovskiy 8 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
The styles can be used to add border and other elements if there are needed. So it needs to have a template of look and feel.
Yes, this can be certainly done. But why do we need different look from the other modal dialogs?
Could you help to find a source task that I got at some moment in the past to complete the part of this logic
implemented in p2j.screen.js
me.chooseFiles = function(direct, uploadId, title, multiple, upload, filters)
I could not find an exact task where the obstacles to use dojo dialog was discussed. From the code the obstacles can be in interactions between dojo uploader and a modal dialog or/and integration of these components into our logic. I can recall only that I wasted time to study dojo dialog sources to implement this logic. But into our
p2j.ModalDialog dojo components can be added easily via their html dom anchors.#19 Updated by Hynek Cihlar 8 months ago
Sergey Ivanovskiy wrote:
I could not find an exact task where the obstacles to use dojo dialog was discussed. From the code the obstacles can be in interactions between dojo uploader and a modal dialog or/and integration of these components into our logic.
Can you clarify what obstacles do you mean? I used dijit/Dialog and never had any issues with that. You probably mean #5487.
#20 Updated by Sergey Ivanovskiy 8 months ago
Yes, dojo dialogs should not be the issue but there is no your review in this task #5487. So I did not recall.
This task to replace p2.ModalDialog can take more time. If there are no objections from Greg, then I can follow it. It needs to have two scenarios where selected files uploaded directly and these files are selected, correct?
#21 Updated by Hynek Cihlar 8 months ago
Sergey Ivanovskiy wrote:
Yes, dojo dialogs should not be the issue but there is no your review in this task #5487. So I did not recall.
This task to replace
p2.ModalDialogcan take more time.
Why is that? The last time I used dijit/Dialog, it took me not more than an hour to have a workable modal dialog.
It needs to have two scenarios where selected files uploaded directly and these files are selected, correct?
I'm not sure how relvant is this for this task?
#22 Updated by Sergey Ivanovskiy 8 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Yes, dojo dialogs should not be the issue but there is no your review in this task #5487. So I did not recall.
This task to replace
p2.ModalDialogcan take more time.Why is that? The last time I used dijit/Dialog, it took me not more than an hour to have a workable modal dialog.
It needs to have two scenarios where selected files uploaded directly and these files are selected, correct?
I'm not sure how relevant is this for this task?
The logic implemented in chooseFiles = function(direct, uploadId, title, multiple, upload, filters) is complex and two dialogs are used: the first one is to run upload as a user action and the second dialog shows uploading progress and possible errors. All these cases are needed to check and to test.
#23 Updated by Hynek Cihlar 8 months ago
Sergey Ivanovskiy wrote:
The logic implemented in
chooseFiles = function(direct, uploadId, title, multiple, upload, filters)is complex and two dialogs are used: the first one is to run upload as a user action and the second dialog shows uploading progress and possible errors. All these cases are needed to check and to test.
Sorry, I don't follow. This issue is about the connection dialog.
#24 Updated by Sergey Ivanovskiy 8 months ago
Now I am confused about what to do. Please explain what would need to do. There is a global task is to replace p2j.ModalDialog with dojo dialogs consistently. There are some p2j.ModalDialog dialogs: open popup dialog to permit windows.open in some cases, dialogs for upload functionality and dialogs to notify about connection issues.
If this task is to make auto height, then these changes are done. I recalled that text with white background without border is what we discussed.
#25 Updated by Hynek Cihlar 8 months ago
Sergey Ivanovskiy wrote:
If this task is to make auto height, then these changes are done. I recalled that text with white background without border is what we discussed.
The goal of the issue is to make the reconnection dialog "less ugly". The height adjust was a solution picked. But my point was to make the dialog a dijit Dialog to make the appearance more elegant and consistent with the other dialogs in the app - file upload, stack trace dialog, report server, etc.
#26 Updated by Sergey Ivanovskiy 8 months ago
Hynek, why did you call this dialog reconnect? First, Greg posted an open resource dialog and the second argument is that we discussed all these dialogs before to have white rectangular background but dojo dialogs has different styles.
#27 Updated by Sergey Ivanovskiy 8 months ago
The third argument is that p2j.ModalDialog can have any styles but styles or templates are not specified. I do not think that restyling dojo dialogs is similarly simple as p2j.ModalDialog.
#28 Updated by Hynek Cihlar 8 months ago
Sergey Ivanovskiy wrote:
Hynek, why did you call this dialog reconnect?
Sorry, I misread the actual dialog type. But I think the same may apply to the reconnect dialog: "It makes the system look unpolished/unfinished." as stated in the first note.
the second argument is that we discussed all these dialogs before to have white rectangular background but dojo dialogs has different styles.
It is certainly subjective, but I agree with Greg, that the simple rectangular appearances of the dialogs don't look appealing.
#29 Updated by Hynek Cihlar 8 months ago
Sergey Ivanovskiy wrote:
The third argument is that
p2j.ModalDialogcan have any styles but styles or templates are not specified. I do not think that restyling dojo dialogs is similarly simple asp2j.ModalDialog.
Why would dojo styling be different? In the end it is still a set of CSS styles and some HTML structure. I'm not trying to sell dojo UI, frankly I think there are better UIs out there, but we already use it, so I think it makes sense to have a unified look and styling.
#30 Updated by Sergey Ivanovskiy 8 months ago
I understand reasons to use dojo dialog but in this case I need a template, because any dialog has title bar and buttons panel. p2j.ModalDialog has some listener logic implemented for this dialog because for this case there are several files downloaded asynchronously and only one dialog for these requests to windows.open.
I did not defend this implementation p2j.ModalDialog but I need some time to replace the logic if Greg agree with this task. I think that I would leave interfaces of p2j.ModalDialog but implement this dialog as dojo dialog. This idea looks more reasonable for me.
#31 Updated by Hynek Cihlar 8 months ago
Sergey Ivanovskiy wrote:
I did not defend this implementation
p2j.ModalDialogbut I need some time to replace the logic if Greg agree with this task.
Sounds good.
I think that I would leave interfaces of
p2j.ModalDialogbut implement this dialog as dojo dialog. This idea looks more reasonable for me.
Good idea.
#32 Updated by Greg Shah 8 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
I did not defend this implementation
p2j.ModalDialogbut I need some time to replace the logic if Greg agree with this task.
Yes, I don't want to have to redo this work every time I see an ugly dialog. Fix them all now.
#33 Updated by Sergey Ivanovskiy 8 months ago
OK. Following this plan #10915-31 in mind.
#34 Updated by Sergey Ivanovskiy 7 months ago
Please review the committed revision 16324 (10915a) that reused dijit.Dialog.
#35 Updated by Sergey Ivanovskiy 7 months ago
Committed rev 16326 (10915a) fixed the footer panel height. Planning to rebase and to add history comments and to clean debug code.
#36 Updated by Sergey Ivanovskiy 7 months ago
We have an issue in the keyboard that trigger SPACE 4GL key press and key release on keyup event. This affects the logic so the notification dialog to be closed on SPACE key down but SPACE keyup delivers the same keydown and up to the converted application, but the actual key down should be eaten by the modal user dialog (purposed to notify a user about uploading file).
#37 Updated by Sergey Ivanovskiy 7 months ago
Hynek, could you review the committed revision 16334 (10915a)? In the summary diff I missed history entries and committing them in rev 16335.
#38 Updated by Sergey Ivanovskiy 7 months ago
- File 16334_sum.patch
added
#39 Updated by Hynek Cihlar 7 months ago
Code review 10915a. The changes look good I just checked in a copyright year update and a couple of formatting issues.
However please note that pressing Escape on the disconnection dialog will make it re-appear with no title bar.
#40 Updated by Sergey Ivanovskiy 7 months ago
Thank you for the review. It seems that it should be server unavailable dialog without title. Will check and fix it.
#41 Updated by Sergey Ivanovskiy 7 months ago
However please note that pressing Escape on the disconnection dialog will make it re-appear with no title bar.
No, I cannot reproduce this issue. May be you were in a hurry and did not note that this was server unavailable dialog without the title. The logic is in p2j.socket: doRedirectToLogoutPage.
#42 Updated by Hynek Cihlar 7 months ago
- File Screencast 2025-12-22 15_04_32.mp4 added
Please see the atttached screen cast.
#43 Updated by Sergey Ivanovskiy 7 months ago
Could you check this video, please? No view was recorded.
#44 Updated by Sergey Ivanovskiy 7 months ago
It is enough to do a print screen. How did you emulate restore connection dialog?
#45 Updated by Hynek Cihlar 7 months ago
Sergey Ivanovskiy wrote:
It is enough to do a print screen. How did you emulate restore connection dialog?
A screen shot wouldn't show the transition. Just kill the server and do a user input (mouse click in the app for example).
#46 Updated by Hynek Cihlar 7 months ago
Sergey Ivanovskiy wrote:
Could you check this video, please? No view was recorded.
Try a different player.
#47 Updated by Sergey Ivanovskiy 7 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
It is enough to do a print screen. How did you emulate restore connection dialog?
A screen shot wouldn't show the transition. Just kill the server and do a user input (mouse click in the app for example).
I do not understand but I have no issues because I used the same scenarios. The server is unavailable what I can see on your video with VLC. You moved the dialog and pressed escape.
#48 Updated by Sergey Ivanovskiy 7 months ago
The server unavailable dialog has no title by its construction. Please see the code.
serverUnavailableDialog = new p2j.ModalDialog("serverUnavailableDialog",
document.body,
serverUnavailableMessage + " " + p2j.pressEscape,
p2j.pressEscape,
true, {"noTitle" : true, "closable" : false});
#49 Updated by Hynek Cihlar 7 months ago
Sergey Ivanovskiy wrote:
The server unavailable dialog has no title by its construction. Please see the code.
Should it have one?
#50 Updated by Sergey Ivanovskiy 7 months ago
This dialog has no title by the previous design. If you proposed to add title to this dialog, then what would be its title name? Please make your notes clear for me. The WebClient_nl_NL.json should be changed because of new translation.
#51 Updated by Hynek Cihlar 7 months ago
Sergey Ivanovskiy wrote:
This dialog has no title by the previous design. If you proposed to add title to this dialog, then what would be its title name? Please make your notes clear for me. The
WebClient_nl_NL.jsonshould be changed because of new translation.
All the modal dialogs in the app have a title. The title clearly communicates to the end-user what is going on. If the title says "Server Unavailable", the user that already saw the dialog in the past doesn't need to scan the dialog content. Please go ahead with the needed changes.
#52 Updated by Sergey Ivanovskiy 7 months ago
I added missed javadoc comments and two new titles for "Server Unavailable" and "Connection restored" dialogs, changed the most dialogs to be cancelable on X button.
Please review changes rev 16337 (10915a). Thank you for formatting changes but I also had this in mind.
#53 Updated by Sergey Ivanovskiy 7 months ago
Hynek, I tested changes rev 16338 (10915a). The changes have no regressions that I just noted that the onCancel application trigger executes the same action to hide dialog as a the default trigger.
#54 Updated by Hynek Cihlar 7 months ago
- % Done changed from 100 to 90
- Status changed from Review to WIP
Code review 10915a.
In dojo.connect(u, "onComplete", function(files) sendFileChoose is called conditionally if files evaluates to true. But sendFileChoose should be called unconditionally because server waits for the MSG_FILE_CHOOSE response.
In dojo.connect(u, "onComplete", function(files) me.processMouse is set to false but when direct upload it is not restored.
Otherwise the changes look good.
#55 Updated by Sergey Ivanovskiy 7 months ago
OK, I will check this later because working on the different task now. Although I tested direct upload and the old approach and it could be that missed these issues.
#56 Updated by Sergey Ivanovskiy 6 months ago
- File test-web-file-upload-1.p
added
Hynek, please review, the mouse handler was not restored because I missed tests after the hot changes in onClose dialog listener. I added debug logs for you. This test test-web-file-upload-1.p looks fine.files should be not null value if a file is selected.
#57 Updated by Sergey Ivanovskiy 6 months ago
revno: 16349
branch nick: 10915a
message:
missed tests after changes in the dialog close listener logic, fixed the review notes (refs: #10915-54)
#58 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Hynek, please review, the mouse handler was not restored because I missed tests after the hot changes in
onClosedialog listener. I added debug logs for you. This testtest-web-file-upload-1.plooks fine.
I didn't test, but it looks good.
#59 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek, please review, the mouse handler was not restored because I missed tests after the hot changes in
onClosedialog listener. I added debug logs for you. This testtest-web-file-upload-1.plooks fine.I didn't test, but it looks good.
Committed new rev 16353 (10915a). I tested direct case and the case that supports the additional dialog.
#60 Updated by Sergey Ivanovskiy 6 months ago
- Status changed from WIP to Review
- % Done changed from 90 to 100
#61 Updated by Hynek Cihlar 6 months ago
Sergey, if you haven't also please test the various edge cases. An upload is interrupted by the user, a connection error during upload, file selection dialog opened, but no files selected, etc.
#62 Updated by Hynek Cihlar 6 months ago
Hynek Cihlar wrote:
In
dojo.connect(u, "onComplete", function(files)sendFileChooseis called conditionally iffilesevaluates to true. ButsendFileChooseshould be called unconditionally because server waits for theMSG_FILE_CHOOSEresponse.
Sergey, please also respond to this concern.
#63 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Hynek Cihlar wrote:
In
dojo.connect(u, "onComplete", function(files)sendFileChooseis called conditionally iffilesevaluates to true. ButsendFileChooseshould be called unconditionally because server waits for theMSG_FILE_CHOOSEresponse.Sergey, please also respond to this concern.
Hynek, this is discussed in my response to your message #10915-56
#64 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey, if you haven't also please test the various edge cases. An upload is interrupted by the user, a connection error during upload, file selection dialog opened, but no files selected, etc.
Yes.
#65 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Hynek Cihlar wrote:
In
dojo.connect(u, "onComplete", function(files)sendFileChooseis called conditionally iffilesevaluates to true. ButsendFileChooseshould be called unconditionally because server waits for theMSG_FILE_CHOOSEresponse.Sergey, please also respond to this concern.
Hynek, this is discussed in my response to your message #10915-56
#10915-56 only addresses the restore of me.processMouse. Or am I missing something?
#66 Updated by Sergey Ivanovskiy 6 months ago
Yes, I think that you missed. I tested the corresponding testcase and found that sendFileChoose is invoked if files are selected. The files are selected that means files is not null. Correct?
#67 Updated by Sergey Ivanovskiy 6 months ago
Is there a possible case to get onComplete message with files object evaluated to false? I think that it is not possible.
#68 Updated by Sergey Ivanovskiy 6 months ago
I changed my opinion and committed the corresponding changes as rev 16354 (10915a) where this case was taken into account.
#69 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Is there a possible case to get
onCompletemessage withfilesobject evaluated to false? I think that it is not possible.
In that case the added if (statement) doesn't make sense and only renders the code hard to follow. Its presence implies files could evaluate to false.
#70 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Is there a possible case to get
onCompletemessage withfilesobject evaluated to false? I think that it is not possible.In that case the added
if (statement)doesn't make sense and only renders the code hard to follow. Its presence impliesfilescould evaluate tofalse.
I agree that makes sense for me. What additional tests should be done for merging this task?
#71 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
I agree that makes sense for me. What additional tests should be done for merging this task?
Ideally all the modal dialogs affected and the related UI flows should be tested.
The changes in 10915a look good.
#72 Updated by Sergey Ivanovskiy 6 months ago
10915a was rebased up to rev 16383.
#73 Updated by Sergey Ivanovskiy 6 months ago
Could this branch be merged into the trunk?
#74 Updated by Hynek Cihlar 6 months ago
- Status changed from Review to Internal Test
Is all the regression testing finished?
#75 Updated by Sergey Ivanovskiy 6 months ago
I rebased up to rev 16426 (10915a) and tested with the large customer application. Found the translation issue, the translation messages with spaces between words were braced with escaped double quotes, and finally the escaped double quotes \" were added around them and prevented keys to be translated.
Fixed this issue with rev 16427 (10915a), please review.
#76 Updated by Sergey Ivanovskiy 6 months ago
- Status changed from Internal Test to WIP
Another issue that can be reproduced only with the customer application is that ESC keydown event has been missed due to the focused html web browser widget. Investigated this issue.
#77 Updated by Sergey Ivanovskiy 5 months ago
- Status changed from WIP to Review
#78 Updated by Sergey Ivanovskiy 5 months ago
Committed revision 16428 (10915a) fixed the found configuration issue, the progress bar dialog was changed and closed button was added to this dialog because it should cache the close button dialog loaded by
<link rel="stylesheet" type="text/css" href="${webRoot}/dojo-toolkit/dijit/themes/claro/Dialog.css">
Please review.
#79 Updated by Sergey Ivanovskiy 5 months ago
Hynek, could you review this task. I tested the changes, found issues and fixed them. Now the manual tests passed. Could we commit this task after the review?
#80 Updated by Hynek Cihlar 5 months ago
Sergey Ivanovskiy wrote:
Hynek, could you review this task. I tested the changes, found issues and fixed them. Now the manual tests passed. Could we commit this task after the review?
Yes, sorry for the delay, I'm on it now.
#81 Updated by Hynek Cihlar 5 months ago
Code review 10915a.
Just one point. I think removeEscapedDoubleQuotes will throw StringIndexOutOfBoundsException when the input is \".
Otherwise the changes look good. Any regression testing remaining?
#82 Updated by Sergey Ivanovskiy 5 months ago
Hynek Cihlar wrote:
Code review 10915a.
Just one point. I think
removeEscapedDoubleQuoteswill throwStringIndexOutOfBoundsExceptionwhen the input is\".
Yes, what would you you propose? I can add a check.
Otherwise the changes look good. Any regression testing remaining?
It seems that I tested the all cases of dialogs.
#83 Updated by Hynek Cihlar 5 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Code review 10915a.
Just one point. I think
removeEscapedDoubleQuoteswill throwStringIndexOutOfBoundsExceptionwhen the input is\".Yes, what would you you propose? I can add a check.
I would just remove the quote and return the rest of the string. Unless you had a different intention with the method.
#84 Updated by Sergey Ivanovskiy 5 months ago
The aim was to remove only paired escaped double quotes. Committed revision 16433 (10915a). Rebasing the branch.
#85 Updated by Sergey Ivanovskiy 5 months ago
Hynek Cihlar wrote:
Code review 10915a.
Just one point. I think
removeEscapedDoubleQuoteswill throwStringIndexOutOfBoundsExceptionwhen the input is\".Otherwise the changes look good. Any regression testing remaining?
Committed rev 16436 (10915a).
#86 Updated by Sergey Ivanovskiy 5 months ago
- Status changed from Review to Feedback
Hynek, please give your feedback.
#88 Updated by Sergey Ivanovskiy 5 months ago
- Status changed from Feedback to WIP
#89 Updated by Sergey Ivanovskiy 5 months ago
- Status changed from WIP to Review
#90 Updated by Sergey Ivanovskiy 4 months ago
Rebased revision 16490 (10915a).
#92 Updated by Sergey Ivanovskiy 4 months ago
Greg Shah wrote:
Hynek: Please review.
Actually the code was already reviewed. The problem can be related to missed issues while testing these changes.
#94 Updated by Sergey Ivanovskiy 4 months ago
I tested 10915a and found two issues: one is related to progress bar cancel button and the other issue is related to the partly broken reconnect logic that was incorrectly tested previously. All of them are fixed.
#95 Updated by Sergey Ivanovskiy 4 months ago
Could this branch be reviewed and be merged into the trunk? The last commits fixed found issues that was reproduced when the network is switched or failed and restored. Thus it contains also the fix for the trunk.
Although I can extract this fix into a separate task where it was introduced.
#96 Updated by Sergey Ivanovskiy 4 months ago
Rebased up to 16528 (10915a). This revision needs a final review.
#97 Updated by Sergey Ivanovskiy 4 months ago
- Status changed from Internal Test to Review
#98 Updated by Hynek Cihlar 3 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
- [MAJOR] functional
p2j.js.close: AfterdestroyRecursive(false)is called onthat.dojoDialog, the next statement accessesthat.dojoDialog.domNodeand attemptsthat.container.removeChild(...). If dijit'sdestroy()nullsdomNode(as specified in_WidgetBase), theremoveChildis unreachable dead code. If it does not (version-dependent behavior),removeChildthrowsNotFoundErrorbecause the node was already removed from the DOM bydestroyRecursive. In the exception case, all subsequent cleanup is skipped -that.disposedis never set totrue,dialogs.delete(that.id)never executes, and listener/trigger cleanup is bypassed, leaving a stale entry in thedialogsSet that causesisDialogDisplayed()to permanently returntrue, blocking keyboard input. Additionally,that.unregistry()called further down attemptsdestroyRecursivea second time on the already-destroyed widget (guarded by try/catch, but redundant). Suggested fix: remove theremoveChildblock (lines 2780-2783) and the redundantunregistry()call (line 2811), sincedestroyRecursive(false)already handles DOM removal and registry cleanup.
- [MINOR] functional
p2j.js.createDojoDialog(onCancelhandler): When the user clicks the X close button, dijit firesonCancel. The handler calls the applicationonCancellistener (which for the reconnect/unavailable dialogs callsclose()), and then unconditionally callsthat.hide(). Sinceclose()is asynchronous (deferred-based),hide()runs before the close chain completes, resulting in bothclose()andhide()async chains operating on the same dialog. While unlikely to crash (dijit'shide()is mostly idempotent), this is fragile. Consider guarding thehide()call withif (!that.disposed)or removing it entirely when the listener already callsclose().
- [MINOR] style
p2j.screen.jsheader: Duplicate history continuation line "Added a new method updateWindowState to update the window state. Refs #9973a." appears both as a continuation of the existing entry (line 256) and is repeated in the new additions before entry 099. This is likely a rebase artifact.
- [MINOR] style
p2j.keyboard.jsheader: Typo in history entry 039 - "dyalog" should be "dialog".
- [MINOR] style
Utils.javaheader: History entry 110 says "Added removeDoubleQuotesArround" but the actual method is namedremoveEscapedDoubleQuotes. The description does not match the method name, and "Arround" is misspelled ("Around").
#99 Updated by Sergey Ivanovskiy 3 months ago
Hynek Cihlar wrote:
- [MAJOR] functional
p2j.js.close: AfterdestroyRecursive(false)is called onthat.dojoDialog, the next statement accessesthat.dojoDialog.domNodeand attemptsthat.container.removeChild(...). If dijit'sdestroy()nullsdomNode(as specified in_WidgetBase), theremoveChildis unreachable dead code. If it does not (version-dependent behavior),removeChildthrowsNotFoundErrorbecause the node was already removed from the DOM bydestroyRecursive. In the exception case, all subsequent cleanup is skipped -that.disposedis never set totrue,dialogs.delete(that.id)never executes, and listener/trigger cleanup is bypassed, leaving a stale entry in thedialogsSet that causesisDialogDisplayed()to permanently returntrue, blocking keyboard input. Additionally,that.unregistry()called further down attemptsdestroyRecursivea second time on the already-destroyed widget (guarded by try/catch, but redundant). Suggested fix: remove theremoveChildblock (lines 2780-2783) and the redundantunregistry()call (line 2811), sincedestroyRecursive(false)already handles DOM removal and registry cleanup.
I did not observe errors and this part is generated, is not?
#100 Updated by Sergey Ivanovskiy 3 months ago
It looks like no sense.
#101 Updated by Sergey Ivanovskiy 3 months ago
Taking into account that this part was manually written.
#102 Updated by Sergey Ivanovskiy 3 months ago
I think that such type of review is good but the sequence of this logic should have a proof even if the large LLM can bit man in many tasks. The offline LLM that I used recently produced incorrect code in a simple task and the generated code can be used only after several prompts to fix compiler errors.
#103 Updated by Hynek Cihlar 3 months ago
Sergey, the review is generated by AI and currated by myself. I always check the AI outputs. I looked in the code and the points make sense to me. Of course I may be wrong.
#104 Updated by Sergey Ivanovskiy 3 months ago
Hynek Cihlar wrote:
Sergey, the review is generated by AI and currated by myself. I always check the AI outputs. I looked in the code and the points make sense to me. Of course I may be wrong.
This is not a problem. The issue here is that this part was written intentionally. I think this part is difficult because it relates to dijit widgets and must be proven. The proof can be the code that works incorrectly.
#105 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Sergey, the review is generated by AI and currated by myself. I always check the AI outputs. I looked in the code and the points make sense to me. Of course I may be wrong.
This is not a problem. The issue here is that this part was written intentionally. I think this part is difficult because it relates to dijit widgets and must be proven. The proof can be the code that works incorrectly.
Which point do you mean?
#106 Updated by Sergey Ivanovskiy 3 months ago
Hynek, all sequence of generated reasoning can be look like truth. You should give a proof.
#107 Updated by Sergey Ivanovskiy 3 months ago
Hynek Cihlar wrote:
- [MAJOR] functional
p2j.js.close: AfterdestroyRecursive(false)is called onthat.dojoDialog, the next statement accessesthat.dojoDialog.domNodeand attemptsthat.container.removeChild(...). If dijit'sdestroy()nullsdomNode(as specified in_WidgetBase), theremoveChildis unreachable dead code. If it does not (version-dependent behavior),removeChildthrowsNotFoundErrorbecause the node was already removed from the DOM bydestroyRecursive. In the exception case, all subsequent cleanup is skipped -that.disposedis never set totrue,dialogs.delete(that.id)never executes, and listener/trigger cleanup is bypassed, leaving a stale entry in thedialogsSet that causesisDialogDisplayed()to permanently returntrue, blocking keyboard input. Additionally,that.unregistry()called further down attemptsdestroyRecursivea second time on the already-destroyed widget (guarded by try/catch, but redundant). Suggested fix: remove theremoveChildblock (lines 2780-2783) and the redundantunregistry()call (line 2811), sincedestroyRecursive(false)already handles DOM removal and registry cleanup.
This review describes a error in the code ( error scenario) but actually the code has no logged errors.
#108 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
Hynek, all sequence of generated reasoning can be look like truth. You should give a proof.
Sergey, I typically don't test all the cases when reviewing code. This would be an overkill. I often point out potential issues, and yes I may be wrong. The point is we both settle on an agreement whether the points are real issues or not. In this case you have much better knowledge of the code changes and the affected use cases, so you may recognize the pointed issue is a non-issue right away, in which case I'm fine with that. But you could also realize this was a gap in the implementation.
#109 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
- [MAJOR] functional
p2j.js.close: AfterdestroyRecursive(false)is called onthat.dojoDialog, the next statement accessesthat.dojoDialog.domNodeand attemptsthat.container.removeChild(...). If dijit'sdestroy()nullsdomNode(as specified in_WidgetBase), theremoveChildis unreachable dead code. If it does not (version-dependent behavior),removeChildthrowsNotFoundErrorbecause the node was already removed from the DOM bydestroyRecursive. In the exception case, all subsequent cleanup is skipped -that.disposedis never set totrue,dialogs.delete(that.id)never executes, and listener/trigger cleanup is bypassed, leaving a stale entry in thedialogsSet that causesisDialogDisplayed()to permanently returntrue, blocking keyboard input. Additionally,that.unregistry()called further down attemptsdestroyRecursivea second time on the already-destroyed widget (guarded by try/catch, but redundant). Suggested fix: remove theremoveChildblock (lines 2780-2783) and the redundantunregistry()call (line 2811), sincedestroyRecursive(false)already handles DOM removal and registry cleanup.This review describes a error in the code ( error scenario) but actually the code has no logged errors.
I don't think it says you should see an error logged. "If dijit's destroy() nulls domNode (as specified in _WidgetBase), the removeChild is unreachable dead code. If it does not version-dependent behavior)...".
But If you are sure this is fine and don't see any bad behavior, let's just dismiss this as a non-issue.
#110 Updated by Sergey Ivanovskiy 3 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
- [MAJOR] functional
p2j.js.close: AfterdestroyRecursive(false)is called onthat.dojoDialog, the next statement accessesthat.dojoDialog.domNodeand attemptsthat.container.removeChild(...). If dijit'sdestroy()nullsdomNode(as specified in_WidgetBase), theremoveChildis unreachable dead code. If it does not (version-dependent behavior),removeChildthrowsNotFoundErrorbecause the node was already removed from the DOM bydestroyRecursive. In the exception case, all subsequent cleanup is skipped -that.disposedis never set totrue,dialogs.delete(that.id)never executes, and listener/trigger cleanup is bypassed, leaving a stale entry in thedialogsSet that causesisDialogDisplayed()to permanently returntrue, blocking keyboard input. Additionally,that.unregistry()called further down attemptsdestroyRecursivea second time on the already-destroyed widget (guarded by try/catch, but redundant). Suggested fix: remove theremoveChildblock (lines 2780-2783) and the redundantunregistry()call (line 2811), sincedestroyRecursive(false)already handles DOM removal and registry cleanup.This review describes a error in the code ( error scenario) but actually the code has no logged errors.
I don't think it says you should see an error logged. "If dijit's
destroy()nullsdomNode(as specified in_WidgetBase), theremoveChildis unreachable dead code. If it does not version-dependent behavior)...".But If you are sure this is fine and don't see any bad behavior, let's just dismiss this as a non-issue.
I think so because this code was written intentionally after manual tests but taking into account the review there should be proofs that this is a real issue or not. Thus I need to check the code by tests. The problem here is that there are no testcases that cover this code.
#111 Updated by Sergey Ivanovskiy 3 months ago
I think that this methodology to apply AI helpers to review should be together with tests coverage.
#112 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
I think that this methodology to apply AI helpers to review should be together with tests coverage.
That would be ideal, but not that easy to do.
#113 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
- [MAJOR] functional
p2j.js.close: AfterdestroyRecursive(false)is called onthat.dojoDialog, the next statement accessesthat.dojoDialog.domNodeand attemptsthat.container.removeChild(...). If dijit'sdestroy()nullsdomNode(as specified in_WidgetBase), theremoveChildis unreachable dead code. If it does not (version-dependent behavior),removeChildthrowsNotFoundErrorbecause the node was already removed from the DOM bydestroyRecursive. In the exception case, all subsequent cleanup is skipped -that.disposedis never set totrue,dialogs.delete(that.id)never executes, and listener/trigger cleanup is bypassed, leaving a stale entry in thedialogsSet that causesisDialogDisplayed()to permanently returntrue, blocking keyboard input. Additionally,that.unregistry()called further down attemptsdestroyRecursivea second time on the already-destroyed widget (guarded by try/catch, but redundant). Suggested fix: remove theremoveChildblock (lines 2780-2783) and the redundantunregistry()call (line 2811), sincedestroyRecursive(false)already handles DOM removal and registry cleanup.This review describes a error in the code ( error scenario) but actually the code has no logged errors.
I don't think it says you should see an error logged. "If dijit's
destroy()nullsdomNode(as specified in_WidgetBase), theremoveChildis unreachable dead code. If it does not version-dependent behavior)...".But If you are sure this is fine and don't see any bad behavior, let's just dismiss this as a non-issue.
I think so because this code was written intentionally after manual tests but taking into account the review there should be proofs that this is a real issue or not. Thus I need to check the code by tests. The problem here is that there are no testcases that cover this code.
I think AI is correct here and this is also why I kept it as an issue. If you look in your code:
if (that.dojoDialog)
{
//do not preserve dom
that.dojoDialog.destroyRecursive(false);
}
if (that.dojoDialog.domNode)
{
that.container.removeChild(that.dojoDialog.domNode);
}
In the call that.dojoDialog.destroyRecursive(false) the supplied argument tells dojo it should not preserve the dom and so
if (that.dojoDialog.domNode)
{
that.container.removeChild(that.dojoDialog.domNode);
}
either adds noise or could even cause issues (even in the future when dojo version changes) if domNode is not nulled. Exactly as AI identified.
#114 Updated by Sergey Ivanovskiy 3 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
- [MAJOR] functional
p2j.js.close: AfterdestroyRecursive(false)is called onthat.dojoDialog, the next statement accessesthat.dojoDialog.domNodeand attemptsthat.container.removeChild(...). If dijit'sdestroy()nullsdomNode(as specified in_WidgetBase), theremoveChildis unreachable dead code. If it does not (version-dependent behavior),removeChildthrowsNotFoundErrorbecause the node was already removed from the DOM bydestroyRecursive. In the exception case, all subsequent cleanup is skipped -that.disposedis never set totrue,dialogs.delete(that.id)never executes, and listener/trigger cleanup is bypassed, leaving a stale entry in thedialogsSet that causesisDialogDisplayed()to permanently returntrue, blocking keyboard input. Additionally,that.unregistry()called further down attemptsdestroyRecursivea second time on the already-destroyed widget (guarded by try/catch, but redundant). Suggested fix: remove theremoveChildblock (lines 2780-2783) and the redundantunregistry()call (line 2811), sincedestroyRecursive(false)already handles DOM removal and registry cleanup.This review describes a error in the code ( error scenario) but actually the code has no logged errors.
I don't think it says you should see an error logged. "If dijit's
destroy()nullsdomNode(as specified in_WidgetBase), theremoveChildis unreachable dead code. If it does not version-dependent behavior)...".But If you are sure this is fine and don't see any bad behavior, let's just dismiss this as a non-issue.
I think so because this code was written intentionally after manual tests but taking into account the review there should be proofs that this is a real issue or not. Thus I need to check the code by tests. The problem here is that there are no testcases that cover this code.
I think AI is correct here and this is also why I kept it as an issue. If you look in your code:
[...]
In the call
that.dojoDialog.destroyRecursive(false)the supplied argument tells dojo it should not preserve the dom and so
[...]either adds noise or could even cause issues (even in the future when dojo version changes) if
domNodeis not nulled. Exactly as AI identified.
This is not what this review state. unregistry and destroyRecursive is not the same and if unregistry is not invoked, then the next call to createDialog would fail.
I will check this part
if (that.dojoDialog)
{
//do not preserve dom
that.dojoDialog.destroyRecursive(false);
}
if (that.dojoDialog.domNode)
{
that.container.removeChild(that.dojoDialog.domNode);
}
but it is not what the previous text states.
#115 Updated by Sergey Ivanovskiy 3 months ago
Hynek Cihlar wrote:
- [MINOR] functional
p2j.js.createDojoDialog(onCancelhandler): When the user clicks the X close button, dijit firesonCancel. The handler calls the applicationonCancellistener (which for the reconnect/unavailable dialogs callsclose()), and then unconditionally callsthat.hide(). Sinceclose()is asynchronous (deferred-based),hide()runs before the close chain completes, resulting in bothclose()andhide()async chains operating on the same dialog. While unlikely to crash (dijit'shide()is mostly idempotent), this is fragile. Consider guarding thehide()call withif (!that.disposed)or removing it entirely when the listener already callsclose().
Dialog.hide() returns a promise but it also set this._set("open", false); and according this code
hide: function(){
// summary:
// Hide the dialog
// returns: dojo/promise/Promise
// Promise object that resolves when the display animation is complete
// If we haven't been initialized yet then we aren't showing and we can just return.
// Likewise if we are already hidden, or are currently fading out.
if(!this._alreadyInitialized || !this.open){
return resolvedDeferred.promise;
}
can be invoked double times without any side issues.
#116 Updated by Sergey Ivanovskiy 3 months ago
Finally, the major issue is actually the code that is not performed
if (that.dojoDialog.domNode)
{
that.container.removeChild(that.dojoDialog.domNode);
}
that was found manually.
Format and language spelling issues are found.
#117 Updated by Sergey Ivanovskiy 3 months ago
- % Done changed from 90 to 100
Committed revision 16529 (10915a).
#118 Updated by Sergey Ivanovskiy 3 months ago
- Status changed from WIP to Review
Please review 16529 (10915a).
#119 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
This is not what this review state.
unregistryanddestroyRecursiveis not the same and ifunregistryis not invoked, then the next call tocreateDialogwould fail.
I will check this part
[...]
but it is not what the previous text states.
Actually it is. I was able to locate the code without any problem. The mention of unregistry is a second and related issue. AI correctly states that destroyRecursive is called for the second time. Frankly, not a big problem, just unnecessary noise that can be easily resolved I believe.
#120 Updated by Sergey Ivanovskiy 3 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
Hynek, yesterday I tested 10915a with the testcases project and found that the web upload dialog failed in this scenario
on r anywhere do: WEB-FILE-UPLOAD REGISTER b1 in frame f choose, select-mouse-click upload title "test" filters "Source Files (*.p)" "*.p", "R-code Files (*.r)" "*.r". end. on d anywhere do: WEB-FILE-UPLOAD DE-REGISTER b1 in frame f. end.
Press 'd' to remove the web upload widget listener for button b1, then press 'r' to create the web upload widget listener for button b1. Finally, selecting new file to upload, the upload dialog failed to create.
Working on this issue.
#121 Updated by Sergey Ivanovskiy 3 months ago
Hynek, we don't have a way to debug dojo jscript code from the box, do we? DojoToolkitHandler currently loads requested resources from dojo-1.17.3-distribution.zip that contains uncompressed js code too. Could we implement the debug option to load uncompressed versions *.js.uncompressed.js of target resources *.js in order to debug code easily?
Gemini noted that there two versions of dojo Legacy Dojo (1.x) and Modern Dojo (v2+). It seems that we are using Legacy Dojo (1.x).
#122 Updated by Sergey Ivanovskiy 3 months ago
Found that the issue was related to FileList widget that is not finished asynchronous operation while the result notification dialog has been already closed so all its content has been disposed. I have a fix and can add debug opition to enable debugging Legacy Dojo (1.x).
I don't know if it makes sense to consider Modern Dojo (v2+) for FWD web client.
#123 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
I don't know if it makes sense to consider Modern Dojo (v2+) for FWD web client.
What does Dojo 2 bring for this issue?
#124 Updated by Sergey Ivanovskiy 3 months ago
Modern Dojo (v2+) https://dojo.io/ is a complete reboot of the framework, not compatible with the old versions Legacy Dojo (1.x).
#125 Updated by Sergey Ivanovskiy 3 months ago
- % Done changed from 90 to 100
- Status changed from WIP to Review
Committed revision 16534 (10915a) fixed issues raised by methods show(), hide(), close() that start background asynchronous operations, added DOJO_SOURCE_DEBUG constant to enable dojo source code debugging, tried to cleanup the code.
#126 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
Modern Dojo (v2+) https://dojo.io/ is a complete reboot of the framework, not compatible with the old versions Legacy Dojo (1.x).
I mean does it solve any pains we have? Do we need it? Besides, version 2 is still in beta.
#127 Updated by Hynek Cihlar 3 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
Code review 10915a revisions 16509..16534
- [MAJOR] functional
p2j.js.createOpenPopupDialog: The guard changed from!openPopupDialog || openPopupDialog.disposedto!isDialogDisplayed(), which checks whether anyModalDialogis in thedialogsSet (viadialogs.size > 0), not specifically the open-popup dialog. If an unrelated dialog is displayed,createOpenPopupDialogwill silently skip creation. On first call with another dialog open,openPopupDialogisundefined, and theelsebranch callingopenPopupDialog.addTrigger(...)would throw aTypeError. This is a functional regression from the original instance-specific check.
- [MAJOR] functional
p2j.js.onCancel: TheonCancelhandler on the dojo dialog callsthat.hide()unconditionally after invoking the application listener. ButrestoreConnectionDialogEscapeTriggerandserverUnavailableDialogEscapeTrigger(registered viaaddTrigger("onCancel", ...)) callclose(), which internally callsdojoDialog.hide(). Sinceclose()is async but not awaited by the synchronouslistener()call, theonCancelhandler immediately proceeds to callthat.hide(). Bothclose()andhide()then race to callthat.dojoDialog.hide()on the underlying dojo widget, andclose()may nulldojoDialogbeforehide()uses it.
- [MAJOR] functional
p2j.js.show/hide: Both areasyncfunctions thatawait createDialogAction. Ifshow()is called and thenhide()is called beforeshow()completes its await,hide()checksisVisible()which is stillfalse(not yet set byshow) and returns early. Thenshow()resumes, sets visible=true, adds todialogsSet. The dialog remains visible with no way to dismiss it. There is no re-check of desired state after theawait.
- [MAJOR] functional
p2j.socket.js.checkLostPings: The ping-pong watcher timeout is halved viapingPongInterval >> 1andmaxLostPingschanged fromMath.trunc(maxIdleTime / pingPongInterval) + 1toMath.max(Math.trunc(maxIdleTime / (2 * pingPongInterval)), 2). The effective detection window is now roughlymaxIdleTime/4instead ofmaxIdleTime, making the client detect lost connections approximately 4x faster. Was this intentional?
- [MAJOR] functional
p2j.socket.js:idleTimerchanged frommaxIdleTimetoMath.max(watchdogTimeout, maxIdleTime)andconnectivityTimerchanged fromMath.min(watchdogTimeout, maxIdleTime)toMath.max(watchdogTimeout, maxIdleTime). The client now waits longer before giving up on reconnection attempts. This is related to the previous point, was it intentional?
- [MAJOR] style
p2j.screen.js.getAcceptedFileSpecification:console.debug(filters[i] + " " + filters[i+1]), please remove the debug output.
- [MINOR] functional
p2j.js.setTitle:titleis trimmed twice, please remove the noise.
- [MINOR] functional
p2j.screen.js.chooseFiles/onComplete: Theif (!multiple) { closeAction(); return; }early-return for single-file uploads was removed. Single-file uploads now show the result footer and wait for the 5sdelayForCloseActiontimeout before auto-closing, a user-visible behavior change. Was this functional change intentional?
- [MINOR] functional
p2j.screen.js.chooseFiles: CSS values"0px!important"set viadojo.query().style(). The!importantmodifier does not work when set via JavaScript's style API - it only works in stylesheet rules. These overrides will silently lose!importantand may fail to override competing CSS rules.
- [MINOR] functional
p2j.js.history.pushState/p2j.socket.js.serverUnavailableDialogEscapeTrigger: Silent exception swallowing with//nopin catch blocks. Ifwindow.parent.location.replace(logoutPage)fails silently, the user is left on a stale page with no feedback. At minimum, the failure should be logged.
- [MINOR] style
p2j.js,ModalDialogmethods: Missing space before parenthesis incatch(e)throughout the new code (inshow,hide,close,overrideDialogStyle,overrideTitleStyle,setContent,setTextContent,setButtons,setFooter,setTitle). Per coding standard:catch (e).
- [MINOR] style
p2j.js.createDojoDialog: Missing space afterifkeyword in several places:if(!borderContainer.domNode),if(centerNode),if(w). Per coding standard:if (x)notif(x).
- [MINOR] style
p2j.js.createDojoDialog: Commented-out code//dojoDialog.resize();looks like dead code rather than a debug toggle and should be removed.
#128 Updated by Sergey Ivanovskiy 3 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Modern Dojo (v2+) https://dojo.io/ is a complete reboot of the framework, not compatible with the old versions Legacy Dojo (1.x).
I mean does it solve any pains we have? Do we need it? Besides, version 2 is still in beta.
Legacy Dojo (1.x). looks good, fitted for this task.
#129 Updated by Sergey Ivanovskiy 3 months ago
[MAJOR] functional p2j.socket.js.checkLostPings: The ping-pong watcher timeout is halved via pingPongInterval >> 1 and maxLostPings changed from Math.trunc(maxIdleTime / pingPongInterval) + 1 to Math.max(Math.trunc(maxIdleTime / (2 * pingPongInterval)), 2). The effective detection window is now roughly maxIdleTime/4 instead of maxIdleTime, making the client detect lost connections approximately 4x faster. Was this intentional?
Yes, the issue was that pingPong listener was canceled before the lost ping was detected, finally watchdog timeout was hit. I missed this issue because tested incorrectly. The correct test should be switching network or turn off the Ethernet cable but my test was only to kill the server.
#130 Updated by Sergey Ivanovskiy 3 months ago
[MAJOR] functional p2j.js.createOpenPopupDialog: The guard changed from !openPopupDialog || openPopupDialog.disposed to !isDialogDisplayed(), which checks whether any ModalDialog is in the dialogs Set (via dialogs.size > 0), not specifically the open-popup dialog. If an unrelated dialog is displayed, createOpenPopupDialog will silently skip creation. On first call with another dialog open, openPopupDialog is undefined, and the else branch calling openPopupDialog.addTrigger(...) would throw a TypeError. This is a functional regression from the original instance-specific check.
Yes, it is an issue. The changes was done mechanically.
#131 Updated by Sergey Ivanovskiy 3 months ago
[MAJOR] functional p2j.socket.js: idleTimer changed from maxIdleTime to Math.max(watchdogTimeout, maxIdleTime) and connectivityTimer changed from Math.min(watchdogTimeout, maxIdleTime) to Math.max(watchdogTimeout, maxIdleTime). The client now waits longer before giving up on reconnection attempts. This is related to the previous point, was it intentional?
Yes, tried to wait longer.
#132 Updated by Sergey Ivanovskiy 3 months ago
[MAJOR] functional p2j.js.onCancel: The onCancel handler on the dojo dialog calls that.hide() unconditionally after invoking the application listener. But restoreConnectionDialogEscapeTrigger and serverUnavailableDialogEscapeTrigger (registered via addTrigger("onCancel", ...)) call close(), which internally calls dojoDialog.hide(). Since close() is async but not awaited by the synchronous listener() call, the onCancel handler immediately proceeds to call that.hide(). Both close() and hide() then race to call that.dojoDialog.hide() on the underlying dojo widget, and close() may null dojoDialog before hide() uses it.
Thank you for finding. I tried to fix all similar issues.
#133 Updated by Sergey Ivanovskiy 3 months ago
[MAJOR] functional p2j.js.onCancel: The onCancel handler on the dojo dialog calls that.hide() unconditionally after invoking the application listener. But restoreConnectionDialogEscapeTrigger and serverUnavailableDialogEscapeTrigger (registered via addTrigger("onCancel", ...)) call close(), which internally calls dojoDialog.hide(). Since close() is async but not awaited by the synchronous listener() call, the onCancel handler immediately proceeds to call that.hide(). Both close() and hide() then race to call that.dojoDialog.hide() on the underlying dojo widget, and close() may null dojoDialog before hide() uses it.
[MAJOR] functional p2j.js.show / hide: Both are async functions that await createDialogAction. If show() is called and then hide() is called before show() completes its await, hide() checks isVisible() which is still false (not yet set by show) and returns early. Then show() resumes, sets visible=true, adds to dialogs Set. The dialog remains visible with no way to dismiss it. There is no re-check of desired state after the await.
These two should be resolved using the chain of promises, actually the resolved promise that represents the last UI operation and the next UI operation starts only after the last operation is done.
#134 Updated by Sergey Ivanovskiy 3 months ago
- Status changed from WIP to Review
- % Done changed from 90 to 100
Please review the committed 16535, 16536 (10915a) that should fix all major issues related to async code usages.
#135 Updated by Hynek Cihlar 3 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
Code review 10915a revisions 16534..16536
- [CRITICAL] functional
show: Returnsthis.operationGuardinstead ofoperationGuard. The variableoperationGuardis a localvarin the constructor scope and is never assigned tothis, sothis.operationGuardisundefined. - [MAJOR] style p2j.js file header: Missing history entry for this changeset. A new entry (032) is needed describing the async
operationGuardrefactoring ofModalDialog. - [MINOR] style p2j.socket.js: The existing
catch(e)near theconsole.error(e)change lacks a space before the parenthesis. The diff fixes this same pattern (catch(e)tocatch (e)) in p2j.js in multiple places but not in the adjacent code in p2j.socket.js. - [MINOR] style p2j.js,
close: Trailing semicolon after function declaration closing brace (};). Function declarations should not have a trailing semicolon.
#137 Updated by Sergey Ivanovskiy 3 months ago
Rebased rev. 16564 (10915a).
#138 Updated by Hynek Cihlar 3 months ago
Code review 10915a revisions 16537..16564
- [CRITICAL] functional
ModalDialog.show: Returnsthis.operationGuardinstead of the localoperationGuardvariable.operationGuardis declared as a localvarand is never assigned as a property onthis, soawait dialog.show()resolves toundefined. Every other async API method (hide,close,setTitle,setContent,setTextContent,setButtons,setFooter,overrideDialogStyle,overrideTitleStyle,updateLayout) correctly returns the localoperationGuard. Callers awaitingshow()lose the ordering guarantee the operationGuard pattern is meant to provide. This is the critical bug flagged in the Redmine summary as not yet confirmed fixed - it remains in the diff.
- [MAJOR] functional
ModalDialog.doDialogLayout: Interleaves DOM writes and reads in a way that forces layout thrashing on every show. WritestopPane.domNode.style.height,footerPane.domNode.style.height,dojoDialog.domNode.style.height; then readsoffsetHeighton multiple panes; then writesstyle.topvalues; then reads four pairs ofscrollWidth/offsetWidth; then writesstyle.width. Each read after a style write triggers a forced synchronous reflow. Repeated unconditionally on everyshow()andupdateLayout(). Group reads first then writes, or schedule viarequestAnimationFrame.
- [MAJOR] functional
ModalDialog.show: After awaitingdojoDialog.show(), the code callsthat.dojoDialog.containerNode.focus()unconditionally. This overrides theautofocus: truesetting that already focused the first focusable child (e.g. an OK button created bysetButtons). Breaks "Press Enter to confirm" UX because focus is moved off the default button.
- [MAJOR] functional
onKeyDown: Moving thep2j.isDialogDisplayed()early-return to the start ofkeydownskips the OS modifier-key propagationp2j.socket.sendOSKeyEvent(keyCode, false)that previously executed before the dialog gate. While dialogs are displayed, the server no longer receives Alt/Ctrl/Shift up/down notifications, leaving the server's modifier state out of sync once the dialog closes. The pre-processing ofkeyPressEmitted = false; lastPressedKey = undefined;andactivateKeyboardInput(forceActivateInput)is also skipped. Now I'm not sure this is an actual issie, but worth to check.
- [MAJOR] functional
chooseFiles: The newdojo.connect(u, "onProgress", ...)handler unconditionally callsactionResultsDialog.show().onProgressfires for every chunk during upload, and eachshow()enqueues anoperationGuardpromise step that runsdoDialogLayout()when the dialog is already visible (forced reads ofscrollHeight/offsetHeightfollowed by style writes - synchronous layout per tick). The previous code triggered noshow()inonProgressand a guardedshow()inonError; both guards are now gone. Add anif (!actionResultsDialog.isVisible())guard, or drop theshow()fromonProgresssinceonChangealready shows the dialog before upload starts.
- [MAJOR] style
Utils: History entry111 SBI 20260206 Added removeDoubleQuotesArround.has typo "Arround" (should be "Around") and references the wrong method name (removeDoubleQuotesArroundvs actualremoveEscapedDoubleQuotes). The history description must match the symbol name.
- [MAJOR] style
p2j.keyboard.jshistory entry 040: Typo "dyalog" should be "dialog" in the description ("Rejected processing keydown event if the web client modal dyalog is opened.").
- [MAJOR] style
chooseFiles: Mis-indentedif (!multiple)block (8 spaces leading whitespace instead of 9), making it one column shy of its surrounding block - the matching brace below uses 9 spaces.
- [MAJOR] style
ModalDialog.createDojoDialog: Mixed indentation depths insideunregistry()- some innertry { ... }blocks use 2-space indentation instead of the project's 3-space step. Inside thenew Dialog({...})literal, key spacing is inconsistent:id : that.idnext toclassName: "dialogFWDOverride"andautofocus: true.
- [MAJOR] style
ModalDialog.doDialogLayout: Lines exceed the 110-character limit, e.g.var borderPanelWidth = Math.max(borderContainer.domNode.scrollWidth,borderContainer.domNode.offsetWidth);and the immediately followingborderPanelWidth = Math.max(...)line. Also missing space after the comma inMath.max(...,borderContainer...).
- [MINOR] functional
p2j: Duplicatevar dialogs = new Set();declaration introduced inp2j.js. The original line was kept and an identical second declaration with the same JSDoc comment was added immediately below it. Functionally harmless because both Sets are empty at this point with no intervening writes (the second simply overwrites the first reference before any element is added), but a clear copy-paste/merge artifact that should be removed.
- [MINOR] functional
DojoToolkitHandler.mapToResource: WhendebugModeis on, every*.jsrequest (not already*.js.uncompressed.js) is rewritten to*.js.uncompressed.jswith no fallback;AbstractModulesHandler.deliverModulesilently returns HTTP 404 if the resource is missing. The dojo-1.17.3 distribution contains 14 plain.jsfiles without an.uncompressed.jssibling (e.g.configRhino.js,configNode.js, profile/build artifacts) - mostly non-browser build/config files unlikely to be requested in normal runtime, but the rewrite is still brittle. Either fall back to the original target on 404, or scope the rewrite to known modules.
- [MINOR] functional
ModalDialog.show: Whenshow()is called whileisVisible()is already true, the new code callsthat.doDialogLayout()unconditionally - so even no-op shows force a full layout pass (DOM reads/writes plusborderContainer.resize()). The old direct-DOM implementation did nothing in this case.
- [MINOR] functional
ModalDialog:this.removeTrigger = removeTrigger;was removed butthis.addTriggerremains. TheremoveTriggerfunction is still defined and used internally (inclose()'s forEach loops) but is no longer exposed on the dialog instance. External callers can no longer remove a previously-added trigger - backward-incompatible API surface reduction.
- [MINOR] performance
ModalDialog.createDojoDialog:dojo.require(...)and AMDrequire([...10 modules...])run on every dialog construction. While modules are cached, each call still walks the dependency list and queues a microtask. For dialogs created repeatedly (loadingDialog, connection dialogs, file-upload progress), hoisting the require once and caching resolved modules would amortize the cost. InDOJO_SOURCE_DEBUGmode the impact is larger becausecacheBust=truedefeats browser cache.
- [MINOR] performance
p2j.dialogs Set: Now stores dialog ID strings rather than DOM nodes. If two ModalDialog instances are created with the sameid(e.g. recreating afterclose()),dialogs.delete(that.id)from the first instance silently removes the tracker for the second. TheloadingDialog/restoreConnectionDialog/connectionRestoredDialog/serverUnavailableDialogIDs are reused across reconnects. Please check whether this is an actual issue.
- [MINOR] style
ModalDialog.logError: JsDoc@return{Function}@ description is empty. Either remove the tag or document what is returned.
- [MINOR] style
p2j.client.css: Mixed indentation in new rules (some lines 11 spaces, some 23 spaces) instead of consistent 3-space steps. Trailing whitespace after}on the.dijitDialogPaneContent.dijitDialogSingleChildblock.
- [MINOR] style
p2j.socket.js.checkLostPings: Indentation broken - the openingif (ws)is at 9 spaces but inner blocks use 12 spaces, while the comment lines start at column 8, creating misaligned visual nesting.
#139 Updated by Sergey Ivanovskiy 3 months ago
Hynek Cihlar wrote:
Code review 10915a revisions 16537..16564
- [CRITICAL] functional
ModalDialog.show: Returnsthis.operationGuardinstead of the localoperationGuardvariable.operationGuardis declared as a localvarand is never assigned as a property onthis, soawait dialog.show()resolves toundefined. Every other async API method (hide,close,setTitle,setContent,setTextContent,setButtons,setFooter,overrideDialogStyle,overrideTitleStyle,updateLayout) correctly returns the localoperationGuard. Callers awaitingshow()lose the ordering guarantee the operationGuard pattern is meant to provide. This is the critical bug flagged in the Redmine summary as not yet confirmed fixed - it remains in the diff.
Hynek, what does this note "This is the critical bug flagged in the Redmine summary as not yet confirmed fixed - it remains in the diff." mean?
#140 Updated by Sergey Ivanovskiy 3 months ago
[MAJOR] functional
onKeyDown: Moving thep2j.isDialogDisplayed()early-return to the start ofkeydownskips the OS modifier-key propagationp2j.socket.sendOSKeyEvent(keyCode, false)that previously executed before the dialog gate. While dialogs are displayed, the server no longer receives Alt/Ctrl/Shift up/down notifications, leaving the server's modifier state out of sync once the dialog closes. The pre-processing ofkeyPressEmitted = false;lastPressedKey = undefined;andactivateKeyboardInput(forceActivateInput)is also skipped. Now I'm not sure this is an actual issue, but worth to check.
The idea in this code is to prevent sending keyboard events to the business logic because the implemented dialogs are not involved into the business logic.
#141 Updated by Sergey Ivanovskiy 3 months ago
[MAJOR] functional
chooseFiles: The newdojo.connect(u, "onProgress", ...)handler unconditionally callsactionResultsDialog.show().onProgressfires for every chunk during upload, and eachshow()enqueues an operationGuard promise step that runsdoDialogLayout()when the dialog is already visible (forced reads of s@crollHeight/offsetHeight@ followed by style writes - synchronous layout per tick). The previous code triggered noshow()inonProgressand a guardedshow()inonError; both guards are now gone. Add anif (!actionResultsDialog.isVisible())guard, or drop theshow()fromonProgresssinceonChangealready shows the dialog before upload starts.
The idea in this code is to adjust dialog size but it seems onChange should update the dialog size according to the selected files.
#142 Updated by Sergey Ivanovskiy 3 months ago
[MINOR]functionalModalDialog.show: Whenshow()is called whileisVisible()is already true, the new code callsthat.doDialogLayout()unconditionally - so even no-op shows force a full layout pass (DOM reads/writes plusborderContainer.resize()). The old direct-DOM implementation did nothing in this case.
Yes, if the dialog is already visible, then the code calls doDialogLayout().
#143 Updated by Sergey Ivanovskiy 3 months ago
[MAJOR] functional
ModalDialog.doDialogLayout: Interleaves DOM writes and reads in a way that forces layout thrashing on every show. WritestopPane.domNode.style.height,footerPane.domNode.style.height,dojoDialog.domNode.style.height; then readsoffsetHeighton multiple panes; then writesstyle.topvalues; then reads four pairs ofscrollWidth/offsetWidth; then writesstyle.width. Each read after a style write triggers a forced synchronous reflow. Repeated unconditionally on everyshow()andupdateLayout(). Group reads first then writes, or schedule viarequestAnimationFrame.
This is the code. Could you explain if this is possible to improve here something?
function doDialogLayout()
{
var dim = computeDialogSize();
// console.debug("doDialogLayout(): dim=" + JSON.stringify(dim));
topPane.domNode.style.height = dim.topHeight + 'px';
footerPane.domNode.style.height = dim.footerHeight + 'px';
dojoDialog.domNode.style.height = dim.height + 'px';
var topPanelHeight = topPane.domNode.offsetHeight;
var centerPanelHeight = centerPane.domNode.offsetHeight;
centerPane.domNode.style.top = topPane.domNode.offsetHeight + 'px';
footerPane.domNode.style.top = (topPane.domNode.offsetHeight + centerPane.domNode.offsetHeight) + 'px';
var centerPanelWidth = Math.max(centerPane.domNode.scrollWidth, centerPane.domNode.offsetWidth);
var topPanelWidth = Math.max(topPane.domNode.scrollWidth, topPane.domNode.offsetWidth);
var footerPanelWidth = Math.max(footerPane.domNode.scrollWidth, footerPane.domNode.offsetWidth);
var borderPanelWidth = Math.max(borderContainer.domNode.scrollWidth,borderContainer.domNode.offsetWidth);
borderPanelWidth = Math.max(dim.width, topPanelWidth, centerPanelWidth, footerPanelWidth, borderPanelWidth);
borderContainer.domNode.style.width = borderPanelWidth + 'px';
borderContainer.resize();
}
that.doDialogLayout = doDialogLayout;
#144 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
[MAJOR] functional
onKeyDown: Moving thep2j.isDialogDisplayed()early-return to the start ofkeydownskips the OS modifier-key propagationp2j.socket.sendOSKeyEvent(keyCode, false)that previously executed before the dialog gate. While dialogs are displayed, the server no longer receives Alt/Ctrl/Shift up/down notifications, leaving the server's modifier state out of sync once the dialog closes. The pre-processing ofkeyPressEmitted = false;lastPressedKey = undefined;andactivateKeyboardInput(forceActivateInput)is also skipped. Now I'm not sure this is an actual issue, but worth to check.The idea in this code is to prevent sending keyboard events to the business logic because the implemented dialogs are not involved into the business logic.
Fair enough.
#145 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
Hynek, what does this note "This is the critical bug flagged in the Redmine summary as not yet confirmed fixed - it remains in the diff." mean?
This means the issue was already identified in one of the previous reviews.
#146 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
[MAJOR] functional
ModalDialog.doDialogLayout: Interleaves DOM writes and reads in a way that forces layout thrashing on every show. WritestopPane.domNode.style.height,footerPane.domNode.style.height,dojoDialog.domNode.style.height; then readsoffsetHeighton multiple panes; then writesstyle.topvalues; then reads four pairs ofscrollWidth/offsetWidth; then writesstyle.width. Each read after a style write triggers a forced synchronous reflow. Repeated unconditionally on everyshow()andupdateLayout(). Group reads first then writes, or schedule viarequestAnimationFrame.This is the code. Could you explain if this is possible to improve here something?
The idea is to group together the writes and reads. Perhaps something like the following.
function doDialogLayout()
{
var dim = computeDialogSize();
// Phase 1: writes that change measured heights
topPane.domNode.style.height = dim.topHeight + 'px';
footerPane.domNode.style.height = dim.footerHeight + 'px';
dojoDialog.domNode.style.height = dim.height + 'px';
// Phase 2: all reads (one forced reflow, not three)
var topH = topPane.domNode.offsetHeight;
var centerH = centerPane.domNode.offsetHeight;
var topW = Math.max(topPane.domNode.scrollWidth, topPane.domNode.offsetWidth);
var centerW = Math.max(centerPane.domNode.scrollWidth, centerPane.domNode.offsetWidth);
var footerW = Math.max(footerPane.domNode.scrollWidth, footerPane.domNode.offsetWidth);
var borderW = Math.max(borderContainer.domNode.scrollWidth, borderContainer.domNode.offsetWidth);
var finalW = Math.max(dim.width, topW, centerW, footerW, borderW);
// Phase 3: remaining writes
centerPane.domNode.style.top = topH + 'px';
footerPane.domNode.style.top = (topH + centerH) + 'px';
borderContainer.domNode.style.width = finalW + 'px';
borderContainer.resize();
}
But unless there are some visible layout shifts I would ignore this.
#147 Updated by Sergey Ivanovskiy 3 months ago
[MINOR] functional
ModalDialog:this.removeTrigger = removeTrigger;was removed butthis.addTriggerremains. TheremoveTriggerfunction is still defined and used internally (inclose()'sforEachloops) but is no longer exposed on the dialog instance. External callers can no longer remove a previously-added trigger - backward-incompatible API surface reduction.
Yes, removeTrigger is used internally on close() to simplify ModalDialog usages.
#148 Updated by Sergey Ivanovskiy 3 months ago
[MINOR] performance
p2j.dialogs Set: Now stores dialog ID strings rather than DOM nodes. If twoModalDialoginstances are created with the same id (e.g. recreating afterclose()),dialogs.delete(that.id)from the first instance silently removes the tracker for the second. The loadingDialog/restoreConnectionDialog/connectionRestoredDialog/serverUnavailableDialog IDs are reused across reconnects. Please check whether this is an actual issue.
It is supposed that each ModalDialog dialog has its own unique id. The same dialog can be recreated after close().
#149 Updated by Sergey Ivanovskiy 3 months ago
Committed revision 16570 (10915a) should fix the most issues except
[MINOR] performance
ModalDialog.createDojoDialog:dojo.require(...)and AMDrequire([...10 modules...])run on every dialog construction. While modules are cached, each call still walks the dependency list and queues a microtask. For dialogs created repeatedly (loadingDialog, connection dialogs, file-upload progress), hoisting the require once and caching resolved modules would amortize the cost. InDOJO_SOURCE_DEBUGmode the impact is larger becausecacheBust=truedefeats browser cache.
#150 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
[MINOR] functional
ModalDialog:this.removeTrigger = removeTrigger;was removed butthis.addTriggerremains. TheremoveTriggerfunction is still defined and used internally (inclose()'sforEachloops) but is no longer exposed on the dialog instance. External callers can no longer remove a previously-added trigger - backward-incompatible API surface reduction.Yes,
removeTriggeris used internally onclose()to simplifyModalDialogusages.
Right, in that case it should not be exposed.
#151 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
[MINOR] performance
p2j.dialogs Set: Now stores dialog ID strings rather than DOM nodes. If twoModalDialoginstances are created with the same id (e.g. recreating afterclose()),dialogs.delete(that.id)from the first instance silently removes the tracker for the second. The loadingDialog/restoreConnectionDialog/connectionRestoredDialog/serverUnavailableDialog IDs are reused across reconnects. Please check whether this is an actual issue.It is supposed that each
ModalDialogdialog has its own unique id. The same dialog can be recreated afterclose().
I looked at this closer and this should not be an issue. Please dismiss this.
#152 Updated by Sergey Ivanovskiy 3 months ago
- % Done changed from 90 to 100
- Status changed from WIP to Review
#153 Updated by Sergey Ivanovskiy 2 months ago
Each time AI assistant based on Claude Code finds new issues. I rebased this branch 10915a up to rev 16587.
#154 Updated by Sergey Ivanovskiy 2 months ago
Committed revision 16588 (10915a) minor changes found by the gcd-code-style review.
#155 Updated by Sergey Ivanovskiy 2 months ago
Running fwd-code-review reported these issues:
FWD Code Review — Curated Findings¶
Summary¶
The diff modifies 14 files across the FWD web client subsystem, primarily refactoring the client-side ModalDialog from custom HTML/CSS to Dojo dijit.Dialog with async operation queuing, autofocus/refocus, and proper lifecycle management. A new DOJO_SOURCE_DEBUG config flag serves uncompressed Dojo sources. Keyboard event handling moves the isDialogDisplayed() check earlier to block server-bound events when a modal is active. CSS is rewritten with Dojo dialog overrides, and various JS files are updated for the new dialog API.
Findings¶
- [CRITICAL] functional
p2j.keyboard.jsonkeydown(ChUI): NoisDialogDisplayed()check exists in the ChUI keyboard handler. Only the GUI handler was modified. In ChUI mode, all keyboard events bypass the modal dialog guard entirely.
- [CRITICAL] functional
ModalDialogcreateDojoDialog: No timeout ifrequire()callback never fires. If Dojo module loading fails silently,createDialogDeferredis never resolved or rejected. All subsequent operations hang forever onawait createDialogAction, leaving the dialog in a permanently broken state.
- [MAJOR] functional
p2j.keyboard.jsonkeyup: OS key events are sent to the server before theisDialogDisplayed()check. Onlyonkeydownwas fixed in this diff. The server receives unbalanced key events with no matching keydowns, potentially corrupting key state tracking.
- [MAJOR] functional
ModalDialogconstructor (loading dialog): Loading dialog created withclosable: true, allowing users to dismiss the system loading progress dialog via the close button. The old custom modal had no close button.
- [MAJOR] functional
ModalDialogclose: Theclose()method does not setthat.visible = false. Afterclose()completes,isVisible()returns stale state.
- [MAJOR] functional
ModalDialogclose: CallsdojoDialog.hide()unconditionally whilehide()guards withisVisible(). Can fire spurious DojoonHidecallbacks.
- [MAJOR] functional
ModalDialogclose:onCloseapplication listener (which restoresme.processMouse) is called inside try block afterdojoDialog.hide(). Ifhide()throws, listener is never invoked, leavingme.processMousepermanentlyfalse.
- [MAJOR] functional
ModalDialogclose:dialogs.delete(that.id)runs beforeonCloselistener fires. During listener execution,isDialogDisplayed()returnsfalseso keyboard events are not blocked.
- [MAJOR] functional
ModalDialogclose:dojoDialog.hide()called redundantly beforeunregistry()->destroyRecursive(false). If Dojo's internalonHidefires during redundanthide()and throws, it preventsdestroyRecursivefrom running, leaking widget state.
- [MAJOR] functional
ModalDialogonCancel:that.hide()is fire-and-forget (un-awaited). If applicationonCancellistener callsthat.close(), ordering surprises can occur for code listening to bothonCancelandonClose.
- [MAJOR] functional
p2j.keyboard.jsonkeypress:keyPressEmitted = trueis set before theisDialogDisplayed()check. When dialog blocks the event, the flag remainstrue, corrupting keydown/keypress synchronization for the next real keypress.
- [MAJOR] functional
p2j.mouse.jsprocessWindowBorder: The onlyisDialogDisplayed()check in mouse.js is for the resize cursor.processMouseMovecan bypass the guard whensendMouseMoveis true.
- [MAJOR] performance
computeDialogSize/doDialogLayout: Layout thrashing. Settingstyle.height = 'auto'(write) followed immediately by reads of scroll/offset dimensions forces 2-3 synchronous browser reflows per dialog show.
- [MAJOR] performance
ModalDialogclose: AfterdestroyRecursivedisposes the Dojo widget,operationGuardchain keeps the closed-over environment alive viathat. Fieldsthat.centerPane,that.footerPane,that.topPaneare never nulled, so the destroyed Dojo widget subtree remains reachable through the closure.
- [MAJOR] security
p2j.screen.jschooseFiles(onError):JSON.stringify(error)is injected viainnerHTMLwithout HTML sanitization. Attacker-controlled file names with embedded HTML can execute script on upload failure.
- [MAJOR] style
AbstractModulesHandler: No history entry added despite significant modifications (new field, constructor, changed method signature, modifieddeliverModule).
- [MAJOR] style
WebResourceHandler: No history entry added and copyright year not updated (still 2018-2025). File was modified in 2026.
- [MAJOR] style
p2j.jsModalDialog/createDojoDialog: Line exceeds 110-character limit (123 chars).
- [MAJOR] style
p2j.jsModalDialog/createDojoDialog: Inconsistent colon spacing in object literal (mixesid : that.idandclassName: "...").
- [MINOR] style
ConfigItem.javaDOJO_SOURCE_DEBUG: Continuation-line indentation uses 10 spaces, not a multiple of 3-space rule.
- [MINOR] style
p2j.jsModalDialog/createDojoDialog: Inconsistent brace placement for object literals (some use same-line {, others brace on own line).
- [MINOR] style
p2j.jscomputeDialogSize: Inconsistent colon spacing in return object literal.
- [MINOR] style
p2j.socket.js: Pre-existing duplicate sequence ID 081.
- [MINOR] security
WebPageHandler.javaWebPageKeysProvider: Configuration values substituted into script string literal via raw string replacement with no HTML/JS escaping. A config value containing a single quote would break out of the JS string context.
- [MINOR] security
p2j.socket.jsserverUnavailableDialogEscapeTrigger:console.error(e)on cross-origin navigation failure leaks error details to console.
- [MINOR] performance
ModalDialogcreateDojoDialog: Loadsdijit/form/Buttonbut never instantiates or uses it.
- [MINOR] performance
ModalDialogclose:contentDivandtitleDivnever set tonullafterunregistry(), keeping destroyed DOM subtrees alive via closures.
- [MINOR] performance
ModalDialogcreateDojoDialog:dojo.require("dojo.Deferred")called synchronously every time, adding redundant lookups.
- [MINOR] performance
ModalDialogsetTitle:that.noTitle = title.length == 0evaluated unnecessarily for truthy cases regardless of whether title changed.
- [MINOR] performance
p2j.socket.jsconnectivityTimer/idleTimer:Math.maxinstead ofMath.minextends the reconnection loop lifetime.
- [MINOR] performance
ModalDialogoverrideDialogStyle/overrideTitleStyle: Async serialization for simpledomClass.togglecall means style override cannot take effect until the entire create chain completes.
- [MINOR] performance
ModalDialog:changeDisplayStyle/changeVisibilityStyledead code from old dialog implementation.
- [MINOR] functional
ModalDialogcreateDojoDialog:dojo.require("dojo.Deferred")is unnecessary with AMD-stylerequire().
- [MINOR] functional
ModalDialogoverrideDialogStyle/overrideTitleStyle: API changed from style-object to CSS-class-name. Old callers using inline style objects will silently fail.
- [MINOR] functional
p2j.jssetLoadingCheckpoint: Progress updates continue on hidden (but not disposed) dialog after user dismisses it via X button.
- [MINOR] functional Focus state divergence on dialog close:
autofocus: true/refocus: trueon Dojo Dialog manages browser-level focus, but FWD server-sideFocusManageris not notified.
- [MINOR] functional
p2j.screen.jsactivateWindow: Returnsundefinedinstead offalsewhenisDialogDisplayed()is true.
- [MINOR] functional
p2j.screen.jschooseFilesclose:actionResultsDialog.close()anddialog.close()are not awaited.
- [MINOR] functional
ModalDialogsetButtons: Afterclose()setsbuttonsDiv = null, callingsetButtonsagain silently does nothing.
- [MINOR] functional
p2j.keyboard.jsonkeyup: Missing&& evt.key != "Process"filter compared to equivalent check inonkeydown.
#156 Updated by Sergey Ivanovskiy 2 months ago
- % Done changed from 100 to 90
- Status changed from Review to WIP
Some of those issues can be fixed. So I will change to WIP.
#157 Updated by Sergey Ivanovskiy 2 months ago
- File test-web-file-upload-1.p
added
I tested repeatedly the direct upload web functionality and found that buttons do not trigger actions if Enter was pressed down and up, but pressing Space triggers actions. Pressing Enter triggers only chose action if there is an application trigger. This issue is independent from 10915a changes so it is the trunk issue.
#158 Updated by Sergey Ivanovskiy 2 months ago
No, this is related to the dojo code.
var okButton = new dijit.form.Button(
{
label : okButtonLabel,
onClick: clickOnInputFieldToSelectFiles
});
I will fix it.
#159 Updated by Sergey Ivanovskiy 2 months ago
Committed revision 16591.(10915a). Fixed critical and major issues found in the AI review (#10915a-155).
#160 Updated by Sergey Ivanovskiy 2 months ago
Committed revision 16592 (10915a) fixed most of minor issues and I run new code review to collect what was left or ignored.
#161 Updated by Sergey Ivanovskiy 2 months ago
Stefanel, could you help with the test case to check the reauth dialog style from p2j.sso_reauth.js?
#162 Updated by Sergey Ivanovskiy 2 months ago
The current rev 16593 has this report
FWD Code Review — Curated Findings¶
Summary¶
This diff spans 20 files covering a ModalDialog rewrite (raw HTML to Dojo dijit/Dialog), connection management improvements, keyboard/mouse event hardening, Dojo source debugging support, and CSS restructuring. The previously identified CRITICAL issue (p2j.sso_reauth.js overrideDialogStyle API break) has been fixed — the caller now correctly passes CSS class name "ssoReauthDialog" with matching CSS class defined in p2j.client.css.
Findings¶
- [MAJOR] style
p2j.js: History entry 034 first date (20251220) predates entry 033 (20260326). History entries should be in chronological order.
- [MAJOR] style
p2j.socket.js: History entry 083 first date (20251220) predates entry 082 (20260326). Chronology error.
- [MAJOR] style
p2j.screen.js: History entry 102 first date (20251220) predates entry 101 (20260504). Chronology error.
- [MAJOR] style
Utils.java: History entry 111 first date (20260206) predates entry 110 (20260402). Chronology error.
- [MAJOR] style
ConfigItem.java.DOJO_SOURCE_DEBUG: Javadoc/** Enable the dojo source code debugging */at 3-space indent, butpublic static final ConfigItem<Boolean> DOJO_SOURCE_DEBUGat 4-space indent — inconsistent by 1 space.
- [MAJOR] style
p2j.js.doDialogLayout: Function keyword at 17 spaces, but siblingcomputeDialogSizeat 16 spaces within the sametryblock. Off by 1 space.
- [MAJOR] style
p2j.js.ModalDialog: Object literal{"noTitle" : false, "closable" : false}uses space before colon, while multi-line object literals in the same file (e.g.design: 'headline',region: 'center') do not. Three different colon spacing conventions coexist.
- [MAJOR] style
p2j.keyboard.js.onkeypress(CHUI): Newif (p2j.isDialogDisplayed())guard at 11 spaces indent, while surrounding code uses 10 spaces. Inconsistent by 1 space.
- [MAJOR] style
p2j.mouse.js.processMouseMove: New code at 10 spaces indent where the GCD 3-space rule dictates 9 spaces (3 levels deep: function → inner function → body = 3 x 3).
- [MAJOR] functional
ModalDialog.setTitle:setTitle("")does not clear the previous title because empty string is falsy in JavaScript, sodojoDialog.set("title", title)is never called. The previous title text persists.
- [MAJOR] functional
ModalDialog.close:dialogs.delete(that.id)moved to AFTER theonCloselistener. During theonClosecallback,isDialogDisplayed()still returnstrue— all keyboard/mouse handlers block events even though the dialog is logically closing.
- [MAJOR] functional
ModalDialog.close: Callsthat.dojoDialog.hide()directly, bypassing the publichide()method. TheonHidelistener is never fired whenclose()disposes a visible dialog.
- [MAJOR] functional
ModalDialog.close: Not awaited by several callers (p2j.socket.js,p2j.sso_reauth.js,p2j.js). The close operation chains onoperationGuardbut callers may null the dialog reference while the async chain is still pending.
- [MAJOR] functional
ModalDialog.hide: Nothat.disposedguard before accessingthat.dojoDialog. Works accidentally (null check ondojoDialogserves as proxy) but fragile.
- [MAJOR] functional
ModalDialog.addTrigger: For dialogs withclosable: false(all system dialogs), theonCancellistener is stored butdojoDialog.onCancelis only overridden whenclosable === true. The stored listener is never invoked — dead code.
- [MAJOR] functional
ModalDialog.hidevsclose:dialogs.delete()ordering inconsistency.hide()deletes fromdialogsBEFORE invokingonHidelistener.close()deletes AFTER invokingonCloselistener. DuringonHide,isDialogDisplayed()returnsfalse; duringonClose, it returnstrue.
- [MAJOR] functional
p2j.socket.js.ping.checkLostPings: Connection-loss detection timing changed from ~maxIdleTimeto ~maxIdleTime/4. NewmaxLostPingsformula with watcher atpingPongInterval/2detects loss up to 4x faster. Risks premature reconnect before the server declares the session dead.
- [MAJOR] functional
p2j.socket.js.connectivityTimer.idleTimer: Changed fromMath.min(watchdogTimeout, maxIdleTime)toMath.max(watchdogTimeout, maxIdleTime). This reverses the effective timeout logic — previously the tighter bound constrained timers; now the looser bound applies.
- [MAJOR] functional
ModalDialog.onCancel:that.hide()is not awaited in the Dojo dialog'sonCancelcallback. If theonCancellistener itself invokesclose(), the two serialized operations race.
- [MAJOR] functional
ModalDialog.createDojoDialog.dojoDialog.onCancel:that.hide()is fire-and-forget — the onCancel function does not return/await it, and Dijit does not awaitonCancel. However,hide()catches errors internally via try/catch, so unhandled rejection risk is mitigated.
- [MAJOR] functional
p2j.socket.js:pingPongIntervalfloored at 100ms viaMath.max(cfg.socket.pingPongInterval, 100). If the configured value is non-numeric or missing,Math.max(undefined, 100)yieldsNaN, causing silent timer failures.
- [MINOR] style
p2j.socket.js:Math.trunc( maxIdleTime / (2 * pingPongInterval))has a space afterMath.trunc(— violates "none inside parentheses" rule.
- [MINOR] style
p2j.clipboard.js: Trailing space before)onexcludedContainer.contains(evt.target)).
- [MINOR] style
p2j.screen.js.chooseFiles:const okButtonLabel = p2j.i18n.gettext("OK")— double space after=.
- [MINOR] style
p2j.client.css:padding-top: 0px— zero values should omit thepxunit.
- [MINOR] style
p2j.client.css:padding: 1px 0px 1px 0px— zero values should omit thepxunit.
- [MINOR] performance
AbstractModulesHandler.deliverModule: Thesynchronizedmethod serializes all concurrent module resource requests — primary contention source preexisting this change. Debug mode adds a fallback path (1 extramapToResource+ 1 extragetResource) when the uncompressed resource is absent.
- [MINOR] performance
ModalDialog: Every method wraps its body inoperationGuard.then(async () => {...}), allocating a new Promise + async function closure per invocation. Adds per-call garbage pressure for operations called in rapid succession.
- [MINOR] performance
ModalDialog.computeDialogSize.doDialogLayout: Forces 1 synchronous layout reflow pershowviaborderContainer.domNode.style.height = 'auto'combined withscrollHeight/offsetHeightreads.
- [MINOR] performance
p2j.keyboard.js.p2j.mouse.js:p2j.isDialogDisplayed()(O(1)) added to everykeydown/keypress/keyuphandler (6 locations) andmousemovehandler (1 location). In highest-frequency event path.
- [MINOR] performance
DojoToolkitHandler.mapToResource: In debug mode, every.jsrequest hits twoString.endsWithchecks thenString.concat(".uncompressed.js"), allocating an intermediate string per request.
- [MINOR] security
p2j.screen.js.chooseFiles.onComplete: RemaininginnerHTMLusage withp2j.i18n.ngettext()(lines 8205, 8212) inconsistent with thetextContentfix applied toonError. Only numeric parameters interpolated today (no current exploit path), but should usetextContentfor consistency.
- [MINOR] security
p2j.socket.js.checkLostPings: WebSocket close reason string includes runtime valueslostPingsandmaxLostPingstransmitted in-band viaws.close(), exposing internal configuration to the server endpoint.
- [MINOR] functional
ModalDialog.setTitle:noTitlelogic for empty string is inverted.setTitle("")evaluates tofalse(since""is falsy), so title bar is shown empty rather than hidden.
- [MINOR] functional
ModalDialog.constructor: Whenhidden=false,show()is called withoutawait. Sinceshow()chains through asyncoperationGuard, dialog may not be fully shown when the constructor returns. All current callers passhidden=true, but latent.
- [MINOR] functional
ModalDialog.createDojoDialog: 30-second timeout does not setthat.disposedon rejection. Callers checkingisDisposed()see a non-disposed dialog that is actually unusable.
- [MINOR] functional
ModalDialog.constructor: UnnecessarytextDivDOM. A<div class="text">is created even for dialogs that usesetContent()(which clearscontentDiv).
- [MINOR] functional
p2j.screen.js.chooseFiles.onComplete: Old short-circuitedcloseAction()for!multiplefiles. New code always shows the result dialog for 5 seconds — visible UX change.
- [MINOR] functional
p2j.screen.js.chooseFiles.onProgress: Old code checkedevent.type == "load"; new code unconditionally callsactionResultsDialog.show(). Changed from completion-triggered to progress-triggered.
- [MINOR] functional
p2j.screen.js.chooseFiles:me.processMousechanged fromdirectparameter to hardcodedfalse. Mouse processing always disabled during file selection regardless ofdirectflag.
- [MINOR] functional
p2j.screen.js.chooseFiles:sendFileChoose()called beforecloseAction()completes inonErrorandonCompletehandlers. Server notification fires before dialog cleanup finishes.
- [MINOR] functional
p2j.screen.js.activateWindow: Returnsfalseinstead ofundefined. Both falsy but return type changed from implicit void to explicit boolean.
- [MINOR] functional
processMouseMove:isDialogDisplayed()guard placed beforesendMouseMovecheck. When modal dialog displayed,sendMouseMove=trueone-shot is silently consumed.
- [MINOR] functional
Utils.removeEscapedDoubleQuotes: Only handles backslash-escaped double quotes (\"), not"XML entities.
- [MINOR] functional
Utils.removeEscapedDoubleQuotes: Does not trim whitespace after quote removal. Input" text "produces" text "(leading/trailing spaces preserved).
I found interesting issue that AI can makes a change in the review from its previous note to the opposite note.
[MAJOR] functional ModalDialog close: dialogs.delete(that.id) runs before onClose listener fires. During listener execution, isDialogDisplayed() returns false so keyboard events are not blocked.
to
[MAJOR] functional ModalDialog.hide vs close: dialogs.delete() ordering inconsistency. hide() deletes from dialogs BEFORE invoking onHide listener. close() deletes AFTER invoking onClose listener. During onHide, isDialogDisplayed() returns false; during onClose, it returns true.
That is probably the matter of the agreement of how to use listeners and when they are invoked.
#163 Updated by Sergey Ivanovskiy 2 months ago
Finally I realized that onHide and onClose listeners should be protected and do not send any key and mouse events to the business logic so I was confused by the review committed rev 16594 (10915a).
#164 Updated by Sergey Ivanovskiy 2 months ago
FWD Code Review — Curated Findings¶
Summary¶
20 files modified (2957 line diff). The prior CRITICAL finding (sso_reauth.js overrideDialogStyle API break) and 6 MAJOR functional issues were fixed. 39 issues remain across style, functional, performance, and security.
Fixed issues include: sso_reauth.js overrideDialogStyle API break; ModalDialog.setTitle("") clearing; dialogs.delete ordering (moved before onClose); hide/close dialogs.delete consistency; ping/checkLostPings timing clarified; connectivityTimer/idleTimer min→max reversal intentional; onProgress restructured.
Findings¶
- [MAJOR] style
p2j.js: History entry 034 first date (20251220) predates entry 033 (20260326). Not chronological.
- [MAJOR] style
p2j.socket.js: History entry 083 first date (20251220) predates entry 082 (20260326). Not chronological.
- [MAJOR] style
p2j.screen.js: History entry 102 first date (20251220) predates entries 100/101 (20260401/20260504). Not chronological.
- [MAJOR] style
Utils.java: History entry 111 first date (20260206) predates entry 110 (20260402). Not chronological.
- [MAJOR] style
p2j.mouse.js.processMouseMove: NewisDialogDisplayedguard at 10-space indent; existing code at same nesting level uses 9 spaces.
- [MAJOR] style
p2j.keyboard.js.onkeypress(CHUI): Dialog guard at 10-space indent; surrounding code at same level uses 9 spaces.
- [MAJOR] style
p2j.socket.js.serverUnavailableDialogEscapeTrigger:try-catchblock inside function body at 0 indent (commented debug lines also at 0 indent).
- [MAJOR] functional
ModalDialog.close: Bypasseshide()— callsdojoDialog.hide()directly rather thanthat.hide(). TheonHidelistener registered viaaddTrigger("onHide", ...)is never invoked whenclose()disposes a visible dialog.
- [MAJOR] functional
ModalDialog.setTitle:that.noTitle = title ? title.length 0 : false— whentitle="", the falsy branch yieldsfalse, so the title bar is shown (viahideTitle(false)) rather than hidden. Thetitle.length0branch is unreachable for any real input.
- [MAJOR] functional
p2j.screen.js.chooseFiles.onComplete: Theif (!multiple) { closeAction(); return; }short-circuit was removed. Single-file uploads now wait the full 5-seconddelayForCloseActionbefore closing, regressing from immediate-close behavior.
- [MAJOR] functional
ModalDialog.close: Not awaited by most callers (loadingDialog.close()in p2j.js,restoreConnectionDialog.close()andserverUnavailableDialog.close()in socket.js,alertDialog.close()in screen.js,reauthDialog.close()in sso_reauth.js). Noneawaitthe returned promise.
- [MAJOR] functional
p2j.mouse.js.processMouseMove:isDialogDisplayed()guard at line 362 fires BEFORE the!sendMouseMovecheck at line 367, defeating the comment's stated purpose that mouse moves must be sent for dialog-boxes afterSET_CURSOR.
- [MAJOR] functional
p2j.screen.js.chooseFiles:me.processMousechanged fromdirectto hardcodedfalse, disabling all mouse event processing during file selection regardless of thedirectflag.
- [MAJOR] performance
AbstractModulesHandler.deliverModule: Method issynchronized, serializing all module requests through a single lock. Every page load with 10-50+ JS module requests contends on this lock.
- [MINOR] style
ConfigItem.java.DOJO_SOURCE_DEBUG: Field continuation uses 7-space indent, while neighboringJS_DEBUG_LOGGINGuses a different continuation style. Inconsistent.
- [MINOR] style
p2j.socket.js:Math.trunc( maxIdleTime...— space after(, should be removed.
- [MINOR] style
p2j.clipboard.js: Trailing whitespace after)on line 283.
- [MINOR] style
p2j.screen.js.chooseFiles:const okButtonLabel = p2j...— double space after=.
- [MINOR] style
p2j.js:catch(e)should becatch (e)(space before condition).
- [MINOR] style
p2j.screen.js:catch(e)should becatch (e)(space before condition).
- [MINOR] style
p2j.client.css:padding-top: 0px— zero values should omitpx.
- [MINOR] style
p2j.client.css:padding: 1px 0px 1px 0px— zero values should omitpx.
- [MINOR] performance
ModalDialog: Every method (show,hide,close,setContent,setTextContent,setButtons,setFooter,setTitle,overrideDialogStyle,overrideTitleStyle,updateLayout) chains.then()onoperationGuard, allocating a new Promise per call.
- [MINOR] performance
ModalDialog.computeDialogSize: Writesstyle.height='auto'then reads offset/scroll properties, forcing 1 synchronous reflow per call.
- [MINOR] performance
p2j.keyboard.js/p2j.mouse.js:isDialogDisplayed()called in all GUI and CHUI keyboard handlers plusprocessMouseMove— expanded hot-path footprint (dialogs.size > 0, O(1), but in highest-frequency events).
- [MINOR] performance
DojoToolkitHandler.mapToResource:concat(".uncompressed.js")+replace()= 2 string allocations per request whendebugModeenabled.
- [MINOR] performance
p2j.socket.js.ping:setTimeoutfires atpingPongInterval >> 1, doubling the healthy-pathcheckLostPingscallback rate vs oldpingPongInterval.
- [MINOR] performance
ModalDialog.show: CallsdoDialogLayout()on already-visible dialog, forcing unnecessary reflow per repeatedshow().
- [MINOR] security
p2j.screen.js.chooseFiles.onComplete: RemaininginnerHTMLusage at lines 8205 and 8212 forresultDiv.onErrorwas correctly changed totextContent, butonCompletewas not — inconsistent.
- [MINOR] security
p2j.socket.js.checkLostPings:closeWebSocketSafely()at line 5876 transmits internal config values (lostPings,maxLostPings) in the WebSocket close reason frame, observable by network intermediaries.
- [MINOR] functional
ModalDialog.addTrigger: For dialogs withclosable: false(all system dialogs), theonCancellistener stored viaaddTrigger("onCancel", handler, false)is stored inthat.listeners, butdojoDialog.onCancelis only bound whenthat.closableis true. The listeners are unreachable dead code.
- [MINOR] functional
ModalDialog.onCancel:that.hide()called withoutawaitinside dojo dialog'sonCancel.hide()is async; Dojo will not await the returned promise.
- [MINOR] functional
ModalDialog.hide: Nothat.disposedguard. Unlikeshow()andclose(),hide()does not explicitly check disposed state. Works accidentally via!that.dojoDialognull check.
- [MINOR] functional
p2j.socket.js:Math.max(cfg.socket.pingPongInterval, 100)— if configured value isundefined, returnsNaN, breaking all ping/pong timing calculations downstream.
- [MINOR] functional
ModalDialog.constructor: Whenhidden=false,show()called withoutawait. Constructor is synchronous;show()is async. All current callers passhidden=true, but latent.
- [MINOR] functional
ModalDialog.createDojoDialog: 30-second timeout handler rejects the deferred but does not setthat.disposed = true, leaving the dialog in an ambiguous non-disposed but unusable state.
- [MINOR] functional
ModalDialog.constructor: InitialtextDivcreated insidecreateDojoDialogis later replaced bysetTextContent/setContent, creating wasted DOM nodes.
- [MINOR] functional
Utils.removeEscapedDoubleQuotes: Only strips\"wraps, not"HTML entities (another common wrapping for XML-configured string values).
- [MINOR] functional
Utils.removeEscapedDoubleQuotes: Does nottrim()the result. Input" value "produces" value "with leading/trailing spaces.
#165 Updated by Sergey Ivanovskiy 2 months ago
At the moment of writing the code this part was intentional:
[MAJOR] functional ModalDialog.close: Bypasses hide() — calls dojoDialog.hide() directly rather than that.hide(). The onHide listener registered via addTrigger("onHide", ...) is never invoked when close() disposes a visible dialog.
#166 Updated by Hynek Cihlar 2 months ago
Code review 10915a revisions 16559..16591
- [MAJOR] functional
chooseFiles:onErrorreadsactionResultsDialog.files.length, butactionResultsDialog.filesis only assigned insideonChange. If an upload error fires beforeonChange(e.g., immediate server rejection in direct mode),actionResultsDialog.filesisundefinedand thengettextcall throws.
Test disconnet dialogs still work well under various network conditions (slow/fast network, higher latencies).
- [MAJOR] functional
startConnect(p2j.socket):restoreConnectionDialog(the "lost, trying to reconnect" UI) is given the title"Server Unavailable", the same title used for the terminalserverUnavailableDialog. This is misleading: "Server Unavailable" implies a terminal state, while the restore dialog represents a transient retry state. A title such as "Connection Lost" or "Reconnecting" would be more accurate.
- [MAJOR] functional
doRedirectToLogoutPage: In thewindow.fetch(logoutPage).catch(...)branch the new code clearshideRestoreConnectionDialogand callsrestoreConnectionDialog.hide()beforeserverUnavailableDialog.show(). The two calls schedule onto separateoperationGuardchains, so there is no guaranteerestoreConnectionDialogis hidden beforeserverUnavailableDialogbecomes visible. For a brief window both dialogs may overlap in the DOM, especially with the legacyupdateZIndexoverlay logic now removed. Please double check this.
- [MAJOR] functional
startupServer(EmbeddedWebServerImpl): WhenDOJO_SOURCE_DEBUGis enabled, the embedded web server serves uncompressed Dojo source files without any production-mode gating, audit log, or startup warning. Consider logging a WARNING when debug mode is activated.
Please double check the code indentations are at 3 characters, I noticed some places where 4 were used.
#167 Updated by Sergey Ivanovskiy 2 months ago
Yes, this one restoreConnectionDialog.setTitle(p2j.i18n.gettext("Server Unavailable")); can be removed because the reconnection dialog uses this title restoreConnectionDialog.setTitle(p2j.i18n.gettext("Attempt #%1",connectionTries));. Don't understand why this line was here.
#168 Updated by Sergey Ivanovskiy 2 months ago
This one
- [MAJOR] functional
p2j.mouse.js.processMouseMove:isDialogDisplayed()guard at line 362 fires BEFORE the!sendMouseMovecheck at line 367, defeating the comment's stated purpose that mouse moves must be sent for dialog-boxes afterSET_CURSOR.
is related to dialogs created by the converted code. From the other side ModalDialogs should not impact the converted code that implements the application business logic so key and mouse events should not be sent to the java web client.
#169 Updated by Stefanel Pezamosca 2 months ago
Sergey Ivanovskiy wrote:
Stefanel, could you help with the test case to check the reauth dialog style from
p2j.sso_reauth.js?
Yes, I can help. Is 10915a ready to be tested with this or should I wait for other changes to be committed?
#170 Updated by Sergey Ivanovskiy 2 months ago
Yes, the current code looks suitable but there can be issues with ModalDialog usages that needs to be checked. Actually, dialogs methods show(), hide(), setTitle() and etc. are asynchronous but their execution order is supported.
#171 Updated by Sergey Ivanovskiy 2 months ago
This one
[MAJOR] functional doRedirectToLogoutPage: In the window.fetch(logoutPage).catch(...) branch the new code clears hideRestoreConnectionDialog and calls restoreConnectionDialog.hide() before serverUnavailableDialog.show(). The two calls schedule onto separate operationGuard chains, so there is no guarantee restoreConnectionDialog is hidden before serverUnavailableDialog becomes visible. For a brief window both dialogs may overlap in the DOM, especially with the legacy updateZIndex overlay logic now removed. Please double check this.
I checked the code and can confirm that the order of ModalDialog method calls is supported and only when one method body is completed, the next method call starts its execution.
#172 Updated by Sergey Ivanovskiy 2 months ago
If it is important for the caller of ModalDialog to wait until its method is completed, then await construction should be used await dialog.show() or await dialog.hide().
#173 Updated by Stefanel Pezamosca 2 months ago
- File reauth-dialog.png added
Sergey Ivanovskiy wrote:
Stefanel, could you help with the test case to check the reauth dialog style from
p2j.sso_reauth.js?
I think it looks ok. I didn't see other issues.
#174 Updated by Sergey Ivanovskiy 2 months ago
Stefanel, thank you for help with this dialog checking! If we require Close dialog button (X) and the title, then
reauthDialog = new p2j.ModalDialog('p2j-sso-reauth-dialog', document.body, '', '', true, {"noTitle" : false, "closable" : true});
reauthDialog.setTitle(...);
#175 Updated by Sergey Ivanovskiy 2 months ago
To remove the dialog title bar we need to set this option value noTitle : true
reauthDialog = new p2j.ModalDialog('p2j-sso-reauth-dialog', document.body, '', '', true, {"noTitle" : true, "closable" : false});
#176 Updated by Sergey Ivanovskiy 2 months ago
I think that false options can be omitted so
reauthDialog = new p2j.ModalDialog('p2j-sso-reauth-dialog', document.body, '', '', true, {"closable" : true});
reauthDialog = new p2j.ModalDialog('p2j-sso-reauth-dialog', document.body, '', '', true, {"noTitle" : true});
#177 Updated by Sergey Ivanovskiy 2 months ago
Committed revision 16600 (10915a) fixed
[MAJOR] functional startupServer (EmbeddedWebServerImpl): When DOJO_SOURCE_DEBUG is enabled, the embedded web server serves uncompressed Dojo source files without any production-mode gating, audit log, or startup warning. Consider logging a WARNING when debug mode is activated.#178 Updated by Sergey Ivanovskiy 2 months ago
Hynek, what was the reason that this code was placed at the top before logKeyEvent(evt, "keypress"); and guards?
* ALT key is the modifier which sets the key code's 10th bit. If this is determined to be
* pressed together with the key, than bit 10 will be set and this key will be pushed to the
* {@link SwingKeyboardReader#queue}, but only if the key code's label is not the empty string.
*
* @param {KeyboardEvent} evt
* The browser generated keyboard event.
*/
function onkeypress(evt)
{
if (evt.key === undefined || evt.key == "Unidentified" || evt.key == "")
{
if (evt.charCode !== undefined && evt.charCode !== 0)
{
var keyCode = getKeyCode(evt);
var newKey = String.fromCharCode(evt.charCode);
var newEvt = p2j.createKeyEvent("keypress", evt.bubbles, evt.cancelable, evt.view,
evt.ctrlKey, evt.altKey, evt.shiftKey, evt.metaKey,
keyCode, evt.charCode, newKey, evt.code);
onkeypress(newEvt);
return;
}
}
logKeyEvent(evt, "keypress");
if (rejectKeyEvent(evt))
{
return;
}
if (p2j.isDialogDisplayed())
{
return false;
}
#179 Updated by Sergey Ivanovskiy 2 months ago
Committed rev 16603(10915a) should fix most found issues (those that can be fixed) except
- [MAJOR] functional
p2j.screen.jsmouseDownHandler,mouseUpHandler,mouseClickHandler,mouseContextMenuHandler: WhenisDialogDisplayed()is true, these handlers callp2j.consumeEvent(evt)(which callsstopPropagation/preventDefaultbut does not halt execution) and then continue throughdispatchEvent→sendMouseEvent, sending mouse events to the server behind a modal dialog. OnlymouseMoveHandlercorrectly returns early after consuming the event.
that can be addressed after we discussed #10915-178.
#180 Updated by Sergey Ivanovskiy 2 months ago
- Status changed from WIP to Feedback
Hynek, we need to discuss #10915-178 before I finalized the code for the review.
#181 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
Hynek, what was the reason that this code was placed at the top before logKeyEvent(evt, "keypress"); and guards?
This was for the cases when evt.key is not defined. key itself is deprecated and in some environments it is not set anymore. One such case is Lyra built on top of Playwright.
#182 Updated by Sergey Ivanovskiy 2 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek, what was the reason that this code was placed at the top before logKeyEvent(evt, "keypress"); and guards?
This was for the cases when
evt.keyis not defined.keyitself is deprecated and in some environments it is not set anymore. One such case is Lyra built on top of Playwright.
In this case we should guard this code by lyra flag.
#183 Updated by Sergey Ivanovskiy 2 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek, what was the reason that this code was placed at the top before logKeyEvent(evt, "keypress"); and guards?
This was for the cases when
evt.keyis not defined.keyitself is deprecated and in some environments it is not set anymore. One such case is Lyra built on top of Playwright.
MDN does not deprecate key field!
https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
#184 Updated by Sergey Ivanovskiy 2 months ago
- Status changed from Feedback to WIP
#185 Updated by Sergey Ivanovskiy 2 months ago
- Status changed from WIP to Review
- % Done changed from 90 to 100
Please review the last fixes rev. 16605 (10915a).
#186 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek, what was the reason that this code was placed at the top before logKeyEvent(evt, "keypress"); and guards?
This was for the cases when
evt.keyis not defined.keyitself is deprecated and in some environments it is not set anymore. One such case is Lyra built on top of Playwright.MDN does not deprecate key field!
https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
Sorry for the confusion, Playwright (in Lyra) only fills charCode, that is why key must be calculated. I will add this explanation in a code comment in 10860b.
#187 Updated by Sergey Ivanovskiy 2 months ago
OK. I added the guide for this code. Could you review the last code rev 16620. I tried to fix the most issues.
#188 Updated by Hynek Cihlar 2 months ago
- % Done changed from 100 to 90
- Status changed from Review to WIP
Code review 10915a revisions 16573..16620
- [CRITICAL] functional
ModalDialog.show:dialogs.add(that.id)is invoked only afterawait that.dojoDialog.show()which resolves after dijit's fade-in animation (~400 ms) completes. During this windowp2j.isDialogDisplayed()returns false, so the keyboard guards inp2j.keyboard.jsand the mouse guard inp2j.mouse.jsstill dispatch user input to the FWD canvas — modality is not enforced during the dialog open. The previous implementation setdialogs.add(dialog)synchronously. Fix: addthat.idtodialogssynchronously whenshow()is invoked (and revert on failure). I think this is worthwile to look at a quick typing during dialog open could dispatch the events to the legacy event queue.
- [MAJOR] functional
ModalDialog.addTrigger: Guardif (!that.closable && eventType "onCancel") return;silently swallows the registration.p2j.socket.jsregistersaddTrigger("onCancel", ...)onrestoreConnectionDialogandserverUnavailableDialog(bothclosable: false), so both handlers are dead. Fix: drop the guard (dijit'sonCancelis not wired whenclosableis false anyway, so registration is harmless), or remove the now-deadaddTrigger("onCancel", ...)calls inp2j.socket.js.
- [MAJOR] functional
p2j.socket.doRedirectToLogoutPage:restoreConnectionDialog.hide()andserverUnavailableDialog.show()are issued back-to-back on two separate dialog instances, each with its ownoperationGuard. The chains race;serverUnavailableDialogmay enterDialogLevelManager._dialogStackand grab the underlay beforerestoreConnectionDialogfinishes fading out, leaving the underlay tied to the wrong dialog. Fix:await restoreConnectionDialog.hide()before invokingserverUnavailableDialog.show(). I think it makes sense to add the await there.
- [MAJOR] functional
ssoReauth.handleSsoReauth:reauthDialog.show()is asynchronous (chained onoperationGuard) butbtnRelogin.focus()is called synchronously right after. At that momentcreateDojoDialoghas not yet resolved, the panel is still detached, andbtnRelogin.focus()is a no-op. Initial focus depends entirely on dijit'sautofocus. Fix:await reauthDialog.show()before focusing, or register anonShowlistener that focusesbtnRelogin.
- [MAJOR] functional
ssoReauth.handleSsoReauth:new p2j.ModalDialog('p2j-sso-reauth-dialog', document.body, '', '', true)omits thetitleOptionargument so the constructor defaults tonoTitle: false. The dijit Dialog renders an empty title bar above the SSO panel — UI regression vs the previous custom-HTML dialog. Fix: pass{noTitle: true, closable: false}.
- [MAJOR] functional
CHUIKeyboardReader.onkeyup: The newisDialogDisplayed()early return prevents the handler from callingconsumeEvent/preventDefault, so ESC/arrow keys hitting the CHUI canvas while a dialog is shown may trigger browser-native behavior (page scrolling, history back, etc.). Consume the event before returning, or rely on the dialog's own consumption. Please check this one.
- [MAJOR] functional
GUIKeyboardReader.onkeypress: The fallback that synthesizes a key event whenevt.key = undefined || evt.key "Unidentified" || evt.key ""was wrapped inif (p2j.lyra). Non-Lyra clients (Playwright tests, Safari, etc.) now fall through tokeyPressEmitted = true; lastPressedKey = evt.key Pl;withundefined/empty key. Either remove thep2j.lyragate or document why the synthesis is Lyra-only and add an equivalent fallback for the standard path. Please don't limit this to Lyra. If for any reason we run a test directly with Playwright this workaround won't work.
- [MAJOR] functional
MouseHandler.processMouseMove: The newif (p2j.isDialogDisplayed()) return;is placed BEFORE the!p2j.screen.canProcessOsEvent(evt, win) && !sendMouseMovecheck, defeating the documented force-send pathway used bysetGlobalCursorwhereme.sendMouseMove = trueforces one mousemove through. Even withsendMouseMovetrue, the event is dropped when any FWD modal dialog is up. Gate the new check with&& !sendMouseMoveif force-send must still pass. Please test how modal dialogs interact with a global cursor active.
- [MAJOR] functional
EmbeddedWebHandler.<init>: Still constructsnew DojoToolkitHandler(TARGET_EMBEDDED)via the legacy constructor (forcesdebugMode=false). The newDOJO_SOURCE_DEBUGflag has no effect on the embedded web app. Either plumb the flag here or document the limitation in theConfigItemjavadoc.
#189 Updated by Sergey Ivanovskiy 2 months ago
- % Done changed from 90 to 100
These issues are shuffled from AI review to another one. Could you select the ones that can be fixed?
#190 Updated by Sergey Ivanovskiy 2 months ago
I would reject them all.
#191 Updated by Sergey Ivanovskiy 2 months ago
- Status changed from WIP to Review
#192 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
These issues are shuffled from AI review to another one. Could you select the ones that can be fixed?
These were genuine from the latest state of the code. I checked each of them and they seem legit to me.
#193 Updated by Sergey Ivanovskiy 2 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
These issues are shuffled from AI review to another one. Could you select the ones that can be fixed?
These were genuine from the latest state of the code. I checked each of them and they seem legit to me.
May be you are correct. Those seem to me like shuffled old issues because of asynchronous code. Will try to fix them.
#194 Updated by Sergey Ivanovskiy 2 months ago
- Status changed from Review to WIP
#195 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
May be you are correct. Those seem to me like shuffled old issues because of asynchronous code. Will try to fix them.
Actually I never do that. I always do review of the most recent code state and always check item by item removing anything, which is a non-issue. Obviously I can make mistakes as I typically don't runtime-check everything.
#196 Updated by Sergey Ivanovskiy 2 months ago
OK. Thank you. I see.
#197 Updated by Sergey Ivanovskiy 2 months ago
The first issue I should discuss here
await that.dojoDialog.show();
setVisible(true);
dialogs.add(that.id);
that.dojoDialog.show() code performs async operations and the propose to block mouse events to FWD converted business logic. The proposed solution can be
dialogs.add(that.id);
await that.dojoDialog.show();
setVisible(true);
#198 Updated by Sergey Ivanovskiy 2 months ago
The second issue is really came from my changes in which I did the dialog without closed button x but forgot to remove addTrigger("onCancel",.)
#199 Updated by Sergey Ivanovskiy 2 months ago
The third issue looks bad because adding await requires to add async marker the hosted function.
[MAJOR] functional p2j.socket.doRedirectToLogoutPage: restoreConnectionDialog.hide() and serverUnavailableDialog.show() are issued back-to-back on two separate dialog instances, each with its own operationGuard. The chains race; serverUnavailableDialog may enter DialogLevelManager._dialogStack and grab the underlay before restoreConnectionDialog finishes fading out, leaving the underlay tied to the wrong dialog. Fix: await restoreConnectionDialog.hide() before invoking serverUnavailableDialog.show(). I think it makes sense to add the await there.
#200 Updated by Sergey Ivanovskiy 2 months ago
The 4th issue is similar to 3d.
[MAJOR] functional ssoReauth.handleSsoReauth: reauthDialog.show() is asynchronous (chained on operationGuard) but btnRelogin.focus() is called synchronously right after. At that moment createDojoDialog has not yet resolved, the panel is still detached, and btnRelogin.focus() is a no-op. Initial focus depends entirely on dijit's autofocus. Fix: await reauthDialog.show() before focusing, or register an onShow listener that focuses btnRelogin.
#201 Updated by Sergey Ivanovskiy 2 months ago
This one is simple but should be discussed, The proposed solution is to remove title.
[MAJOR] functional ssoReauth.handleSsoReauth: new p2j.ModalDialog('p2j-sso-reauth-dialog', document.body, '', '', true) omits the titleOption argument so the constructor defaults to noTitle: false. The dijit Dialog renders an empty title bar above the SSO panel — UI regression vs the previous custom-HTML dialog. Fix: pass {noTitle: true, closable: false}.
#202 Updated by Sergey Ivanovskiy 2 months ago
The 6th issue must be discussed because I do not know why it should be consumed.
[MAJOR] functional CHUIKeyboardReader.onkeyup: The new isDialogDisplayed() early return prevents the handler from calling consumeEvent/preventDefault, so ESC/arrow keys hitting the CHUI canvas while a dialog is shown may trigger browser-native behavior (page scrolling, history back, etc.). Consume the event before returning, or rely on the dialog's own consumption. Please check this one.
#203 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
This one is simple but should be discussed, The proposed solution is to remove title.
Is there title in trunk? If not, just remove the title bar from the dialog in this case so that it doesn't look like something's missing.
#204 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
The 6th issue must be discussed because I do not know why it should be consumed.
This item is about default browser behavior. Like when you press TAB key, we don't want the focus leave FWD running app in the browser's address bar.
#205 Updated by Sergey Ivanovskiy 2 months ago
The 7th issue is due to unclear code that was from Playwright and Lyra. I proposed to add the guard here. If this one p2j.lyra is not generic, then it must be added another one.
[MAJOR] functional GUIKeyboardReader.onkeypress: The fallback that synthesizes a key event when evt.key = undefined || evt.key "Unidentified" || evt.key "" was wrapped in if (p2j.lyra). Non-Lyra clients (Playwright tests, Safari, etc.) now fall through to keyPressEmitted = true; lastPressedKey = evt.key Pl; with undefined/empty key. Either remove the p2j.lyra gate or document why the synthesis is Lyra-only and add an equivalent fallback for the standard path. Please don't limit this to Lyra. If for any reason we run a test directly with Playwright this workaround won't work.
#206 Updated by Sergey Ivanovskiy 2 months ago
At least we need to add comments before evt.key = undefined || evt.key "Unidentified" || evt.key ""
#207 Updated by Sergey Ivanovskiy 2 months ago
Th 8-th issue should be discussed because we should not need to send mouse and key events to the business layer. It is supposed that events are performed in UI thread so the dialog is directed to show sequentially. The modal dialog is shown above the application view and it does not matter which state has the business cursor at the moment before the modal dialog appears.
[MAJOR] functional MouseHandler.processMouseMove: The new if (p2j.isDialogDisplayed()) return; is placed BEFORE the !p2j.screen.canProcessOsEvent(evt, win) && !sendMouseMove check, defeating the documented force-send pathway used by setGlobalCursor where me.sendMouseMove = true forces one mousemove through. Even with sendMouseMove true, the event is dropped when any FWD modal dialog is up. Gate the new check with && !sendMouseMove if force-send must still pass. Please test how modal dialogs interact with a global cursor active.
#208 Updated by Sergey Ivanovskiy 2 months ago
The 9-th issue is quite clear.
[MAJOR] functional EmbeddedWebHandler.<init>: Still constructs new DojoToolkitHandler(TARGET_EMBEDDED) via the legacy constructor (forces debugMode=false). The new DOJO_SOURCE_DEBUG flag has no effect on the embedded web app. Either plumb the flag here or document the limitation in the ConfigItem javadoc.
#209 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
At least we need to add comments before
evt.key = undefined || evt.key "Unidentified" || evt.key ""
Please see #10915-186.
#210 Updated by Sergey Ivanovskiy 2 months ago
OK. I will leave this and remove p2j.lyra guard.
#211 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
Th 8-th issue should be discussed because we should not need to send mouse and key events to the business layer. It is supposed that events are performed in UI thread so the dialog is directed to show sequentially. The modal dialog is shown above the application view and it does not matter which state has the business cursor at the moment before the modal dialog appears.
[MAJOR] functional MouseHandler.processMouseMove: The new if (p2j.isDialogDisplayed()) return; is placed BEFORE the !p2j.screen.canProcessOsEvent(evt, win) && !sendMouseMove check, defeating the documented force-send pathway used by setGlobalCursor where me.sendMouseMove = true forces one mousemove through. Even with sendMouseMove true, the event is dropped when any FWD modal dialog is up. Gate the new check with && !sendMouseMove if force-send must still pass. Please test how modal dialogs interact with a global cursor active.
The question is should the global cursor be set to the default when a non-legacy modal dialog is displayed? I would say it should, but then after it is dismissed it should be reverted back to the previously set global cursor. This is not a major issue, but it surfaced because the changes modify the previous behavior.
#212 Updated by Sergey Ivanovskiy 2 months ago
Sergey Ivanovskiy wrote:
The second issue is really came from my changes in which I did the dialog without closed button x but forgot to remove
addTrigger("onCancel",.)
This can be discussed. I supposed initially that these dialogs have no Close x button. Should they have this button? At least the server unavailable dialog can have this button.
#213 Updated by Sergey Ivanovskiy 2 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Th 8-th issue should be discussed because we should not need to send mouse and key events to the business layer. It is supposed that events are performed in UI thread so the dialog is directed to show sequentially. The modal dialog is shown above the application view and it does not matter which state has the business cursor at the moment before the modal dialog appears.
[MAJOR] functional MouseHandler.processMouseMove: The new if (p2j.isDialogDisplayed()) return; is placed BEFORE the !p2j.screen.canProcessOsEvent(evt, win) && !sendMouseMove check, defeating the documented force-send pathway used by setGlobalCursor where me.sendMouseMove = true forces one mousemove through. Even with sendMouseMove true, the event is dropped when any FWD modal dialog is up. Gate the new check with && !sendMouseMove if force-send must still pass. Please test how modal dialogs interact with a global cursor active.
The question is should the global cursor be set to the default when a non-legacy modal dialog is displayed? I would say it should, but then after it is dismissed it should be reverted back to the previously set global cursor. This is not a major issue, but it surfaced because the changes modify the previous behavior.
I do not know how to do it because the cursor must be controlled by the business logic. This part is not elaborated. Especially when we change the global cursor trying to restore some intermediate state when the non-legacy dialog is completed.
#214 Updated by Sergey Ivanovskiy 2 months ago
I do not know how to do it because the cursor must be controlled by the business logic. This part is not elaborated. Especially when we change the global cursor trying to restore some intermediate state when the non-legacy dialog is completed.
Hynek, I meant that the cursor position and the restored cursor can be unrelated. Should we do this?
#215 Updated by Sergey Ivanovskiy 2 months ago
I committed rev 16661 (10915a) and started code review. I did not do anything with these issues: issue 6, 8, 9.
#216 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
I do not know how to do it because the cursor must be controlled by the business logic. This part is not elaborated. Especially when we change the global cursor trying to restore some intermediate state when the non-legacy dialog is completed.
Hynek, I meant that the cursor position and the restored cursor can be unrelated. Should we do this?
Ideally the behavior should not change from trunk. But the related code changed, so I suggest you test to change global cursor, display a dialog and then close it. Compare the behavior against trunk.
#217 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
Sergey Ivanovskiy wrote:
The second issue is really came from my changes in which I did the dialog without closed button x but forgot to remove
addTrigger("onCancel",.)This can be discussed. I supposed initially that these dialogs have no Close x button. Should they have this button? At least the server unavailable dialog can have this button.
I don't think close title button is necessary here as the dialog buttons already provide the required ui flow.
#218 Updated by Sergey Ivanovskiy 2 months ago
I have these critical issues rooted in the legacy code. Could those be fixed in new optimization task?
- [CRITICAL] performance
AbstractModulesHandler.deliverModule: The method issynchronized, serializing every dojo/web-resource request through a single monitor per handler instance. The lock exists only becauseAbstractHandlerCommons.bufferis a shared mutable instance field; making the buffer a local insendResponsewould remove the need for synchronization. WithDOJO_SOURCE_DEBUG=trueeach miss triggers a secondClassLoader.getResourceunder the same lock. - [CRITICAL] performance
AbstractHandlerCommons.sendResponse: The sharedprivate byte[] buffer = new byte[BUFFER_SIZE]instance field forces the caller to synchronize, becoming the choke point for the module handlers. Allocate the buffer per-call (or useis.transferTo(os)) so concurrent module requests can run in parallel. - [CRITICAL] performance
AbstractModulesHandler.deliverModule: NoETag/Last-Modified/If-None-Matchhandling for dojo or webjar modules — every/dojo-toolkit/...request returns a full 200 body, while/clientand/commonviaHashedResourceHandlercorrectly emit ETags and return 304s. UnderDOJO_SOURCE_DEBUG=trueeach (large) uncompressed module is re-downloaded on every page load.
#219 Updated by Sergey Ivanovskiy 2 months ago
I ran several rounds of the review. The process yielded highly useful insights because the codebase is both asynchronous and generic, presenting numerous complex use cases. However, there is a distinct downside to this approach: later iterations continuously uncover new issues, likely because the LLM is following the statistically high-probability continuation of the ongoing review context.
Frankly, this process became exhausting due to the immense cognitive load required to trace every asynchronous execution path and account for all edge cases. On the positive side, it served as great training. Ultimately, I believe that if code changes were tightly scoped to a few minor fixes per iteration, passing the AI review would be a much easier and more manageable process.
#220 Updated by Sergey Ivanovskiy 2 months ago
Committed rev 16625. There are edge cases that still not fixed.
#221 Updated by Teodor Gorghe 2 months ago
Sergey Ivanovskiy wrote:
I have these critical issues rooted in the legacy code. Could those be fixed in new optimization task?
- [CRITICAL] performance
AbstractModulesHandler.deliverModule: NoETag/Last-Modified/If-None-Matchhandling for dojo or webjar modules — every/dojo-toolkit/...request returns a full 200 body, while/clientand/commonviaHashedResourceHandlercorrectly emit ETags and return 304s. UnderDOJO_SOURCE_DEBUG=trueeach (large) uncompressed module is re-downloaded on every page load.
This is related with #11452, which I have skipped handling caching for dojo toolkit because it required more work to do, which was not related to the issue from task.
#222 Updated by Sergey Ivanovskiy 2 months ago
OK. I am trying to pass this review as soon as possible due to incoming bugs #11412 and #11485 that were fixed in 10915a.
#223 Updated by Sergey Ivanovskiy 2 months ago
I asked to prepare proposed solutions to each of the reported issues in the separated file corresponding each major issue in the ai review after the issue description at the top.
#224 Updated by Sergey Ivanovskiy 2 months ago
The results look interesting. Can they be posted? I would apply some of them because their looks are reasonable.
#225 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
Frankly, this process became exhausting due to the immense cognitive load required to trace every asynchronous execution path and account for all edge cases. On the positive side, it served as great training. Ultimately, I believe that if code changes were tightly scoped to a few minor fixes per iteration, passing the AI review would be a much easier and more manageable process.
It is important to recognize, which identified points can be safely skipped. The review is currently quite sensitive and marks even "issues" that practically never surface. For example the performance points, technically they may be correct, but do they surface when the dialogs open? If not I would just skip them.
#226 Updated by Sergey Ivanovskiy 2 months ago
- File issue_8.txt
added
OK. Please look at this issue that is not related to my diff.
#228 Updated by Sergey Ivanovskiy 2 months ago
- File issue_25.txt
added
This issue can be discussed. Hynek, please look at this change. I would apply it too.
#229 Updated by Sergey Ivanovskiy 2 months ago
Committed revision 16626 (10915a) is a good candidate for the review. Applied almost patches and running the review now.
#230 Updated by Sergey Ivanovskiy 2 months ago
Also I tested these changes with testcases.
#231 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
OK. Please look at this issue that is not related to my diff.
If it is not related to your changes and also present in trunk, please create new Redmine issue.
#232 Updated by Sergey Ivanovskiy 2 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
OK. Please look at this issue that is not related to my diff.
If it is not related to your changes and also present in trunk, please create new Redmine issue.
The source code is in src/com/goldencode/p2j/main/VirtualDesktopWebHandler.java but I am not sure the new bug should be in Runtime Infrastructure or in UI project?
#233 Updated by Hynek Cihlar 2 months ago
Sergey Ivanovskiy wrote:
If it is not related to your changes and also present in trunk, please create new Redmine issue.
The source code is in
src/com/goldencode/p2j/main/VirtualDesktopWebHandler.javabut I am not sure the new bug should be in Runtime Infrastructure or in UI project?
Runtime Infrastructure.
#234 Updated by Sergey Ivanovskiy 2 months ago
Committed rev 16628 got this result
- 0 CRITICAL — the 1 originally proposed (close() deadlock) was challenged and rejected (the postponed close runs after
locked=false; no self-referential dependency).
- ~17 MAJOR:
- Security: WebPageHandler injects admin-controlled strings into JS literals without escaping (the removeEscapedDoubleQuotes
helper is NOT an XSS sanitizer).
- ModalDialog: keydown ESC handlers blocked during 30 s Dojo-load window (eager dialogs.add vs wrappedHandler gating on
isVisible()); postponedActions drain has no try/catch; hide() failure leaves id in dialogs Set; stacked dialogs both fire on ESC
(no z-order check); non-closable dialogs still close on ESC via dijit's default onCancel; setTitle("") on non-closable overrides
explicit noTitle:true.
- chooseFiles: closeButton.onClick bypasses closeAction so dojo connect links / cancel listener / closeTimeout leak.
- SsoReauth: btnRelogin retry guaranteed to fail (state consumed on first callback); no re-entrancy guard → dijit id collision.
- Performance: AbstractModulesHandler.deliverModule synchronized + shared buffer + debug-mode doubled lookup.
- Style: 6 items (header > 110 chars, "withot" typo, brace style, missing space before (, inline braces, awkward warning
grammar).
- ~30 MINOR: postMessage nonce, dialog state interleavings, setContent dijit widget leak, addTrigger silent overwrite/drop,
removeTrigger not exposed, processMouse permanently false on edge cases, modifier-only key dismisses ConnectionRestored notice,
btnLogout hang on stuck close, query parsing duplicates, IME "Process" filter asymmetry, AbstractModulesHandler binary compat
break, mapToResource debug-mode doubled lookup + no .. defense, etc.
- Rejected: the deadlock claim; show→hide re-add race (operationGuard serializes); chooseFiles me.processMouse=false "regression"
(pre-existing); actionResultsDialog over selectUploadFilesDialog stacking (hide runs first); CHUI keyPressEmitted stale (resets
are in onkeydown, fire on every event); SsoReauth countdownInterval double-arming (cleanup clears it); pingPongWatcher
cadence-doubling (misread timer semantics); evt.repeat stuck-key scenario (browser doesn't set repeat on keyup).
Notable: the postMessage nonce finding (security) was downgraded to MINOR on grounds that exploitation already implies same-origin
XSS — consider whether defense-in-depth still justifies the nonce.
Those can be fixed now or later. Some of these are not related to these changes.
#235 Updated by Sergey Ivanovskiy about 2 months ago
- File issue_1.txt
added
This issue can be discussed. It relates to dialog messages used as translation keys and read from the directory. I postponed this fix.
#236 Updated by Hynek Cihlar about 2 months ago
Sergey Ivanovskiy wrote:
This issue can be discussed. It relates to dialog messages used as translation keys and read from the directory. I postponed this fix.
This can be ignored, the strings are coming from a trusted source - i18n bundles.
#237 Updated by Sergey Ivanovskiy about 2 months ago
OK. Committed revision 16629 (10915a) has opened major issues that can be fixed later in the different tasks.
Running new review.
#238 Updated by Sergey Ivanovskiy about 2 months ago
- Status changed from WIP to Review
Post-r16629 summary:
- 0 CRITICAL — clean.
- 11 MAJOR:
- Security: WebPageHandler still injects admin-controlled strings into JS literals without escaping (removeEscapedDoubleQuotes
is not an XSS sanitizer).
- ModalDialog: stacked-dialog ESC has no z-order check; close() returns before actually closing when locked is true (causes
dijit-id collision in SSO reauth re-entry); aria-label set from tooltip only (no text fallback) at construction — SSO reauth gets
empty aria-label; partial-construction failure leaks dijit registry entry; hide() doesn't check that.locked like close() does;
show() eager-add during in-flight close causes phantom isDialogDisplayed.
- ChooseFiles: me.processMouse stays false permanently if dialog.close() throws before finalHandler.
- SocketController.init: clicking X on restoreConnectionDialog now unconditionally redirects to logout — verify intent.
- activateWindow: dropped during Dojo module-load window (eager dialogs.add); server's ACTIVE-WINDOW diverges from user
perception.
- Performance: AbstractModulesHandler.deliverModule still synchronized due to shared instance buffer in
AbstractHandlerCommons.sendResponse.
- ~31 MINOR (functional/perf/security) plus 16 style pass-throughs.
- Rejected: 2 — old code also only set aria-label on noTitle:true (no HTML title attribute lost); EmbeddedWebHandler constructor
was always package-private (no out-of-tree binary compat to break).
- Notable: 2 MAJOR perf findings were downgraded to MINOR after challenge: the eager-add "remains forever" claim is mitigated by
every failure branch deleting the id; the u-destruction claim in chooseFiles is false (uploader is not placed inside the dialog
content).
Please review the current changes.
#239 Updated by Hynek Cihlar about 2 months ago
- Status changed from Review to Internal Test
Code review 10915a revisions 16573..16629
The changes look good. Please go ahead with regression testing, ideally you should recheck every use case involving ModalDialog including use cases such as direct upload. This is a high-impact change.
#240 Updated by Sergey Ivanovskiy about 2 months ago
- reviewer Stefanel Pezamosca added
Hynek, I found several regressions in the code. Please review the committed revision 16639 (10915a).
Stefanel, please review p2j_sso_reauth.js changes.
#241 Updated by Sergey Ivanovskiy about 2 months ago
It seems that 10915a doesn't have CHUI changes. Should I run CHUI regression tests?
#242 Updated by Hynek Cihlar about 2 months ago
Sergey Ivanovskiy wrote:
It seems that 10915a doesn't have CHUI changes. Should I run CHUI regression tests?
There are changes for Web ChUI, that must be regression tested. It's hard to say whether the changes also affect terminal ChUI, probably not, but I would run the ChUI regression tests anyway.
#243 Updated by Sergey Ivanovskiy about 2 months ago
OK. The current code p2j.ModalDialog is over complicated. I was confused by AI review at some moment. Please review only p2j_sso_reauth.js changes.
#244 Updated by Sergey Ivanovskiy about 2 months ago
I finished manual GUI testing of rev 16644 (10915a). The rest tasks are CHUI regression testing and review/testing p2j_sso_reauth.js changes. Stefanel, could you give me instructions to test Hotel Gui and p2j_sso_reauth.js changes using this authentication schema OidcSsoAuthenticator?
#245 Updated by Stefanel Pezamosca about 2 months ago
Sergey Ivanovskiy wrote:
Stefanel, could you give me instructions to test Hotel Gui and
p2j_sso_reauth.jschanges using this authentication schema OidcSsoAuthenticator?
I'll check the changes now and I can test while reviewing them if you want.
#246 Updated by Sergey Ivanovskiy about 2 months ago
Thank you. Are there any simulations for Oidc provider for testing?
#247 Updated by Stefanel Pezamosca about 2 months ago
Sergey Ivanovskiy wrote:
Thank you. Are there any simulations for Oidc provider for testing?
I use this: docker run -p 127.0.0.1:8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:26.6.2 start-dev
#248 Updated by Stefanel Pezamosca about 2 months ago
I tested the changes related to p2j.sso_reauth.js, and they look good and work well for me.
#249 Updated by Sergey Ivanovskiy about 2 months ago
Stefanel, thank you for the review.
#250 Updated by Sergey Ivanovskiy about 2 months ago
The first round of the main regression tests completed with 3 failed tests #7143-1937.
#251 Updated by Sergey Ivanovskiy about 2 months ago
Sergey Ivanovskiy wrote:
The first round of the main regression tests completed with 3 failed tests #7143-1937.
The trunk version has the same failed tests.
#252 Updated by Sergey Ivanovskiy about 2 months ago
Thus 10915a passed ctrl_c regression tests and main regression tests with 3 failed. For the trunk I got the same results.
Hynek, could 10915a be merged into the trunk?
#253 Updated by Hynek Cihlar about 2 months ago
- % Done changed from 100 to 90
- Status changed from Internal Test to WIP
Code review 10915a revisions 16580..16639
Please check the following points. The critical one should be easy to check.
- [CRITICAL] functional
ModalDialog.close: When a `documentListener` keydown trigger handler awaits `dialog.close()`, the call deadlocks permanently. `wrappedChainedListener` sets `that.locked = lock` and then does `await chainedListeners.handle(event)`, which invokes the user handler. The handler awaits `close()`, whose chained `.then` runs `await waitLockAvailable()` — which awaits g`that.locked.promise`. That promise resolves only at `lock.resolve(true)`, which is unreachable until `chainedListeners.handle` returns. Concrete triggers: pressing ESC in `restoreConnectionDialog` (p2j.socket.js `restoreConnectionDialogEscapeTrigger` awaits `restoreConnectionDialog.close()` inside the keydown handler), pressing ESC in `serverUnavailableDialog` (`serverUnavailableDialogEscapeTrigger` awaits `serverUnavailableDialog.close()`), and pressing ENTER in `openPopupDialog` (awaits `openPopupDialog.close()`). The dialog never closes, the redirect to logout / new-window never runs, and all subsequent keyboard events are blocked because `that.locked` is never released.
- [MAJOR] functional
ModalDialog.addTrigger: The `wrappedChainedListener` registered on `window` runs the user handler inside an awaited microtask (`await chainedListeners.handle(event)`), so `p2j.consumeEvent(event)` calls inside async user handlers (the keydown handlers attached in p2j.socket.js for `restoreConnectionDialog` / `serverUnavailableDialog` / `connectionRestoredDialog`) execute after the synchronous event-dispatch phase has completed; `stopPropagation`/`preventDefault` are then no-ops. Trigger: user presses ESC on the visible `restoreConnectionDialog` — the window-capture listener returns a Promise immediately, the event keeps propagating to dijit/Dialog's own ESC handler which also invokes `onCancel`, so the user's keydown handler and the application `onCancel` listener BOTH run.
- [MAJOR] functional
p2j.socket.restoreConnectionDialog/serverUnavailableDialog: Both an `onCancel` application listener AND a window-level `keydown` ESC trigger are wired to the same escape function (`restoreConnectionDialogEscapeTrigger` / `serverUnavailableDialogEscapeTrigger`). Pressing ESC fires both paths. For `restoreConnectionDialog` this runs `doRedirectToLogoutPage()` (`clearSessionAuthCookie`, `closeWebSocketSafely`, `window.fetch(logoutPage)`, then `window.top.location.replace`) twice; for `serverUnavailableDialog` it runs `setLoadingCheckpoint(100)` + `window.parent.location.replace(logoutPage)` twice. `close()` is idempotent but the redirect/fetch side effects are not — two real HTTP requests to the logout endpoint per ESC press.
- [MAJOR] functional
screen.setWaitState: Server-pushed wait-state-on (`MSG_SET_WAIT_STATE` with isWaitState=true) is silently dropped while any dialog is open and never replayed when the dialog closes. After dialog dismissal `me.isWaitState` stays false, so the global wait cursor is not shown and `lockMousePointer` takes the wrong branch (the `me.isWaitState && !ptr` check is false instead of returning early), allowing the cursor to be locked to a widget pointer while the server believes the client is in WAIT-STATE. The pre-diff `setWaitState` was unconditional; the diff introduces the desync. Concrete trigger: server enters wait-state (e.g., during a PROCESS-EVENTS pause) while any `ModalDialog` (e.g., `selectUploadFilesDialog`/`actionResultsDialog` during async user file selection, `connectionRestoredDialog`, `alertSignatureDialog`) is on-screen. How does trunk behave when global cursor is set and a reconnection modal dialog is dsisplayed?
- [MAJOR] functional
ModalDialog.close: Closing a never-shown dialog unconditionally removes the active global cursor. `restoreGlobalCursor()` runs at the tail of `close()` and tests `that.globalCursorStyle != null`; for a dialog that was constructed but never had `show()` called, `that.globalCursorStyle` is `undefined`, which fails that check (loose comparison `undefined != null` is false) and falls through to `me.removeGlobalCursor()`. Concrete trigger: `chooseFiles` direct mode — `clickOnInputFieldToSelectFiles` opens the native file picker without calling `dialog.show()`; the user cancels the picker → `cancelListener` → `closeAction` → `dialog.close()` on the never-shown `selectUploadFilesDialog`. Any global cursor (e.g. a server-set wait-state cursor active before `chooseFiles` was invoked) is silently cleared.
- [MAJOR] functional
ModalDialog.show: Re-invoking `show()` on an already-visible dialog overwrites the previously captured `that.globalCursorStyle` with the current (now-`null`) module-level `globalCursorStyle`, so `restoreGlobalCursor()` on subsequent `hide`/`close` calls `me.removeGlobalCursor()` instead of restoring the original style. Concrete trigger: a single `chooseFiles` upload session calls `actionResultsDialog.show()` unconditionally from the `onError`, `onChange` (success and validation-error branches), and `onComplete` handlers — only the `onProgress` path is guarded by `actionResultsShown`. The first `show()` captures the live cursor X and clears module-level to `null`; the second `show()` overwrites `that.globalCursorStyle` with `null`. When `closeAction` finally closes the dialog, the original X cursor is removed instead of restored.
- [MINOR] functional
StandardServer.embedded: `handlers[--num] = new EmbeddedWebHandler(ConfigItem.DOJO_SOURCE_DEBUG.read(false))` enables server-side `.js`→`.uncompressed.js` rewriting for embedded clients but logs nothing when the flag is true. `EmbeddedWebServerImpl.startupServer` (touched by the same changeset) does emit a `LOG.warning(...)` advising of degraded performance under the same condition; the embedded server-side branch in `StandardServer` is silent. Concrete trigger: set `webClient/dojoSourceDebug=true` and start the server with embedded mode enabled — operators see no log line about uncompressed Dojo serving at that wiring point. (Severity downgraded from MAJOR — operational visibility only, no runtime correctness defect.)
The commented out //p2j.consumeEvent(evt);, if it is not needed, just remove completely.
#254 Updated by Sergey Ivanovskiy about 2 months ago
CRITICAL] functional ModalDialog.close: When a `documentListener` keydown trigger handler awaits `dialog.close()`, the call deadlocks permanently. `wrappedChainedListener` sets `that.locked = lock` and then does `await chainedListeners.handle(event)`, which invokes the user handler. The handler awaits `close()`, whose chained `.then` runs `await waitLockAvailable()` — which awaits g`that.locked.promise`. That promise resolves only at `lock.resolve(true)`, which is unreachable until `chainedListeners.handle` returns. Concrete triggers: pressing ESC in `restoreConnectionDialog` (p2j.socket.js `restoreConnectionDialogEscapeTrigger` awaits `restoreConnectionDialog.close()` inside the keydown handler), pressing ESC in `serverUnavailableDialog` (`serverUnavailableDialogEscapeTrigger` awaits `serverUnavailableDialog.close()`), and pressing ENTER in `openPopupDialog` (awaits `openPopupDialog.close()`). The dialog never closes, the redirect to logout / new-window never runs, and all subsequent keyboard events are blocked because `that.locked` is never released.
Hynek, I have no critical issues in my review. This one looks odd because there are no code `wrappedChainedListener` sets `that.locked = lock`. There is no dead lock in wait close().
#255 Updated by Sergey Ivanovskiy about 2 months ago
Sergey Ivanovskiy wrote:
I finished manual GUI testing of rev 16644 (10915a). The rest tasks are CHUI regression testing and review/testing
p2j_sso_reauth.jschanges. Stefanel, could you give me instructions to test Hotel Gui andp2j_sso_reauth.jschanges using this authentication schema OidcSsoAuthenticator?
This was posted yesterday but your code review was 16639.
#256 Updated by Sergey Ivanovskiy about 2 months ago
This is my last review for rev 16444(10915a)
Modified areas: com.goldencode.p2j.main (4 files), com.goldencode.p2j.ui.client.driver.web (10 files), com.goldencode.p2j.ui.client.gui.driver.web (1 file), com.goldencode.p2j.web (3 files), com.goldencode.p2j.util (2 files), plus a translation JSON file
Domains reviewed: fwd-server-infrastructure, fwd-web-gui-driver, fwd-web-services-admin, fwd-web-login-process, fwd-i18n-translation
- [MAJOR] functional
p2j.socket.js.checkLostPings: Watcher timeout changed frompingPongIntervaltopingPongInterval >> 1andmaxLostPingsfromMath.trunc(maxIdleTime / pingPongInterval) + 1toMath.max(Math.trunc(maxIdleTime / (2 * pingPongInterval)), 2). SincelostPingsstill increments atpingPongIntervalrate (idleTimer is unchanged), the wall-clock time to declare the connection lost is roughly halved. Concrete example:maxIdleTime=60s,pingPongInterval=10s— oldmaxLostPings=7→ ~70s to declare lost; newmaxLostPings=3→ ~30s. Trigger: any deployment with a tunedpingPongInterval; lossy networks may see more false-positive disconnects than before. History entry 072 mentions a "maxLostPings logic change" but does not justify the wall-clock reduction.
- [MAJOR] style
p2j.js: Entry 034 carries an out-of-order date (20251220 predates entry 033 dated 20260326), and several lines in the multi-line description (lines 82-92) exceed the 110-character limit.
- [MAJOR] style
p2j.socket.js: The history block contains a duplicate sequence ID 081 — the old SB 081 and the new SBI 081 (renumbered to 082 in this diff) leave a duplicated 081 entry. Sequence IDs must be successive without duplicates.
- [MAJOR] style
ModalDialog.createDojoDialog: Therequire()callback body indentation does not align with thefunctionkeyword; opening brace at line 2005 is at column 9 while thefunctionkeyword sits at column 12.
- [MAJOR] style
ModalDialog.computeDialogSize: The early-return object literal (lines 2110-2119) uses deep column-aligned padding (keys at column 32) while the second return literal (lines 2150-2158) uses standard 3-space indent. Inconsistent within the same function.
- [MAJOR] style
ModalDialog.computeDialogSize: Double blank line at lines 2147-2149 betweenvar dialogHeight = ...andreturn. Mid-function double blank lines are non-standard.
- [MINOR] functional
p2j.screen.js.chooseFiles(direct=true path):chooseFilesunconditionally constructsnew p2j.ModalDialog("selectUploadFilesDialog", ...)at p2j.screen.js:7942, whose constructor synchronously callscreateDojoDialog→new Dialog({id: that.id})at p2j.js:2016 which reserves the dijit registry id. Fordirect=true,dialog.show()is never called, sodialogs.add(that.id)never runs andp2j.isDialogDisplayed()stays false. A second user mouse event (mousedown/mouseup/click each independently callprocessDirectUploadat p2j.screen.js:1244/1295/1343, gated only byisDialogDisplayed()) before the firstdojo.readycallback completes can reachchooseFiles(true, ...)again, producing a secondnew Dialog({id: "selectUploadFilesDialog"})that throws on the id collision. No upstream re-entry guard exists.
- [MINOR] style
ModalDialog.restoreGlobalCursor: Emptyifbranch with only a comment as body (p2j.js:2389-2392).
- [MINOR] style
ModalDialog.show: Ternary assignment continuation (lines 2415-2417) uses excessive right-padding instead of normal 3-space wrap.
- [MINOR] style
ModalDialog.removeAllChildren: Missing space betweenwhilekeyword and(at p2j.js:2620.
- [MINOR] style
ModalDialog.close:forEachcallback brace not aligned withfunctionkeyword (p2j.js:3010-3019).
- [MINOR] style
WebPageHandler.WebPageKeysProvider: Missing blank line before the newStringBuilder dojoConfigdeclaration block at line 257.
- [MINOR] style
EmbeddedWebServerImpl: Warning message concatenation uses a leading-space-inside-string join rather than trailing-space-on-prior-segment; continuation indent at 6 spaces rather than 3.
- [MINOR] style
Utils.removeEscapedDoubleQuotes: Double blank line mid-method between theif (text == null)block andint end = text.length();.
- [MINOR] style
p2j.sso_reauth.js.handleSsoReauth: Missing space incatch(e)at line 1845 (should becatch (e)).
- [MINOR] style
p2j.socket.js.createOpenPopupDialog: Function declaration ends with};— top-levelfunctiondeclarations should not have a trailing semicolon.
Hynek, could it be accepted?
#257 Updated by Sergey Ivanovskiy about 2 months ago
- Status changed from WIP to Review
- % Done changed from 90 to 100
#258 Updated by Hynek Cihlar about 2 months ago
Sergey Ivanovskiy wrote:
Sergey Ivanovskiy wrote:
I finished manual GUI testing of rev 16644 (10915a). The rest tasks are CHUI regression testing and review/testing
p2j_sso_reauth.jschanges. Stefanel, could you give me instructions to test Hotel Gui andp2j_sso_reauth.jschanges using this authentication schema OidcSsoAuthenticator?This was posted yesterday but your code review was 16639.
You are right, I didn't update to the latest.
What about the //p2j.consumeEvent(evt), if not needed, please remove and go ahead with regression testing.
#259 Updated by Sergey Ivanovskiy about 2 months ago
OK. I tested manually all dialogs and Stefanel reviewed/tested Oidc dialogs. CHUI regression tests are passed.
#260 Updated by Hynek Cihlar about 2 months ago
Sergey Ivanovskiy wrote:
OK. I tested manually all dialogs and Stefanel reviewed/tested Oidc dialogs. CHUI regression tests are passed.
Did you also test Web ChUI?
#261 Updated by Sergey Ivanovskiy about 2 months ago
Yes, Hotel, Hotel_GUI, the customers applications and testcases. Committed rev 16645 (10915a) removed commented code.
#262 Updated by Hynek Cihlar about 2 months ago
No more testing planned?
#263 Updated by Sergey Ivanovskiy about 2 months ago
Yes, I tested rev 16644 (10915a) but as rev 16645 is only a cleanup, then it seems done.
#264 Updated by Hynek Cihlar about 2 months ago
- Status changed from Review to Merge Pending
Sergey Ivanovskiy wrote:
Yes, I tested rev 16644 (10915a) but as rev 16645 is only a cleanup, then it seems done.
OK, please merge 10915a to trunk.
#265 Updated by Sergey Ivanovskiy about 2 months ago
- Status changed from Merge Pending to Test
10915a was merged into the trunk as rev 16585 and then archived.