From b08ee6a4984bacdb61218cfaa0df6d575edeea98 Mon Sep 17 00:00:00 2001 From: Fabian Lupa Date: Fri, 9 Nov 2018 05:36:44 +0100 Subject: [PATCH] CTS integration (#2061) * Implement facade for Change Transport System * Render lock item in VIEW_REPO * Add jump to SE01 * Display transport on stage page * Optimize transport read on stage page * Error handling CTS * Fix indentation * Disable transport column for local packages * Code review changes --- src/ui/zcl_abapgit_gui_page_stage.clas.abap | 79 ++++++++++++- src/ui/zcl_abapgit_gui_router.clas.abap | 18 ++- src/ui/zcl_abapgit_gui_view_repo.clas.abap | 79 ++++++++++--- src/zabapgit_js_common.w3mi.data.js | 88 +++++++-------- src/zcl_abapgit_cts_api.clas.abap | 118 ++++++++++++++++++++ src/zcl_abapgit_cts_api.clas.xml | 18 +++ src/zcl_abapgit_factory.clas.abap | 13 ++- src/zcl_abapgit_injector.clas.abap | 9 +- src/zif_abapgit_cts_api.intf.abap | 42 +++++++ src/zif_abapgit_cts_api.intf.xml | 16 +++ src/zif_abapgit_definitions.intf.abap | 1 + 11 files changed, 413 insertions(+), 68 deletions(-) create mode 100644 src/zcl_abapgit_cts_api.clas.abap create mode 100644 src/zcl_abapgit_cts_api.clas.xml create mode 100644 src/zif_abapgit_cts_api.intf.abap create mode 100644 src/zif_abapgit_cts_api.intf.xml diff --git a/src/ui/zcl_abapgit_gui_page_stage.clas.abap b/src/ui/zcl_abapgit_gui_page_stage.clas.abap index 47151ee04..25e18c795 100644 --- a/src/ui/zcl_abapgit_gui_page_stage.clas.abap +++ b/src/ui/zcl_abapgit_gui_page_stage.clas.abap @@ -34,6 +34,12 @@ CLASS zcl_abapgit_gui_page_stage DEFINITION END OF ty_changed_by . TYPES: ty_changed_by_tt TYPE SORTED TABLE OF ty_changed_by WITH UNIQUE KEY item. + TYPES: + BEGIN OF ty_transport, + item TYPE zif_abapgit_definitions=>ty_item, + transport TYPE trkorr, + END OF ty_transport, + ty_transport_tt TYPE SORTED TABLE OF ty_transport WITH UNIQUE KEY item. DATA mo_repo TYPE REF TO zcl_abapgit_repo_online . DATA ms_files TYPE zif_abapgit_definitions=>ty_stage_files . @@ -45,6 +51,11 @@ CLASS zcl_abapgit_gui_page_stage DEFINITION !it_local TYPE zif_abapgit_definitions=>ty_files_item_tt RETURNING VALUE(rt_changed_by) TYPE ty_changed_by_tt . + METHODS find_transports + IMPORTING + it_local TYPE zif_abapgit_definitions=>ty_files_item_tt + RETURNING + VALUE(rt_transports) TYPE ty_transport_tt. METHODS render_list RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html . @@ -54,6 +65,7 @@ CLASS zcl_abapgit_gui_page_stage DEFINITION !is_file TYPE zif_abapgit_definitions=>ty_file !is_item TYPE zif_abapgit_definitions=>ty_item OPTIONAL !iv_changed_by TYPE xubname OPTIONAL + !iv_transport TYPE trkorr OPTIONAL RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html . METHODS render_actions @@ -77,7 +89,7 @@ ENDCLASS. -CLASS ZCL_ABAPGIT_GUI_PAGE_STAGE IMPLEMENTATION. +CLASS zcl_abapgit_gui_page_stage IMPLEMENTATION. METHOD build_menu. @@ -135,6 +147,43 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_STAGE IMPLEMENTATION. ENDMETHOD. + METHOD find_transports. + DATA: li_cts_api TYPE REF TO zif_abapgit_cts_api, + ls_new LIKE LINE OF rt_transports. + FIELD-SYMBOLS: LIKE LINE OF it_local, + LIKE LINE OF rt_transports. + + li_cts_api = zcl_abapgit_factory=>get_cts_api( ). + + TRY. + LOOP AT it_local ASSIGNING WHERE item IS NOT INITIAL. + IF -item-obj_type IS NOT INITIAL AND + -item-obj_name IS NOT INITIAL AND + -item-devclass IS NOT INITIAL. + + IF li_cts_api->is_chrec_possible_for_package( -item-devclass ) = abap_false. + EXIT. " Assume all other objects are also in packages without change recording + + ELSEIF li_cts_api->is_object_type_lockable( -item-obj_type ) = abap_true AND + li_cts_api->is_object_locked_in_transport( iv_object_type = -item-obj_type + iv_object_name = -item-obj_name ) = abap_true. + + ls_new-item = -item. + + ls_new-transport = li_cts_api->get_current_transport_for_obj( + iv_object_type = -item-obj_type + iv_object_name = -item-obj_name + iv_resolve_task_to_request = abap_false ). + + INSERT ls_new INTO TABLE rt_transports. + ENDIF. + ENDIF. + ENDLOOP. + CATCH zcx_abapgit_exception. + ASSERT 1 = 2. + ENDTRY. + ENDMETHOD. + METHOD get_page_patch. @@ -288,11 +337,15 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_STAGE IMPLEMENTATION. METHOD render_file. - DATA: lv_param TYPE string, - lv_filename TYPE string. + DATA: lv_param TYPE string, + lv_filename TYPE string, + lv_transport_string TYPE string, + lv_transport_html TYPE string. CREATE OBJECT ro_html. + lv_transport_string = iv_transport. + lv_filename = is_file-path && is_file-filename. * make sure whitespace is preserved in the DOM REPLACE ALL OCCURRENCES OF ` ` IN lv_filename WITH ' '. @@ -308,13 +361,21 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_STAGE IMPLEMENTATION. lv_filename = zcl_abapgit_html=>a( iv_txt = lv_filename iv_act = |{ zif_abapgit_definitions=>c_action-go_diff }?{ lv_param }| ). + + IF iv_transport IS NOT INITIAL. + lv_transport_html = zcl_abapgit_html=>a( + iv_txt = lv_transport_string + iv_act = |{ zif_abapgit_definitions=>c_action-jump_transport }?{ iv_transport }| ). + ENDIF. ro_html->add( |{ is_item-obj_type }| ). ro_html->add( |{ lv_filename }| ). ro_html->add( |{ iv_changed_by }| ). + ro_html->add( |{ lv_transport_html }| ). WHEN 'remote'. ro_html->add( '-' ). " Dummy for object type ro_html->add( |{ lv_filename }| ). ro_html->add( '' ). " Dummy for changed-by + ro_html->add( '' ). " Dummy for transport ENDCASE. ro_html->add( |?| ). @@ -328,7 +389,9 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_STAGE IMPLEMENTATION. METHOD render_list. DATA: lt_changed_by TYPE ty_changed_by_tt, - ls_changed_by LIKE LINE OF lt_changed_by. + ls_changed_by LIKE LINE OF lt_changed_by, + lt_transports TYPE ty_transport_tt, + ls_transport LIKE LINE OF lt_transports. FIELD-SYMBOLS: LIKE LINE OF ms_files-remote, LIKE LINE OF ms_files-local. @@ -338,6 +401,7 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_STAGE IMPLEMENTATION. ro_html->add( '' ). lt_changed_by = find_changed_by( ms_files-local ). + lt_transports = find_transports( ms_files-local ). " Local changes LOOP AT ms_files-local ASSIGNING . @@ -346,6 +410,7 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_STAGE IMPLEMENTATION. ro_html->add( '' ). ro_html->add( '' ). ro_html->add( '' ). + ro_html->add( '' ). ro_html->add( '' ). " Status ro_html->add( '' ). diff --git a/src/ui/zcl_abapgit_gui_router.clas.abap b/src/ui/zcl_abapgit_gui_router.clas.abap index 68c2a301c..e9393bc67 100644 --- a/src/ui/zcl_abapgit_gui_router.clas.abap +++ b/src/ui/zcl_abapgit_gui_router.clas.abap @@ -40,11 +40,14 @@ CLASS zcl_abapgit_gui_router DEFINITION METHODS get_page_playground RETURNING VALUE(ri_page) TYPE REF TO zif_abapgit_gui_page RAISING zcx_abapgit_exception zcx_abapgit_cancel. + + CLASS-METHODS jump_display_transport + IMPORTING iv_getdata TYPE clike. ENDCLASS. -CLASS ZCL_ABAPGIT_GUI_ROUTER IMPLEMENTATION. +CLASS zcl_abapgit_gui_router IMPLEMENTATION. METHOD get_page_background. @@ -241,6 +244,9 @@ CLASS ZCL_ABAPGIT_GUI_ROUTER IMPLEMENTATION. WHEN zif_abapgit_definitions=>c_action-jump_pkg. " Open SE80 zcl_abapgit_services_repo=>open_se80( |{ iv_getdata }| ). ev_state = zif_abapgit_definitions=>c_event_state-no_more_act. + WHEN zif_abapgit_definitions=>c_action-jump_transport. + jump_display_transport( iv_getdata ). + ev_state = zif_abapgit_definitions=>c_event_state-no_more_act. " DB actions WHEN zif_abapgit_definitions=>c_action-db_edit. @@ -376,4 +382,14 @@ CLASS ZCL_ABAPGIT_GUI_ROUTER IMPLEMENTATION. ENDCASE. ENDMETHOD. + + METHOD jump_display_transport. + DATA: lv_transport TYPE trkorr. + + lv_transport = iv_getdata. + + CALL FUNCTION 'TR_DISPLAY_REQUEST' + EXPORTING + i_trkorr = lv_transport. + ENDMETHOD. ENDCLASS. diff --git a/src/ui/zcl_abapgit_gui_view_repo.clas.abap b/src/ui/zcl_abapgit_gui_view_repo.clas.abap index a0034192b..46697a918 100644 --- a/src/ui/zcl_abapgit_gui_view_repo.clas.abap +++ b/src/ui/zcl_abapgit_gui_view_repo.clas.abap @@ -50,8 +50,9 @@ CLASS zcl_abapgit_gui_view_repo DEFINITION RETURNING VALUE(ro_toolbar) TYPE REF TO zcl_abapgit_html_toolbar RAISING zcx_abapgit_exception, render_item - IMPORTING is_item TYPE zif_abapgit_definitions=>ty_repo_item - RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html + IMPORTING is_item TYPE zif_abapgit_definitions=>ty_repo_item + iv_render_transports TYPE abap_bool + RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html RAISING zcx_abapgit_exception, render_item_files IMPORTING is_item TYPE zif_abapgit_definitions=>ty_repo_item @@ -65,6 +66,9 @@ CLASS zcl_abapgit_gui_view_repo DEFINITION get_item_icon IMPORTING is_item TYPE zif_abapgit_definitions=>ty_repo_item RETURNING VALUE(rv_html) TYPE string, + render_item_lock_column + IMPORTING is_item TYPE zif_abapgit_definitions=>ty_repo_item + RETURNING VALUE(rv_html) TYPE string, render_empty_package RETURNING VALUE(rv_html) TYPE string, render_parent_dir @@ -85,7 +89,7 @@ ENDCLASS. -CLASS ZCL_ABAPGIT_GUI_VIEW_REPO IMPLEMENTATION. +CLASS zcl_abapgit_gui_view_repo IMPLEMENTATION. METHOD build_dir_jump_link. @@ -398,20 +402,29 @@ CLASS ZCL_ABAPGIT_GUI_VIEW_REPO IMPLEMENTATION. METHOD render_item. - DATA: lv_link TYPE string. + DATA: lv_link TYPE string, + lv_colspan TYPE i. CREATE OBJECT ro_html. + IF iv_render_transports = abap_false. + lv_colspan = 2. + ELSE. + lv_colspan = 3. + ENDIF. ro_html->add( || ). IF is_item-obj_name IS INITIAL AND is_item-is_dir = abap_false. - ro_html->add( '' + ro_html->add( || && '' ). ELSE. ro_html->add( || ). + IF iv_render_transports = abap_true. + ro_html->add( render_item_lock_column( is_item ) ). + ENDIF. IF is_item-is_dir = abap_true. " Subdir lv_link = build_dir_jump_link( is_item-path ). @@ -528,6 +541,38 @@ CLASS ZCL_ABAPGIT_GUI_VIEW_REPO IMPLEMENTATION. ENDMETHOD. + METHOD render_item_lock_column. + DATA: li_cts_api TYPE REF TO zif_abapgit_cts_api, + lv_transport TYPE trkorr, + lv_transport_string TYPE string, + lv_icon_html TYPE string. + + li_cts_api = zcl_abapgit_factory=>get_cts_api( ). + + TRY. + IF is_item-obj_type IS INITIAL OR is_item-obj_name IS INITIAL OR + li_cts_api->is_object_type_lockable( is_item-obj_type ) = abap_false OR + li_cts_api->is_object_locked_in_transport( iv_object_type = is_item-obj_type + iv_object_name = is_item-obj_name ) = abap_false. + rv_html = ||. + ELSE. + lv_transport = li_cts_api->get_current_transport_for_obj( iv_object_type = is_item-obj_type + iv_object_name = is_item-obj_name + iv_resolve_task_to_request = abap_false ). + lv_transport_string = lv_transport. + lv_icon_html = zcl_abapgit_html=>a( iv_txt = zcl_abapgit_html=>icon( iv_name = 'lock/darkgrey' + iv_hint = lv_transport_string ) + iv_act = |{ zif_abapgit_definitions=>c_action-jump_transport }?| && + lv_transport ). + rv_html = ||. + ENDIF. + CATCH zcx_abapgit_exception. + ASSERT 1 = 2. + ENDTRY. + ENDMETHOD. + METHOD zif_abapgit_gui_page_hotkey~get_hotkey_actions. @@ -563,15 +608,16 @@ CLASS ZCL_ABAPGIT_GUI_VIEW_REPO IMPLEMENTATION. METHOD zif_abapgit_gui_page~render. - DATA: lt_repo_items TYPE zif_abapgit_definitions=>tt_repo_items, - lo_browser TYPE REF TO zcl_abapgit_repo_content_list, - lx_error TYPE REF TO zcx_abapgit_exception, - lv_lstate TYPE char1, - lv_rstate TYPE char1, - lv_max TYPE abap_bool, - lv_max_str TYPE string, - lv_add_str TYPE string, - lo_log TYPE REF TO zcl_abapgit_log. + DATA: lt_repo_items TYPE zif_abapgit_definitions=>tt_repo_items, + lo_browser TYPE REF TO zcl_abapgit_repo_content_list, + lx_error TYPE REF TO zcx_abapgit_exception, + lv_lstate TYPE char1, + lv_rstate TYPE char1, + lv_max TYPE abap_bool, + lv_max_str TYPE string, + lv_add_str TYPE string, + lo_log TYPE REF TO zcl_abapgit_log, + lv_render_transports TYPE abap_bool. FIELD-SYMBOLS LIKE LINE OF lt_repo_items. @@ -582,6 +628,9 @@ CLASS ZCL_ABAPGIT_GUI_VIEW_REPO IMPLEMENTATION. TRY. + lv_render_transports = zcl_abapgit_factory=>get_cts_api( + )->is_chrec_possible_for_package( mo_repo->get_package( ) ). + CREATE OBJECT lo_browser EXPORTING io_repo = mo_repo. @@ -624,7 +673,7 @@ CLASS ZCL_ABAPGIT_GUI_VIEW_REPO IMPLEMENTATION. lv_max = abap_true. EXIT. " current loop ENDIF. - ro_html->add( render_item( ) ). + ro_html->add( render_item( is_item = iv_render_transports = lv_render_transports ) ). ENDLOOP. ENDIF. diff --git a/src/zabapgit_js_common.w3mi.data.js b/src/zabapgit_js_common.w3mi.data.js index 11ec587b2..8efd75a41 100644 --- a/src/zabapgit_js_common.w3mi.data.js +++ b/src/zabapgit_js_common.w3mi.data.js @@ -24,7 +24,7 @@ if (!Function.prototype.bind) { }; if (this.prototype) { - fNOP.prototype = this.prototype; + fNOP.prototype = this.prototype; } fBound.prototype = new fNOP(); @@ -39,7 +39,7 @@ if (!String.prototype.includes) { if (typeof start !== 'number') { start = 0; } - + if (start + search.length > this.length) { return false; } else { @@ -64,7 +64,7 @@ function submitSapeventForm(params, action, method) { var form = document.createElement("form"); form.setAttribute("method", method || "post"); form.setAttribute("action", "sapevent:" + action); - + for(var key in params) { var hiddenField = document.createElement("input"); hiddenField.setAttribute("type", "hidden"); @@ -133,8 +133,8 @@ function perfOut(prefix) { var keys = Object.keys(totals); for (var i = keys.length - 1; i >= 0; i--) { - console.log(prefix - + " " + keys[i] + ": " + console.log(prefix + + " " + keys[i] + ": " + totals[keys[i]].time.toFixed(3) + "ms" + " (" + totals[keys[i]].count.toFixed() +")"); } @@ -190,10 +190,10 @@ function StageHelper(params) { objectSearch: document.getElementById(params.ids.objectSearch), fileCounter: document.getElementById(params.ids.fileCounter) }; - + // Table columns (autodetection) this.colIndex = this.detectColumns(); - this.filterTargets = ["name", "user"]; + this.filterTargets = ["name", "user", "transport"]; // Constants this.HIGHLIGHT_STYLE = "highlight"; @@ -204,7 +204,7 @@ function StageHelper(params) { reset: "?", isValid: function (status) { return "ARI?".indexOf(status) == -1; } }; - + this.TEMPLATES = { cmdReset: "reset", cmdLocal: "add", @@ -275,10 +275,10 @@ StageHelper.prototype.onTableClick = function (event) { } else return; if (["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 @@ -298,7 +298,7 @@ StageHelper.prototype.onTableClick = function (event) { StageHelper.prototype.onFilter = function (e) { if ( // Enter hit or clear, IE SUCKS ! e.type === "input" && !e.target.value && this.lastFilterValue - || e.type === "keypress" && e.which === 13 ) { + || e.type === "keypress" && e.which === 13 ) { this.applyFilterValue(e.target.value); submitSapeventForm({ 'filterValue': e.target.value }, "stage_filter", "post"); @@ -325,7 +325,7 @@ StageHelper.prototype.applyFilterToRow = function (row, filter) { }; }, this); - var isVisible = false; + var isVisible = false; // Apply filter to cells, mark filtered text for (var i = targets.length - 1; i >= 0; i--) { @@ -346,8 +346,8 @@ StageHelper.prototype.applyFilterToRow = function (row, filter) { // Get how status should affect object counter StageHelper.prototype.getStatusImpact = function (status) { - if (typeof status !== "string" - || status.length !== 1 + if (typeof status !== "string" + || status.length !== 1 || this.STATUS.isValid(status) ) { alert("Unknown status"); } else { @@ -383,8 +383,8 @@ StageHelper.prototype.updateRowStatus = function (row, status) { StageHelper.prototype.updateRowCommand = function (row, status) { var cell = row.cells[this.colIndex["cmd"]]; if (status === this.STATUS.reset) { - cell.innerHTML = (row.className == "local") - ? this.TEMPLATES.cmdLocal + cell.innerHTML = (row.className == "local") + ? this.TEMPLATES.cmdLocal : this.TEMPLATES.cmdRemote; } else { cell.innerHTML = this.TEMPLATES.cmdReset; @@ -413,7 +413,7 @@ StageHelper.prototype.collectData = function () { } // Table iteration helper -StageHelper.prototype.iterateStageTab = function (changeMode, cb /*, ...*/) { +StageHelper.prototype.iterateStageTab = function (changeMode, cb /*, ...*/) { var restArgs = Array.prototype.slice.call(arguments, 2); var table = this.dom.stageTab; @@ -502,7 +502,7 @@ function DiffHelper(params) { if (document.getElementById(params.ids.filterMenu)) { this.checkList = new CheckListWrapper(params.ids.filterMenu, this.onFilter.bind(this)); this.dom.filterButton = document.getElementById(params.ids.filterMenu).parentNode; - } + } // Hijack stage command if (this.dom.stageButton) { @@ -581,14 +581,14 @@ function displayNews() { div.style.display = (div.style.display) ? '' : 'none'; } -// Hotkey Overview +// Hotkey Overview function closeHotkeyOverview() { var div = document.getElementById("hotkeys"); div.style.display = (div.style.display) ? '' : 'none'; } function KeyNavigation() { - + } KeyNavigation.prototype.onkeydown = function(oEvent) { @@ -621,7 +621,7 @@ KeyNavigation.prototype.getActiveElementParent = function () { }; KeyNavigation.prototype.onEnterOrSpace = function (oEvent) { - + // Enter or space clicks the selected link var liSelected = this.getLiSelected(); @@ -695,7 +695,7 @@ function enableArrowListNavigation() { } function LinkHints(sLinkHintKey, sColor){ - this.sLinkHintKey = sLinkHintKey; + this.sLinkHintKey = sLinkHintKey; this.sColor = sColor; this.oTooltipMap = {}; this.bTooltipsOn = false; @@ -715,7 +715,7 @@ LinkHints.prototype.fnRenderTooltip = function (oTooltip, iTooltipCounter) { }; LinkHints.prototype.getTooltipStartValue = function(iToolTipCount){ - + // if whe have 333 tooltips we start from 100 return Math.pow(10,iToolTipCount.toString().length - 1); @@ -724,10 +724,10 @@ LinkHints.prototype.getTooltipStartValue = function(iToolTipCount){ LinkHints.prototype.fnRenderTooltips = function () { // all possible links which should be accessed via tooltip have - // sub span which is hidden by default. If we like to show the + // sub span which is hidden by default. If we like to show the // tooltip we have to toggle the css class 'hidden'. - // - // We use numeric values for the tooltip label. Maybe we can + // + // We use numeric values for the tooltip label. Maybe we can // support also alphanumeric chars in the future. Then we have to // calculate permutations and that's work. So for the sake of simplicity // we stick to numeric values and just increment them. @@ -784,7 +784,7 @@ LinkHints.prototype.fnFilterTooltips = function (sPending) { }; LinkHints.prototype.fnActivateDropDownMenu = function (oTooltip) { - // to enable link hint navigation for drop down menu, we must expand + // to enable link hint navigation for drop down menu, we must expand // like if they were hovered oTooltip.parentElement.parentElement.classList.toggle("block"); }; @@ -810,7 +810,7 @@ LinkHints.prototype.onkeypress = function(oEvent){ } var activeElementType = ((document.activeElement && document.activeElement.nodeName) || ""); - + // link hints are disabled for input and textareas for obvious reasons. // Maybe we must add other types here in the future if (oEvent.key === this.sLinkHintKey && activeElementType !== "INPUT" && activeElementType !== "TEXTAREA") { @@ -818,7 +818,7 @@ LinkHints.prototype.onkeypress = function(oEvent){ this.fnToggleAllTooltips(); } else if (this.bTooltipsOn === true) { - + // the user tries to reach a tooltip this.sPending += oEvent.key; var oTooltip = this.oTooltipMap[this.sPending]; @@ -856,8 +856,8 @@ function Hotkeys(oKeyMap){ // these are the hotkeys provided by the backend Object.keys(this.oKeyMap).forEach(function(sKey){ - var action = this.oKeyMap[sKey]; - + var action = this.oKeyMap[sKey]; + // We replace the actions with callback functions to unify // the hotkey execution this.oKeyMap[sKey] = function(oEvent) { @@ -872,7 +872,7 @@ function Hotkeys(oKeyMap){ if (window[action]) { window[action].call(this); } - + // Or a SAP event var sUiSapEvent = this.getSapEvent(action); if (sUiSapEvent) { @@ -889,7 +889,7 @@ function Hotkeys(oKeyMap){ Hotkeys.prototype.showHotkeys = function() { var elHotkeys = document.querySelector('#hotkeys'); - + if (elHotkeys) { elHotkeys.style.display = (elHotkeys.style.display) ? '' : 'none'; } @@ -906,7 +906,7 @@ Hotkeys.prototype.getSapEvent = function(sSapEvent) { var aSapEvents = document.querySelectorAll('a[href^="sapevent:' + sSapEvent + '"]'); - var aFilteredAndNormalizedSapEvents = + var aFilteredAndNormalizedSapEvents = [].map.call(aSapEvents, function(oSapEvent){ return fnNormalizeSapEventHref(sSapEvent, oSapEvent); }) @@ -931,7 +931,7 @@ Hotkeys.prototype.onkeydown = function(oEvent){ return; } - var + var sKey = oEvent.key || String.fromCharCode(oEvent.keyCode), fnHotkey = this.oKeyMap[sKey]; @@ -948,7 +948,7 @@ function setKeyBindings(oKeyMap){ } -/* +/* Patch / git add -p */ @@ -971,7 +971,7 @@ function Patch() { PATCH_ADD_ALL: 'patch_add_all', PATCH_REMOVE_ALL: 'patch_remove_all' }; - + this.ACTION = { PATCH_STAGE: 'patch_stage' }; @@ -999,7 +999,7 @@ Patch.prototype.registerClickHandlerSingleLine = function(){ Patch.prototype.registerClickHandlerAllFile = function(){ - // registers the link handlers for add and remove all changes for a file + // registers the link handlers for add and remove all changes for a file this.registerClickHandlerForPatchLinkAll('#' + this.ID.PATCH_ADD_ALL, this.ADD_REMOVE); this.registerClickHandlerForPatchLinkAll('#' + this.ID.PATCH_REMOVE_ALL, this.REMOVE_ADD); @@ -1007,14 +1007,14 @@ Patch.prototype.registerClickHandlerAllFile = function(){ }; Patch.prototype.registerClickHandlerForPatchLink = function(oClassCombination) { - // register onclick handler. When a link is clicked it is + // register onclick handler. When a link is clicked it is // deactivated and its corresponding link gets active // - // e.g. if you click on 'add' add is deactivated and 'remove' + // e.g. if you click on 'add' add is deactivated and 'remove' // is activated. var elLinkAll = document.querySelectorAll('.' + this.CSS_CLASS.PATCH + ' a.' + oClassCombination.sClassLinkClicked); - + [].forEach.call(elLinkAll,function(elLink){ elLink.addEventListener('click',function(oEvent){ @@ -1025,7 +1025,7 @@ Patch.prototype.registerClickHandlerForPatchLink = function(oClassCombination) { }; -Patch.prototype.togglePatchActive = function(oEvent, elClicked, elCorrespondingLink){ +Patch.prototype.togglePatchActive = function(oEvent, elClicked, elCorrespondingLink){ if (!elClicked.classList.contains(this.CSS_CLASS.PATCH_ACTIVE)){ elClicked.classList.toggle(this.CSS_CLASS.PATCH_ACTIVE); @@ -1046,7 +1046,7 @@ Patch.prototype.togglePatchActiveForClassLink = function(oEvent, elClicked, oCla Patch.prototype.getCorrespodingLinkId = function(sClickedLinkId, oClassCombination){ - // e.g. + // e.g. // // add_patch_z_test_git_add_p.prog.abap_28 => remove_patch_z_test_git_add_p.prog.abap_28 // @@ -1066,7 +1066,7 @@ Patch.prototype.patchLinkClickAll = function(oClassCombination) { var sTableId = oEvent.srcElement.parentElement.parentElement.parentElement.parentElement.id; var elAddAll = document.querySelectorAll('#' + this.escapeDots(sTableId) + ' a.' + oClassCombination.sClassLinkClicked); - + [].forEach.call(elAddAll,function(elem){ this.togglePatchActiveForClassLink(oEvent, elem, oClassCombination); }.bind(this)); diff --git a/src/zcl_abapgit_cts_api.clas.abap b/src/zcl_abapgit_cts_api.clas.abap new file mode 100644 index 000000000..23bf54d39 --- /dev/null +++ b/src/zcl_abapgit_cts_api.clas.abap @@ -0,0 +1,118 @@ +"! Change transport system API +CLASS zcl_abapgit_cts_api DEFINITION + PUBLIC + FINAL + CREATE PRIVATE + GLOBAL FRIENDS zcl_abapgit_factory. + + PUBLIC SECTION. + INTERFACES: + zif_abapgit_cts_api. + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + + +CLASS zcl_abapgit_cts_api IMPLEMENTATION. + METHOD zif_abapgit_cts_api~get_current_transport_for_obj. + DATA: lv_object_lockable TYPE abap_bool, + lv_locked TYPE abap_bool, + lv_transport_request TYPE trkorr, + lv_task TYPE trkorr, + lv_tr_object_name TYPE trobj_name. + + lv_tr_object_name = iv_object_name. + + CALL FUNCTION 'TR_CHECK_OBJECT_LOCK' + EXPORTING + wi_pgmid = iv_program_id + wi_object = iv_object_type + wi_objname = lv_tr_object_name + IMPORTING + we_lockable_object = lv_object_lockable + we_locked = lv_locked + we_lock_order = lv_transport_request + we_lock_task = lv_task + EXCEPTIONS + empty_key = 1 + no_systemname = 2 + no_systemtype = 3 + unallowed_lock_order = 4 + OTHERS = 5. + IF sy-subrc <> 0. + zcx_abapgit_exception=>raise_t100( ). + ENDIF. + + IF lv_locked = abap_false. + zcx_abapgit_exception=>raise( |Object { iv_program_id }-{ iv_object_type }-{ iv_object_name } is not locked| ). + ENDIF. + + IF lv_object_lockable = abap_false. + zcx_abapgit_exception=>raise( |Object type { iv_program_id }-{ iv_object_type } not lockable| ). + ENDIF. + + IF lv_task IS NOT INITIAL AND lv_task <> lv_transport_request AND iv_resolve_task_to_request = abap_false. + rv_transport = lv_task. + ELSE. + rv_transport = lv_transport_request. + ENDIF. + ENDMETHOD. + + METHOD zif_abapgit_cts_api~is_object_locked_in_transport. + DATA: ls_object_key TYPE e071, + lv_type_check_result TYPE c LENGTH 1, + ls_lock_key TYPE tlock_int, + lv_lock_flag TYPE c LENGTH 1. + + ls_object_key-pgmid = iv_program_id. + ls_object_key-object = iv_object_type. + ls_object_key-obj_name = iv_object_name. + + CALL FUNCTION 'TR_CHECK_TYPE' + EXPORTING + wi_e071 = ls_object_key + IMPORTING + pe_result = lv_type_check_result + we_lock_key = ls_lock_key. + + IF lv_type_check_result <> 'L'. + zcx_abapgit_exception=>raise( |Object type { iv_program_id }-{ iv_object_type } not lockable| ). + ENDIF. + + CALL FUNCTION 'TRINT_CHECK_LOCKS' + EXPORTING + wi_lock_key = ls_lock_key + IMPORTING + we_lockflag = lv_lock_flag + EXCEPTIONS + empty_key = 1 + OTHERS = 2. + IF sy-subrc <> 0. + zcx_abapgit_exception=>raise( |TRINT_CHECK_LOCKS: { sy-subrc }| ). + ENDIF. + + rv_locked = boolc( lv_lock_flag <> space ). + ENDMETHOD. + + METHOD zif_abapgit_cts_api~is_object_type_lockable. + DATA: ls_object_key TYPE e071, + lv_type_check_result TYPE c LENGTH 1. + + ls_object_key-pgmid = iv_program_id. + ls_object_key-object = iv_object_type. + ls_object_key-obj_name = '*'. + + CALL FUNCTION 'TR_CHECK_TYPE' + EXPORTING + wi_e071 = ls_object_key + IMPORTING + pe_result = lv_type_check_result. + + rv_lockable = boolc( lv_type_check_result = 'L' ). + ENDMETHOD. + + METHOD zif_abapgit_cts_api~is_chrec_possible_for_package. + rv_possible = zcl_abapgit_factory=>get_sap_package( iv_package )->are_changes_recorded_in_tr_req( ). + ENDMETHOD. +ENDCLASS. diff --git a/src/zcl_abapgit_cts_api.clas.xml b/src/zcl_abapgit_cts_api.clas.xml new file mode 100644 index 000000000..9373450a4 --- /dev/null +++ b/src/zcl_abapgit_cts_api.clas.xml @@ -0,0 +1,18 @@ + + + + + + ZCL_ABAPGIT_CTS_API + 1 + E + Change transport system API + 1 + X + X + X + X + + + + diff --git a/src/zcl_abapgit_factory.clas.abap b/src/zcl_abapgit_factory.clas.abap index b3d417139..ac0ff094c 100644 --- a/src/zcl_abapgit_factory.clas.abap +++ b/src/zcl_abapgit_factory.clas.abap @@ -54,6 +54,9 @@ CLASS zcl_abapgit_factory DEFINITION CLASS-METHODS get_stage_logic RETURNING VALUE(ri_logic) TYPE REF TO zif_abapgit_stage_logic . + CLASS-METHODS get_cts_api + RETURNING + VALUE(ri_cts_api) TYPE REF TO zif_abapgit_cts_api. PRIVATE SECTION. TYPES: @@ -96,6 +99,7 @@ CLASS zcl_abapgit_factory DEFINITION CLASS-DATA gt_syntax_check TYPE tty_syntax_check . CLASS-DATA gi_branch_overview TYPE REF TO zif_abapgit_branch_overview . CLASS-DATA gi_stage_logic TYPE REF TO zif_abapgit_stage_logic . + CLASS-DATA gi_cts_api TYPE REF TO zif_abapgit_cts_api. CLASS-DATA gi_adhoc_code_inspector TYPE REF TO zif_abapgit_code_inspector. ENDCLASS. @@ -218,6 +222,13 @@ CLASS zcl_abapgit_factory IMPLEMENTATION. ENDMETHOD. + METHOD get_cts_api. + IF gi_cts_api IS NOT BOUND. + CREATE OBJECT gi_cts_api TYPE zcl_abapgit_cts_api. + ENDIF. + + ri_cts_api = gi_cts_api. + ENDMETHOD. METHOD get_adhoc_code_inspector. @@ -246,6 +257,4 @@ CLASS zcl_abapgit_factory IMPLEMENTATION. ENDIF. ENDMETHOD. - - ENDCLASS. diff --git a/src/zcl_abapgit_injector.clas.abap b/src/zcl_abapgit_injector.clas.abap index 09ca4b5f4..692d98c60 100644 --- a/src/zcl_abapgit_injector.clas.abap +++ b/src/zcl_abapgit_injector.clas.abap @@ -24,12 +24,15 @@ CLASS zcl_abapgit_injector DEFINITION CLASS-METHODS set_stage_logic IMPORTING !ii_logic TYPE REF TO zif_abapgit_stage_logic . + CLASS-METHODS set_cts_api + IMPORTING + ii_cts_api TYPE REF TO zif_abapgit_cts_api. PRIVATE SECTION. ENDCLASS. -CLASS ZCL_ABAPGIT_INJECTOR IMPLEMENTATION. +CLASS zcl_abapgit_injector IMPLEMENTATION. METHOD set_code_inspector. @@ -115,4 +118,8 @@ CLASS ZCL_ABAPGIT_INJECTOR IMPLEMENTATION. zcl_abapgit_factory=>gi_tadir = ii_tadir. ENDMETHOD. + + METHOD set_cts_api. + zcl_abapgit_factory=>gi_cts_api = ii_cts_api. + ENDMETHOD. ENDCLASS. diff --git a/src/zif_abapgit_cts_api.intf.abap b/src/zif_abapgit_cts_api.intf.abap new file mode 100644 index 000000000..e09c2d26a --- /dev/null +++ b/src/zif_abapgit_cts_api.intf.abap @@ -0,0 +1,42 @@ +"! Change transport system API +INTERFACE zif_abapgit_cts_api PUBLIC. + METHODS: + "! Returns the transport request / task the object is currently locked in + "! @parameter iv_program_id | Program ID + "! @parameter iv_object_type | Object type + "! @parameter iv_object_name | Object name + "! @parameter iv_resolve_task_to_request | Return the transport request number if the object is locked in a task + "! @parameter rv_transport | Transport request / task + "! @raising zcx_abapgit_exception | Object is not locked in a transport + get_current_transport_for_obj IMPORTING iv_program_id TYPE pgmid DEFAULT 'R3TR' + iv_object_type TYPE trobjtype + iv_object_name TYPE sobj_name + iv_resolve_task_to_request TYPE abap_bool DEFAULT abap_true + RETURNING VALUE(rv_transport) TYPE trkorr + RAISING zcx_abapgit_exception, + "! Check if the object is currently locked in a transport + "! @parameter iv_program_id | Program ID + "! @parameter iv_object_type | Object type + "! @parameter iv_object_name | Object name + "! @parameter rv_locked | Object is locked + "! @raising zcx_abapgit_exception | Object type is not lockable + is_object_locked_in_transport IMPORTING iv_program_id TYPE pgmid DEFAULT 'R3TR' + iv_object_type TYPE trobjtype + iv_object_name TYPE sobj_name + RETURNING VALUE(rv_locked) TYPE abap_bool + RAISING zcx_abapgit_exception, + "! Check if the object type is lockable + "! @parameter iv_program_id | Program ID + "! @parameter iv_object_type | Object type + "! @parameter rv_lockable | Lockable + is_object_type_lockable IMPORTING iv_program_id TYPE pgmid DEFAULT 'R3TR' + iv_object_type TYPE trobjtype + RETURNING VALUE(rv_lockable) TYPE abap_bool, + "! Check if change recording is possible for the given package + "! @parameter iv_package | Package + "! @parameter rv_possible | Change recording is possible + "! @raising zcx_abapgit_exception | Package could not be loaded + is_chrec_possible_for_package IMPORTING iv_package TYPE devclass + RETURNING VALUE(rv_possible) TYPE abap_bool + RAISING zcx_abapgit_exception. +ENDINTERFACE. diff --git a/src/zif_abapgit_cts_api.intf.xml b/src/zif_abapgit_cts_api.intf.xml new file mode 100644 index 000000000..296410a5c --- /dev/null +++ b/src/zif_abapgit_cts_api.intf.xml @@ -0,0 +1,16 @@ + + + + + + ZIF_ABAPGIT_CTS_API + 1 + E + Change transport system API + 2 + 1 + X + + + + diff --git a/src/zif_abapgit_definitions.intf.abap b/src/zif_abapgit_definitions.intf.abap index 2c1e56709..1d12acc64 100644 --- a/src/zif_abapgit_definitions.intf.abap +++ b/src/zif_abapgit_definitions.intf.abap @@ -481,6 +481,7 @@ INTERFACE zif_abapgit_definitions PUBLIC. jump TYPE string VALUE 'jump', jump_pkg TYPE string VALUE 'jump_pkg', + jump_transport TYPE string VALUE 'jump_transport', url TYPE string VALUE 'url', END OF c_action .
TypeFiles to add (click to see diff)Changed byTransport' ). ro_html->add( 'addreset↓' ). @@ -355,12 +420,16 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_STAGE IMPLEMENTATION. ENDAT. READ TABLE lt_changed_by INTO ls_changed_by WITH KEY item = -item. "#EC CI_SUBRC + READ TABLE lt_transports INTO ls_transport WITH KEY item = -item. "#EC CI_SUBRC ro_html->add( render_file( iv_context = 'local' is_file = -file is_item = -item - iv_changed_by = ls_changed_by-name ) ). + iv_changed_by = ls_changed_by-name + iv_transport = ls_transport-transport ) ). + + CLEAR ls_transport. AT LAST. ro_html->add( '
' && 'non-code and meta files' && '{ get_item_icon( is_item ) }| && + |{ lv_icon_html }| && + |