Repo overview - rework action buttons + cosmetic changes (#4771)

* Repo overview - cosmetic changes

* extract logic to method

* Update src/ui/zcl_abapgit_gui_page_repo_over.clas.abap

Co-authored-by: abaplint[bot] <24845621+abaplint[bot]@users.noreply.github.com>

* fix if in if

* unshorten remote, move package, improve wrapping

* Add max width for columns

* Mostly working now

* add prefixes

* Remove checkbox, move package where it was

* Keyboard navigation

< > to navigate in list (arrow keys don't seem to trigger), enter to open selected

* Ellipsis for repo url, use css variable

* Fix css, js persistence

* Fix invalid function name

* add back !important to override hover color

* abaplint

* Don't use const in js

* more eslint

* Remove unused field symbol

* eslint

* Bring back repo lock icon, styling improvements

Co-authored-by: Marc Bernard <59966492+mbtools@users.noreply.github.com>
This commit is contained in:
Frederik Hudák 2021-06-14 14:44:38 +02:00 committed by GitHub
parent 6f8e3f45fa
commit d4cbf7059e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 477 additions and 219 deletions

View File

@ -17,6 +17,12 @@ CLASS zcl_abapgit_html DEFINITION
!iv_onclick TYPE string OPTIONAL !iv_onclick TYPE string OPTIONAL
RETURNING RETURNING
VALUE(rv_str) TYPE string . VALUE(rv_str) TYPE string .
CLASS-METHODS checkbox
IMPORTING
iv_id TYPE string OPTIONAL
iv_checked TYPE abap_bool OPTIONAL
RETURNING
VALUE(rv_html) TYPE string .
PROTECTED SECTION. PROTECTED SECTION.
PRIVATE SECTION. PRIVATE SECTION.
@ -58,17 +64,11 @@ CLASS zcl_abapgit_html DEFINITION
!is_context TYPE ty_indent_context !is_context TYPE ty_indent_context
RETURNING RETURNING
VALUE(rs_result) TYPE ty_study_result . VALUE(rs_result) TYPE ty_study_result .
METHODS checkbox
IMPORTING
!iv_id TYPE string
!iv_checked TYPE abap_bool OPTIONAL
RETURNING
VALUE(rv_html) TYPE string .
ENDCLASS. ENDCLASS.
CLASS ZCL_ABAPGIT_HTML IMPLEMENTATION. CLASS zcl_abapgit_html IMPLEMENTATION.
METHOD checkbox. METHOD checkbox.
@ -79,8 +79,12 @@ CLASS ZCL_ABAPGIT_HTML IMPLEMENTATION.
lv_checked = |checked|. lv_checked = |checked|.
ENDIF. ENDIF.
rv_html = |<input type="checkbox" id="{ iv_id }" { lv_checked }>|. rv_html = |<input type="checkbox" { lv_checked } |.
IF iv_id IS NOT INITIAL.
rv_html = rv_html && |id="{ iv_id }"|.
ENDIF.
rv_html = rv_html && `/>`.
ENDMETHOD. ENDMETHOD.

View File

@ -297,7 +297,7 @@ table.repo_tab {
.repo_tab tr:first-child td { border-top: 0px; } .repo_tab tr:first-child td { border-top: 0px; }
.repo_tab tr:hover { .repo_tab tr:hover {
background-color: rgb(245, 245, 245) !important; background-color: var(--theme-greyscale-dark) !important;
} }
@ -560,6 +560,9 @@ div.db_list {
overflow-x: auto; overflow-x: auto;
} }
table.db_tab{
table-layout: fixed;
}
table.db_tab pre { table.db_tab pre {
display: inline-block; display: inline-block;
overflow: hidden; overflow: hidden;
@ -578,11 +581,29 @@ table.db_tab th {
table.db_tab td { table.db_tab td {
padding: 4px 8px; padding: 4px 8px;
vertical-align: middle; vertical-align: middle;
word-break: break-all;
max-width: 250px;
} }
table.db_tab th.package {
width: 45ch;
}
table.db_tab td.data { table.db_tab td.data {
font-style: italic; font-style: italic;
} }
span.action_link.enabled{
visibility: visible;
position: relative;
}
span.action_link:not(enabled){
visibility: hidden;
position: fixed; /* so it does not take up space when hidden */
}
/* DB ENTRY DISPLAY */ /* DB ENTRY DISPLAY */
div.db_entry { div.db_entry {
padding: 0.5em; padding: 0.5em;
@ -933,7 +954,6 @@ table.commit tr .title {
.repo-overview { font-size: smaller; } .repo-overview { font-size: smaller; }
.repo-overview tbody td { height: 2em; } .repo-overview tbody td { height: 2em; }
.ro-detail { display: none; } .ro-detail { display: none; }
.ro-action { width: 260px; }
.ro-go { font-size: 150%; } .ro-go { font-size: 150%; }
/* Branch Overview Page */ /* Branch Overview Page */

View File

@ -168,6 +168,10 @@ table.db_tab th {
border-bottom-color: #333; border-bottom-color: #333;
} }
table.db_tab tr.selected {
background: rgba(92, 92, 92, 1) !important;
}
/* ERROR LOGS */ /* ERROR LOGS */
div.log { color: var(--theme-greyscale-dark); } div.log { color: var(--theme-greyscale-dark); }
.close-btn, .message-panel, .message-panel-commands a { color: var(--theme-greyscale-dark); } .close-btn, .message-panel, .message-panel-commands a { color: var(--theme-greyscale-dark); }

View File

@ -28,6 +28,11 @@ body {
font-size: var(--theme-font-size); font-size: var(--theme-font-size);
} }
a, a:visited { color: var(--theme-link-color); } a, a:visited { color: var(--theme-link-color); }
.link {
color: var(--theme-link-color);
cursor: pointer;
}
input, textarea, select { border-color: #ddd; } input, textarea, select { border-color: #ddd; }
input:focus, textarea:focus { border-color: #8cadd9; } input:focus, textarea:focus { border-color: #8cadd9; }
@ -341,8 +346,8 @@ table.diff_tab td.patch, th.patch {
.syntax-hl span.variables { color:purple; } .syntax-hl span.variables { color:purple; }
/* DEBUG INFO STYLES */ /* DEBUG INFO STYLES */
div.debug_container { div.debug_container {
color: #444; color: #444;
background-color: var(--theme-container-background-color); background-color: var(--theme-container-background-color);
} }
@ -356,6 +361,10 @@ table.db_tab th {
border-bottom-color: #ddd; border-bottom-color: #ddd;
} }
table.db_tab tr.selected {
background-color: rgba(191, 191, 191, 1) !important;
}
/* DB ENTRY DISPLAY */ /* DB ENTRY DISPLAY */
div.db_entry { div.db_entry {
background-color: var(--theme-container-background-color); background-color: var(--theme-container-background-color);

View File

@ -86,6 +86,12 @@ if (!String.prototype.startsWith) {
}); });
} }
// forEach polyfill, taken from https://developer.mozilla.org
// used for querySelectorAll results
if (window.NodeList && !NodeList.prototype.forEach) {
NodeList.prototype.forEach = Array.prototype.forEach;
}
/********************************************************** /**********************************************************
* Common functions * Common functions
**********************************************************/ **********************************************************/
@ -250,16 +256,161 @@ function RepoOverViewHelper() {
this.toggleFilterIcon(icon, this.isDetailsDisplayed); this.toggleFilterIcon(icon, this.isDetailsDisplayed);
icon = document.getElementById("icon-filter-favorite"); icon = document.getElementById("icon-filter-favorite");
this.toggleFilterIcon(icon, this.isOnlyFavoritesDisplayed); this.toggleFilterIcon(icon, this.isOnlyFavoritesDisplayed);
this.registerRowSelection();
this.registerKeyboardShortcuts();
} }
RepoOverViewHelper.prototype.setHooks = function () {
window.onload = this.onPageLoad.bind(this);
};
RepoOverViewHelper.prototype.onPageLoad = function () {
var data = window.localStorage && JSON.parse(window.localStorage.getItem(this.pageId));
if (data) {
if (data.isDetailsDisplayed) {
this.toggleItemsDetail(true);
}
if (data.isOnlyFavoritesDisplayed) {
this.toggleItemsFavorites(true);
}
if (data.selectedRepoKey) {
this.selectRowByRepoKey(data.selectedRepoKey);
} else {
this.selectRowByIndex(0);
}
}
};
RepoOverViewHelper.prototype.registerKeyboardShortcuts = function () {
var self = this;
document.addEventListener("keypress", function (event) {
if (document.activeElement.id === "filter") {
return;
}
var keycode = event.keyCode;
var rows = Array.prototype.slice.call(self.getVisibleRows());
var selected = document.querySelector(".repo.selected");
var indexOfSelected = rows.indexOf(selected);
if (keycode == 13) {
// "enter" to open
self.openSelectedRepo();
}
else if (keycode == 44 && indexOfSelected > 0) {
// "<" for previous
self.selectRowByIndex(indexOfSelected - 1);
} else if (keycode == 46 && indexOfSelected < rows.length - 1) {
// ">" for next
self.selectRowByIndex(indexOfSelected + 1);
}
});
};
RepoOverViewHelper.prototype.openSelectedRepo = function () {
this.selectedRepoKey = document.querySelector(".repo.selected").dataset.key;
this.saveLocalStorage();
document.querySelector(".repo.selected td.ro-go a").click();
};
RepoOverViewHelper.prototype.selectRowByIndex = function (index) {
var rows = this.getVisibleRows();
if (rows.length >= index) {
var selectedRow = rows[index];
if (selectedRow.classList.contains("selected")) {
return;
}
this.deselectAllRows();
rows[index].classList.add("selected");
this.selectedRepoKey = selectedRow.dataset.key;
this.updateActionLinks(selectedRow);
this.saveLocalStorage();
}
};
RepoOverViewHelper.prototype.selectRowByRepoKey = function (key) {
var attributeQuery = "[data-key='" + key + "']";
var row = document.querySelector(".repo" + attributeQuery);
// navigation to already selected repo
if (row.dataset.key === key && row.classList.contains("selected")) {
return;
}
this.deselectAllRows();
row.classList.add("selected");
this.selectedRepoKey = key;
this.updateActionLinks(row);
this.saveLocalStorage();
};
RepoOverViewHelper.prototype.updateActionLinks = function (selectedRow) {
// now we have a repo selected, determine which action buttons are relevant
var selectedRepoKey = selectedRow.dataset.key;
var selectedRepoIsOffline = selectedRow.dataset.offline === "X";
var actionLinks = document.querySelectorAll("a.action_link");
actionLinks.forEach(function (link) {
// adjust repo key in urls
link.href = link.href.replace(/\?key=(#|\d+)/, "?key=" + selectedRepoKey);
// toggle button visibility
if (link.classList.contains("action_offline_repo")) {
if (selectedRepoIsOffline) {
link.parentElement.classList.add("enabled");
} else {
link.parentElement.classList.remove("enabled");
}
}
else if (link.classList.contains("action_online_repo")) {
if (!selectedRepoIsOffline) {
link.parentElement.classList.add("enabled");
} else {
link.parentElement.classList.remove("enabled");
}
}
else {
// if the action is for both repository types, it will only have the .action_link class
// it still needs to be toggled as we want to hide everything if no repo is selected
link.parentElement.classList.add("enabled");
}
});
};
RepoOverViewHelper.prototype.deselectAllRows = function () {
document.querySelectorAll(".repo").forEach(function (x) {
x.classList.remove("selected");
});
};
RepoOverViewHelper.prototype.getVisibleRows = function () {
return document.querySelectorAll(".repo:not(.nodisplay)");
};
RepoOverViewHelper.prototype.registerRowSelection = function () {
var self = this;
document.querySelectorAll(".repo td:not(.ro-go)").forEach(function (repoListRowCell) {
repoListRowCell.addEventListener("click", function () {
self.selectRowByRepoKey(this.parentElement.dataset.key);
});
});
document.querySelectorAll(".repo td.ro-go").forEach(function (openRepoIcon) {
openRepoIcon.addEventListener("click", function () {
var selectedRow = this.parentElement;
self.selectRowByRepoKey(selectedRow.dataset.key);
self.openSelectedRepo();
});
});
};
RepoOverViewHelper.prototype.toggleRepoListDetail = function (forceDisplay) { RepoOverViewHelper.prototype.toggleRepoListDetail = function (forceDisplay) {
if (this.detailCssClass) { if (this.detailCssClass) {
this.toggleItemsDetail(forceDisplay); this.toggleItemsDetail(forceDisplay);
this.saveFilter(); this.saveLocalStorage();
} }
}; };
RepoOverViewHelper.prototype.toggleItemsDetail = function(forceDisplay){ RepoOverViewHelper.prototype.toggleItemsDetail = function (forceDisplay) {
if (this.detailCssClass) { if (this.detailCssClass) {
this.isDetailsDisplayed = forceDisplay || !this.isDetailsDisplayed; this.isDetailsDisplayed = forceDisplay || !this.isDetailsDisplayed;
@ -273,7 +424,6 @@ RepoOverViewHelper.prototype.toggleItemsDetail = function(forceDisplay){
} }
this.detailCssClass.style.display = this.isDetailsDisplayed ? "" : "none"; this.detailCssClass.style.display = this.isDetailsDisplayed ? "" : "none";
this.actionCssClass.style.display = this.isDetailsDisplayed ? "none" : "";
var icon = document.getElementById("icon-filter-detail"); var icon = document.getElementById("icon-filter-detail");
this.toggleFilterIcon(icon, this.isDetailsDisplayed); this.toggleFilterIcon(icon, this.isDetailsDisplayed);
} }
@ -291,10 +441,10 @@ RepoOverViewHelper.prototype.toggleFilterIcon = function (icon, isEnabled) {
RepoOverViewHelper.prototype.toggleRepoListFavorites = function (forceDisplay) { RepoOverViewHelper.prototype.toggleRepoListFavorites = function (forceDisplay) {
this.toggleItemsFavorites(forceDisplay); this.toggleItemsFavorites(forceDisplay);
this.saveFilter(); this.saveLocalStorage();
}; };
RepoOverViewHelper.prototype.toggleItemsFavorites = function(forceDisplay){ RepoOverViewHelper.prototype.toggleItemsFavorites = function (forceDisplay) {
this.isOnlyFavoritesDisplayed = forceDisplay || !this.isOnlyFavoritesDisplayed; this.isOnlyFavoritesDisplayed = forceDisplay || !this.isOnlyFavoritesDisplayed;
var repositories = document.getElementsByClassName("repo"); var repositories = document.getElementsByClassName("repo");
var icon = document.getElementById("icon-filter-favorite"); var icon = document.getElementById("icon-filter-favorite");
@ -303,38 +453,24 @@ RepoOverViewHelper.prototype.toggleItemsFavorites = function(forceDisplay){
var repo = repositories[i]; var repo = repositories[i];
if (this.isOnlyFavoritesDisplayed) { if (this.isOnlyFavoritesDisplayed) {
if (!repo.classList.contains("favorite")) { if (!repo.classList.contains("favorite")) {
repo.style.display = "none"; repo.classList.add("nodisplay");
} }
} else { } else {
repo.style.display = ""; repo.classList.remove("nodisplay");
} }
} }
}; };
RepoOverViewHelper.prototype.setHooks = function () { RepoOverViewHelper.prototype.saveLocalStorage = function () {
window.onload = this.onPageLoad.bind(this);
};
RepoOverViewHelper.prototype.saveFilter = function () {
if (!window.localStorage) return; if (!window.localStorage) return;
var data = { var data = {
isDetailsDisplayed: this.isDetailsDisplayed, isDetailsDisplayed: this.isDetailsDisplayed,
isOnlyFavoritesDisplayed: this.isOnlyFavoritesDisplayed isOnlyFavoritesDisplayed: this.isOnlyFavoritesDisplayed,
selectedRepoKey: this.selectedRepoKey,
}; };
window.localStorage.setItem(this.pageId, JSON.stringify(data)); window.localStorage.setItem(this.pageId, JSON.stringify(data));
}; };
RepoOverViewHelper.prototype.onPageLoad = function () {
var data = window.localStorage && JSON.parse(window.localStorage.getItem(this.pageId));
if (data) {
if (data.isDetailsDisplayed) {
this.toggleItemsDetail(true);
}
if (data.isOnlyFavoritesDisplayed) {
this.toggleItemsFavorites(true);
}
}
};
/********************************************************** /**********************************************************
* STAGE PAGE Logic * STAGE PAGE Logic

View File

@ -26,7 +26,6 @@ CLASS zcl_abapgit_gui_page_repo_over DEFINITION
PRIVATE SECTION. PRIVATE SECTION.
TYPES: TYPES:
BEGIN OF ty_overview, BEGIN OF ty_overview,
favorite TYPE string, favorite TYPE string,
@ -42,73 +41,95 @@ CLASS zcl_abapgit_gui_page_repo_over DEFINITION
deserialized_by TYPE xubname, deserialized_by TYPE xubname,
deserialized_at TYPE string, deserialized_at TYPE string,
write_protected TYPE abap_bool, write_protected TYPE abap_bool,
END OF ty_overview . END OF ty_overview,
TYPES:
ty_overviews TYPE STANDARD TABLE OF ty_overview ty_overviews TYPE STANDARD TABLE OF ty_overview
WITH NON-UNIQUE DEFAULT KEY . WITH NON-UNIQUE DEFAULT KEY.
CONSTANTS: CONSTANTS:
BEGIN OF c_action, BEGIN OF c_action,
select TYPE string VALUE 'select', select TYPE string VALUE 'select',
apply_filter TYPE string VALUE 'apply_filter', apply_filter TYPE string VALUE 'apply_filter',
END OF c_action . END OF c_action .
DATA mv_order_descending TYPE abap_bool .
DATA mv_filter TYPE string .
DATA mv_time_zone TYPE timezone .
DATA mt_col_spec TYPE zif_abapgit_definitions=>ty_col_spec_tt .
DATA mt_overview TYPE ty_overviews .
METHODS render_text_input DATA: mv_order_descending TYPE abap_bool,
IMPORTING mv_filter TYPE string,
!iv_name TYPE string mv_time_zone TYPE timezone,
!iv_label TYPE string mt_col_spec TYPE zif_abapgit_definitions=>ty_col_spec_tt,
!iv_value TYPE string OPTIONAL mt_overview TYPE ty_overviews.
!iv_max_length TYPE string OPTIONAL
!iv_autofocus TYPE abap_bool DEFAULT abap_false METHODS: render_text_input
RETURNING IMPORTING iv_name TYPE string
VALUE(ri_html) TYPE REF TO zif_abapgit_html . iv_label TYPE string
METHODS apply_filter iv_value TYPE string OPTIONAL
CHANGING iv_max_length TYPE string OPTIONAL
!ct_overview TYPE ty_overviews . !iv_autofocus TYPE abap_bool DEFAULT abap_false
METHODS map_repo_list_to_overview RETURNING VALUE(ri_html) TYPE REF TO zif_abapgit_html,
RETURNING
VALUE(rt_overview) TYPE ty_overviews apply_filter
RAISING CHANGING
zcx_abapgit_exception . ct_overview TYPE ty_overviews,
METHODS render_table_header
IMPORTING map_repo_list_to_overview
!ii_html TYPE REF TO zif_abapgit_html . RETURNING
METHODS render_table VALUE(rt_overview) TYPE ty_overviews
IMPORTING RAISING
!ii_html TYPE REF TO zif_abapgit_html zcx_abapgit_exception,
!it_overview TYPE ty_overviews
RAISING render_table_header
zcx_abapgit_exception . IMPORTING
METHODS render_table_body ii_html TYPE REF TO zif_abapgit_html,
IMPORTING
!ii_html TYPE REF TO zif_abapgit_html render_table
!it_overview TYPE ty_overviews IMPORTING
RAISING ii_html TYPE REF TO zif_abapgit_html
zcx_abapgit_exception . it_overview TYPE ty_overviews
METHODS render_header_bar RAISING
IMPORTING zcx_abapgit_exception,
!ii_html TYPE REF TO zif_abapgit_html .
METHODS apply_order_by render_table_body
CHANGING IMPORTING
!ct_overview TYPE ty_overviews . ii_html TYPE REF TO zif_abapgit_html
METHODS _add_column it_repo_list TYPE ty_overviews
IMPORTING RAISING
!iv_tech_name TYPE string OPTIONAL zcx_abapgit_exception,
!iv_display_name TYPE string OPTIONAL
!iv_css_class TYPE string OPTIONAL render_header_bar
!iv_add_tz TYPE abap_bool OPTIONAL IMPORTING
!iv_title TYPE string OPTIONAL ii_html TYPE REF TO zif_abapgit_html,
!iv_allow_order_by TYPE any OPTIONAL .
apply_order_by
CHANGING ct_overview TYPE ty_overviews,
_add_column
IMPORTING
iv_tech_name TYPE string OPTIONAL
iv_display_name TYPE string OPTIONAL
iv_css_class TYPE string OPTIONAL
iv_add_tz TYPE abap_bool OPTIONAL
iv_title TYPE string OPTIONAL
iv_allow_order_by TYPE any OPTIONAL.
METHODS render_scripts METHODS render_scripts
RETURNING RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING RAISING
zcx_abapgit_exception . zcx_abapgit_exception.
METHODS shorten_repo_url
IMPORTING iv_full_url TYPE string
iv_max_length TYPE i DEFAULT 60
RETURNING VALUE(rv_shortened) TYPE string.
METHODS render_actions
IMPORTING ii_html TYPE REF TO zif_abapgit_html.
METHODS column
IMPORTING iv_content TYPE string OPTIONAL
iv_css_class TYPE string OPTIONAL
RETURNING VALUE(rv_html) TYPE string.
METHODS action_link
IMPORTING iv_content TYPE string
RETURNING VALUE(rv_html) TYPE string.
ENDCLASS. ENDCLASS.
@ -178,9 +199,9 @@ CLASS zcl_abapgit_gui_page_repo_over IMPLEMENTATION.
METHOD map_repo_list_to_overview. METHOD map_repo_list_to_overview.
DATA: ls_overview LIKE LINE OF rt_overview, DATA: ls_overview LIKE LINE OF rt_overview,
lv_date TYPE d, lv_date TYPE d,
lv_time TYPE t, lv_time TYPE t,
lt_repo_obj_list TYPE zif_abapgit_repo_srv=>ty_repo_list. lt_repo_obj_list TYPE zif_abapgit_repo_srv=>ty_repo_list.
FIELD-SYMBOLS <ls_repo> LIKE LINE OF lt_repo_obj_list. FIELD-SYMBOLS <ls_repo> LIKE LINE OF lt_repo_obj_list.
@ -255,6 +276,8 @@ CLASS zcl_abapgit_gui_page_repo_over IMPLEMENTATION.
iv_act = |gHelper.toggleRepoListDetail()| iv_act = |gHelper.toggleRepoListDetail()|
iv_typ = zif_abapgit_html=>c_action_type-onclick ) ). iv_typ = zif_abapgit_html=>c_action_type-onclick ) ).
render_actions( ii_html = ii_html ).
ii_html->add( |</div>| ). ii_html->add( |</div>| ).
ENDMETHOD. ENDMETHOD.
@ -274,11 +297,11 @@ CLASS zcl_abapgit_gui_page_repo_over IMPLEMENTATION.
METHOD render_table. METHOD render_table.
ii_html->add( |<div class="db_list repo-overview">| ). ii_html->add( |<div class="db_list repo-overview">| ).
ii_html->add( |<table class="db_tab w100">| ). ii_html->add( |<table class="db_tab">| ).
render_table_header( ii_html ). render_table_header( ii_html ).
render_table_body( ii_html = ii_html render_table_body( ii_html = ii_html
it_overview = it_overview ). it_repo_list = it_overview ).
ii_html->add( |</table>| ). ii_html->add( |</table>| ).
ii_html->add( |</div>| ). ii_html->add( |</div>| ).
@ -288,35 +311,33 @@ CLASS zcl_abapgit_gui_page_repo_over IMPLEMENTATION.
METHOD render_table_body. METHOD render_table_body.
CONSTANTS: lc_separator TYPE string VALUE `<span class="separator">|</span>`.
DATA: DATA:
lv_type_icon TYPE string, lv_type_icon TYPE string,
lv_favorite_icon TYPE string, lv_favorite_icon TYPE string,
lv_favorite_class TYPE string, lv_favorite_class TYPE string,
lv_stage_link TYPE string, lv_stage_link TYPE string,
lv_patch_link TYPE string, lv_patch_link TYPE string,
lv_zip_import_link TYPE string, lv_zip_import_link TYPE string,
lv_zip_export_link TYPE string, lv_zip_export_link TYPE string,
lv_check_link TYPE string, lv_check_link TYPE string,
lv_text TYPE string, lv_text TYPE string,
lv_lock TYPE string, lv_lock TYPE string,
lv_settings_link TYPE string. lv_toggle_favorite_link TYPE string,
DATA lv_new_length TYPE i. lv_repo_go_link TYPE string.
FIELD-SYMBOLS: <ls_overview> LIKE LINE OF it_overview. FIELD-SYMBOLS: <ls_repo> LIKE LINE OF it_repo_list.
ii_html->add( '<tbody>' ). ii_html->add( '<tbody>' ).
LOOP AT it_overview ASSIGNING <ls_overview>. LOOP AT it_repo_list ASSIGNING <ls_repo>.
IF <ls_overview>-type = abap_true. IF <ls_repo>-type = abap_true.
lv_type_icon = 'plug/darkgrey'. lv_type_icon = 'plug/darkgrey'.
ELSE. ELSE.
lv_type_icon = 'cloud-upload-alt/darkgrey'. lv_type_icon = 'cloud-upload-alt/darkgrey'.
ENDIF. ENDIF.
IF <ls_overview>-favorite = abap_true. IF <ls_repo>-favorite = abap_true.
lv_favorite_icon = 'star/blue'. lv_favorite_icon = 'star/blue'.
lv_favorite_class = 'favorite'. lv_favorite_class = 'favorite'.
ELSE. ELSE.
@ -324,119 +345,91 @@ CLASS zcl_abapgit_gui_page_repo_over IMPLEMENTATION.
lv_favorite_class = ''. lv_favorite_class = ''.
ENDIF. ENDIF.
ii_html->add( |<tr class="repo { lv_favorite_class }">| ). ii_html->add(
ii_html->add( |<td class="wmin">| ). |<tr class="repo { lv_favorite_class }" data-key="{ <ls_repo>-key }" data-offline="{ <ls_repo>-type }">| ).
ii_html->add_a( iv_act = |{ zif_abapgit_definitions=>c_action-repo_toggle_fav }?key={ <ls_overview>-key }|
iv_txt = ii_html->icon( iv_name = lv_favorite_icon lv_toggle_favorite_link = ii_html->a(
iv_class = 'pad-sides' iv_act = |{ zif_abapgit_definitions=>c_action-repo_toggle_fav }?key={ <ls_repo>-key }|
iv_hint = 'Click to toggle favorite' ) ). iv_txt = ii_html->icon( iv_name = lv_favorite_icon
ii_html->add( |</td>| ). iv_class = 'pad-sides'
iv_hint = 'Click to toggle favorite' ) ).
ii_html->add(
column( iv_content = lv_toggle_favorite_link
iv_css_class = 'wmin' ) ).
CLEAR lv_lock. CLEAR lv_lock.
IF <ls_overview>-write_protected = abap_true. IF <ls_repo>-write_protected = abap_true.
lv_lock = ii_html->icon( iv_name = 'lock/grey70' lv_lock = ii_html->icon( iv_name = 'lock/grey70'
iv_class = 'm-em5-sides' iv_class = 'm-em5-sides'
iv_hint = 'Locked from pulls' ). iv_hint = 'Locked from pulls' ).
ENDIF. ENDIF.
ii_html->add( |<td class="wmin">{ ii_html->icon( lv_type_icon ) }</td>| ). ii_html->add(
column( iv_content = ii_html->icon( lv_type_icon )
iv_css_class = 'wmin' ) ).
ii_html->add( |<td>{ ii_html->a( iv_txt = <ls_overview>-name ii_html->add(
iv_act = |{ c_action-select }?key={ <ls_overview>-key }| ) }{ lv_lock }</td>| ). column( iv_content = ii_html->a( iv_txt = <ls_repo>-name
iv_act = |{ c_action-select }?key={ <ls_repo>-key }| ) && lv_lock ) ).
IF <ls_overview>-type = abap_false. ii_html->add(
lv_text = <ls_overview>-url. column( iv_content = zcl_abapgit_gui_chunk_lib=>render_package_name(
REPLACE FIRST OCCURRENCE OF 'https://' IN lv_text WITH ''. iv_package = <ls_repo>-package
REPLACE FIRST OCCURRENCE OF 'http://' IN lv_text WITH ''. iv_suppress_title = abap_true )->render( ) ) ).
IF lv_text CP '*.git'.
lv_new_length = strlen( lv_text ) - 4. IF <ls_repo>-type = abap_false.
lv_text = lv_text(lv_new_length). lv_text = shorten_repo_url( <ls_repo>-url ).
ENDIF. ii_html->add( column( iv_content = |{ ii_html->a(
ii_html->add( |<td>{ ii_html->a(
iv_txt = lv_text iv_txt = lv_text
iv_title = <ls_overview>-url iv_title = <ls_repo>-url
iv_act = |{ zif_abapgit_definitions=>c_action-url }?url={ <ls_overview>-url }| ) }</td>| ). iv_act = |{ zif_abapgit_definitions=>c_action-url }?url={ <ls_repo>-url }| ) }| ) ).
ELSE. ELSE.
ii_html->add( |<td></td>| ). ii_html->add( column( ) ).
ENDIF. ENDIF.
ii_html->add( |<td>| ). IF <ls_repo>-branch IS INITIAL.
ii_html->add( zcl_abapgit_gui_chunk_lib=>render_package_name( ii_html->add( column( iv_content = |&nbsp;| ) ).
iv_package = <ls_overview>-package
iv_suppress_title = abap_true ) ).
ii_html->add( |</td>| ).
IF <ls_overview>-branch IS INITIAL.
ii_html->add( |<td>&nbsp;</td>| ).
ELSE. ELSE.
ii_html->add( |<td>| ). ii_html->add(
ii_html->add( zcl_abapgit_gui_chunk_lib=>render_branch_name( column( iv_content = zcl_abapgit_gui_chunk_lib=>render_branch_name(
iv_branch = <ls_overview>-branch iv_branch = <ls_repo>-branch
iv_repo_key = <ls_overview>-key ) ). iv_repo_key = <ls_repo>-key )->render( ) ) ).
ii_html->add( |</td>| ).
ENDIF. ENDIF.
ii_html->add( |<td class="ro-detail">| ). ii_html->add(
ii_html->add( zcl_abapgit_gui_chunk_lib=>render_user_name( column( iv_content = zcl_abapgit_gui_chunk_lib=>render_user_name(
iv_username = <ls_overview>-deserialized_by iv_username = <ls_repo>-deserialized_by
iv_suppress_title = abap_true ) ). iv_suppress_title = abap_true )->render( )
ii_html->add( |</td>| ). iv_css_class = 'ro-detail' ) ).
ii_html->add( |<td class="ro-detail">{ <ls_overview>-deserialized_at }</td>| ).
ii_html->add( |<td class="ro-detail">| ).
ii_html->add( zcl_abapgit_gui_chunk_lib=>render_user_name(
iv_username = <ls_overview>-created_by
iv_suppress_title = abap_true ) ).
ii_html->add( |</td>| ).
ii_html->add( |<td class="ro-detail">{ <ls_overview>-created_at }</td>| ).
ii_html->add( |<td class="ro-detail">{ <ls_overview>-key }</td>| ).
ii_html->add( |<td class='ro-action'> | ). ii_html->add(
column( iv_content = <ls_repo>-deserialized_at
iv_css_class = 'ro-detail' ) ).
lv_check_link = ii_html->a( ii_html->add(
iv_txt = |Check| column( iv_content = zcl_abapgit_gui_chunk_lib=>render_user_name(
iv_act = |{ zif_abapgit_definitions=>c_action-repo_code_inspector }?key={ <ls_overview>-key } | ). iv_username = <ls_repo>-created_by
iv_suppress_title = abap_true )->render( )
iv_css_class = 'ro-detail' ) ).
ii_html->add( lv_check_link && lc_separator ). ii_html->add(
column( iv_content = <ls_repo>-created_at
iv_css_class = 'ro-detail' ) ).
IF <ls_overview>-type = abap_false. " online repo ii_html->add(
lv_stage_link = ii_html->a( column( iv_content = |{ <ls_repo>-key }|
iv_txt = |Stage| iv_css_class = 'ro-detail' ) ).
iv_act = |{ zif_abapgit_definitions=>c_action-go_stage }?key={ <ls_overview>-key } | ).
ii_html->add( lv_stage_link && lc_separator ). " the link is clicked in javascript
lv_repo_go_link = ii_html->a(
iv_txt = ``
iv_act = |{ c_action-select }?key={ <ls_repo>-key }|
iv_class = 'hidden' ).
lv_patch_link = ii_html->a( ii_html->add( column(
iv_txt = |Patch| iv_content = |<span class="link" title="Open">&rsaquo;{ lv_repo_go_link }</span>|
iv_act = |{ zif_abapgit_definitions=>c_action-go_patch }?key={ <ls_overview>-key } | ). iv_css_class = 'ro-go' ) ).
ii_html->add( lv_patch_link && lc_separator ).
ELSE. " offline repo
lv_zip_import_link = ii_html->a(
iv_txt = |Import|
iv_act = |{ zif_abapgit_definitions=>c_action-zip_import }?key={ <ls_overview>-key } | ).
ii_html->add( lv_zip_import_link && lc_separator ).
lv_zip_export_link = ii_html->a(
iv_txt = |Export|
iv_act = |{ zif_abapgit_definitions=>c_action-zip_export }?key={ <ls_overview>-key } | ).
ii_html->add( lv_zip_export_link && lc_separator ).
ENDIF.
lv_settings_link = ii_html->a(
iv_txt = |Settings|
iv_act = |{ zif_abapgit_definitions=>c_action-repo_settings }?key={ <ls_overview>-key } | ).
ii_html->add( lv_settings_link ).
ii_html->add( |</td>| ).
ii_html->add( |<td class='ro-go'><span>{
ii_html->a(
iv_txt = `&rsaquo;`
iv_act = |{ c_action-select }?key={ <ls_overview>-key }| ) }</span></td>| ).
ii_html->add( |</tr>| ).
ENDLOOP. ENDLOOP.
@ -444,6 +437,91 @@ CLASS zcl_abapgit_gui_page_repo_over IMPLEMENTATION.
ENDMETHOD. ENDMETHOD.
METHOD render_actions.
CONSTANTS:
lc_separator TYPE string VALUE `<span class="separator">|</span>`,
lc_dummy_key TYPE string VALUE `?key=#`,
lc_offline_class TYPE string VALUE `action_offline_repo`,
lc_online_class TYPE string VALUE `action_online_repo`,
lc_action_class TYPE string VALUE `action_link`.
DATA:
lv_settings_link TYPE string,
lv_check_link TYPE string,
lv_stage_link TYPE string,
lv_patch_link TYPE string.
DATA:
lv_zip_import_link TYPE string,
lv_zip_export_link TYPE string.
ii_html->add( |<div class="float-right">| ).
lv_check_link = ii_html->a(
iv_txt = |Check|
iv_act = |{ zif_abapgit_definitions=>c_action-repo_code_inspector }{ lc_dummy_key }|
iv_class = |{ lc_action_class }| ).
ii_html->add( action_link( lv_check_link && lc_separator ) ).
lv_stage_link = ii_html->a(
iv_txt = |Stage|
iv_act = |{ zif_abapgit_definitions=>c_action-go_stage }{ lc_dummy_key }|
iv_class = |{ lc_action_class } { lc_online_class } | ).
ii_html->add( action_link( lv_stage_link && lc_separator ) ).
lv_patch_link = ii_html->a(
iv_txt = |Patch|
iv_act = |{ zif_abapgit_definitions=>c_action-go_patch }{ lc_dummy_key }|
iv_class = |{ lc_action_class } { lc_online_class } | ).
ii_html->add( action_link( lv_patch_link && lc_separator ) ).
lv_zip_import_link = ii_html->a(
iv_txt = |Import|
iv_act = |{ zif_abapgit_definitions=>c_action-zip_import }{ lc_dummy_key }|
iv_class = |{ lc_action_class } { lc_offline_class }| ).
ii_html->add( action_link( lv_zip_import_link && lc_separator ) ).
lv_zip_export_link = ii_html->a(
iv_txt = |Export|
iv_act = |{ zif_abapgit_definitions=>c_action-zip_export }{ lc_dummy_key }|
iv_class = |{ lc_action_class } { lc_offline_class }| ).
ii_html->add( action_link( lv_zip_export_link && lc_separator ) ).
lv_settings_link = ii_html->a(
iv_txt = |Settings|
iv_act = |{ zif_abapgit_definitions=>c_action-repo_settings }{ lc_dummy_key }|
iv_class = |{ lc_action_class }| ).
ii_html->add( action_link( lv_settings_link ) ).
ii_html->add( |</div>| ).
ENDMETHOD.
METHOD shorten_repo_url.
DATA lt_results TYPE match_result_tab.
DATA lv_new_length TYPE i.
DATA: lv_length_to_truncate_to TYPE i.
rv_shortened = iv_full_url.
REPLACE FIRST OCCURRENCE OF 'https://' IN rv_shortened WITH ''.
REPLACE FIRST OCCURRENCE OF 'http://' IN rv_shortened WITH ''.
IF rv_shortened CP '*.git'.
lv_new_length = strlen( rv_shortened ) - 4.
rv_shortened = rv_shortened(lv_new_length).
ENDIF.
IF strlen( rv_shortened ) > iv_max_length.
lv_length_to_truncate_to = iv_max_length - 3.
rv_shortened = rv_shortened(lv_length_to_truncate_to) && `...`.
ENDIF.
ENDMETHOD.
METHOD render_table_header. METHOD render_table_header.
@ -465,13 +543,14 @@ CLASS zcl_abapgit_gui_page_repo_over IMPLEMENTATION.
iv_allow_order_by = abap_true ). iv_allow_order_by = abap_true ).
_add_column( _add_column(
iv_tech_name = 'URL' iv_tech_name = 'PACKAGE'
iv_display_name = 'Url' iv_display_name = 'Package'
iv_css_class = 'package'
iv_allow_order_by = abap_true ). iv_allow_order_by = abap_true ).
_add_column( _add_column(
iv_tech_name = 'PACKAGE' iv_tech_name = 'URL'
iv_display_name = 'Package' iv_display_name = 'Remote'
iv_allow_order_by = abap_true ). iv_allow_order_by = abap_true ).
_add_column( _add_column(
@ -497,7 +576,6 @@ CLASS zcl_abapgit_gui_page_repo_over IMPLEMENTATION.
iv_css_class = 'ro-detail' iv_css_class = 'ro-detail'
iv_allow_order_by = abap_true ). iv_allow_order_by = abap_true ).
_add_column( _add_column(
iv_tech_name = 'CREATED_AT' iv_tech_name = 'CREATED_AT'
iv_display_name = 'Created at' iv_display_name = 'Created at'
@ -511,12 +589,6 @@ CLASS zcl_abapgit_gui_page_repo_over IMPLEMENTATION.
iv_css_class = 'ro-detail' iv_css_class = 'ro-detail'
iv_allow_order_by = abap_true ). iv_allow_order_by = abap_true ).
_add_column(
iv_tech_name = 'ACTION'
iv_display_name = 'Action'
iv_css_class = 'ro-action'
iv_allow_order_by = abap_false ).
_add_column( _add_column(
iv_tech_name = 'GO' iv_tech_name = 'GO'
iv_css_class = 'ro-go' iv_css_class = 'ro-go'
@ -618,4 +690,17 @@ CLASS zcl_abapgit_gui_page_repo_over IMPLEMENTATION.
<ls_col>-add_tz = iv_add_tz. <ls_col>-add_tz = iv_add_tz.
<ls_col>-allow_order_by = iv_allow_order_by. <ls_col>-allow_order_by = iv_allow_order_by.
ENDMETHOD. ENDMETHOD.
METHOD column.
IF iv_css_class IS NOT INITIAL.
rv_html = |<td class="{ iv_css_class }">| && iv_content && |</td>|.
ELSE.
rv_html = |<td>| && iv_content && |</td>|.
ENDIF.
ENDMETHOD.
METHOD action_link.
rv_html = |<span class="action_link">| && iv_content && |</span>|.
ENDMETHOD.
ENDCLASS. ENDCLASS.