Merge pull request #618 from sbcgua/master

Stage page UX improvements
This commit is contained in:
Lars Hvam 2017-02-13 15:18:38 +01:00 committed by GitHub
commit 659225ac5c
7 changed files with 306 additions and 148 deletions

View File

@ -24,12 +24,12 @@ img { border: 0px; vertical-align: middle; }
table { border-collapse: collapse; } table { border-collapse: collapse; }
pre { display: inline; } pre { display: inline; }
form input, textarea, select { input, textarea, select {
border: 1px solid #DDD;
padding: 3px 6px; padding: 3px 6px;
border: 1px solid #ddd;
} }
form input:focus, textarea:focus { input:focus, textarea:focus {
border: 1px solid #8cadd9; border: 1px solid #8cadd9;
} }
@ -373,7 +373,6 @@ table.repo_tab {
} }
.stage_tab th { .stage_tab th {
color: #BBB; color: #BBB;
font-size: 10pt;
text-align: left; text-align: left;
font-weight: normal; font-weight: normal;
background-color: #edf2f9; background-color: #edf2f9;
@ -382,22 +381,23 @@ table.repo_tab {
.stage_tab td.status { .stage_tab td.status {
width: 2em; width: 2em;
text-align: center; text-align: center;
color: #ccc;
background-color: #fafafa;
} }
.stage_tab td.highlight {
color: #444 !important;
font-weight: bold;
}
.stage_tab td.cmd a { padding: 0px 4px; }
.stage_tab th.cmd a { padding: 0px 4px; }
.stage_tab td.method { color: #ccc; }
.stage_tab td.user { color: #aaa; }
.stage_tab td.type { color: #aaa; }
.stage_tab tbody tr:first-child td { padding-top: 0.5em; } .stage_tab tbody tr:first-child td { padding-top: 0.5em; }
.stage_tab tbody tr:last-child td { padding-bottom: 0.5em; } .stage_tab tbody tr:last-child td { padding-bottom: 0.5em; }
.stage_tab td.cmd a { padding: 0px 4px; } .stage_tab mark {
color: white;
/* STAGE */ background-color: #79a0d2;
.stage_tab td.method {
color: #ccc;
}
.stage_tab tr.firstrow td { border-top: 0px; }
.stage_tab tr.title td {
color: #BBB;
font-size: 10pt;
background-color: #edf2f9;
padding: 4px 0.5em;
text-align: center;
} }
/* COMMIT */ /* COMMIT */

View File

@ -32,6 +32,10 @@ CLASS lcl_gui_chunk_lib DEFINITION FINAL.
RETURNING VALUE(ro_html) TYPE REF TO lcl_html RETURNING VALUE(ro_html) TYPE REF TO lcl_html
RAISING lcx_exception. RAISING lcx_exception.
CLASS-METHODS render_js_error_banner
RETURNING VALUE(ro_html) TYPE REF TO lcl_html
RAISING lcx_exception.
ENDCLASS. "lcl_gui_chunk_lib ENDCLASS. "lcl_gui_chunk_lib
CLASS lcl_gui_chunk_lib IMPLEMENTATION. CLASS lcl_gui_chunk_lib IMPLEMENTATION.
@ -196,10 +200,17 @@ CLASS lcl_gui_chunk_lib IMPLEMENTATION.
lv_error = iv_error. lv_error = iv_error.
ENDIF. ENDIF.
ro_html->add( '<div class="dummydiv attention">' ). ro_html->add( '<div class="dummydiv error">' ).
ro_html->add( |{ lcl_html=>icon( 'alert/red' ) } Error: { lv_error }| ). ro_html->add( |{ lcl_html=>icon( 'alert/red' ) } Error: { lv_error }| ).
ro_html->add( '</div>' ). ro_html->add( '</div>' ).
ENDMETHOD. "render_error ENDMETHOD. "render_error
METHOD render_js_error_banner.
CREATE OBJECT ro_html.
ro_html->add( '<div id="js-error-banner" class="dummydiv error">' ).
ro_html->add( |{ lcl_html=>icon( 'alert/red' ) } JS init error, please log an issue| ).
ro_html->add( '</div>' ).
ENDMETHOD. "render_js_error_stub
ENDCLASS. "lcl_gui_chunk_lib ENDCLASS. "lcl_gui_chunk_lib

View File

@ -71,6 +71,22 @@ function submitFormById(id) {
document.getElementById(id).submit(); document.getElementById(id).submit();
} }
// JS error stub
function errorStub(event) {
var element = event.target || event.srcElement;
var targetName = element.id || element.name || "???";
alert("JS Error, please log an issue (@" + targetName + ")");
}
// confirm JS initilization
function confirmInitialized() {
var errorBanner = document.getElementById("js-error-banner");
if (errorBanner) {
errorBanner.style.display = "none";
}
debugOutput("js: OK"); // Final final confirmation :)
}
/********************************************************** /**********************************************************
* STAGE PAGE Logic * STAGE PAGE Logic
**********************************************************/ **********************************************************/
@ -78,131 +94,219 @@ function submitFormById(id) {
// Stage helper constructor // Stage helper constructor
function StageHelper(params) { function StageHelper(params) {
this.pageSeed = params.seed; this.pageSeed = params.seed;
this.tabId = params.stageTabId;
this.formAction = params.formAction; this.formAction = params.formAction;
this.commitNodeId = params.commitNodeId;
this.commitAllNodeId = params.commitAllNodeId;
this.choiseCount = 0; this.choiseCount = 0;
this.setHook(); this.lastSearchValue = "";
// DOM nodes
this.dom = {
stageTab: document.getElementById(params.ids.stageTab),
commitBtn: document.getElementById(params.ids.commitBtn),
commitAllBtn: document.getElementById(params.ids.commitAllBtn),
objectSearch: document.getElementById(params.ids.objectSearch),
fileCounter: document.getElementById(params.ids.fileCounter)
};
// Table columns (autodetection)
this.col = this.detectColumns();
// Constants
this.HIGHLIGHT_STYLE = "highlight";
this.STATUS = {
"add": "A",
"remove": "R",
"ignore": "I",
"reset": "?"
};
this.setHooks();
} }
// Hook global click listener on table, load/unload actions // Hook global click listener on table, load/unload actions
StageHelper.prototype.setHook = function() { StageHelper.prototype.setHooks = function() {
var stageTab = document.getElementById(this.tabId); this.dom.stageTab.onclick = this.onTableClick.bind(this);
this.dom.commitBtn.onclick = this.submit.bind(this);
if (stageTab.addEventListener) { this.dom.objectSearch.oninput = this.onSearch.bind(this);
stageTab.addEventListener("click", this.onEvent.bind(this)); this.dom.objectSearch.onkeypress = this.onSearch.bind(this);
} else {
stageTab.attachEvent("onclick", this.onEvent.bind(this));
}
window.onbeforeunload = this.onPageUnload.bind(this); window.onbeforeunload = this.onPageUnload.bind(this);
window.onload = this.onPageLoad.bind(this); window.onload = this.onPageLoad.bind(this);
} }
// Detect column index
StageHelper.prototype.detectColumns = function() {
var dataRow = this.dom.stageTab.tBodies[0].rows[0];
var cols = {};
for (var i = dataRow.cells.length - 1; i >= 0; i--) {
if (dataRow.cells[i].className) cols[dataRow.cells[i].className] = i;
}
return cols;
}
// Store table state on leaving the page // Store table state on leaving the page
StageHelper.prototype.onPageUnload = function() { StageHelper.prototype.onPageUnload = function() {
if (!window.sessionStorage) return;
var data = this.collectData(); var data = this.collectData();
window.sessionStorage.setItem(this.pageSeed, JSON.stringify(data)); window.sessionStorage.setItem(this.pageSeed, JSON.stringify(data));
} }
// Re-store table state on entering the page // Re-store table state on entering the page
StageHelper.prototype.onPageLoad = function() { StageHelper.prototype.onPageLoad = function() {
var data = JSON.parse(window.sessionStorage.getItem(this.pageSeed));
var stage = document.getElementById(this.tabId);
for (var i = stage.rows.length - 1; i >= 0; i--) { var data = window.sessionStorage && JSON.parse(window.sessionStorage.getItem(this.pageSeed));
var tr = stage.rows[i];
if (tr.parentNode.tagName == "THEAD") continue;
var context = tr.parentNode.className;
var cmd = data[tr.cells[1].innerText];
if (!cmd) continue;
this.formatTR(tr, cmd, context); if (data) {
this.choiseCount += (this.countChoiceImpact(cmd) > 0) ? 1 : 0; this.iterateStageTab(function (row) {
var status = data[row.cells[this.col.name].innerText];
this.updateRow(row, status || this.STATUS.reset);
});
debugOutput("StageHelper.onPageLoad from Storage");
} else { // Render initial commands
this.iterateStageTab(function (row) {
this.updateRow(row, this.STATUS.reset);
});
debugOutput("StageHelper.onPageLoad initial state");
} }
this.updateMenu(); this.updateMenu();
} }
// Event handler, change status // Table event handler, change status
StageHelper.prototype.onEvent = function (event) { StageHelper.prototype.onTableClick = function (event) {
if (!event.target) { var target = event.target || event.srcElement;
if (event.srcElement) { event.target = event.srcElement; } if (!target || target.tagName != "A") return;
else { return; }
var td = target.parentNode;
if (!td || ["TD","TH"].indexOf(td.tagName) == -1 || td.className != "cmd") return;
var status = this.STATUS[target.innerText]; // Convert anchor text to status
var targetRow = td.parentNode;
if (td.tagName === "TD") {
this.updateRow(targetRow, status);
} else { // TH
this.iterateStageTab(function (row) {
if (row.style.display !== "none" // Not filtered out
&& row.className === targetRow.className // Same context as header
) {
this.updateRow(row, status);
}
});
} }
if (event.target.tagName != "A") return;
var td = event.target.parentNode;
if (!td || td.tagName != "TD" || td.className != "cmd") return;
var cmd = event.target.innerText;
var tr = td.parentNode;
var context = tr.parentNode.className;
switch (cmd) {
case "add": cmd = "A"; break;
case "remove": cmd = "R"; break;
case "ignore": cmd = "I"; break;
case "reset": cmd = "?"; break;
}
this.formatTR(tr, cmd, context);
this.choiseCount += this.countChoiceImpact(cmd);
this.updateMenu(); this.updateMenu();
} }
// Update action counter -> affects menu update after // Search object
StageHelper.prototype.countChoiceImpact = function (cmd) { StageHelper.prototype.onSearch = function (e) {
if ("ARI".indexOf(cmd) > -1) { return 1; } if ( // Enter hit or clear, IE SUCKS !
else if ("?".indexOf(cmd) > -1) { return -1; } e.type === "input" && !e.target.value && this.lastSearchValue
else { alert("Unknown command"); } || e.type === "keypress" && e.which === 13 ) {
this.lastSearchValue = e.target.value;
this.iterateStageTab(this.applyFilterToRow, e.target.value);
}
} }
// Re-format table line StageHelper.prototype.applyFilterToRow = function (row, filter) {
StageHelper.prototype.formatTR = function (tr, cmd, context) { var td = row.cells[this.col.name];
var cmdReset = "<a>reset</a>"; var origTxt = td.innerText; // without tags
var cmdLocal = "<a>add</a>"; var newTxt = "";
var cmdRemote = "<a>ignore</a><a>remove</a>";
tr.cells[0].innerText = cmd; if (filter) {
if (cmd == "?") { newTxt = origTxt.replace(filter, "<mark>"+filter+"</mark>");
tr.cells[0].style.color = "#CCC"; //grey if (newTxt !== origTxt) { // fits filter
tr.cells[2].innerHTML = (context == "local") ? cmdLocal : cmdRemote; row.style.display = "table-row";
} else { } else {
tr.cells[0].style.color = ""; row.style.display = "none";
tr.cells[2].innerHTML = cmdReset; }
} else { // No filter -> just reset the value
newTxt = origTxt;
row.style.display = "table-row";
}
if (td.firstChild.tagName === "A") {
td.firstChild.innerHTML = newTxt;
} else {
td.innerHTML = newTxt;
}
}
// Get how status should affect object counter
StageHelper.prototype.getStatusImpact = function (status) {
if (typeof status !== "string"
|| status.length !== 1
|| "ARI?".indexOf(status) == -1) {
alert("Unknown status");
} else {
return (status !== this.STATUS.reset) ? 1 : 0;
}
}
// Update table line
StageHelper.prototype.updateRow = function (row, newStatus) {
var oldStatus = row.cells[this.col.status].innerText;
if (oldStatus !== newStatus) {
row.cells[this.col.status].innerText = newStatus;
if (newStatus === this.STATUS.reset) {
row.cells[this.col.status].classList.remove(this.HIGHLIGHT_STYLE);
} else {
row.cells[this.col.status].classList.add(this.HIGHLIGHT_STYLE);
}
this.updateRowCommand(row, newStatus);
} else if (!row.cells[this.col.cmd].innerText) {
this.updateRowCommand(row, newStatus); // For initial run
}
this.choiseCount += this.getStatusImpact(newStatus) - this.getStatusImpact(oldStatus);
}
// Update command cell (render set of commands)
StageHelper.prototype.updateRowCommand = function (row, status) {
var CMD_RESET = "<a>reset</a>";
var CMD_LOCAL = "<a>add</a>";
var CMD_REMOTE = "<a>ignore</a><a>remove</a>";
if (status === this.STATUS.reset) {
row.cells[this.col.cmd].innerHTML = (row.className == "local") ? CMD_LOCAL : CMD_REMOTE;
} else {
row.cells[this.col.cmd].innerHTML = CMD_RESET;
} }
} }
// Update menu items visibility // Update menu items visibility
StageHelper.prototype.updateMenu = function () { StageHelper.prototype.updateMenu = function () {
if (this.choiseCount > 0) { this.dom.commitBtn.style.display = (this.choiseCount > 0) ? "inline" : "none";
document.getElementById(this.commitNodeId).style.display = "inline"; this.dom.commitAllBtn.style.display = (this.choiseCount > 0) ? "none" : "inline";
document.getElementById(this.commitAllNodeId).style.display = "none"; this.dom.fileCounter.innerHTML = this.choiseCount.toString();
} else {
document.getElementById(this.commitNodeId).style.display = "none";
document.getElementById(this.commitAllNodeId).style.display = "inline";
}
} }
// Submin stage state to the server // Submit stage state to the server
StageHelper.prototype.submit = function () { StageHelper.prototype.submit = function () {
var data = this.collectData(); submitSapeventForm(this.collectData(), this.formAction);
submitSapeventForm(data, this.formAction);
} }
// Extract data from the table // Extract data from the table
StageHelper.prototype.collectData = function () { StageHelper.prototype.collectData = function () {
var stage = document.getElementById(this.tabId);
var data = {}; var data = {};
this.iterateStageTab(function (row) {
for (var i = 0; i < stage.rows.length; i++) { data[row.cells[this.col.name].innerText] = row.cells[this.col.status].innerText;
var row = stage.rows[i]; });
if (row.parentNode.tagName == "THEAD") continue;
data[row.cells[1].innerText] = row.cells[0].innerText;
}
return data; return data;
} }
// table iteration helper
StageHelper.prototype.iterateStageTab = function (cb /*, ...*/) {
for (var b = 0, bN = this.dom.stageTab.tBodies.length; b < bN; b++) {
var tbody = this.dom.stageTab.tBodies[b];
for (var r = 0, rN = tbody.rows.length; r < rN; r++) {
args = [tbody.rows[r]].concat(Array.prototype.slice.call(arguments, 1));
cb.apply(this, args); // callback
}
}
}

View File

@ -55,7 +55,7 @@ CLASS lcl_object_smim IMPLEMENTATION.
SELECT SINGLE chng_user FROM smimloio INTO rv_user SELECT SINGLE chng_user FROM smimloio INTO rv_user
WHERE loio_id = lv_loio. "#EC CI_GENBUFF WHERE loio_id = lv_loio. "#EC CI_GENBUFF
IF sy-subrc <> 0. IF sy-subrc <> 0 OR rv_user IS INITIAL.
rv_user = c_user_unknown. rv_user = c_user_unknown.
ENDIF. ENDIF.

View File

@ -176,7 +176,7 @@ CLASS lcl_gui_page IMPLEMENTATION.
IF lo_script IS BOUND AND lo_script->is_empty( ) = abap_false. IF lo_script IS BOUND AND lo_script->is_empty( ) = abap_false.
ro_html->add( '<script type="text/javascript">' ). ro_html->add( '<script type="text/javascript">' ).
ro_html->add( lo_script ). ro_html->add( lo_script ).
ro_html->add( 'debugOutput("js: OK");' ). ro_html->add( 'confirmInitialized();' ).
ro_html->add( '</script>' ). ro_html->add( '</script>' ).
ENDIF. ENDIF.

View File

@ -101,10 +101,13 @@ CLASS lcl_gui_page_commit IMPLEMENTATION.
lt_stage = mo_stage->get_all( ). lt_stage = mo_stage->get_all( ).
ro_html->add( '<table class="stage_tab">' ). ro_html->add( '<table class="stage_tab">' ).
ro_html->add( '<tr class="title firstrow">'). ro_html->add( '<thead>' ).
ro_html->add( '<td colspan="2">Staged files</td>'). ro_html->add( '<tr>').
ro_html->add( '<th colspan="2">Staged files</th>').
ro_html->add( '</tr>' ). ro_html->add( '</tr>' ).
ro_html->add( '</thead>' ).
ro_html->add( '<tbody>' ).
LOOP AT lt_stage ASSIGNING <ls_stage>. LOOP AT lt_stage ASSIGNING <ls_stage>.
ro_html->add( '<tr>' ). ro_html->add( '<tr>' ).
ro_html->add( '<td class="method">' ). ro_html->add( '<td class="method">' ).
@ -115,6 +118,7 @@ CLASS lcl_gui_page_commit IMPLEMENTATION.
ro_html->add( '</td>' ). ro_html->add( '</td>' ).
ro_html->add( '</tr>' ). ro_html->add( '</tr>' ).
ENDLOOP. ENDLOOP.
ro_html->add( '</tbody>' ).
ro_html->add( '</table>' ). ro_html->add( '</table>' ).

View File

@ -32,8 +32,9 @@ CLASS lcl_gui_page_stage DEFINITION FINAL INHERITING FROM lcl_gui_page.
render_list render_list
RETURNING VALUE(ro_html) TYPE REF TO lcl_html, RETURNING VALUE(ro_html) TYPE REF TO lcl_html,
render_file render_file
IMPORTING is_file TYPE ty_file IMPORTING iv_context TYPE string
iv_context TYPE string is_file TYPE ty_file
is_item TYPE ty_item OPTIONAL
RETURNING VALUE(ro_html) TYPE REF TO lcl_html, RETURNING VALUE(ro_html) TYPE REF TO lcl_html,
render_menu render_menu
RETURNING VALUE(ro_html) TYPE REF TO lcl_html, RETURNING VALUE(ro_html) TYPE REF TO lcl_html,
@ -44,6 +45,8 @@ CLASS lcl_gui_page_stage DEFINITION FINAL INHERITING FROM lcl_gui_page.
METHODS process_stage_list METHODS process_stage_list
IMPORTING it_postdata TYPE cnht_post_data_tab IMPORTING it_postdata TYPE cnht_post_data_tab
RAISING lcx_exception. RAISING lcx_exception.
METHODS build_menu
RETURNING VALUE(ro_menu) TYPE REF TO lcl_html_toolbar.
ENDCLASS. ENDCLASS.
@ -52,9 +55,9 @@ CLASS lcl_gui_page_stage IMPLEMENTATION.
METHOD constructor. METHOD constructor.
super->constructor( ). super->constructor( ).
ms_control-page_title = 'STAGE'. ms_control-page_title = 'STAGE'.
mo_repo = io_repo. mo_repo = io_repo.
ms_files = lcl_stage_logic=>get( mo_repo ). ms_files = lcl_stage_logic=>get( mo_repo ).
CREATE OBJECT mo_stage CREATE OBJECT mo_stage
@ -64,8 +67,21 @@ CLASS lcl_gui_page_stage IMPLEMENTATION.
GET TIME STAMP FIELD mv_ts. GET TIME STAMP FIELD mv_ts.
ms_control-page_menu = build_menu( ).
ENDMETHOD. ENDMETHOD.
METHOD build_menu.
CREATE OBJECT ro_menu.
IF lines( ms_files-local ) > 0.
ro_menu->add( iv_txt = |All diffs|
iv_act = |{ gc_action-go_diff }?key={ mo_repo->get_key( ) }| ).
ENDIF.
ENDMETHOD. "build_menu
METHOD lif_gui_page~on_event. METHOD lif_gui_page~on_event.
FIELD-SYMBOLS: <ls_file> LIKE LINE OF ms_files-local. FIELD-SYMBOLS: <ls_file> LIKE LINE OF ms_files-local.
@ -146,25 +162,25 @@ CLASS lcl_gui_page_stage IMPLEMENTATION.
CREATE OBJECT ro_html. CREATE OBJECT ro_html.
ro_html->add( '<table id="stage_tab" class="stage_tab">' ). ro_html->add( '<table id="stageTab" class="stage_tab">' ).
" Local changes " Local changes
LOOP AT ms_files-local ASSIGNING <ls_local>. LOOP AT ms_files-local ASSIGNING <ls_local>.
AT FIRST. AT FIRST.
ro_html->add('<thead><tr>'). ro_html->add('<thead><tr class="local">').
ro_html->add('<th></th><th colspan="2">LOCAL</th>' ). ro_html->add('<th>Type</th>').
ro_html->add('<th>' ). ro_html->add('<th>Files to add (click to see diff)</th>' ).
IF lines( ms_files-local ) > 1. ro_html->add('<th>Changed by</th>').
ro_html->add_a( iv_txt = |{ lines( ms_files-local ) } diffs| ro_html->add('<th></th>' ). " Status
iv_act = |{ gc_action-go_diff }?key={ mo_repo->get_key( ) }| ). ro_html->add('<th class="cmd">&#x2193;<a>add</a>/<a>reset</a>&#x2193;</th>' ).
ENDIF.
ro_html->add('</th>').
ro_html->add('<th>Last changed by</th>').
ro_html->add('</tr></thead>'). ro_html->add('</tr></thead>').
ro_html->add('<tbody class="local">'). ro_html->add('<tbody>').
ENDAT. ENDAT.
ro_html->add( render_file( is_file = <ls_local>-file iv_context = 'local' ) ). ro_html->add( render_file(
iv_context = 'local'
is_file = <ls_local>-file
is_item = <ls_local>-item ) ). " TODO Refactor, unify structure
AT LAST. AT LAST.
ro_html->add('</tbody>'). ro_html->add('</tbody>').
@ -174,13 +190,19 @@ CLASS lcl_gui_page_stage IMPLEMENTATION.
" Remote changes " Remote changes
LOOP AT ms_files-remote ASSIGNING <ls_remote>. LOOP AT ms_files-remote ASSIGNING <ls_remote>.
AT FIRST. AT FIRST.
ro_html->add('<thead><tr>'). ro_html->add( '<thead><tr class="remote">' ).
ro_html->add('<th></th><th colspan="3">REMOTE</th>' ). ro_html->add( '<th></th>' ). " Type
ro_html->add('</tr></thead>'). ro_html->add( '<th colspan="2">Files to remove or non-code</th>' ).
ro_html->add('<tbody class="remote">'). ro_html->add( '<th></th>' ). " Status
ro_html->add( '<th class="cmd">' &&
'&#x2193;<a>ignore</a><a>remove</a><a>reset</a>&#x2193;</th>' ).
ro_html->add( '</tr></thead>' ).
ro_html->add( '<tbody>' ).
ENDAT. ENDAT.
ro_html->add( render_file( is_file = <ls_remote> iv_context = 'remote' ) ). ro_html->add( render_file(
iv_context = 'remote'
is_file = <ls_remote> ) ).
AT LAST. AT LAST.
ro_html->add('</tbody>'). ro_html->add('</tbody>').
@ -194,30 +216,31 @@ CLASS lcl_gui_page_stage IMPLEMENTATION.
METHOD render_file. METHOD render_file.
DATA: lv_param TYPE string, DATA: lv_param TYPE string,
lv_user TYPE xubname. lv_filename TYPE string.
CREATE OBJECT ro_html. CREATE OBJECT ro_html.
lv_filename = is_file-path && is_file-filename.
ro_html->add( |<tr class="{ iv_context }">| ). ro_html->add( |<tr class="{ iv_context }">| ).
ro_html->add( |<td class="status" style="color: #CCC">?</td>| ).
ro_html->add( |<td>{ is_file-path && is_file-filename }</td>| ).
CASE iv_context. CASE iv_context.
WHEN 'local'. WHEN 'local'.
lv_param = lcl_html_action_utils=>file_encode( iv_key = mo_repo->get_key( ) lv_param = lcl_html_action_utils=>file_encode( iv_key = mo_repo->get_key( )
ig_file = is_file ). ig_file = is_file ).
ro_html->add( '<td class="cmd"><a>add</a></td>' ). lv_filename = lcl_html=>a( iv_txt = lv_filename
ro_html->add( '<td>' ). iv_act = |{ gc_action-go_diff }?{ lv_param }| ).
ro_html->add_a( iv_txt = 'diff' iv_act = |{ gc_action-go_diff }?{ lv_param }| ). ro_html->add( |<td class="type">{ is_item-obj_type }</td>| ).
ro_html->add( '</td>' ). ro_html->add( |<td class="name">{ lv_filename }</td>| ).
ro_html->add( |<td class="user">{ read_last_changed_by( is_file ) }</td>| ).
lv_user = read_last_changed_by( is_file ).
ro_html->add( |<td>{ lv_user }</td> | ).
WHEN 'remote'. WHEN 'remote'.
ro_html->add( '<td class="cmd"><a>ignore</a><a>remove</a></td>' ). ro_html->add( '<td class="type">-</td>' ). " Dummy for object type
ro_html->add( |<td><span class="grey">-</span></td>| ). ro_html->add( |<td class="name">{ lv_filename }</td>| ).
ro_html->add( '<td></td>' ). " Dummy for changed-by
ENDCASE. ENDCASE.
ro_html->add( |<td class="status">?</td>| ).
ro_html->add( '<td class="cmd"></td>' ). " Command added in JS
ro_html->add( '</tr>' ). ro_html->add( '</tr>' ).
ENDMETHOD. "render_file ENDMETHOD. "render_file
@ -228,6 +251,7 @@ CLASS lcl_gui_page_stage IMPLEMENTATION.
ro_html->add( '<div class="repo">' ). ro_html->add( '<div class="repo">' ).
ro_html->add( lcl_gui_chunk_lib=>render_repo_top( mo_repo ) ). ro_html->add( lcl_gui_chunk_lib=>render_repo_top( mo_repo ) ).
ro_html->add( lcl_gui_chunk_lib=>render_js_error_banner( ) ).
ro_html->add( render_menu( ) ). ro_html->add( render_menu( ) ).
ro_html->add( render_list( ) ). ro_html->add( render_list( ) ).
ro_html->add( '</div>' ). ro_html->add( '</div>' ).
@ -236,22 +260,29 @@ CLASS lcl_gui_page_stage IMPLEMENTATION.
METHOD render_menu. METHOD render_menu.
DATA lv_local_count TYPE i.
CREATE OBJECT ro_html. CREATE OBJECT ro_html.
lv_local_count = lines( ms_files-local ).
ro_html->add( '<div class="paddings">' ). ro_html->add( '<div class="paddings">' ).
ro_html->add_a( iv_act = 'gHelper.submit();' ro_html->add_a( iv_act = 'errorStub(event)' " Will be reinit by JS
iv_typ = gc_action_type-onclick iv_typ = gc_action_type-onclick
iv_id = 'act_commit' iv_id = 'commitButton'
iv_style = 'display: none' iv_style = 'display: none'
iv_txt = 'Commit' iv_txt = 'Commit (<span id="fileCounter"></span>)'
iv_opt = gc_html_opt-strong ) ##NO_TEXT. iv_opt = gc_html_opt-strong ) ##NO_TEXT.
IF lines( ms_files-local ) > 0. IF lv_local_count > 0.
ro_html->add_a( iv_act = |{ c_action-stage_all }| ro_html->add_a( iv_act = |{ c_action-stage_all }|
iv_id = 'act_commit_all' iv_id = 'commitAllButton'
iv_txt = 'Add all and commit') ##NO_TEXT. iv_txt = |Add all and commit ({ lv_local_count })| ) ##NO_TEXT.
ENDIF. ENDIF.
ro_html->add( '</div>' ). ro_html->add( '</div>' ).
ro_html->add( '<div>' ).
ro_html->add( '<input id="objectSearch" type="search" placeholder="Filter objects">' ).
ro_html->add( '</div>' ).
ENDMETHOD. "render_menu ENDMETHOD. "render_menu
METHOD scripts. METHOD scripts.
@ -260,10 +291,16 @@ CLASS lcl_gui_page_stage IMPLEMENTATION.
ro_html->add( 'var gStageParams = {' ). ro_html->add( 'var gStageParams = {' ).
ro_html->add( | seed: "stage{ mv_ts }",| ). ro_html->add( | seed: "stage{ mv_ts }",| ).
ro_html->add( ' stageTabId: "stage_tab",' ).
ro_html->add( ' formAction: "stage_commit",' ). ro_html->add( ' formAction: "stage_commit",' ).
ro_html->add( ' commitNodeId: "act_commit",' ).
ro_html->add( ' commitAllNodeId: "act_commit_all"' ). ro_html->add( ' ids: {' ).
ro_html->add( ' stageTab: "stageTab",' ).
ro_html->add( ' commitBtn: "commitButton",' ).
ro_html->add( ' commitAllBtn: "commitAllButton",' ).
ro_html->add( ' objectSearch: "objectSearch",' ).
ro_html->add( ' fileCounter: "fileCounter"' ).
ro_html->add( ' }' ).
ro_html->add( '}' ). ro_html->add( '}' ).
ro_html->add( 'var gHelper = new StageHelper(gStageParams);' ). ro_html->add( 'var gHelper = new StageHelper(gStageParams);' ).
@ -281,6 +318,8 @@ CLASS lcl_gui_page_stage IMPLEMENTATION.
CATCH lcx_exception. CATCH lcx_exception.
CLEAR rv_user. "Should not raise errors if user last changed by was not found CLEAR rv_user. "Should not raise errors if user last changed by was not found
ENDTRY. ENDTRY.
rv_user = to_lower( rv_user ).
ENDMETHOD. ENDMETHOD.
ENDCLASS. ENDCLASS.