Skip to content

Instantly share code, notes, and snippets.

@mbtools
Created December 21, 2020 20:33
Show Gist options
  • Save mbtools/e9d67932622b8345417af8dba1aaafed to your computer and use it in GitHub Desktop.
Save mbtools/e9d67932622b8345417af8dba1aaafed to your computer and use it in GitHub Desktop.
abapGit HTML
/*
* ABAPGIT COMMON CSS
*/
/* GLOBALS */
body {
overflow-x: hidden;
}
a, a:visited {
text-decoration: none;
}
a:hover, a:active {
cursor: pointer;
text-decoration: underline;
}
img {
border-width: 0px;
vertical-align: middle;
}
table { border-collapse: collapse; }
pre { display: inline; }
sup {
vertical-align: top;
position: relative;
top: -0.5em;
font-size: 75%;
}
input, textarea, select {
padding: 3px 0.5em;
border: 1px solid;
}
input:focus, textarea:focus {
border: 1px solid;
}
.cursor-pointer {
cursor: pointer;
}
span.separator {
padding-left: 0.5em;
padding-right: 0.5em;
opacity: 0.25;
}
/* MODIFIERS */
.emphasis { font-weight: bold !important; }
.crossout { text-decoration: line-through !important; }
.right { text-align:right; }
.center { text-align:center; }
.paddings { padding: 0.5em 0.5em; }
.pad-sides { padding-left: 0.3em; padding-right: 0.3em; }
.margin-v5 { margin-top: 0.5em; margin-bottom: 0.5em; }
.margin-v1 { margin-top: 1em; margin-bottom: 1em; }
.margin-30px { margin-top: 30px !important; margin-bottom: 30px !important; }
.indent5em { padding-left: 0.5em; }
.pad4px { padding: 4px; }
.w100 { width: 100%; }
.wmin { width: 1%; }
.w40 { width: 40%; }
.float-right { float: right; }
.pad-right { padding-right: 6px; }
.inline { display: inline; }
.hidden { visibility: hidden; }
.nodisplay { display: none }
.m-em5-sides { margin-left: 0.5em; margin-right: 0.5em }
.w600px { width: 600px }
.wmax600px { max-width: 600px }
.auto-center { /* use with max-width */
width: 100%;
margin-left: auto !important;
margin-right: auto !important;
}
/* PANELS */
div.panel {
border-radius: 3px;
padding: 0.5em 0.5em;
margin: 0.5em 0.5em;
}
div.dummydiv {
padding: 0.5em 1em;
text-align: center;
}
a.close-btn {
text-decoration: none;
}
/* STRUCTURE DIVS, HEADER & FOOTER */
div#header {
padding: 0.5em 0.5em;
border-bottom: 3px double;
}
div#header > div { display: inline-block }
.logo .icon { display: inline-block }
.logo .icon:before { width: auto }
/* official logo colors, not vars, redefine in themes directly*/
.logo .icon.icon-git-alt { color: #f03c2e }
.logo .icon.icon-abapgit {
color: #362701;
vertical-align: bottom;
}
div#header .logo { font-size: x-large }
div#header .page-title { font-size: x-large }
div#header span.spacer {
display: inline-block;
padding-right: 0.25em;
padding-left: 0.25em;
}
div#footer .logo { font-size: large }
div#footer {
padding: 0.5em 1em;
border-top: 3px double;
}
div#footer .version {
margin-top: 0.5em;
font-size: small;
}
#debug-output {
text-align: right;
padding-right: 0.5em;
font-size: smaller;
font-family: monospace;
}
#debug-output p {
margin-top: 0em;
margin-bottom: 0em;
}
/* ERROR LOG */
div.log {
padding: 6px;
margin: 4px;
border: 1px solid;
border-radius: 4px;
}
div.log > span { display:block; }
div.log .icon { padding-right: 6px; }
/* REPOSITORY */
div.repo {
margin-top: 3px;
margin-bottom: 3px;
padding: 0.5em 1em 0.5em 1em;
position: relative;
}
.repo_name span.name {
font-weight: bold;
font-size: 14pt;
}
.repo_name a.url {
font-size: 12pt;
margin-left: 0.5em;
}
.repo_name span.url {
font-size: 12pt;
margin-left: 0.5em;
}
.repo_name .icon {
padding-right: 4px;
}
.repo_attr {
font-size: 12pt;
}
.repo_attr span {
margin-left: 0.2em;
margin-right: 0.5em;
}
.repo_attr span.bg_marker {
border: 1px solid;
border-radius: 3px;
font-size: 8pt;
padding: 4px 2px 3px 2px;
}
span.branch {
padding: 2px 4px;
border: 1px solid;
border-radius: 4px;
}
/* MISC AND REFACTOR */
.hidden-submit {
border: 0 none;
height: 0;
width: 0;
padding: 0;
margin: 0;
overflow: hidden;
}
/* STATE BLOCK COMMON*/
span.state-block {
margin-left: 1em;
font-family: Consolas, Lucida Console, Courier, monospace;
font-size: x-small;
vertical-align: 13%;
display: inline-block;
text-align: center;
white-space: nowrap;
}
span.state-block span {
display: inline-block;
padding: 0px 3px;
border-width: 1px;
border-style: solid;
}
/* REPOSITORY TABLE*/
div.repo_container {
position: relative;
}
div.repo_banner {
margin: 0em 1em 1em;
padding: 0.5em 0.5em;
text-align: center;
font-size: 85%;
}
table.repo_tab {
border: 1px solid;
border-radius: 3px;
width: 100%;
line-height: 1.5;
}
.repo_tab th {
text-align: left;
padding: 0.5em;
border-bottom: 1px solid;
font-weight: normal;
}
.repo_tab td {
border-top: 1px solid;
vertical-align: middle;
padding-top: 2px;
padding-bottom: 2px;
}
.repo_tab td.icon {
width: 1px;
text-align: center;
padding-left: 8px;
padding-right: 4px;
}
.repo_tab td.icon:not(:first-child) {
width: 26px;
text-align: left;
}
.repo_tab td.type {
width: 4em;
padding-left: 0.5em;
}
.repo_tab td.object {
padding-left: 0.5em;
}
.repo_tab td.files {
padding-left: 0.5em;
line-height: 1.5;
}
.repo_tab td.cmd, .repo_tab th.cmd {
text-align: right;
padding-left: 0.5em;
padding-right: 0.7em;
}
.repo_tab th.cmd .icon{
padding-right: 8px;
}
.repo_tab tr:first-child td { border-top: 0px; }
.repo_tab tr:hover {
background-color: rgb(245, 245, 245) !important;
}
/* STAGE */
th.stage-status { width: 30px; }
th.stage-objtype { width: 30px; }
input.stage-filter { width: 18em; }
.stage_tab {
border: 1px solid;
margin-top: 0.2em;
line-height: 1.5;
}
.stage_tab td {
border-top: 1px solid;
vertical-align: middle;
padding: 2px 0.5em;
}
.stage_tab th {
text-align: left;
font-weight: normal;
padding: 4px 0.5em;
}
.stage_tab td.status {
width: 2em;
text-align: center;
}
.stage_tab td.highlight {
font-weight: bold;
}
.stage_tab tr:hover {
background-color: rgb(245, 245, 245) !important;
}
.stage_tab td.cmd { cursor: pointer; }
.stage_tab td.cmd a { padding: 0px 4px; }
.stage_tab th.cmd a { padding: 0px 4px; }
.stage_tab tbody tr:first-child td { padding-top: 0.5em; }
.stage_tab tbody tr:last-child td { padding-bottom: 0.5em; }
/* COMMIT */
div.form-container {
padding: 1em 1em;
}
form.aligned-form {
display: table;
border-spacing: 2px;
}
form.aligned-form label {
padding-right: 1em;
vertical-align: middle;
}
form.aligned-form select {
padding-right: 1em;
vertical-align: middle;
}
form.aligned-form span.sub-title {
font-size: smaller;
padding-top: 8px;
}
form.aligned-form div.row { display: table-row; }
form.aligned-form label { display: table-cell; }
form.aligned-form input { display: table-cell; }
form.aligned-form input[type="text"] { width: 25em; }
form.aligned-form span.cell { display: table-cell; }
/* SETTINGS STYLES */
div.settings_container {
padding: 0.5em 0.5em 1em;
font-size: 10pt;
}
div.settings_section {
margin-left:50px
}
table.settings td:first-child {
padding-left: 1em;
padding-right: 1em;
}
table.settings-package-requirements {
/*max-width: 300px;*/
}
/* DIFF */
div.diff {
padding: 0.7em
}
div.diff_head {
padding-bottom: 0.7em;
}
span.diff_name {
padding-left: 0.5em;
}
span.diff_changed_by {
float: right;
}
span.diff_changed_by span.user {
border-radius: 3px;
border: solid 1px;
padding: 1px 0.4em;
}
span.diff_banner {
border-style: solid;
border-width: 1px;
border-radius: 3px;
padding-left: 0.3em;
padding-right: 0.3em;
}
div.diff_content {
border-top: 1px solid;
border-bottom: 1px solid;
}
div.diff_content tbody tr td{
width: 50%;
vertical-align: top
}
div.diff_head span.state-block {
margin-left: 0.5em;
font-size: inherit;
vertical-align: initial;
}
div.diff_head span.state-block span {
padding: 0px 4px;
}
/* DIFF TABLE */
table.diff_tab {
font-family: Consolas, Courier, monospace;
font-size: 10pt;
width: 100%;
}
table.diff_tab td,th {
padding-left: 0.5em;
padding-right: 0.5em;
}
table.diff_tab th {
text-align: left;
font-weight: normal;
padding-top: 3px;
padding-bottom: 3px;
}
table.diff_tab thead.header th {
text-align: left;
font-weight: bold;
padding-left: 0.5em;
font-size: 9pt;
}
table.diff_tab td.num, th.num {
width: 1%;
min-width: 2em;
padding-right: 8px;
padding-left: 8px;
text-align: right !important;
border-left: 1px solid;
border-right: 1px solid;
-ms-user-select: none;
user-select: none;
}
table.diff_tab td.patch, th.patch {
width: 1%;
min-width: 1.5em;
padding-right: 8px;
padding-left: 8px;
text-align: right !important;
border-left: 1px solid;
border-right: 1px solid;
-ms-user-select: none;
user-select: none;
cursor: pointer;
}
table.diff_tab td.num::before {
content: attr(line-num);
}
table.diff_tab code {
font-family: inherit;
white-space: pre;
}
table.diff_tab td.code {
word-wrap: break-word;
white-space: pre-wrap;
overflow: visible;
}
table.diff_tab tbody tr:first-child td { padding-top: 0.5em; }
table.diff_tab tbody tr:last-child td { padding-bottom: 0.5em; }
table.diff_tab td.mark, th.mark {
width: 0.1%;
-ms-user-select: none;
user-select: none;
cursor: default;
}
.diff_select_left td.diff_right,
.diff_select_left td.diff_right *,
.diff_select_left th.diff_right,
.diff_select_left th.diff_right *,
.diff_select_right td.diff_left,
.diff_select_right td.diff_left *,
.diff_select_right th.diff_left,
.diff_select_right th.diff_left * {
-ms-user-select: none;
user-select: none;
cursor: text;
}
.diff_select_left td.diff_left,
.diff_select_left td.diff_left *,
.diff_select_left th.diff_left,
.diff_select_left th.diff_left *,
.diff_select_right td.diff_right,
.diff_select_right td.diff_right *,
.diff_select_right th.diff_right,
.diff_select_right th.diff_right * {
-ms-user-select: text;
user-select: text;
}
td.diff_others::selection,
td.diff_others *::selection,
th.diff_others::selection,
th.diff_others *::selection {
background-color: transparent;
cursor: default;
}
.diff_select_left td.diff_right::selection,
.diff_select_left td.diff_right *::selection,
.diff_select_left th.diff_right::selection,
.diff_select_left th.diff_right *::selection,
.diff_select_right td.diff_left::selection,
.diff_select_right td.diff_left *::selection,
.diff_select_right th.diff_left::selection,
.diff_select_right th.diff_left *::selection {
background-color: transparent;
cursor: text;
}
/* DEBUG INFO STYLES */
div.debug_container {
padding: 0.5em;
font-size: 10pt;
font-family: Consolas, Courier, monospace;
}
div.debug_container p {
margin: 0px;
}
/* DB ENTRIES */
div.db_list {
padding: 0.5em;
overflow-x: auto;
}
table.db_tab pre {
display: inline-block;
overflow: hidden;
word-wrap:break-word;
white-space: pre-wrap;
margin: 0px;
width: 30em;
}
table.db_tab tr.firstrow td { padding-top: 0.5em; }
table.db_tab th {
text-align: left;
padding: 0.5em;
border-bottom: 1px solid;
}
table.db_tab td {
padding: 4px 8px;
vertical-align: middle;
}
table.db_tab td.data {
font-style: italic;
}
/* DB ENTRY DISPLAY */
div.db_entry {
padding: 0.5em;
}
div.db_entry pre {
display: block;
font-size: 10pt;
overflow: hidden;
word-wrap:break-word;
white-space: pre-wrap;
border: 1px solid;
border-radius: 3px;
padding: 0.5em;
margin: 0.5em 0em;
width: 60em;
}
div.db_entry textarea { margin: 0.5em 0em; }
div.db_entry table.toolbar {
width: 50em;
}
table.tag {
display: inline-block;
border: 1px solid;
border-radius: 3px;
margin-right: 0.5em;
}
table.tag td { padding: 0.2em 0.5em; }
/* TUTORIAL */
div.tutorial {
margin-top: 3px;
padding: 0.5em 1em 0.5em 1em;
}
div.tutorial li { margin: 2px 0px }
div.tutorial h1 { font-size: 18pt; }
div.tutorial h2 { font-size: 14pt;}
/* MENU */
/* Special credits to example at https://codepen.io/philhoyt/pen/ujHzd */
/* container div, aligned left,
but with .float-right modifier alignes right */
.nav-container ul {
list-style: none;
position: relative;
float: left;
margin: 0;
padding: 0;
white-space: nowrap;
text-align: left;
}
.nav-container.float-right ul { float: right; }
.nav-container ul a {
display: block;
text-decoration: none;
line-height: 30px;
padding: 0 12px;
}
/* clearfix https://css-tricks.com/snippets/css/clear-fix/ */
.nav-container:after { clear: both; display: block; content: ""; }
/* submenues align to left or right border of the active item
depending on .float-right modifier */
.nav-container ul li {
position: relative;
float: left;
margin: 0;
padding: 0;
}
.nav-container.float-right ul ul { left: auto; right: 0; }
.nav-container ul li.current-menu-item { font-weight: 700; }
.nav-container ul li.force-nav-hover ul { display: block; }
.nav-container ul li:hover > ul { display: block; }
/* special selection style for 1st level items (see also .corner below) */
.nav-container ul ul {
display: none;
position: absolute;
top: 100%;
left: 0;
z-index: 1;
padding: 0;
box-shadow: 1px 1px 3px 0px #bbb;
}
.nav-container ul ul li {
float: none;
min-width: 160px;
}
.nav-container ul ul a {
line-height: 120%;
padding: 8px 15px;
}
.nav-container ul ul ul {
top: 0;
left: 100%;
}
.nav-container.float-right ul ul ul {
left: auto;
right: 100%;
}
/* Minizone to extent hover area,
aligned to the left or to the right of the selected item
depending on .float-right modifier */
.nav-container > ul > li > div.minizone {
display: none;
z-index: 1;
position: absolute;
padding: 0px;
width: 16px;
height: 100%;
bottom: 0px;
left: 100%;
}
.nav-container > ul > li:hover div.minizone { display: block; }
.nav-container.float-right > ul > li > div.minizone {
left: auto;
right: 100%;
}
/* icons - text-align strictly left - otherwise look ugly
+ bite a bit of left padding for nicer look
+ forbids item text wrapping (maybe can be done differently) */
.nav-container ul ul li a .icon {
padding-right: 10px;
margin-left: -3px;
}
.nav-container ul.with-icons li {
text-align: left;
white-space: nowrap;
}
/* Special .corner modifier - hangs menu at the top right corner
and cancels 1st level background coloring */
.nav-container.corner {
position: absolute;
right: 0px;
}
/* Toolbar separator style */
.nav-container ul ul li.separator {
font-size: x-small;
text-align: center;
padding: 4px 0;
text-transform: uppercase;
border-bottom: 1px solid;
border-top: 1px solid;
}
.nav-container ul ul li.separator:first-child { border-top: none; }
/* News Announcement */
div.info-panel {
position: absolute;
z-index: 99;
top: 36px;
left: 50%;
width: 40em;
margin-left: -20em;
box-shadow: 1px 1px 3px 2px #dcdcdc;
}
div.info-panel-fixed {
position: fixed;
top: 15%;
}
div.info-panel div.info-hint {
text-transform: uppercase;
font-size: small;
padding: 8px 6px 0px;
text-align: center;
}
div.info-panel div.info-title {
text-transform: uppercase;
font-size: small;
padding: 6px;
text-align: center;
}
div.info-panel div.info-title a.close-btn {
padding-left: 12px;
padding-right: 2px;
position: relative;
bottom: 1px;
}
div.info-panel div.info-list {
padding: 0.8em 0.7em 1em;
}
div.info-panel li {
padding-left: 10px;
list-style-type: none;
}
div.info-panel h1:first-child { margin: auto; }
div.info-panel h1 {
font-size: inherit;
padding: 6px 4px;
margin: 4px auto auto;
text-decoration: underline;
font-weight: normal;
}
div.info-panel .version-marker {
display: inline-block;
margin-left: 20px;
border-radius: 3px;
padding: 0px 6px;
border: 1px solid;
}
div.info-panel .update { border: 1px solid; }
div.info-panel div.info-list td { padding-right: 1em }
/* Error message Panel */
div.message-panel {
z-index: 99;
box-shadow: 2px 2px 4px 0px hsla(0, 0%, 0%, .1);
padding: 12px;
margin-left: -48%;
position: fixed;
bottom: 12px;
width: 94%;
left: 50%;
border: 1px solid;
border-radius: 5px;
border-color: hsl(0, 42%, 64%);
background-color: hsla(0, 42%, 90%, 1);
}
.message-panel-commands {
display: none;
margin-right: 2em;
}
.message-panel-commands a {
padding: 0em 0.5em;
border-left: 1px solid;
border-left-color: #ccc;
}
.message-panel-commands a:first-child {
padding-left: 0;
border-left: none;
}
div.message-panel:hover .message-panel-commands {
display: block
}
/* Tooltip text */
.link-hint {
line-height: 1em;
text-align: center;
padding: 5px 15px;
border-radius: 4px;
/* Position the tooltip text */
position: absolute;
z-index: 1;
margin-top: -30px;
}
.link-hint-a {
margin-left: -60px;
}
.link-hint-input {
margin-left: -30px;
}
.link-hint .pending { color: hsla(0, 0%, 0%, 0.2); }
/* Tooltip arrow */
.link-hint::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent;
}
/* HOTKEYS */
ul.hotkeys {
list-style-type: none;
padding: 0;
margin: 0;
font-size: smaller;
}
ul.hotkeys span.key-id {
border: 1px solid;
border-radius: 3px;
padding: 1px 7px;
width: 1em;
display: inline-block;
text-align: center;
margin-top: 0.2em;
}
ul.hotkeys span.key-descr {
margin-left: 1.2em;
}
div.corner-hint {
position: fixed;
bottom: 10px;
right: 10px;
border: 1px solid;
border-radius: 3px;
padding: 4px;
font-size: smaller;
opacity: 0.5;
z-index: 99;
}
/* Commit popup */
table.commit tr .title {
font-weight: bold;
vertical-align: top;
}
/* Repo overview */
.repo-overview { font-size: smaller; }
.repo-overview tbody td { height: 2em; }
.ro-detail { display: none; }
.ro-action { width: 260px; }
.ro-go { font-size: 150%; }
/* Branch Overview Page */
.gitGraph-scrollWrapper, .gitGraph-Wrapper{
overflow-y: hidden;
}
.gitGraph-scrollWrapper{
overflow-x: auto;
height: 20px;
}
.gitGraph-Wrapper{
overflow-x: hidden;
}
.gitGraph-HTopScroller {
width:1000px;
height: 20px;
}
/* code inspector */
.ci-head { padding: 0.5em 1em; }
.ci-head .package-name span { margin-left: 0.3em; }
.ci-variant { font-weight: bold; }
.ci-result {
padding: 6px;
margin-top: 4px;
}
.ci-result li {
list-style-type: none;
padding: 0.3em 0.8em;
margin-top: 6px;
border-left: 4px solid;
}
.ci-result li:first-child { margin-top: 0px; }
.ci-result li > span { display: block; }
/* Floating buttons */
.floating-button {
position: fixed;
top: 8em;
right: 2.8em;
padding: 1em 1.8em;
border-radius: 4px;
border-width: 1px;
border-style: solid;
box-shadow: 2px 2px 6px 0px #ccc;
cursor: pointer;
}
/* Command palette */
.cmd-palette {
position: absolute;
z-index: 99;
top: 36px;
left: 50%;
width: 40em;
margin-left: -20em;
box-shadow: 1px 1px 3px 2px #dcdcdc;
background-color: white;
border: solid 2px;
padding: 0px 1px;
}
.cmd-palette input {
width: 100%;
box-sizing: border-box;
}
.cmd-palette ul {
max-height: 10em;
overflow-y: scroll;
margin: 4px 0;
padding: 2px 4px;
}
.cmd-palette li {
list-style-type: none;
cursor: default;
padding: 4px 6px;
}
.cmd-palette li .icon {
margin-right: 10px;
}
/* SETTINGS */
table.settings_tab {
border: 1px solid;
max-width: 600px;
line-height: 1.5;
}
table.settings_tab th {
text-align: left;
padding: 0.5em;
border-bottom: 1px solid;
}
table.settings_tab td {
text-align: left;
padding: 0.3em 0.5em;
border-top: 1px solid;
}
table.settings_tab input {
border: none;
text-align: center;
}
settings_tab tr:first-child td { border-top: 0px; }
/* DIALOGS */
.dialog {
border: 1px solid;
padding: 1em 1em;
border-radius: 6px;
text-align: left;
}
.dialog ul {
padding: 0;
margin: 0;
}
.dialog li {
padding: 5px 10px;
display: block;
list-style: none;
position: relative;
}
.dialog li.dialog-commands {
text-align: right;
margin-top: 12px;
}
.dialog li.dialog-commands a {
border: 1px solid;
cursor: pointer;
text-decoration: none;
padding: 6px 12px;
border-radius: 3px;
font-size: smaller;
}
.dialog li.dialog-commands input[type="submit"] {
border: 1px solid;
padding: 6px 12px;
border-radius: 3px;
cursor: pointer;
}
.dialog li.dialog-commands input[type="submit"].main {
border: 1px solid transparent;
}
.dialog label {
display: block;
font-size: 90%;
margin-top: 6px;
margin-bottom: 6px;
padding-left: 0.5em;
}
.dialog li.error small {
display: block;
font-size: 75%;
margin: 4px 0px;
padding-left: 0.5em;
}
.dialog .radio-container {
border: 1px solid;
display: inline-block;
padding: 4px;
border-radius: 3px;
}
.dialog input[type="checkbox"] + label {
display: inline-block;
}
.dialog input[type="text"],
.dialog input[type="password"] {
width: 100%;
box-sizing : border-box;
height: 2.5em;
}
.dialog .radio-container input[type="radio"] {
visibility: hidden;
display: none;
height: 0px;
width: 0px;
}
.dialog .radio-container input[type="radio"] + label {
border: 1px solid transparent;
cursor: pointer;
width: auto;
margin: 0px;
padding: 3px 8px;
border-radius: 2px;
display: inline-block;
}
.dialog .radio-container input[type="radio"]:checked + label {
border: 1px solid transparent;
}
.dialog li.with-command div.input-container {
display: table-cell;
width: 100%;
}
.dialog li.with-command div.command-container {
display: table-cell;
}
.dialog li.with-command input[type="submit"] {
height: 2.5em;
}
.dialog fieldset {
margin-top: 1em;
border: 1px solid;
border-radius: 6px; /* doesn't work in IE ? */
padding-bottom: 1em;
}
.dialog fieldset:first-child {
margin-top: 0;
}
.dialog fieldset legend {
font-size: small;
text-transform: uppercase;
padding-left: 0.5em;
padding-right: 0.5em;
}
/* This icon is slightly wider than other icons */
.icon-cloud-upload-alt {
padding-right: 5px;
}
/*
* ABAPGIT COLOR THEME CSS - DEFAULT
*/
:root {
--theme-background-color: #E8E8E8;
--theme-container-background-color: #f2f2f2;
--theme-container-border-color: lightgrey;
--theme-primary-font: Arial,Helvetica,sans-serif;
--theme-primary-font-color: #333333;
--theme-primary-font-color-reduced: #ccc;
--theme-font-size: 12pt;
--theme-link-color: #4078c0;
--theme-table-border-color: #eee;
--theme-greyscale-dark: #808080;
--theme-greyscale-medium: #b3b3b3;
--theme-greyscale-light: #ccc;
--theme-greyscale-lighter: lightgrey;
--theme-linkhint-background: lightgreen;
--theme-debug-color: #aaa;
}
/* GLOBALS */
body {
background-color: var(--theme-background-color);
font-family: var(--theme-primary-font);
color: var(--theme-primary-font-color);
font-size: var(--theme-font-size);
}
a, a:visited { color: var(--theme-link-color); }
input, textarea, select { border-color: #ddd; }
input:focus, textarea:focus { border-color: #8cadd9; }
/* COLOR PALETTE */
.grey { color: var(--theme-greyscale-lighter) !important; }
.grey70 { color: var(--theme-greyscale-medium) !important; }
.grey80 { color: var(--theme-greyscale-light) !important; }
.darkgrey { color: var(--theme-greyscale-dark) !important; }
.bgorange { background-color: orange; }
.attention { color: red !important; }
.error { color: #d41919 !important; }
.warning { color: #efb301 !important; }
.success { color: green !important; }
.blue { color: #5e8dc9 !important; }
.red { color: red !important; }
.white { color: white !important; }
/* Floating buttons and color sets */
.blue-set {
border-color: #abc3e3;
color: #5e8dc9;
background-color: #d9e4f2;
}
.grey-set {
border-color: #c7c7c7;
color: var(--theme-greyscale-dark);
background-color: #e6e6e6;
}
/* PANELS */
/* TODO: add warning and error colors */
div.panel.success {
color: #589a58 !important;
background-color: #c5eac5;
}
div.panel.error {
color: #d41919;
background-color: #fad6d6;
}
div.panel.warning {
color: #efb301;
background-color: lightyellow;
}
#debug-output { color: var(--theme-debug-color); }
div.dummydiv { background-color: var(--theme-container-background-color); }
/* STRUCTURE DIVS, HEADER & FOOTER */
div#header { border-bottom-color: var(--theme-container-border-color); }
div#header .page-title { color: var(--theme-greyscale-medium); }
div#footer .version { color: var(--theme-greyscale-medium); }
div#footer { border-top-color: var(--theme-container-border-color); }
/* ERROR LOG */
div.log {
background-color: #fee6e6;
border-color: #fdcece;
}
/* REPOSITORY */
div.repo { background-color: var(--theme-container-background-color); }
.repo_name span.name { color: #333; }
.repo_name span.url { color: var(--theme-primary-font-color-reduced); }
.repo_name a.url { color: var(--theme-primary-font-color-reduced); }
.repo_attr { color: grey; }
.repo_attr span.bg_marker {
border-color: #d2d2d2;
background-color: #d8d8d8;
color: #fff;
}
.repo_attr span.branch_head {
border-color: #d8dff3;
background-color: #eceff9;
}
span.branch {
border-color: #d9d9d9;
background-color: #e2e2e2;
}
span.branch_branch {
border-color: #e7d9b1;
background-color: #f8f0d8;
}
/* REPOSITORY TABLE*/
table.repo_tab {
border-color: #ddd;
background-color: #fff;
}
.repo_tab th {
color: #888888;
border-bottom-color: #ddd;
}
.repo_tab td {
color: #333;
border-top-color: var(--theme-table-border-color);
}
.repo_tab .inactive { color: orange; }
.repo_tab tr.unsupported { color: var(--theme-greyscale-lighter); }
.repo_tab tr.modified { background-color: #fbf7e9; }
.repo_tab td.current_dir { color: var(--theme-primary-font-color-reduced); }
/*.repo_tab td.cmd span.state-block span { border-color: #000; }*/
/*.repo_tab td.cmd span.state-block span.added {
background-color: #69ad74;
border-color: #579e64;
color: white;
}
.repo_tab td.cmd span.state-block span.changed {
background-color: #e0c150;
border-color: #d4af25;
color: white;
}
.repo_tab td.cmd span.state-block span.mixed {
background-color: #e0c150;
border-color: #579e64;
color: #69ad74;
}
.repo_tab td.cmd span.state-block span.deleted {
background-color: #c76861;
border-color: #b8605a;
color: white;
}
.repo_tab td.cmd span.state-block span.none {
background-color: #e8e8e8;
border-color: #dbdbdb;
color: #c8c8c8;
}
*/
/* STAGE */
.stage_tab {
border-color: #ddd;
background-color: #fff;
}
.stage_tab td {
color: #333;
border-top-color: var(--theme-table-border-color);
}
.stage_tab th {
color: var(--theme-greyscale-medium);
background-color: #edf2f9;
}
.stage_tab td.status {
color: var(--theme-primary-font-color-reduced);
background-color: #fafafa;
}
.stage_tab td.highlight { color: #444 !important; }
.stage_tab td.method { color: var(--theme-primary-font-color-reduced); }
.stage_tab td.user { color: var(--theme-greyscale-medium); }
.stage_tab td.type { color: var(--theme-greyscale-medium); }
.stage_tab mark {
color: white;
background-color: #79a0d2;
}
/* COMMIT */
div.form-container { background-color: #F8F8F8; }
form.aligned-form label { color: var(--theme-greyscale-medium); }
form.aligned-form span.sub-title { color: var(--theme-greyscale-medium); }
/* SETTINGS STYLES */
div.settings_container {
color: #444;
background-color: var(--theme-container-background-color);
}
/* DIFF */
div.diff { background-color: var(--theme-container-background-color); }
span.diff_name { color: grey; }
span.diff_name strong { color: #333; }
span.diff_changed_by { color: grey; }
span.diff_changed_by span.user {
border-color: #c2d4ea;
background-color: #d9e4f2;
}
.diff_ins {
border-color: #abf2ab;
background-color: #e0ffe0;
}
.diff_del {
border-color: #ff667d;
background-color: #ffccd4;
}
.diff_upd {
border-color: #dada00;
background-color: #ffffcc;
}
div.diff_content {
background-color: #fff;
border-top-color: #ddd;
border-bottom-color: #ddd;
}
/*div.diff_head span.state-block span {
border-color: #000;
}
div.diff_head span.state-block span.added {
background-color: #69ad74;
border-color: #579e64;
color: white;
}
div.diff_head span.state-block span.changed {
background-color: #e0c150;
border-color: #d4af25;
color: white;
}
div.diff_head span.state-block span.mixed {
background-color: #e0c150;
border-color: #579e64;
color: #69ad74;
}
div.diff_head span.state-block span.deleted {
background-color: #c76861;
border-color: #b8605a;
color: white;
}
div.diff_head span.state-block span.none {
background-color: #e8e8e8;
border-color: #dbdbdb;
color: #c8c8c8;
}
*/
/* STATE BLOCK COLORS */
/*span.state-block span {
border-color: #000;
}*/
span.state-block span.added {
background-color: #69ad74;
border-color: #579e64;
color: white;
}
span.state-block span.changed {
background-color: #e0c150;
border-color: #d4af25;
color: white;
}
span.state-block span.mixed {
background-color: #e0c150;
border-color: #579e64;
color: #69ad74;
}
span.state-block span.deleted {
background-color: #c76861;
border-color: #b8605a;
color: white;
}
span.state-block span.none {
background-color: #e8e8e8;
border-color: #dbdbdb;
color: #c8c8c8;
}
/* DIFF TABLE */
table.diff_tab td,th {
color: #444;
}
table.diff_tab thead.header th {
color: #eee;
background-color: var(--theme-greyscale-medium);
}
table.diff_tab thead.nav_line {
background-color: #edf2f9;
}
table.diff_tab thead.nav_line th {
color: var(--theme-greyscale-medium);
}
table.diff_tab td.num, th.num {
color: var(--theme-primary-font-color-reduced);
border-left-color: var(--theme-table-border-color);
border-right-color: var(--theme-table-border-color);
}
table.diff_tab td.patch, th.patch {
color: var(--theme-primary-font-color-reduced);
border-left-color: var(--theme-table-border-color);
border-right-color: var(--theme-table-border-color);
}
/* STYLES for Syntax Highlighting */
/* abap */
.syntax-hl span.keyword { color: #0a69ce; }
.syntax-hl span.text { color: #48ce4f; }
.syntax-hl span.comment { color: var(--theme-greyscale-dark); font-style: italic; }
/* xml+html */
.syntax-hl span.xml_tag { color: #457ce3; }
.syntax-hl span.attr { color: #b777fb; }
.syntax-hl span.attr_val { color: #7a02f9; }
/* css+js */
.syntax-hl span.properties { color:#0a69ce; }
.syntax-hl span.values { color:blue; }
.syntax-hl span.units { color:maroon; }
.syntax-hl span.selectors { color:purple; }
.syntax-hl span.functions { color:purple; }
.syntax-hl span.colors { color:purple; }
.syntax-hl span.extensions { color:darkblue; }
.syntax-hl span.at_rules { color:darkblue; }
.syntax-hl span.html { color:green; }
.syntax-hl span.variables { color:purple; }
/* DEBUG INFO STYLES */
div.debug_container {
color: #444;
background-color: var(--theme-container-background-color);
}
/* DB ENTRIES */
div.db_list { background-color: #fff; }
table.db_tab td { color: #333; }
table.db_tab td.data { color: #888; }
table.db_tab tbody tr:hover, tr:active { background-color: #f4f4f4; }
table.db_tab th {
color: #888888;
border-bottom-color: #ddd;
}
/* DB ENTRY DISPLAY */
div.db_entry {
background-color: var(--theme-container-background-color);
}
div.db_entry pre {
background-color: #fcfcfc;
border-color: #eaeaea;
}
table.tag {
border-color: #b3c1cc;
background-color: #eee;
}
table.tag td.label { background-color: #b3c1cc; }
/* TUTORIAL */
div.tutorial { background-color: var(--theme-container-background-color); }
div.tutorial hr { border-color: var(--theme-greyscale-light); }
div.tutorial h1, h2 { color: #404040; }
/* MENU */
.nav-container ul ul li:hover { background-color: #f6f6f6; }
.nav-container > ul > li:hover > a { background-color: #ffffff80; }
.nav-container ul ul { background-color: #fff; }
.nav-container.corner > ul > li:hover > a { background-color: inherit; }
/* Toolbar separator style */
.nav-container ul ul li.separator {
color: var(--theme-greyscale-medium);
border-bottom-color: #eee;
border-top-color: #eee;
}
.nav-container ul ul li.separator:hover { background-color: inherit; }
/* News Announcement */
div.info-panel { background-color: white; }
div.info-panel div.info-hint { color: var(--theme-greyscale-light); }
div.info-panel div.info-title {
color: #f8f8f8;
background-color: #888;
}
div.info-panel div.info-title a.close-btn { color: #d8d8d8; }
div.info-panel div.info-list { color: #444; }
div.info-panel .version-marker {
color: white;
border-color: #c0c0c0;
background-color: var(--theme-greyscale-light);
}
div.info-panel .update {
border-color: #e8ba30;
background-color: #f5c538;
}
/* Tooltips text */
.link-hint { color: var(--theme-primary-font-color); }
.link-hint { background-color: var(--theme-linkhint-background) }
.link-hint::after { border-top-color: var(--theme-linkhint-background) }
/* HOTKEYS */
ul.hotkeys span.key-id {
background-color: #f0f0f0;
border-color: #dcdcdc;
}
div.corner-hint {
color: var(--theme-greyscale-medium);
border-color: var(--theme-greyscale-light);
background-color: #fff;
}
/* code inspector */
.ci-head { background-color: var(--theme-container-background-color); }
.ci-head .package-name span { color: grey; }
.ci-variant { color: #444; }
.ci-result { background-color: #f6f6f6; }
.ci-result li { color: #444; }
.ci-result li.ci-error { border-left-color: #cd5353; }
.ci-result li.ci-warning { border-left-color: #ecd227; }
.ci-result li.ci-info { border-left-color: #acacac; }
/* Command palette */
.cmd-palette {
border-color: #ccc;
}
.cmd-palette li.selected {
background-color: hsla(214, 50%, 90%, 1);
}
.cmd-palette mark {
color: white;
background-color: #79a0d2;
/* todo merge with stage search */
}
/* SETTINGS */
table.settings_tab {
background-color: #fff;
border-color: #ddd;
}
table.settings_tab th {
color: #888888;
border-bottom-color: #ddd;
}
table.settings_tab td {
color: #333;
border-top-color: #eee;
}
table.settings_tab input {
background-color: #f8f8f8;
}
table.settings_tab input:focus {
background-color: #fff;
}
/* HTML FORMS */
.dialog input::placeholder { color: #ccc }
.dialog input:-ms-input-placeholder { color: #ccc }
.dialog {
border-color: #cbcbcb;
background-color: #f4f4f4;
}
.dialog li.dialog-commands a {
border-color: #ccc;
}
.dialog li.dialog-commands input[type="submit"] {
border-color: #ccc;
}
.dialog li.dialog-commands input[type="submit"].main {
background-color: #64a8ff;
color: #fff;
}
.dialog label {
color: #444;
}
.dialog label em {
color: #64a8ff;
}
.dialog li.error small {
color: #ff5959;
}
.dialog li.error input[type="text"] {
border-color: #ff5959;
}
.dialog .radio-container {
border-color: #ddd;
background-color: #fff;
}
.dialog .radio-container input[type="radio"] + label {
color: #808080;
}
.dialog .radio-container input[type="radio"]:checked + label {
background-color: #64a8ff;
color: #fff;
}
.dialog li.with-command input[type="submit"]:hover {
background-color: #64a8ff;
color: #fff;
}
.dialog fieldset {
border-color: #dfdfdf;
}
.dialog fieldset legend {
color: #ccc;
}
*&---------------------------------------------------------------------*
*& Include ZABAPGIT_FORMS
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Form run
*&---------------------------------------------------------------------*
FORM run.
DATA: lx_exception TYPE REF TO zcx_abapgit_exception.
TRY.
zcl_abapgit_migrations=>run( ).
PERFORM open_gui.
CATCH zcx_abapgit_exception INTO lx_exception.
MESSAGE lx_exception TYPE 'E'.
ENDTRY.
ENDFORM. "run
FORM open_gui RAISING zcx_abapgit_exception.
IF sy-batch = abap_true.
zcl_abapgit_background=>run( ).
ELSE.
zcl_abapgit_services_abapgit=>prepare_gui_startup( ).
zcl_abapgit_ui_factory=>get_gui( )->go_home( ).
CALL SELECTION-SCREEN 1001. " trigger screen
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form branch_popup
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->TT_FIELDS text
* -->PV_CODE text
* -->CS_ERROR text
* -->CV_SHOW_POPUP text
* -->RAISING text
* -->zcx_abapgit_exception text
* -->##CALLED text
* -->##NEEDED text
*----------------------------------------------------------------------*
FORM branch_popup TABLES tt_fields TYPE zif_abapgit_definitions=>ty_sval_tt
USING pv_code TYPE clike
CHANGING cs_error TYPE svale
cv_show_popup TYPE c
RAISING zcx_abapgit_exception ##called ##needed.
* called dynamically from function module POPUP_GET_VALUES_USER_BUTTONS
DATA: lx_error TYPE REF TO zcx_abapgit_exception,
li_popups TYPE REF TO zif_abapgit_popups.
TRY.
li_popups = zcl_abapgit_ui_factory=>get_popups( ).
li_popups->branch_popup_callback(
EXPORTING
iv_code = pv_code
CHANGING
ct_fields = tt_fields[]
cs_error = cs_error
cv_show_popup = cv_show_popup ).
CATCH zcx_abapgit_exception INTO lx_error.
MESSAGE lx_error TYPE 'S' DISPLAY LIKE 'E'.
ENDTRY.
ENDFORM. "branch_popup
FORM output.
DATA:
lt_ucomm TYPE TABLE OF sy-ucomm,
lv_title TYPE sy-title.
" Check if gui title should be set differently
" Used by login page (see ZCL_ABAPGIT_GUI_PAGE_LOGIN)
IMPORT title = lv_title FROM MEMORY ID zif_abapgit_definitions=>gc_memoryid_title.
IF sy-subrc = 0.
SET TITLEBAR '%_T' WITH lv_title.
FREE MEMORY ID zif_abapgit_definitions=>gc_memoryid_title.
ELSE.
SET TITLEBAR '%_T' WITH 'abapGit'.
ENDIF.
PERFORM set_pf_status IN PROGRAM rsdbrunt IF FOUND.
APPEND 'CRET' TO lt_ucomm. "Button Execute
APPEND 'SPOS' TO lt_ucomm. "Button Save
CALL FUNCTION 'RS_SET_SELSCREEN_STATUS'
EXPORTING
p_status = sy-pfkey
TABLES
p_exclude = lt_ucomm.
ENDFORM.
FORM exit RAISING zcx_abapgit_exception.
" The exit logic should only be applied for our 'main' selection screen 1001.
" All other selection-screens are called as popups and shouldn't influence
" the gui navigation as it would lead to inpredictable behaviour like dumps.
IF sy-dynnr <> 1001.
RETURN.
ENDIF.
CASE sy-ucomm.
WHEN 'CBAC' OR 'CCAN'. "Back & Escape
IF zcl_abapgit_ui_factory=>get_gui( )->back( ) = abap_true. " end of stack
zcl_abapgit_ui_factory=>get_gui( )->free( ). " Graceful shutdown
ELSE.
CALL SELECTION-SCREEN 1001.
ENDIF.
ENDCASE.
ENDFORM.
FORM password_popup
USING
pv_repo_url TYPE string
CHANGING
cv_user TYPE string
cv_pass TYPE string.
lcl_password_dialog=>popup(
EXPORTING
iv_repo_url = pv_repo_url
CHANGING
cv_user = cv_user
cv_pass = cv_pass ).
ENDFORM.
FORM remove_toolbar USING pv_dynnr TYPE sy-dynnr.
DATA: ls_header TYPE rpy_dyhead,
lt_containers TYPE dycatt_tab,
lt_fields_to_containers TYPE dyfatc_tab,
lt_flow_logic TYPE swydyflow.
CALL FUNCTION 'RPY_DYNPRO_READ'
EXPORTING
progname = sy-cprog
dynnr = pv_dynnr
IMPORTING
header = ls_header
TABLES
containers = lt_containers
fields_to_containers = lt_fields_to_containers
flow_logic = lt_flow_logic
EXCEPTIONS
cancelled = 1
not_found = 2
permission_error = 3
OTHERS = 4.
IF sy-subrc IS NOT INITIAL.
RETURN. " Ignore errors, just exit
ENDIF.
IF ls_header-no_toolbar = abap_true.
RETURN. " No change required
ENDIF.
ls_header-no_toolbar = abap_true.
CALL FUNCTION 'RPY_DYNPRO_INSERT'
EXPORTING
header = ls_header
suppress_exist_checks = abap_true
TABLES
containers = lt_containers
fields_to_containers = lt_fields_to_containers
flow_logic = lt_flow_logic
EXCEPTIONS
cancelled = 1
already_exists = 2
program_not_exists = 3
not_executed = 4
missing_required_field = 5
illegal_field_value = 6
field_not_allowed = 7
not_generated = 8
illegal_field_position = 9
OTHERS = 10.
IF sy-subrc <> 2 AND sy-subrc <> 0.
RETURN. " Ignore errors, just exit
ENDIF.
ENDFORM.
CLASS zcl_abapgit_gui DEFINITION
PUBLIC
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES zif_abapgit_gui_services .
CONSTANTS:
BEGIN OF c_event_state,
not_handled TYPE i VALUE 0,
re_render TYPE i VALUE 1,
new_page TYPE i VALUE 2,
go_back TYPE i VALUE 3,
no_more_act TYPE i VALUE 4,
new_page_w_bookmark TYPE i VALUE 5,
go_back_to_bookmark TYPE i VALUE 6,
new_page_replacing TYPE i VALUE 7,
END OF c_event_state .
CONSTANTS:
BEGIN OF c_action,
go_home TYPE string VALUE 'go_home',
go_db TYPE string VALUE 'go_db',
END OF c_action .
METHODS go_home
RAISING
zcx_abapgit_exception .
METHODS go_page
IMPORTING
!ii_page TYPE REF TO zif_abapgit_gui_renderable
!iv_clear_stack TYPE abap_bool DEFAULT abap_true
RAISING
zcx_abapgit_exception .
METHODS back
IMPORTING
!iv_to_bookmark TYPE abap_bool DEFAULT abap_false
RETURNING
VALUE(rv_exit) TYPE abap_bool
RAISING
zcx_abapgit_exception .
METHODS on_event
FOR EVENT sapevent OF zif_abapgit_html_viewer
IMPORTING
!action
!frame
!getdata
!postdata
!query_table .
METHODS constructor
IMPORTING
!io_component TYPE REF TO object OPTIONAL
!ii_asset_man TYPE REF TO zif_abapgit_gui_asset_manager OPTIONAL
!ii_hotkey_ctl TYPE REF TO zif_abapgit_gui_hotkey_ctl OPTIONAL
!ii_html_processor TYPE REF TO zif_abapgit_gui_html_processor OPTIONAL
!iv_rollback_on_error TYPE abap_bool DEFAULT abap_true
RAISING
zcx_abapgit_exception .
METHODS free .
PROTECTED SECTION.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_page_stack,
page TYPE REF TO zif_abapgit_gui_renderable,
bookmark TYPE abap_bool,
END OF ty_page_stack .
DATA mv_rollback_on_error TYPE abap_bool .
DATA mi_cur_page TYPE REF TO zif_abapgit_gui_renderable .
DATA:
mt_stack TYPE STANDARD TABLE OF ty_page_stack .
DATA:
mt_event_handlers TYPE STANDARD TABLE OF REF TO zif_abapgit_gui_event_handler .
DATA mi_router TYPE REF TO zif_abapgit_gui_event_handler .
DATA mi_asset_man TYPE REF TO zif_abapgit_gui_asset_manager .
DATA mi_hotkey_ctl TYPE REF TO zif_abapgit_gui_hotkey_ctl .
DATA mi_html_processor TYPE REF TO zif_abapgit_gui_html_processor .
DATA mi_html_viewer TYPE REF TO zif_abapgit_html_viewer .
DATA mo_html_parts TYPE REF TO zcl_abapgit_html_parts .
METHODS cache_html
IMPORTING
!iv_text TYPE string
RETURNING
VALUE(rv_url) TYPE w3url .
METHODS startup
RAISING
zcx_abapgit_exception .
METHODS render
RAISING
zcx_abapgit_exception .
METHODS call_page
IMPORTING
!ii_page TYPE REF TO zif_abapgit_gui_renderable
!iv_with_bookmark TYPE abap_bool DEFAULT abap_false
!iv_replacing TYPE abap_bool DEFAULT abap_false
RAISING
zcx_abapgit_exception .
METHODS handle_action
IMPORTING
!iv_action TYPE c
!iv_getdata TYPE c OPTIONAL
!it_postdata TYPE cnht_post_data_tab OPTIONAL .
METHODS handle_error
IMPORTING
!ix_exception TYPE REF TO zcx_abapgit_exception .
METHODS handle_login
IMPORTING
!ix_login_error TYPE REF TO zcx_abapgit_exception .
ENDCLASS.
CLASS zcl_abapgit_gui IMPLEMENTATION.
METHOD back.
DATA: lv_index TYPE i,
ls_stack LIKE LINE OF mt_stack.
lv_index = lines( mt_stack ).
IF lv_index = 0.
rv_exit = abap_true.
RETURN.
ENDIF.
DO lv_index TIMES.
READ TABLE mt_stack INDEX lv_index INTO ls_stack.
ASSERT sy-subrc = 0.
DELETE mt_stack INDEX lv_index.
ASSERT sy-subrc = 0.
lv_index = lv_index - 1.
IF iv_to_bookmark = abap_false OR ls_stack-bookmark = abap_true.
EXIT.
ENDIF.
ENDDO.
mi_cur_page = ls_stack-page. " last page always stays
render( ).
ENDMETHOD.
METHOD cache_html.
rv_url = zif_abapgit_gui_services~cache_asset(
iv_text = iv_text
iv_type = 'text'
iv_subtype = 'html' ).
ENDMETHOD.
METHOD call_page.
DATA: ls_stack TYPE ty_page_stack.
IF iv_replacing = abap_false AND NOT mi_cur_page IS INITIAL.
ls_stack-page = mi_cur_page.
ls_stack-bookmark = iv_with_bookmark.
APPEND ls_stack TO mt_stack.
ENDIF.
mi_cur_page = ii_page.
render( ).
ENDMETHOD.
METHOD constructor.
IF io_component IS BOUND.
IF zcl_abapgit_gui_utils=>is_renderable( io_component ) = abap_true.
mi_cur_page ?= io_component. " direct page
ELSE.
IF zcl_abapgit_gui_utils=>is_event_handler( io_component ) = abap_false.
zcx_abapgit_exception=>raise( 'Component must be renderable or be an event handler' ).
ENDIF.
mi_router ?= io_component.
ENDIF.
ENDIF.
CREATE OBJECT mo_html_parts.
mv_rollback_on_error = iv_rollback_on_error.
mi_asset_man = ii_asset_man.
mi_hotkey_ctl = ii_hotkey_ctl.
mi_html_processor = ii_html_processor. " Maybe improve to middlewares stack ??
startup( ).
ENDMETHOD.
METHOD free.
SET HANDLER me->on_event FOR mi_html_viewer ACTIVATION space.
mi_html_viewer->close_document( ).
mi_html_viewer->free( ).
FREE mi_html_viewer.
ENDMETHOD.
METHOD go_home.
DATA: ls_stack LIKE LINE OF mt_stack,
lv_mode TYPE tabname.
IF mi_router IS BOUND.
CLEAR: mt_stack, mt_event_handlers.
APPEND mi_router TO mt_event_handlers.
" on_event doesn't accept strings directly
GET PARAMETER ID 'DBT' FIELD lv_mode.
CASE lv_mode.
WHEN 'ZABAPGIT'.
on_event( action = |{ c_action-go_db }| ).
WHEN OTHERS.
on_event( action = |{ c_action-go_home }| ).
ENDCASE.
ELSE.
IF lines( mt_stack ) > 0.
READ TABLE mt_stack INTO ls_stack INDEX 1.
mi_cur_page = ls_stack-page.
ENDIF.
render( ).
ENDIF.
ENDMETHOD.
METHOD go_page.
IF iv_clear_stack = abap_true.
CLEAR mt_stack.
ENDIF.
mi_cur_page = ii_page.
render( ).
ENDMETHOD.
METHOD handle_action.
DATA:
lx_exception TYPE REF TO zcx_abapgit_exception,
li_handler TYPE REF TO zif_abapgit_gui_event_handler,
li_event TYPE REF TO zif_abapgit_gui_event,
ls_handled TYPE zif_abapgit_gui_event_handler=>ty_handling_result.
CREATE OBJECT li_event TYPE zcl_abapgit_gui_event
EXPORTING
ii_gui_services = me
iv_action = iv_action
iv_getdata = iv_getdata
it_postdata = it_postdata.
TRY.
LOOP AT mt_event_handlers INTO li_handler.
ls_handled = li_handler->on_event( li_event ).
IF ls_handled-state IS NOT INITIAL AND ls_handled-state <> c_event_state-not_handled. " is handled
EXIT.
ENDIF.
ENDLOOP.
CASE ls_handled-state.
WHEN c_event_state-re_render.
render( ).
WHEN c_event_state-new_page.
call_page( ls_handled-page ).
WHEN c_event_state-new_page_w_bookmark.
call_page(
ii_page = ls_handled-page
iv_with_bookmark = abap_true ).
WHEN c_event_state-new_page_replacing.
call_page(
ii_page = ls_handled-page
iv_replacing = abap_true ).
WHEN c_event_state-go_back.
back( ).
WHEN c_event_state-go_back_to_bookmark.
back( abap_true ).
WHEN c_event_state-no_more_act.
" Do nothing, handling completed
WHEN OTHERS.
zcx_abapgit_exception=>raise( |Unknown action: { iv_action }| ).
ENDCASE.
CATCH zcx_abapgit_cancel ##NO_HANDLER.
" Do nothing = gc_event_state-no_more_act
CATCH zcx_abapgit_exception INTO lx_exception.
IF lx_exception->is_login( ) = abap_true.
handle_login( lx_exception ).
ELSE.
handle_error( lx_exception ).
ENDIF.
ENDTRY.
ENDMETHOD.
METHOD handle_error.
DATA: li_gui_error_handler TYPE REF TO zif_abapgit_gui_error_handler,
lx_exception TYPE REF TO cx_root.
IF mv_rollback_on_error = abap_true.
ROLLBACK WORK.
ENDIF.
TRY.
li_gui_error_handler ?= mi_cur_page.
IF li_gui_error_handler IS BOUND AND li_gui_error_handler->handle_error( ix_exception ) = abap_true.
" We rerender the current page to display the error box
render( ).
ELSE.
MESSAGE ix_exception TYPE 'S' DISPLAY LIKE 'E'.
ENDIF.
CATCH zcx_abapgit_exception cx_sy_move_cast_error INTO lx_exception.
" In case of fire we just fallback to plain old message
MESSAGE lx_exception TYPE 'S' DISPLAY LIKE 'E'.
ENDTRY.
ENDMETHOD.
METHOD handle_login.
DATA:
li_login_page TYPE REF TO zif_abapgit_gui_renderable,
lx_exception TYPE REF TO zcx_abapgit_exception.
TRY.
li_login_page = zcl_abapgit_gui_page_login=>create( iv_url = ix_login_error->url
iv_count = ix_login_error->count
iv_digest = ix_login_error->digest
io_page = mi_cur_page ).
call_page( ii_page = li_login_page
iv_replacing = abap_true ).
CATCH zcx_abapgit_exception INTO lx_exception.
" In case of fire we just fallback to plain old message
MESSAGE lx_exception TYPE 'S' DISPLAY LIKE 'E'.
ENDTRY.
ENDMETHOD.
METHOD on_event.
handle_action(
iv_action = action
iv_getdata = getdata
it_postdata = postdata ).
ENDMETHOD.
METHOD render.
DATA: lv_url TYPE w3url,
lv_html TYPE string,
li_html TYPE REF TO zif_abapgit_html.
IF mi_cur_page IS NOT BOUND.
zcx_abapgit_exception=>raise( 'GUI error: no current page' ).
ENDIF.
CLEAR mt_event_handlers.
mo_html_parts->clear( ).
IF mi_router IS BOUND.
APPEND mi_router TO mt_event_handlers.
ENDIF.
IF mi_hotkey_ctl IS BOUND.
mi_hotkey_ctl->reset( ).
ENDIF.
li_html = mi_cur_page->render( ).
lv_html = li_html->render( iv_no_indent_jscss = abap_true ).
IF mi_html_processor IS BOUND.
lv_html = mi_html_processor->process(
iv_html = lv_html
ii_gui_services = me ).
ENDIF.
lv_url = cache_html( lv_html ).
mi_html_viewer->show_url( lv_url ).
ENDMETHOD.
METHOD startup.
DATA: lt_events TYPE cntl_simple_events,
ls_event LIKE LINE OF lt_events,
lt_assets TYPE zif_abapgit_gui_asset_manager=>ty_web_assets.
FIELD-SYMBOLS <ls_asset> LIKE LINE OF lt_assets.
mi_html_viewer = zcl_abapgit_ui_factory=>get_html_viewer( ).
IF mi_asset_man IS BOUND.
lt_assets = mi_asset_man->get_all_assets( ).
LOOP AT lt_assets ASSIGNING <ls_asset> WHERE is_cacheable = abap_true.
zif_abapgit_gui_services~cache_asset(
iv_xdata = <ls_asset>-content
iv_url = <ls_asset>-url
iv_type = <ls_asset>-type
iv_subtype = <ls_asset>-subtype ).
ENDLOOP.
ENDIF.
ls_event-eventid = mi_html_viewer->m_id_sapevent.
ls_event-appl_event = abap_true.
APPEND ls_event TO lt_events.
mi_html_viewer->set_registered_events( lt_events ).
SET HANDLER me->on_event FOR mi_html_viewer.
ENDMETHOD.
METHOD zif_abapgit_gui_services~cache_asset.
DATA: lt_xdata TYPE lvc_t_mime,
lv_size TYPE i,
lt_html TYPE w3htmltab.
ASSERT iv_text IS SUPPLIED OR iv_xdata IS SUPPLIED.
IF iv_text IS SUPPLIED. " String input
zcl_abapgit_convert=>string_to_tab(
EXPORTING
iv_str = iv_text
IMPORTING
ev_size = lv_size
et_tab = lt_html ).
mi_html_viewer->load_data(
EXPORTING
iv_type = iv_type
iv_subtype = iv_subtype
iv_size = lv_size
iv_url = iv_url
IMPORTING
ev_assigned_url = rv_url
CHANGING
ct_data_table = lt_html
EXCEPTIONS
OTHERS = 1 ).
ELSE. " Raw input
zcl_abapgit_convert=>xstring_to_bintab(
EXPORTING
iv_xstr = iv_xdata
IMPORTING
ev_size = lv_size
et_bintab = lt_xdata ).
mi_html_viewer->load_data(
EXPORTING
iv_type = iv_type
iv_subtype = iv_subtype
iv_size = lv_size
iv_url = iv_url
IMPORTING
ev_assigned_url = rv_url
CHANGING
ct_data_table = lt_xdata
EXCEPTIONS
OTHERS = 1 ).
ENDIF.
ASSERT sy-subrc = 0. " Image data error
ENDMETHOD.
METHOD zif_abapgit_gui_services~get_current_page_name.
IF mi_cur_page IS BOUND.
rv_page_name = cl_abap_classdescr=>describe_by_object_ref( mi_cur_page )->get_relative_name( ).
ENDIF." ELSE - return is empty => initial page
ENDMETHOD.
METHOD zif_abapgit_gui_services~get_hotkeys_ctl.
ri_hotkey_ctl = mi_hotkey_ctl.
ENDMETHOD.
METHOD zif_abapgit_gui_services~get_html_parts.
ro_parts = mo_html_parts.
ENDMETHOD.
METHOD zif_abapgit_gui_services~register_event_handler.
ASSERT ii_event_handler IS BOUND.
INSERT ii_event_handler INTO mt_event_handlers INDEX 1.
ENDMETHOD.
ENDCLASS.
CLASS zcl_abapgit_gui_chunk_lib DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
TYPES:
BEGIN OF ty_event_signature,
method TYPE string,
name TYPE string,
END OF ty_event_signature .
CLASS-METHODS class_constructor .
CLASS-METHODS render_error
IMPORTING
!ix_error TYPE REF TO zcx_abapgit_exception OPTIONAL
!iv_error TYPE string OPTIONAL
!iv_extra_style TYPE string OPTIONAL
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html .
CLASS-METHODS render_repo_top
IMPORTING
!io_repo TYPE REF TO zcl_abapgit_repo
!iv_show_package TYPE abap_bool DEFAULT abap_true
!iv_show_branch TYPE abap_bool DEFAULT abap_true
!iv_show_commit TYPE abap_bool DEFAULT abap_true
!iv_interactive_branch TYPE abap_bool DEFAULT abap_false
!iv_branch TYPE string OPTIONAL
!io_news TYPE REF TO zcl_abapgit_news OPTIONAL
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING
zcx_abapgit_exception .
CLASS-METHODS render_item_state
IMPORTING
!iv_lstate TYPE char1
!iv_rstate TYPE char1
RETURNING
VALUE(rv_html) TYPE string .
CLASS-METHODS render_js_error_banner
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING
zcx_abapgit_exception .
CLASS-METHODS render_news
IMPORTING
!io_news TYPE REF TO zcl_abapgit_news
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING
zcx_abapgit_exception .
CLASS-METHODS render_commit_popup
IMPORTING
!iv_content TYPE csequence
!iv_id TYPE csequence
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING
zcx_abapgit_exception .
CLASS-METHODS render_error_message_box
IMPORTING
!ix_error TYPE REF TO zcx_abapgit_exception
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html .
CLASS-METHODS render_order_by_header_cells
IMPORTING
!it_col_spec TYPE zif_abapgit_definitions=>ty_col_spec_tt
!iv_order_by TYPE string
!iv_order_descending TYPE abap_bool
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html .
CLASS-METHODS render_warning_banner
IMPORTING
!iv_text TYPE string
!iv_extra_style TYPE string OPTIONAL
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html .
CLASS-METHODS render_infopanel
IMPORTING
!iv_div_id TYPE string
!iv_title TYPE string
!iv_hide TYPE abap_bool DEFAULT abap_true
!iv_hint TYPE string OPTIONAL
!iv_scrollable TYPE abap_bool DEFAULT abap_true
!io_content TYPE REF TO zif_abapgit_html
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING
zcx_abapgit_exception .
CLASS-METHODS render_event_as_form
IMPORTING
!is_event TYPE ty_event_signature
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html .
CLASS-METHODS render_repo_palette
IMPORTING
!iv_action TYPE string
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING
zcx_abapgit_exception .
CLASS-METHODS advanced_submenu
RETURNING
VALUE(ro_menu) TYPE REF TO zcl_abapgit_html_toolbar .
CLASS-METHODS help_submenu
RETURNING
VALUE(ro_menu) TYPE REF TO zcl_abapgit_html_toolbar .
PROTECTED SECTION.
CLASS-METHODS render_repo_top_commit_hash
IMPORTING
!ii_html TYPE REF TO zif_abapgit_html
!io_repo_online TYPE REF TO zcl_abapgit_repo_online
RAISING
zcx_abapgit_exception .
PRIVATE SECTION.
CLASS-DATA gv_time_zone TYPE timezone .
CLASS-METHODS render_branch_span
IMPORTING
!iv_branch TYPE string
!io_repo TYPE REF TO zcl_abapgit_repo_online
!iv_interactive TYPE abap_bool
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING
zcx_abapgit_exception .
CLASS-METHODS get_t100_text
IMPORTING
!iv_msgid TYPE scx_t100key-msgid
!iv_msgno TYPE scx_t100key-msgno
RETURNING
VALUE(rv_text) TYPE string .
CLASS-METHODS normalize_program_name
IMPORTING
!iv_program_name TYPE sy-repid
RETURNING
VALUE(rv_normalized_program_name) TYPE string .
ENDCLASS.
CLASS zcl_abapgit_gui_chunk_lib IMPLEMENTATION.
METHOD advanced_submenu.
DATA: li_gui_functions TYPE REF TO zif_abapgit_gui_functions,
lv_supports_ie_devtools TYPE abap_bool.
li_gui_functions = zcl_abapgit_ui_factory=>get_gui_functions( ).
lv_supports_ie_devtools = li_gui_functions->is_sapgui_for_windows( ).
CREATE OBJECT ro_menu.
ro_menu->add(
iv_txt = 'Database Utility'
iv_act = zif_abapgit_definitions=>c_action-go_db
)->add(
iv_txt = 'Package to Zip'
iv_act = zif_abapgit_definitions=>c_action-zip_package
)->add(
iv_txt = 'Transport to Zip'
iv_act = zif_abapgit_definitions=>c_action-zip_transport
)->add(
iv_txt = 'Object to Files'
iv_act = zif_abapgit_definitions=>c_action-zip_object
)->add(
iv_txt = 'Test Changed by'
iv_act = zif_abapgit_definitions=>c_action-changed_by
)->add(
iv_txt = 'Debug Info'
iv_act = zif_abapgit_definitions=>c_action-go_debuginfo ).
IF lv_supports_ie_devtools = abap_true.
ro_menu->add(
iv_txt = 'Open IE DevTools'
iv_act = zif_abapgit_definitions=>c_action-ie_devtools ).
ENDIF.
ro_menu->add(
iv_txt = 'Performance Test'
iv_act = zif_abapgit_definitions=>c_action-performance_test ).
ENDMETHOD.
METHOD class_constructor.
CALL FUNCTION 'GET_SYSTEM_TIMEZONE'
IMPORTING
timezone = gv_time_zone
EXCEPTIONS
customizing_missing = 1
OTHERS = 2.
ASSERT sy-subrc = 0.
ENDMETHOD.
METHOD get_t100_text.
SELECT SINGLE text
FROM t100
INTO rv_text
WHERE arbgb = iv_msgid
AND msgnr = iv_msgno
AND sprsl = sy-langu.
ENDMETHOD.
METHOD help_submenu.
CREATE OBJECT ro_menu.
ro_menu->add(
iv_txt = 'Tutorial'
iv_act = zif_abapgit_definitions=>c_action-go_tutorial
)->add(
iv_txt = 'Documentation'
iv_act = zif_abapgit_definitions=>c_action-documentation
)->add(
iv_txt = 'Explore'
iv_act = zif_abapgit_definitions=>c_action-go_explore
)->add(
iv_txt = 'Changelog'
iv_act = zif_abapgit_definitions=>c_action-changelog ).
ENDMETHOD.
METHOD normalize_program_name.
rv_normalized_program_name = substring_before(
val = iv_program_name
regex = `(=+CP)?$` ).
ENDMETHOD.
METHOD render_branch_span.
DATA: lv_text TYPE string,
lv_class TYPE string.
lv_text = zcl_abapgit_git_branch_list=>get_display_name( iv_branch ).
IF zcl_abapgit_git_branch_list=>get_type( iv_branch ) = zif_abapgit_definitions=>c_git_branch_type-branch.
lv_class = 'branch branch_branch'.
ELSE.
lv_class = 'branch'.
ENDIF.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
ri_html->add( |<span class="{ lv_class }">| ).
ri_html->add_icon( iv_name = 'code-branch/grey70'
iv_hint = 'Current branch' ).
IF iv_interactive = abap_true.
ri_html->add_a( iv_act = |{ zif_abapgit_definitions=>c_action-git_branch_switch }?key={ io_repo->get_key( ) }|
iv_txt = lv_text ).
ELSE.
ri_html->add( lv_text ).
ENDIF.
ri_html->add( '</span>' ).
ENDMETHOD.
METHOD render_commit_popup.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
ri_html->add( '<ul class="hotkeys">' ).
ri_html->add( |<li>| && |<span>{ iv_content }</span>| && |</li>| ).
ri_html->add( '</ul>' ).
ri_html = render_infopanel(
iv_div_id = |{ iv_id }|
iv_title = 'Commit details'
iv_hide = abap_true
iv_scrollable = abap_false
io_content = ri_html ).
ENDMETHOD.
METHOD render_error.
DATA lv_error TYPE string.
DATA lv_class TYPE string VALUE 'panel error center'.
IF iv_extra_style IS NOT INITIAL.
lv_class = lv_class && ` ` && iv_extra_style.
ENDIF.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
IF ix_error IS BOUND.
lv_error = ix_error->get_text( ).
ELSE.
lv_error = iv_error.
ENDIF.
ri_html->add( |<div class="{ lv_class }">| ).
ri_html->add( |{ ri_html->icon( 'exclamation-circle/red' ) } { lv_error }| ).
ri_html->add( '</div>' ).
ENDMETHOD.
METHOD render_error_message_box.
DATA:
lv_error_text TYPE string,
lv_longtext TYPE string,
lv_program_name TYPE sy-repid,
lv_title TYPE string,
lv_text TYPE string.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
lv_error_text = ix_error->get_text( ).
lv_longtext = ix_error->if_message~get_longtext( abap_true ).
REPLACE FIRST OCCURRENCE OF REGEX
|({ zcx_abapgit_exception=>gc_section_text-cause }{ cl_abap_char_utilities=>newline })|
IN lv_longtext WITH |<h3>$1</h3>|.
REPLACE FIRST OCCURRENCE OF REGEX
|({ zcx_abapgit_exception=>gc_section_text-system_response }{ cl_abap_char_utilities=>newline })|
IN lv_longtext WITH |<h3>$1</h3>|.
REPLACE FIRST OCCURRENCE OF REGEX
|({ zcx_abapgit_exception=>gc_section_text-what_to_do }{ cl_abap_char_utilities=>newline })|
IN lv_longtext WITH |<h3>$1</h3>|.
REPLACE FIRST OCCURRENCE OF REGEX
|({ zcx_abapgit_exception=>gc_section_text-sys_admin }{ cl_abap_char_utilities=>newline })|
IN lv_longtext WITH |<h3>$1</h3>|.
ri_html->add( |<div id="message" class="message-panel">| ).
ri_html->add( |{ ri_html->icon( 'exclamation-circle/red' ) } { lv_error_text }| ).
ri_html->add( |<div class="float-right">| ).
ri_html->add_a(
iv_txt = `&#x274c;`
iv_act = `toggleDisplay('message')`
iv_class = `close-btn`
iv_typ = zif_abapgit_html=>c_action_type-onclick ).
ri_html->add( |</div>| ).
ri_html->add( |<div class="float-right message-panel-commands">| ).
IF ix_error->if_t100_message~t100key-msgid IS NOT INITIAL.
lv_title = get_t100_text(
iv_msgid = ix_error->if_t100_message~t100key-msgid
iv_msgno = ix_error->if_t100_message~t100key-msgno ).
lv_text = |Message ({ ix_error->if_t100_message~t100key-msgid }/{ ix_error->if_t100_message~t100key-msgno })|.
ri_html->add_a(
iv_txt = lv_text
iv_typ = zif_abapgit_html=>c_action_type-sapevent
iv_act = zif_abapgit_definitions=>c_action-goto_message
iv_title = lv_title
iv_id = `a_goto_message` ).
ENDIF.
ix_error->get_source_position( IMPORTING program_name = lv_program_name ).
lv_title = normalize_program_name( lv_program_name ).
ri_html->add_a(
iv_txt = `Goto source`
iv_act = zif_abapgit_definitions=>c_action-goto_source
iv_typ = zif_abapgit_html=>c_action_type-sapevent
iv_title = lv_title
iv_id = `a_goto_source` ).
ri_html->add_a(
iv_txt = `Callstack`
iv_act = zif_abapgit_definitions=>c_action-show_callstack
iv_typ = zif_abapgit_html=>c_action_type-sapevent
iv_id = `a_callstack` ).
ri_html->add( |</div>| ).
ri_html->add( |<div class="message-panel-commands">| ).
ri_html->add( |{ lv_longtext }| ).
ri_html->add( |</div>| ).
ri_html->add( |</div>| ).
ENDMETHOD.
METHOD render_event_as_form.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
ri_html->add(
|<form id='form_{ is_event-name }' method={ is_event-method } action='sapevent:{ is_event-name }'></form>| ).
ENDMETHOD.
METHOD render_infopanel.
DATA lv_display TYPE string.
DATA lv_class TYPE string.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
IF iv_hide = abap_true. " Initially hide
lv_display = 'display:none'.
ENDIF.
lv_class = 'info-panel'.
IF iv_scrollable = abap_false. " Initially hide
lv_class = lv_class && ' info-panel-fixed'.
ENDIF.
ri_html->add( |<div id="{ iv_div_id }" class="{ lv_class }" style="{ lv_display }">| ).
ri_html->add( |<div class="info-title">{ iv_title }|
&& '<div class="float-right">'
&& ri_html->a(
iv_txt = '&#x274c;'
iv_typ = zif_abapgit_html=>c_action_type-onclick
iv_act = |toggleDisplay('{ iv_div_id }')|
iv_class = 'close-btn' )
&& '</div></div>' ).
IF iv_hint IS NOT INITIAL.
ri_html->add( '<div class="info-hint">'
&& ri_html->icon( iv_name = 'exclamation-triangle'
iv_class = 'pad-right' )
&& iv_hint
&& '</div>' ).
ENDIF.
ri_html->add( |<div class="info-list">| ).
ri_html->add( io_content ).
ri_html->add( '</div>' ).
ri_html->add( '</div>' ).
ENDMETHOD.
METHOD render_item_state.
DATA: lv_system TYPE string.
FIELD-SYMBOLS <lv_state> TYPE char1.
rv_html = '<span class="state-block">'.
DO 2 TIMES.
CASE sy-index.
WHEN 1.
ASSIGN iv_lstate TO <lv_state>.
lv_system = 'Local:'.
WHEN 2.
ASSIGN iv_rstate TO <lv_state>.
lv_system = 'Remote:'.
ENDCASE.
CASE <lv_state>.
WHEN zif_abapgit_definitions=>c_state-unchanged. "None or unchanged
IF iv_lstate = zif_abapgit_definitions=>c_state-added OR iv_rstate = zif_abapgit_definitions=>c_state-added.
rv_html = rv_html && |<span class="none" title="{ lv_system } Not exists">X</span>|.
ELSE.
rv_html = rv_html && |<span class="none" title="{ lv_system } No changes">&nbsp;</span>|.
ENDIF.
WHEN zif_abapgit_definitions=>c_state-modified. "Changed
rv_html = rv_html && |<span class="changed" title="{ lv_system } Modified">M</span>|.
WHEN zif_abapgit_definitions=>c_state-added. "Added new
rv_html = rv_html && |<span class="added" title="{ lv_system } Added new">A</span>|.
WHEN zif_abapgit_definitions=>c_state-mixed. "Multiple changes (multifile)
rv_html = rv_html && |<span class="mixed" title="{ lv_system } Multiple changes">&#x25A0;</span>|.
WHEN zif_abapgit_definitions=>c_state-deleted. "Deleted
rv_html = rv_html && |<span class="deleted" title="{ lv_system } Deleted">D</span>|.
ENDCASE.
ENDDO.
rv_html = rv_html && '</span>'.
ENDMETHOD.
METHOD render_js_error_banner.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
ri_html->add( '<div id="js-error-banner" class="dummydiv error">' ).
ri_html->add( |{ ri_html->icon( 'exclamation-triangle/red' ) }| &&
' If this does not disappear soon,' &&
' then there is a JS init error, please log an issue' ).
ri_html->add( '</div>' ).
ENDMETHOD.
METHOD render_news.
DATA: lv_text TYPE string,
lv_hint TYPE string,
lt_log TYPE zcl_abapgit_news=>ty_logs.
FIELD-SYMBOLS: <ls_line> LIKE LINE OF lt_log.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
IF io_news IS NOT BOUND OR io_news->has_news( ) = abap_false.
RETURN.
ENDIF.
lt_log = io_news->get_log( ).
" Render news
LOOP AT lt_log ASSIGNING <ls_line>.
IF <ls_line>-is_header = abap_true.
IF <ls_line>-pos_to_cur > 0.
lv_text = <ls_line>-text && '<span class="version-marker update">update</span>'.
ELSEIF <ls_line>-pos_to_cur = 0.
lv_text = <ls_line>-text && '<span class="version-marker">current</span>'.
ELSE. " < 0
lv_text = <ls_line>-text.
ENDIF.
ri_html->add( |<h1>{ lv_text }</h1>| ).
ELSE.
ri_html->add( |<li>{ <ls_line>-text }</li>| ).
ENDIF.
ENDLOOP.
" Wrap
IF io_news->has_important( ) = abap_true.
lv_hint = 'Please note changes marked with "!"'.
ENDIF.
ri_html = render_infopanel(
iv_div_id = 'news'
iv_title = 'Announcement of the latest changes'
iv_hint = lv_hint
iv_hide = boolc( io_news->has_unseen( ) = abap_false )
io_content = ri_html ).
ENDMETHOD.
METHOD render_order_by_header_cells.
DATA:
lv_tmp TYPE string,
lv_disp_name TYPE string.
FIELD-SYMBOLS <ls_col> LIKE LINE OF it_col_spec.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
LOOP AT it_col_spec ASSIGNING <ls_col>.
" e.g. <th class="ro-detail">Created at [{ gv_time_zone }]</th>
lv_tmp = '<th'.
IF <ls_col>-css_class IS NOT INITIAL.
lv_tmp = lv_tmp && | class="{ <ls_col>-css_class }"|.
ENDIF.
lv_tmp = lv_tmp && '>'.
IF <ls_col>-display_name IS NOT INITIAL.
lv_disp_name = <ls_col>-display_name.
IF <ls_col>-add_tz = abap_true.
lv_disp_name = lv_disp_name && | [{ gv_time_zone }]|.
ENDIF.
IF <ls_col>-tech_name = iv_order_by.
IF iv_order_descending = abap_true.
lv_tmp = lv_tmp && ri_html->a(
iv_txt = lv_disp_name
iv_act = |{ zif_abapgit_definitions=>c_action-direction }?direction=ASCENDING|
iv_title = <ls_col>-title ).
ELSE.
lv_tmp = lv_tmp && ri_html->a(
iv_txt = lv_disp_name
iv_act = |{ zif_abapgit_definitions=>c_action-direction }?direction=DESCENDING|
iv_title = <ls_col>-title ).
ENDIF.
ELSE.
lv_tmp = lv_tmp && ri_html->a(
iv_txt = lv_disp_name
iv_act = |{ zif_abapgit_definitions=>c_action-change_order_by }?orderBy={ <ls_col>-tech_name }|
iv_title = <ls_col>-title ).
ENDIF.
ENDIF.
IF <ls_col>-tech_name = iv_order_by
AND iv_order_by IS NOT INITIAL.
IF iv_order_descending = abap_true.
lv_tmp = lv_tmp && | &#x25BE;|. " arrow down
ELSE.
lv_tmp = lv_tmp && | &#x25B4;|. " arrow up
ENDIF.
ENDIF.
lv_tmp = lv_tmp && '</th>'.
ri_html->add( lv_tmp ).
ENDLOOP.
ENDMETHOD.
METHOD render_repo_palette.
DATA li_repo_srv TYPE REF TO zif_abapgit_repo_srv.
DATA lt_repo_list TYPE zif_abapgit_persistence=>ty_repos.
DATA lv_repo_json TYPE string.
DATA lv_size TYPE i.
DATA lo_repo TYPE REF TO zcl_abapgit_repo.
FIELD-SYMBOLS <ls_repo> LIKE LINE OF lt_repo_list.
li_repo_srv = zcl_abapgit_repo_srv=>get_instance( ).
lt_repo_list = zcl_abapgit_persist_factory=>get_repo( )->list( ).
lv_size = lines( lt_repo_list ).
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
ri_html->add( 'var repoCatalog = [' ). " Maybe separate this into another method if needed in more places
LOOP AT lt_repo_list ASSIGNING <ls_repo>.
lo_repo = li_repo_srv->get( <ls_repo>-key ). " inefficient
lv_repo_json = |\{ key: "{ <ls_repo>-key
}", isOffline: "{ <ls_repo>-offline
}", displayName: "{ lo_repo->get_name( ) }" \}|.
IF sy-tabix < lv_size.
lv_repo_json = lv_repo_json && ','.
ENDIF.
ri_html->add( lv_repo_json ).
ENDLOOP.
ri_html->add( '];' ).
ri_html->add( |var gGoRepoPalette = new CommandPalette(createRepoCatalogEnumerator(repoCatalog, "{
iv_action }"), \{| ).
ri_html->add( ' toggleKey: "F2",' ).
ri_html->add( ' hotkeyDescription: "Go to repo ..."' ).
ri_html->add( '});' ).
ENDMETHOD.
METHOD render_repo_top.
DATA: lo_repo_online TYPE REF TO zcl_abapgit_repo_online,
lo_pback TYPE REF TO zcl_abapgit_persist_background,
lx_error TYPE REF TO zcx_abapgit_exception,
lv_hint TYPE string,
lv_icon TYPE string,
lv_package_jump_data TYPE string.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
CREATE OBJECT lo_pback.
IF io_repo->is_offline( ) = abap_true.
lv_icon = 'plug/darkgrey'.
lv_hint = 'Offline repository'.
ELSE.
lv_icon = 'cloud-upload-alt/blue'.
lv_hint = 'On-line repository'.
ENDIF.
ri_html->add( '<table class="w100"><tr>' ).
ri_html->add( '<td class="repo_name">' ).
" Repo type and name
ri_html->add_icon( iv_name = lv_icon
iv_hint = lv_hint ).
ri_html->add( |<span class="name">{ io_repo->get_name( ) }</span>| ).
IF io_repo->is_offline( ) = abap_false.
lo_repo_online ?= io_repo.
ri_html->add_a( iv_txt = lo_repo_online->get_url( )
iv_act = |{ zif_abapgit_definitions=>c_action-url }?url=|
&& |{ lo_repo_online->get_url( ) }|
iv_class = |url| ).
IF iv_show_commit = abap_true.
render_repo_top_commit_hash( ii_html = ri_html
io_repo_online = lo_repo_online ).
ENDIF.
ENDIF.
" News
IF io_news IS BOUND AND io_news->has_news( ) = abap_true.
IF io_news->has_updates( ) = abap_true.
lv_icon = 'arrow-circle-up/warning'.
ELSE.
lv_icon = 'arrow-circle-up/grey80'.
ENDIF.
ri_html->add_a( iv_act = |toggleDisplay('news')|
iv_typ = zif_abapgit_html=>c_action_type-onclick
iv_txt = ri_html->icon( iv_name = lv_icon
iv_class = 'pad-sides'
iv_hint = 'Display changelog' ) ).
ENDIF.
ri_html->add( '</td>' ).
ri_html->add( '<td class="repo_attr right">' ).
" Fav
IF abap_true = zcl_abapgit_persistence_user=>get_instance( )->is_favorite_repo( io_repo->get_key( ) ).
lv_icon = 'star/blue'.
ELSE.
lv_icon = 'star/grey'.
ENDIF.
ri_html->add_a( iv_act = |{ zif_abapgit_definitions=>c_action-repo_toggle_fav }?key={ io_repo->get_key( ) }|
iv_txt = ri_html->icon( iv_name = lv_icon
iv_class = 'pad-sides'
iv_hint = 'Click to toggle favorite' ) ).
" BG
IF lo_pback->exists( io_repo->get_key( ) ) = abap_true.
ri_html->add( '<span class="bg_marker" title="background">BG</span>' ).
ENDIF.
" Write protect
IF io_repo->get_local_settings( )-write_protected = abap_true.
ri_html->add_icon( iv_name = 'lock/grey70'
iv_hint = 'Locked from pulls' ).
ENDIF.
" Branch
IF io_repo->is_offline( ) = abap_false.
lo_repo_online ?= io_repo.
IF iv_show_branch = abap_true.
IF iv_branch IS INITIAL.
ri_html->add( render_branch_span( iv_branch = lo_repo_online->get_branch_name( )
io_repo = lo_repo_online
iv_interactive = iv_interactive_branch ) ).
ELSE.
ri_html->add( render_branch_span( iv_branch = iv_branch
io_repo = lo_repo_online
iv_interactive = iv_interactive_branch ) ).
ENDIF.
ENDIF.
ENDIF.
" Package
IF iv_show_package = abap_true.
ri_html->add_icon( iv_name = 'box/grey70'
iv_hint = 'SAP package' ).
ri_html->add( '<span>' ).
lv_package_jump_data = zcl_abapgit_html_action_utils=>jump_encode(
iv_obj_type = 'DEVC'
iv_obj_name = io_repo->get_package( ) ).
ri_html->add_a( iv_txt = io_repo->get_package( )
iv_act = |{ zif_abapgit_definitions=>c_action-jump }?{ lv_package_jump_data }| ).
ri_html->add( '</span>' ).
ENDIF.
ri_html->add( '</td>' ).
ri_html->add( '</tr></table>' ).
ENDMETHOD.
METHOD render_repo_top_commit_hash.
DATA: lv_commit_hash TYPE zif_abapgit_definitions=>ty_sha1,
lv_commit_short_hash TYPE zif_abapgit_definitions=>ty_sha1,
lv_display_url TYPE zif_abapgit_persistence=>ty_repo-url,
lv_icon_commit TYPE string.
lv_commit_hash = io_repo_online->get_sha1_remote( ).
lv_commit_short_hash = lv_commit_hash(7).
lv_icon_commit = ii_html->icon( iv_name = 'code-commit'
iv_class = 'pad-sides'
iv_hint = 'Commit' ).
TRY.
lv_display_url = io_repo_online->get_commit_display_url( lv_commit_hash ).
ii_html->add_a( iv_txt = |{ lv_icon_commit }{ lv_commit_short_hash }|
iv_act = |{ zif_abapgit_definitions=>c_action-url }?url={ lv_display_url }|
iv_class = |url| ).
CATCH zcx_abapgit_exception.
ii_html->add( |<span class="url">{ lv_icon_commit }{ lv_commit_short_hash }</span>| ).
ENDTRY.
ENDMETHOD.
METHOD render_warning_banner.
DATA lv_class TYPE string VALUE 'panel warning center'.
IF iv_extra_style IS NOT INITIAL.
lv_class = lv_class && ` ` && iv_extra_style.
ENDIF.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
ri_html->add( |<div class="{ lv_class }">| ).
ri_html->add( |{ ri_html->icon( 'exclamation-triangle/yellow' ) } { iv_text }| ).
ri_html->add( '</div>' ).
ENDMETHOD.
ENDCLASS.
CLASS zcl_abapgit_gui_page_login DEFINITION
PUBLIC
INHERITING FROM zcl_abapgit_gui_component
FINAL
CREATE PRIVATE .
PUBLIC SECTION.
INTERFACES zif_abapgit_gui_event_handler .
INTERFACES zif_abapgit_gui_renderable .
CLASS-METHODS create
IMPORTING
!iv_url TYPE string
!iv_count TYPE i
!iv_digest TYPE string
!io_page TYPE REF TO zif_abapgit_gui_renderable
RETURNING
VALUE(ri_page) TYPE REF TO zif_abapgit_gui_renderable
RAISING
zcx_abapgit_exception .
METHODS constructor
IMPORTING
!iv_url TYPE string
!iv_count TYPE i
!iv_digest TYPE string
!io_page TYPE REF TO zif_abapgit_gui_renderable OPTIONAL
RAISING
zcx_abapgit_exception .
PROTECTED SECTION.
PRIVATE SECTION.
CONSTANTS:
BEGIN OF c_id,
user TYPE string VALUE 'user',
password TYPE string VALUE 'password',
END OF c_id .
CONSTANTS:
BEGIN OF c_event,
login TYPE string VALUE 'login',
go_back TYPE string VALUE 'go_back',
END OF c_event .
DATA mo_validation_log TYPE REF TO zcl_abapgit_string_map .
DATA mo_form_data TYPE REF TO zcl_abapgit_string_map .
DATA mo_form TYPE REF TO zcl_abapgit_html_form .
DATA mv_url TYPE string .
DATA mv_count TYPE i .
DATA mv_digest TYPE string .
DATA mo_page TYPE REF TO zif_abapgit_gui_renderable .
DATA mv_default_user TYPE string .
CLASS-METHODS export_title
IMPORTING
!iv_url TYPE string
RETURNING
VALUE(rv_host) TYPE string
RAISING
zcx_abapgit_exception .
METHODS validate_form
IMPORTING
!io_form_data TYPE REF TO zcl_abapgit_string_map
RETURNING
VALUE(ro_validation_log) TYPE REF TO zcl_abapgit_string_map
RAISING
zcx_abapgit_exception .
METHODS get_form_schema
IMPORTING
iv_username TYPE string
RETURNING
VALUE(ro_form) TYPE REF TO zcl_abapgit_html_form .
ENDCLASS.
CLASS zcl_abapgit_gui_page_login IMPLEMENTATION.
METHOD constructor.
super->constructor( ).
mv_url = iv_url.
mv_count = iv_count.
mv_digest = iv_digest.
mo_page = io_page.
mv_default_user = zcl_abapgit_login_manager=>get_default_user( mv_url ).
CREATE OBJECT mo_validation_log.
CREATE OBJECT mo_form_data.
mo_form = get_form_schema( mv_default_user ).
mo_form_data->set( iv_key = c_id-user
iv_val = mv_default_user ).
ENDMETHOD.
METHOD create.
DATA:
lo_component TYPE REF TO zcl_abapgit_gui_page_login,
lo_repo TYPE REF TO zcl_abapgit_repo,
lv_host TYPE string,
lv_name TYPE string.
CREATE OBJECT lo_component
EXPORTING
iv_url = iv_url
iv_count = iv_count
iv_digest = iv_digest
io_page = io_page.
lv_host = export_title( iv_url ).
IF iv_url <> zcl_abapgit_login_manager=>gc_proxy.
lo_repo = zcl_abapgit_repo_srv=>get_instance( )->get_repo_from_url( iv_url ).
IF lo_repo IS BOUND.
lv_name = |({ zcl_abapgit_html=>icon( 'cloud-upload-alt/grey' )
} { lo_repo->get_name( ) })|.
ENDIF.
ENDIF.
ri_page = zcl_abapgit_gui_page_hoc=>create(
iv_page_title = |Login to <b>{ lv_host }</b> { lv_name }|
ii_child_component = lo_component ).
ENDMETHOD.
METHOD export_title.
DATA lv_title TYPE sy-title.
rv_host = zcl_abapgit_login_manager=>get_host( iv_url ).
lv_title = |Login: { rv_host }|.
EXPORT title = lv_title TO MEMORY ID zif_abapgit_definitions=>gc_memoryid_title.
ENDMETHOD.
METHOD get_form_schema.
ro_form = zcl_abapgit_html_form=>create( iv_form_id = 'login-form' ).
ro_form->text(
iv_name = c_id-user
iv_required = abap_true
iv_autofocus = boolc( iv_username IS INITIAL )
iv_label = 'User Name'
)->text(
iv_name = c_id-password
iv_required = abap_true
iv_autofocus = boolc( iv_username IS NOT INITIAL )
iv_password = abap_true
iv_label = 'Password or Token'
)->command(
iv_label = 'Login'
iv_is_main = abap_true
iv_action = c_event-login
)->command(
iv_label = 'Cancel'
iv_action = c_event-go_back ).
ENDMETHOD.
METHOD validate_form.
ro_validation_log = mo_form->validate_required_fields( io_form_data ).
ENDMETHOD.
METHOD zif_abapgit_gui_event_handler~on_event.
DATA lv_username TYPE string.
" import data from html before re-render
mo_form_data = mo_form->normalize_form_data( ii_event->form_data( ) ).
CASE ii_event->mv_action.
WHEN c_event-go_back.
zcl_abapgit_login_manager=>reset_count( mv_url ).
CREATE OBJECT rs_handled-page TYPE zcl_abapgit_gui_page_main.
rs_handled-state = zcl_abapgit_gui=>c_event_state-new_page_replacing.
WHEN c_event-login.
mo_validation_log = validate_form( mo_form_data ).
IF mo_validation_log->is_empty( ) = abap_true.
lv_username = mo_form_data->get( c_id-user ).
" Save new default user for repo
zcl_abapgit_login_manager=>set_default_user(
iv_uri = mv_url
iv_username = lv_username ).
" Pass username and password to login manager
zcl_abapgit_login_manager=>set(
iv_uri = mv_url
iv_username = lv_username
iv_password = mo_form_data->get( c_id-password )
iv_digest = mv_digest ).
rs_handled-page = mo_page.
rs_handled-state = zcl_abapgit_gui=>c_event_state-new_page_replacing.
ELSE.
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render. " Display errors
ENDIF.
ENDCASE.
ENDMETHOD.
METHOD zif_abapgit_gui_renderable~render.
DATA lv_msg TYPE string.
gui_services( )->register_event_handler( me ).
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
IF mv_count = 1.
IF mv_url = zcl_abapgit_login_manager=>gc_proxy.
lv_msg = 'You have to login to your proxy, first'.
ELSE.
lv_msg = 'You have to login to access this repository'.
ENDIF.
ri_html->add( zcl_abapgit_gui_chunk_lib=>render_warning_banner(
iv_text = lv_msg
iv_extra_style = 'wmax600px auto-center margin-v1' ) ).
ELSEIF mv_count > 1.
lv_msg = 'Sorry, username or password are not correct. Try again!'.
ri_html->add( zcl_abapgit_gui_chunk_lib=>render_error(
iv_error = lv_msg
iv_extra_style = 'wmax600px auto-center margin-v1' ) ).
ENDIF.
ri_html->add( mo_form->render(
iv_form_class = 'dialog wmax600px auto-center margin-30px'
io_values = mo_form_data
io_validation_log = mo_validation_log ) ).
ENDMETHOD.
ENDCLASS.
CLASS zcl_abapgit_gui_page_repo_view DEFINITION
PUBLIC
INHERITING FROM zcl_abapgit_gui_page
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES zif_abapgit_gui_hotkeys .
CONSTANTS:
BEGIN OF c_actions,
repo_list TYPE string VALUE 'abapgit_home' ##NO_TEXT,
change_dir TYPE string VALUE 'change_dir' ##NO_TEXT,
toggle_hide_files TYPE string VALUE 'toggle_hide_files' ##NO_TEXT,
toggle_folders TYPE string VALUE 'toggle_folders' ##NO_TEXT,
toggle_changes TYPE string VALUE 'toggle_changes' ##NO_TEXT,
toggle_diff_first TYPE string VALUE 'toggle_diff_first ' ##NO_TEXT,
display_more TYPE string VALUE 'display_more' ##NO_TEXT,
repo_switch_origin_to_pr TYPE string VALUE 'repo_switch_origin_to_pr',
repo_reset_origin TYPE string VALUE 'repo_reset_origin',
END OF c_actions .
METHODS constructor
IMPORTING
!iv_key TYPE zif_abapgit_persistence=>ty_repo-key
RAISING
zcx_abapgit_exception .
METHODS zif_abapgit_gui_event_handler~on_event
REDEFINITION .
PROTECTED SECTION.
METHODS render_content REDEFINITION.
PRIVATE SECTION.
DATA mo_repo TYPE REF TO zcl_abapgit_repo .
DATA mv_cur_dir TYPE string .
DATA mv_hide_files TYPE abap_bool .
DATA mv_max_lines TYPE i .
DATA mv_max_setting TYPE i .
DATA mv_show_folders TYPE abap_bool .
DATA mv_changes_only TYPE abap_bool .
DATA mv_order_by TYPE string .
DATA mv_order_descending TYPE abap_bool .
DATA mv_diff_first TYPE abap_bool .
DATA mv_key TYPE zif_abapgit_persistence=>ty_value .
DATA mv_are_changes_recorded_in_tr TYPE abap_bool .
METHODS render_head_line
IMPORTING
!iv_lstate TYPE char1
!iv_rstate TYPE char1
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING
zcx_abapgit_exception .
METHODS build_head_menu
IMPORTING
!iv_lstate TYPE char1
!iv_rstate TYPE char1
RETURNING
VALUE(ro_toolbar) TYPE REF TO zcl_abapgit_html_toolbar
RAISING
zcx_abapgit_exception .
METHODS build_view_menu
RETURNING
VALUE(ro_toolbar) TYPE REF TO zcl_abapgit_html_toolbar
RAISING
zcx_abapgit_exception .
METHODS render_item
IMPORTING
!is_item TYPE zif_abapgit_definitions=>ty_repo_item
!iv_render_transports TYPE abap_bool
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING
zcx_abapgit_exception .
METHODS render_item_files
IMPORTING
!is_item TYPE zif_abapgit_definitions=>ty_repo_item
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html .
METHODS render_item_command
IMPORTING
!is_item TYPE zif_abapgit_definitions=>ty_repo_item
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html .
METHODS get_item_class
IMPORTING
!is_item TYPE zif_abapgit_definitions=>ty_repo_item
RETURNING
VALUE(rv_html) TYPE string .
METHODS get_item_icon
IMPORTING
!is_item TYPE zif_abapgit_definitions=>ty_repo_item
RETURNING
VALUE(rv_html) TYPE string .
METHODS render_item_lock_column
IMPORTING
!is_item TYPE zif_abapgit_definitions=>ty_repo_item
RETURNING
VALUE(rv_html) TYPE string .
METHODS render_parent_dir
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING
zcx_abapgit_exception .
METHODS build_obj_jump_link
IMPORTING
!is_item TYPE zif_abapgit_definitions=>ty_repo_item
RETURNING
VALUE(rv_html) TYPE string .
METHODS build_dir_jump_link
IMPORTING
!iv_path TYPE string
RETURNING
VALUE(rv_html) TYPE string .
METHODS build_inactive_object_code
IMPORTING
!is_item TYPE zif_abapgit_definitions=>ty_repo_item
RETURNING
VALUE(rv_inactive_html_code) TYPE string .
METHODS open_in_master_language
RAISING
zcx_abapgit_exception .
METHODS render_order_by
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html .
METHODS apply_order_by
CHANGING
!ct_repo_items TYPE zif_abapgit_definitions=>ty_repo_item_tt .
METHODS build_branch_dropdown
IMPORTING
!iv_wp_opt LIKE zif_abapgit_html=>c_html_opt-crossout
RETURNING
VALUE(ro_branch_dropdown) TYPE REF TO zcl_abapgit_html_toolbar
RAISING
zcx_abapgit_exception .
METHODS build_tag_dropdown
IMPORTING
!iv_wp_opt LIKE zif_abapgit_html=>c_html_opt-crossout
RETURNING
VALUE(ro_tag_dropdown) TYPE REF TO zcl_abapgit_html_toolbar
RAISING
zcx_abapgit_exception .
METHODS build_advanced_dropdown
IMPORTING
!iv_wp_opt LIKE zif_abapgit_html=>c_html_opt-crossout
!iv_lstate TYPE char1
!iv_rstate TYPE char1
RETURNING
VALUE(ro_advanced_dropdown) TYPE REF TO zcl_abapgit_html_toolbar
RAISING
zcx_abapgit_exception .
METHODS build_main_toolbar
IMPORTING
!iv_pull_opt LIKE zif_abapgit_html=>c_html_opt-crossout
!iv_lstate TYPE char1
!iv_rstate TYPE char1
!io_tb_branch TYPE REF TO zcl_abapgit_html_toolbar
!io_tb_tag TYPE REF TO zcl_abapgit_html_toolbar
!io_tb_advanced TYPE REF TO zcl_abapgit_html_toolbar
RETURNING
VALUE(ro_toolbar) TYPE REF TO zcl_abapgit_html_toolbar
RAISING
zcx_abapgit_exception .
METHODS switch_to_pr
IMPORTING
!it_fields TYPE tihttpnvp OPTIONAL
!iv_revert TYPE abap_bool OPTIONAL
RETURNING
VALUE(rv_switched) TYPE abap_bool
RAISING
zcx_abapgit_exception .
METHODS build_main_menu
RETURNING
VALUE(ro_menu) TYPE REF TO zcl_abapgit_html_toolbar .
METHODS render_scripts
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html
RAISING
zcx_abapgit_exception .
ENDCLASS.
CLASS zcl_abapgit_gui_page_repo_view IMPLEMENTATION.
METHOD apply_order_by.
DATA:
lt_sort TYPE abap_sortorder_tab,
ls_sort LIKE LINE OF lt_sort,
lt_non_code_and_metadata_items LIKE ct_repo_items,
lt_code_items LIKE ct_repo_items,
lt_diff_items LIKE ct_repo_items.
FIELD-SYMBOLS:
<ls_repo_item> TYPE zif_abapgit_definitions=>ty_repo_item.
IF mv_order_by IS INITIAL.
RETURN.
ENDIF.
" we want to preserve non-code and metadata files at the top,
" so we isolate them and and sort only the code artifacts
LOOP AT ct_repo_items ASSIGNING <ls_repo_item>.
IF <ls_repo_item>-obj_type IS INITIAL AND <ls_repo_item>-is_dir = abap_false.
INSERT <ls_repo_item> INTO TABLE lt_non_code_and_metadata_items.
ELSE.
INSERT <ls_repo_item> INTO TABLE lt_code_items.
ENDIF.
ENDLOOP.
IF mv_diff_first = abap_true.
" fix diffs on the top, right after non-code and metadata
LOOP AT lt_code_items ASSIGNING <ls_repo_item>
WHERE changes > 0.
INSERT <ls_repo_item> INTO TABLE lt_diff_items.
ENDLOOP.
DELETE lt_code_items WHERE changes > 0.
ENDIF.
CLEAR: ct_repo_items.
ls_sort-name = mv_order_by.
ls_sort-descending = mv_order_descending.
ls_sort-astext = abap_true.
INSERT ls_sort INTO TABLE lt_sort.
SORT lt_code_items BY (lt_sort).
SORT lt_diff_items BY (lt_sort).
INSERT LINES OF lt_non_code_and_metadata_items INTO TABLE ct_repo_items.
INSERT LINES OF lt_diff_items INTO TABLE ct_repo_items.
INSERT LINES OF lt_code_items INTO TABLE ct_repo_items.
ENDMETHOD.
METHOD build_advanced_dropdown.
DATA:
lv_crossout LIKE zif_abapgit_html=>c_html_opt-crossout.
CREATE OBJECT ro_advanced_dropdown.
IF iv_rstate IS NOT INITIAL OR iv_lstate IS NOT INITIAL. " In case of asyncronicities
ro_advanced_dropdown->add( iv_txt = 'Reset Local (Force Pull)'
iv_act = |{ zif_abapgit_definitions=>c_action-git_reset }?key={ mv_key }|
iv_opt = iv_wp_opt ).
ENDIF.
IF mo_repo->is_offline( ) = abap_false. " Online ?
ro_advanced_dropdown->add( iv_txt = 'Background Mode'
iv_act = |{ zif_abapgit_definitions=>c_action-go_background }?key={ mv_key }| ).
ro_advanced_dropdown->add( iv_txt = 'Change Remote'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_remote_change }?key={ mv_key }| ).
ro_advanced_dropdown->add( iv_txt = 'Make Off-line'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_remote_detach }?key={ mv_key }| ).
ro_advanced_dropdown->add( iv_txt = 'Force Stage'
iv_act = |{ zif_abapgit_definitions=>c_action-go_stage }?key={ mv_key }| ).
CLEAR lv_crossout.
IF zcl_abapgit_auth=>is_allowed( zif_abapgit_auth=>gc_authorization-transport_to_branch ) = abap_false.
lv_crossout = zif_abapgit_html=>c_html_opt-crossout.
ENDIF.
ro_advanced_dropdown->add(
iv_txt = 'Transport to Branch'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_transport_to_branch }?key={ mv_key }|
iv_opt = lv_crossout ).
ELSE.
ro_advanced_dropdown->add( iv_txt = 'Make On-line'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_remote_attach }?key={ mv_key }| ).
ENDIF.
IF mv_are_changes_recorded_in_tr = abap_true.
ro_advanced_dropdown->add(
iv_txt = 'Add all objects to transport request'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_add_all_obj_to_trans_req }?key={ mv_key }| ).
ENDIF.
ro_advanced_dropdown->add( iv_txt = 'Syntax Check'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_syntax_check }?key={ mv_key }| ).
ro_advanced_dropdown->add( iv_txt = 'Run Code Inspector'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_code_inspector }?key={ mv_key }| ).
CLEAR lv_crossout.
IF zcl_abapgit_auth=>is_allowed( zif_abapgit_auth=>gc_authorization-update_local_checksum ) = abap_false.
lv_crossout = zif_abapgit_html=>c_html_opt-crossout.
ENDIF.
ro_advanced_dropdown->add( iv_txt = 'Update Local Checksums'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_refresh_checksums }?key={ mv_key }|
iv_opt = lv_crossout ).
IF mo_repo->get_dot_abapgit( )->get_master_language( ) <> sy-langu.
ro_advanced_dropdown->add(
iv_txt = 'Open in Master Language'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_open_in_master_lang }?key={ mv_key }| ).
ENDIF.
ro_advanced_dropdown->add( iv_txt = 'Remove'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_remove }?key={ mv_key }| ).
CLEAR lv_crossout.
IF mo_repo->get_local_settings( )-write_protected = abap_true
OR zcl_abapgit_auth=>is_allowed( zif_abapgit_auth=>gc_authorization-uninstall ) = abap_false.
lv_crossout = zif_abapgit_html=>c_html_opt-crossout.
ENDIF.
ro_advanced_dropdown->add( iv_txt = 'Uninstall'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_purge }?key={ mv_key }|
iv_opt = lv_crossout ).
ENDMETHOD.
METHOD build_branch_dropdown.
DATA lo_repo_online TYPE REF TO zcl_abapgit_repo_online.
CREATE OBJECT ro_branch_dropdown.
IF mo_repo->is_offline( ) = abap_true.
RETURN.
ENDIF.
ro_branch_dropdown->add( iv_txt = 'Overview'
iv_act = |{ zif_abapgit_definitions=>c_action-go_branch_overview }?key={ mv_key }| ).
ro_branch_dropdown->add( iv_txt = 'Switch'
iv_act = |{ zif_abapgit_definitions=>c_action-git_branch_switch }?key={ mv_key }|
iv_opt = iv_wp_opt ).
ro_branch_dropdown->add( iv_txt = 'Create'
iv_act = |{ zif_abapgit_definitions=>c_action-git_branch_create }?key={ mv_key }| ).
ro_branch_dropdown->add( iv_txt = 'Delete'
iv_act = |{ zif_abapgit_definitions=>c_action-git_branch_delete }?key={ mv_key }| ).
lo_repo_online ?= mo_repo. " TODO refactor this disaster
IF lo_repo_online->get_switched_origin( ) IS NOT INITIAL.
ro_branch_dropdown->add(
iv_txt = 'Switch Origin: Revert <sup>beta<sup>'
iv_act = |{ c_actions-repo_reset_origin }| ).
ELSE.
ro_branch_dropdown->add(
iv_txt = 'Switch Origin: to PR <sup>beta<sup>'
iv_act = |{ c_actions-repo_switch_origin_to_pr }| ).
ENDIF.
ENDMETHOD.
METHOD build_dir_jump_link.
DATA lv_path TYPE string.
DATA lv_encode TYPE string.
DATA li_html TYPE REF TO zif_abapgit_html.
CREATE OBJECT li_html TYPE zcl_abapgit_html.
lv_path = iv_path.
REPLACE FIRST OCCURRENCE OF mv_cur_dir IN lv_path WITH ''.
lv_encode = zcl_abapgit_html_action_utils=>dir_encode( lv_path ).
rv_html = li_html->a(
iv_txt = lv_path
iv_act = |{ c_actions-change_dir }?{ lv_encode }| ).
ENDMETHOD.
METHOD build_head_menu.
DATA: lo_tb_advanced TYPE REF TO zcl_abapgit_html_toolbar,
lo_tb_branch TYPE REF TO zcl_abapgit_html_toolbar,
lo_tb_tag TYPE REF TO zcl_abapgit_html_toolbar,
lv_wp_opt LIKE zif_abapgit_html=>c_html_opt-crossout,
lv_pull_opt LIKE zif_abapgit_html=>c_html_opt-crossout.
IF mo_repo->get_local_settings( )-write_protected = abap_true.
lv_wp_opt = zif_abapgit_html=>c_html_opt-crossout.
lv_pull_opt = zif_abapgit_html=>c_html_opt-crossout.
ELSE.
lv_pull_opt = zif_abapgit_html=>c_html_opt-strong.
ENDIF.
lo_tb_branch = build_branch_dropdown( lv_wp_opt ).
lo_tb_tag = build_tag_dropdown( lv_wp_opt ).
lo_tb_advanced = build_advanced_dropdown(
iv_wp_opt = lv_wp_opt
iv_rstate = iv_rstate
iv_lstate = iv_lstate ).
ro_toolbar = build_main_toolbar(
iv_pull_opt = lv_pull_opt
iv_rstate = iv_rstate
iv_lstate = iv_lstate
io_tb_branch = lo_tb_branch
io_tb_tag = lo_tb_tag
io_tb_advanced = lo_tb_advanced ).
ENDMETHOD.
METHOD build_inactive_object_code.
IF is_item-inactive = abap_true.
rv_inactive_html_code = zcl_abapgit_html=>icon(
iv_name = 'bolt/orange'
iv_hint = 'Object or object part is inactive'
iv_class = 'inactive' ).
ENDIF.
ENDMETHOD.
METHOD build_main_menu.
CREATE OBJECT ro_menu EXPORTING iv_id = 'toolbar-main'.
ro_menu->add(
iv_txt = zcl_abapgit_gui_buttons=>repo_list( )
iv_act = zif_abapgit_definitions=>c_action-abapgit_home
)->add(
iv_txt = zcl_abapgit_gui_buttons=>settings( )
iv_act = zif_abapgit_definitions=>c_action-go_settings
)->add(
iv_txt = zcl_abapgit_gui_buttons=>advanced( )
io_sub = zcl_abapgit_gui_chunk_lib=>advanced_submenu( )
)->add(
iv_txt = zcl_abapgit_gui_buttons=>help( )
io_sub = zcl_abapgit_gui_chunk_lib=>help_submenu( ) ).
ENDMETHOD.
METHOD build_main_toolbar.
DATA:
li_log TYPE REF TO zif_abapgit_log.
CREATE OBJECT ro_toolbar EXPORTING iv_id = 'toolbar-repo'.
IF mo_repo->is_offline( ) = abap_false.
IF iv_rstate IS NOT INITIAL. " Something new at remote
ro_toolbar->add( iv_txt = 'Pull'
iv_act = |{ zif_abapgit_definitions=>c_action-git_pull }?key={ mv_key }|
iv_opt = iv_pull_opt ).
ENDIF.
IF iv_lstate IS NOT INITIAL. " Something new at local
ro_toolbar->add( iv_txt = 'Stage'
iv_act = |{ zif_abapgit_definitions=>c_action-go_stage }?key={ mv_key }|
iv_opt = zif_abapgit_html=>c_html_opt-strong ).
ENDIF.
IF iv_rstate IS NOT INITIAL OR iv_lstate IS NOT INITIAL. " Any changes
ro_toolbar->add( iv_txt = 'Diff'
iv_act = |{ zif_abapgit_definitions=>c_action-go_diff }?key={ mv_key }|
iv_opt = zif_abapgit_html=>c_html_opt-strong ).
ENDIF.
li_log = mo_repo->get_log( ).
IF li_log IS BOUND AND li_log->count( ) > 0.
ro_toolbar->add( iv_txt = 'Log'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_log }?key={ mv_key }| ).
ENDIF.
ro_toolbar->add( iv_txt = 'Branch'
io_sub = io_tb_branch ).
ro_toolbar->add( iv_txt = 'Tag'
io_sub = io_tb_tag ).
ELSE.
IF mo_repo->has_remote_source( ) = abap_true AND iv_rstate IS NOT INITIAL.
ro_toolbar->add( iv_txt = 'Pull <sup>zip</sup>'
iv_act = |{ zif_abapgit_definitions=>c_action-git_pull }?key={ mv_key }|
iv_opt = zif_abapgit_html=>c_html_opt-strong ).
ro_toolbar->add( iv_txt = 'Diff'
iv_act = |{ zif_abapgit_definitions=>c_action-go_diff }?key={ mv_key }|
iv_opt = zif_abapgit_html=>c_html_opt-strong ).
ENDIF.
ro_toolbar->add( iv_txt = 'Import <sup>zip</sup>'
iv_act = |{ zif_abapgit_definitions=>c_action-zip_import }?key={ mv_key }|
iv_opt = zif_abapgit_html=>c_html_opt-strong ).
ro_toolbar->add( iv_txt = 'Export <sup>zip</sup>'
iv_act = |{ zif_abapgit_definitions=>c_action-zip_export }?key={ mv_key }|
iv_opt = zif_abapgit_html=>c_html_opt-strong ).
li_log = mo_repo->get_log( ).
IF li_log IS BOUND AND li_log->count( ) > 0.
ro_toolbar->add( iv_txt = 'Log'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_log }?key={ mv_key }| ).
ENDIF.
ENDIF.
ro_toolbar->add( iv_txt = 'Advanced'
io_sub = io_tb_advanced ).
ro_toolbar->add( iv_txt = 'View'
io_sub = build_view_menu( ) ).
ro_toolbar->add( iv_txt = 'Refresh'
iv_act = |{ zif_abapgit_definitions=>c_action-repo_refresh }?key={ mv_key }|
iv_opt = zif_abapgit_html=>c_html_opt-strong ).
ro_toolbar->add( iv_txt = zcl_abapgit_html=>icon( iv_name = 'cog' )
iv_act = |{ zif_abapgit_definitions=>c_action-repo_settings }?key={ mv_key }|
iv_title = `Repository Settings` ).
ENDMETHOD.
METHOD build_obj_jump_link.
DATA lv_encode TYPE string.
DATA li_html TYPE REF TO zif_abapgit_html.
CREATE OBJECT li_html TYPE zcl_abapgit_html.
lv_encode = zcl_abapgit_html_action_utils=>jump_encode(
iv_obj_type = is_item-obj_type
iv_obj_name = is_item-obj_name ).
rv_html = li_html->a(
iv_txt = |{ is_item-obj_name }|
iv_act = |{ zif_abapgit_definitions=>c_action-jump }?{ lv_encode }| ).
ENDMETHOD.
METHOD build_tag_dropdown.
CREATE OBJECT ro_tag_dropdown.
IF mo_repo->is_offline( ) = abap_true.
RETURN.
ENDIF.
ro_tag_dropdown->add( iv_txt = 'Overview'
iv_act = |{ zif_abapgit_definitions=>c_action-go_tag_overview }?key={ mv_key }| ).
ro_tag_dropdown->add( iv_txt = 'Switch'
iv_act = |{ zif_abapgit_definitions=>c_action-git_tag_switch }?key={ mv_key }|
iv_opt = iv_wp_opt ).
ro_tag_dropdown->add( iv_txt = 'Create'
iv_act = |{ zif_abapgit_definitions=>c_action-git_tag_create }?key={ mv_key }| ).
ro_tag_dropdown->add( iv_txt = 'Delete'
iv_act = |{ zif_abapgit_definitions=>c_action-git_tag_delete }?key={ mv_key }| ).
ENDMETHOD.
METHOD build_view_menu.
CREATE OBJECT ro_toolbar.
ro_toolbar->add(
iv_txt = 'Changes First'
iv_chk = mv_diff_first
iv_act = c_actions-toggle_diff_first ).
IF mo_repo->has_remote_source( ) = abap_true.
ro_toolbar->add(
iv_txt = 'Changes Only'
iv_chk = mv_changes_only
iv_act = c_actions-toggle_changes ).
ro_toolbar->add(
iv_txt = 'File Paths'
iv_chk = boolc( NOT mv_hide_files = abap_true )
iv_act = c_actions-toggle_hide_files ).
ENDIF.
ro_toolbar->add(
iv_txt = 'Folders'
iv_chk = mv_show_folders
iv_act = c_actions-toggle_folders ).
ENDMETHOD.
METHOD constructor.
DATA: lo_settings TYPE REF TO zcl_abapgit_settings,
lx_error TYPE REF TO zcx_abapgit_exception,
lv_package TYPE devclass.
super->constructor( ).
TRY.
mv_key = iv_key.
mo_repo = zcl_abapgit_repo_srv=>get_instance( )->get( iv_key ).
mv_cur_dir = '/'. " Root
mv_hide_files = zcl_abapgit_persistence_user=>get_instance( )->get_hide_files( ).
mv_changes_only = zcl_abapgit_persistence_user=>get_instance( )->get_changes_only( ).
mv_diff_first = abap_true.
ms_control-page_title = 'Repository'.
ms_control-page_menu = build_main_menu( ).
" Read global settings to get max # of objects to be listed
lo_settings = zcl_abapgit_persist_settings=>get_instance( )->read( ).
mv_max_lines = lo_settings->get_max_lines( ).
mv_max_setting = mv_max_lines.
lv_package = mo_repo->get_package( ).
mv_are_changes_recorded_in_tr = zcl_abapgit_factory=>get_sap_package( lv_package
)->are_changes_recorded_in_tr_req( ).
CATCH zcx_abapgit_exception INTO lx_error.
" Reset 'last shown repo' so next start will go to repo overview
" and allow troubleshooting of issue
zcl_abapgit_persistence_user=>get_instance( )->set_repo_show( || ).
RAISE EXCEPTION lx_error.
ENDTRY.
ENDMETHOD.
METHOD get_item_class.
DATA lt_class TYPE TABLE OF string.
IF is_item-is_dir = abap_true.
APPEND 'folder' TO lt_class.
ELSEIF is_item-changes > 0.
APPEND 'modified' TO lt_class.
ELSEIF is_item-obj_name IS INITIAL.
APPEND 'unsupported' TO lt_class.
ENDIF.
IF lines( lt_class ) > 0.
rv_html = | class="{ concat_lines_of( table = lt_class
sep = ` ` ) }"|.
ENDIF.
ENDMETHOD.
METHOD get_item_icon.
CASE is_item-obj_type.
WHEN 'PROG' OR 'CLAS' OR 'FUGR' OR 'INTF' OR 'TYPE'.
rv_html = zcl_abapgit_html=>icon( 'file-code/darkgrey' ).
WHEN 'W3MI' OR 'W3HT' OR 'SFPF'.
rv_html = zcl_abapgit_html=>icon( 'file-image/darkgrey' ).
WHEN 'DEVC'.
rv_html = zcl_abapgit_html=>icon( 'box/darkgrey' ).
WHEN ''.
rv_html = space. " no icon
WHEN OTHERS.
rv_html = zcl_abapgit_html=>icon( 'file-alt/darkgrey' ).
ENDCASE.
IF is_item-is_dir = abap_true.
rv_html = zcl_abapgit_html=>icon( 'folder/darkgrey' ).
ENDIF.
ENDMETHOD.
METHOD open_in_master_language.
CONSTANTS:
lc_abapgit_tcode TYPE tcode VALUE `ZABAPGIT`.
DATA:
lv_master_language TYPE spras,
lt_spagpa TYPE STANDARD TABLE OF rfc_spagpa,
ls_spagpa LIKE LINE OF lt_spagpa,
ls_item TYPE zif_abapgit_definitions=>ty_item,
lv_subrc TYPE syst-subrc,
lv_save_sy_langu TYPE sy-langu.
" https://blogs.sap.com/2017/01/13/logon-language-sy-langu-and-rfc/
lv_master_language = mo_repo->get_dot_abapgit( )->get_master_language( ).
IF lv_master_language = sy-langu.
zcx_abapgit_exception=>raise( |Repo already opened in master language| ).
ENDIF.
ls_item-obj_name = lc_abapgit_tcode.
ls_item-obj_type = |TRAN|.
IF zcl_abapgit_objects=>exists( ls_item ) = abap_false.
zcx_abapgit_exception=>raise( |Please install the abapGit repository| ).
ENDIF.
lv_save_sy_langu = sy-langu.
SET LOCALE LANGUAGE lv_master_language.
ls_spagpa-parid = zif_abapgit_definitions=>c_spagpa_param_repo_key.
ls_spagpa-parval = mo_repo->get_key( ).
INSERT ls_spagpa INTO TABLE lt_spagpa.
CALL FUNCTION 'ABAP4_CALL_TRANSACTION'
DESTINATION 'NONE'
STARTING NEW TASK 'ABAPGIT'
EXPORTING
tcode = lc_abapgit_tcode
TABLES
spagpa_tab = lt_spagpa
EXCEPTIONS
call_transaction_denied = 1
tcode_invalid = 2
communication_failure = 3
system_failure = 4
OTHERS = 5.
lv_subrc = sy-subrc.
SET LOCALE LANGUAGE lv_save_sy_langu.
IF lv_subrc <> 0.
zcx_abapgit_exception=>raise( |Error from ABAP4_CALL_TRANSACTION. Subrc = { lv_subrc }| ).
ENDIF.
MESSAGE 'Repository opened in a new window' TYPE 'S'.
ENDMETHOD.
METHOD render_content.
DATA: lt_repo_items TYPE zif_abapgit_definitions=>ty_repo_item_tt,
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,
li_log TYPE REF TO zif_abapgit_log,
lv_render_transports TYPE abap_bool,
lv_msg TYPE string,
lo_news TYPE REF TO zcl_abapgit_news.
FIELD-SYMBOLS <ls_item> LIKE LINE OF lt_repo_items.
gui_services( )->get_hotkeys_ctl( )->register_hotkeys( me ).
gui_services( )->register_event_handler( me ).
" Reinit, for the case of type change
mo_repo = zcl_abapgit_repo_srv=>get_instance( )->get( mo_repo->get_key( ) ).
lo_news = zcl_abapgit_news=>create( mo_repo ).
TRY.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
ri_html->add( |<div class="repo" id="repo{ mv_key }">| ).
ri_html->add( zcl_abapgit_gui_chunk_lib=>render_repo_top(
io_repo = mo_repo
io_news = lo_news
iv_interactive_branch = abap_true ) ).
ri_html->add( zcl_abapgit_gui_chunk_lib=>render_news( io_news = lo_news ) ).
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.
lt_repo_items = lo_browser->list( iv_path = mv_cur_dir
iv_by_folders = mv_show_folders
iv_changes_only = mv_changes_only ).
apply_order_by( CHANGING ct_repo_items = lt_repo_items ).
LOOP AT lt_repo_items ASSIGNING <ls_item>.
zcl_abapgit_state=>reduce( EXPORTING iv_cur = <ls_item>-lstate
CHANGING cv_prev = lv_lstate ).
zcl_abapgit_state=>reduce( EXPORTING iv_cur = <ls_item>-rstate
CHANGING cv_prev = lv_rstate ).
ENDLOOP.
ri_html->add( render_head_line( iv_lstate = lv_lstate
iv_rstate = lv_rstate ) ).
li_log = lo_browser->get_log( ).
IF mo_repo->is_offline( ) = abap_false AND li_log->count( ) > 0.
ri_html->add( '<div class="log">' ).
ri_html->add( zcl_abapgit_log_viewer=>to_html( li_log ) ). " shows eg. list of unsupported objects
ri_html->add( '</div>' ).
ENDIF.
ri_html->add( '<div class="repo_container">' ).
CLEAR lv_msg.
IF mo_repo->is_offline( ) = abap_true
AND mo_repo->has_remote_source( ) = abap_true
AND lv_lstate IS INITIAL AND lv_rstate IS INITIAL.
" Offline match banner
lv_msg = 'ZIP source is attached and completely <b>matches</b> the local state'.
ELSEIF lines( lt_repo_items ) = 0.
" Online match banner
IF mv_changes_only = abap_true.
lv_msg = 'Local state completely <b>matches</b> the remote repository'.
ELSE.
lv_msg = |Package is empty. Show { build_dir_jump_link( 'parent' ) } package|.
ENDIF.
ELSE.
" Repo content table
ri_html->add( '<table class="repo_tab">' ).
IF zcl_abapgit_path=>is_root( mv_cur_dir ) = abap_false.
ri_html->add( render_parent_dir( ) ).
ENDIF.
ri_html->add( render_order_by( ) ).
LOOP AT lt_repo_items ASSIGNING <ls_item>.
IF mv_max_lines > 0 AND sy-tabix > mv_max_lines.
lv_max = abap_true.
EXIT. " current loop
ENDIF.
ri_html->add( render_item( is_item = <ls_item>
iv_render_transports = lv_render_transports ) ).
ENDLOOP.
ri_html->add( '</table>' ).
ENDIF.
IF NOT lv_msg IS INITIAL.
ri_html->add( |<div class="panel success repo_banner">{ lv_msg }</div>| ).
ENDIF.
IF lv_max = abap_true.
ri_html->add( '<div class = "dummydiv">' ).
IF mv_max_lines = 1.
lv_max_str = '1 object'.
ELSE.
lv_max_str = |first { mv_max_lines } objects|.
ENDIF.
lv_add_str = |+{ mv_max_setting }|.
ri_html->add( |Only { lv_max_str } shown in list. Display {
ri_html->a( iv_txt = lv_add_str
iv_act = c_actions-display_more )
} more. (Set in Advanced > {
ri_html->a( iv_txt = 'Settings'
iv_act = zif_abapgit_definitions=>c_action-go_settings )
} )| ).
ri_html->add( '</div>' ).
ENDIF.
ri_html->add( '</div>' ).
ri_html->add( '</div>' ).
CATCH zcx_abapgit_exception INTO lx_error.
IF lx_error->is_login( ) = abap_true.
RAISE EXCEPTION lx_error.
ENDIF.
" Reset 'last shown repo' so next start will go to repo overview
" and allow troubleshooting of issue
zcl_abapgit_persistence_user=>get_instance( )->set_repo_show( || ).
ri_html->add(
render_head_line(
iv_lstate = lv_lstate
iv_rstate = lv_rstate ) ).
ri_html->add( zcl_abapgit_gui_chunk_lib=>render_error(
iv_extra_style = 'repo_banner'
ix_error = lx_error ) ).
ENDTRY.
register_deferred_script( render_scripts( ) ).
ENDMETHOD.
METHOD render_head_line.
DATA lo_toolbar TYPE REF TO zcl_abapgit_html_toolbar.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
lo_toolbar = build_head_menu( iv_lstate = iv_lstate
iv_rstate = iv_rstate ).
ri_html->add( '<div class="paddings">' ).
ri_html->add( '<table class="w100"><tr>' ).
IF mv_show_folders = abap_true.
ri_html->add( |<td class="current_dir">{ mv_cur_dir }</td>| ).
ENDIF.
ri_html->add( '<td class="right">' ).
ri_html->add( lo_toolbar->render( iv_right = abap_true ) ).
ri_html->add( '</td>' ).
ri_html->add( '</tr></table>' ).
ri_html->add( '</div>' ).
ENDMETHOD.
METHOD render_item.
DATA: lv_link TYPE string,
lv_colspan TYPE i.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
IF iv_render_transports = abap_false.
lv_colspan = 2.
ELSE.
lv_colspan = 3.
ENDIF.
ri_html->add( |<tr{ get_item_class( is_item ) }>| ).
IF is_item-obj_name IS INITIAL AND is_item-is_dir = abap_false.
ri_html->add( |<td colspan="{ lv_colspan }"></td>|
&& '<td class="object">'
&& '<i class="grey">non-code and meta files</i>'
&& '</td>' ).
ELSE.
ri_html->add( |<td class="icon">{ get_item_icon( is_item ) }</td>| ).
IF iv_render_transports = abap_true.
ri_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 ).
ri_html->add( |<td class="dir" colspan="2">{ lv_link }</td>| ).
ELSE.
lv_link = build_obj_jump_link( is_item ).
ri_html->add( |<td class="type">{ is_item-obj_type }</td>| ).
ri_html->add( |<td class="object">{ lv_link } { build_inactive_object_code( is_item ) }</td>| ).
ENDIF.
ENDIF.
" Files
ri_html->add( '<td class="files">' ).
ri_html->add( render_item_files( is_item ) ).
ri_html->add( '</td>' ).
" Command
IF mo_repo->has_remote_source( ) = abap_true.
ri_html->add( '<td class="cmd">' ).
ri_html->add( render_item_command( is_item ) ).
ri_html->add( '</td>' ).
ENDIF.
ri_html->add( '</tr>' ).
ENDMETHOD.
METHOD render_item_command.
DATA: lv_difflink TYPE string,
ls_file LIKE LINE OF is_item-files.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
IF is_item-is_dir = abap_true. " Directory
ri_html->add( '<div>' ).
ri_html->add( |<span class="grey">{ is_item-changes } changes</span>| ).
ri_html->add( zcl_abapgit_gui_chunk_lib=>render_item_state(
iv_lstate = is_item-lstate
iv_rstate = is_item-rstate ) ).
ri_html->add( '</div>' ).
ELSEIF is_item-changes > 0.
IF mv_hide_files = abap_true AND is_item-obj_name IS NOT INITIAL.
lv_difflink = zcl_abapgit_html_action_utils=>obj_encode(
iv_key = mo_repo->get_key( )
ig_object = is_item ).
ri_html->add( '<div>' ).
ri_html->add_a( iv_txt = |diff ({ is_item-changes })|
iv_act = |{ zif_abapgit_definitions=>c_action-go_diff }?{ lv_difflink }| ).
ri_html->add( zcl_abapgit_gui_chunk_lib=>render_item_state( iv_lstate = is_item-lstate
iv_rstate = is_item-rstate ) ).
ri_html->add( '</div>' ).
ELSE.
LOOP AT is_item-files INTO ls_file.
ri_html->add( '<div>' ).
IF ls_file-is_changed = abap_true.
lv_difflink = zcl_abapgit_html_action_utils=>file_encode(
iv_key = mo_repo->get_key( )
ig_file = ls_file ).
ri_html->add_a( iv_txt = 'diff'
iv_act = |{ zif_abapgit_definitions=>c_action-go_diff }?{ lv_difflink }| ).
ri_html->add( zcl_abapgit_gui_chunk_lib=>render_item_state( iv_lstate = ls_file-lstate
iv_rstate = ls_file-rstate ) ).
ELSE.
ri_html->add( '&nbsp;' ).
ENDIF.
ri_html->add( '</div>' ).
ENDLOOP.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD render_item_files.
DATA: ls_file LIKE LINE OF is_item-files.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
IF mv_hide_files = abap_true AND is_item-obj_type IS NOT INITIAL.
RETURN.
ENDIF.
LOOP AT is_item-files INTO ls_file.
ri_html->add( |<div>{ ls_file-path && ls_file-filename }</div>| ).
ENDLOOP.
ENDMETHOD.
METHOD render_item_lock_column.
DATA li_cts_api TYPE REF TO zif_abapgit_cts_api.
DATA lv_transport TYPE trkorr.
DATA lv_transport_string TYPE string.
DATA lv_icon_html TYPE string.
DATA li_html TYPE REF TO zif_abapgit_html.
CREATE OBJECT li_html TYPE zcl_abapgit_html.
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 = |<td class="icon"></td>|.
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 = li_html->a(
iv_txt = li_html->icon( iv_name = 'briefcase/darkgrey'
iv_hint = lv_transport_string )
iv_act = |{ zif_abapgit_definitions=>c_action-jump_transport }?transport={ lv_transport }| ).
rv_html = |<td class="icon">| &&
|{ lv_icon_html }| &&
|</td>|.
ENDIF.
CATCH zcx_abapgit_exception.
ASSERT 1 = 2.
ENDTRY.
ENDMETHOD.
METHOD render_order_by.
DATA:
lv_icon TYPE string,
lt_col_spec TYPE zif_abapgit_definitions=>ty_col_spec_tt,
ls_col_spec TYPE zif_abapgit_definitions=>ty_col_spec.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
APPEND INITIAL LINE TO lt_col_spec.
IF mv_are_changes_recorded_in_tr = abap_true.
APPEND INITIAL LINE TO lt_col_spec.
ENDIF.
ls_col_spec-tech_name = 'OBJ_TYPE'.
ls_col_spec-display_name = 'Type'.
APPEND ls_col_spec TO lt_col_spec.
ls_col_spec-tech_name = 'OBJ_NAME'.
ls_col_spec-display_name = 'Name'.
APPEND ls_col_spec TO lt_col_spec.
ls_col_spec-tech_name = 'PATH'.
ls_col_spec-display_name = 'Path'.
APPEND ls_col_spec TO lt_col_spec.
APPEND INITIAL LINE TO lt_col_spec.
ri_html->add( |<thead>| ).
ri_html->add( |<tr>| ).
ri_html->add( zcl_abapgit_gui_chunk_lib=>render_order_by_header_cells(
it_col_spec = lt_col_spec
iv_order_by = mv_order_by
iv_order_descending = mv_order_descending ) ).
IF mv_diff_first = abap_true.
lv_icon = 'check/blue'.
ELSE.
lv_icon = 'check/grey'.
ENDIF.
ri_html->add( '</tr>' ).
ri_html->add( '</thead>' ).
ENDMETHOD.
METHOD render_parent_dir.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
ri_html->add( '<tr class="folder">' ).
ri_html->add( |<td class="icon">{ ri_html->icon( 'folder' ) }</td>| ).
ri_html->add( |<td class="object" colspan="4">{ build_dir_jump_link( '..' ) }</td>| ).
IF mo_repo->has_remote_source( ) = abap_true.
ri_html->add( |<td colspan="1"></td>| ). " Dummy for online
ENDIF.
ri_html->add( '</tr>' ).
ENDMETHOD.
METHOD render_scripts.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
ri_html->set_title( cl_abap_typedescr=>describe_by_object_ref( me )->get_relative_name( ) ).
ri_html->add( zcl_abapgit_gui_chunk_lib=>render_repo_palette( zif_abapgit_definitions=>c_action-go_repo ) ).
ENDMETHOD.
METHOD switch_to_pr.
DATA lo_repo_online TYPE REF TO zcl_abapgit_repo_online.
DATA lt_pulls TYPE zif_abapgit_pr_enum_provider=>ty_pull_requests.
DATA ls_pull LIKE LINE OF lt_pulls.
IF mo_repo->is_offline( ) = abap_true.
zcx_abapgit_exception=>raise( 'Unexpected PR switch for offline repo' ).
ENDIF.
IF mo_repo->get_local_settings( )-write_protected = abap_true.
zcx_abapgit_exception=>raise( 'Cannot switch branch. Local code is write-protected by repo config' ).
ENDIF.
lo_repo_online ?= mo_repo.
IF iv_revert = abap_true.
lo_repo_online->switch_origin( '' ).
ELSE.
lt_pulls = zcl_abapgit_pr_enumerator=>new( lo_repo_online )->get_pulls( ).
IF lines( lt_pulls ) = 0.
RETURN. " false
ENDIF.
ls_pull = zcl_abapgit_ui_factory=>get_popups( )->choose_pr_popup( lt_pulls ).
IF ls_pull IS INITIAL.
RETURN. " false
ENDIF.
lo_repo_online->switch_origin( ls_pull-head_url ).
lo_repo_online->set_branch_name( |refs/heads/{ ls_pull-head_branch }| ). " TODO refactor
rv_switched = abap_true.
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_gui_event_handler~on_event.
DATA lv_path TYPE string.
DATA lv_switched TYPE abap_bool.
CASE ii_event->mv_action.
WHEN zif_abapgit_definitions=>c_action-go_repo. " Switch to another repo
CREATE OBJECT rs_handled-page TYPE zcl_abapgit_gui_page_repo_view
EXPORTING
iv_key = |{ ii_event->query( )->get( 'KEY' ) }|.
rs_handled-state = zcl_abapgit_gui=>c_event_state-new_page_replacing.
WHEN c_actions-toggle_hide_files. " Toggle file diplay
mv_hide_files = zcl_abapgit_persistence_user=>get_instance( )->toggle_hide_files( ).
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
WHEN c_actions-change_dir. " Change dir
lv_path = ii_event->query( )->get( 'PATH' ).
mv_cur_dir = zcl_abapgit_path=>change_dir(
iv_cur_dir = mv_cur_dir
iv_cd = lv_path ).
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
WHEN c_actions-toggle_folders. " Toggle folder view
mv_show_folders = boolc( mv_show_folders <> abap_true ).
mv_cur_dir = '/'. " Root
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
WHEN c_actions-toggle_changes. " Toggle changes only view
mv_changes_only = zcl_abapgit_persistence_user=>get_instance( )->toggle_changes_only( ).
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
WHEN c_actions-toggle_diff_first.
mv_diff_first = boolc( mv_diff_first = abap_false ).
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
WHEN c_actions-display_more. " Increase MAX lines limit
mv_max_lines = mv_max_lines + mv_max_setting.
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
WHEN zif_abapgit_definitions=>c_action-change_order_by.
mv_order_by = ii_event->query( )->get( 'ORDERBY' ).
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
WHEN zif_abapgit_definitions=>c_action-direction.
mv_order_descending = boolc( ii_event->query( )->get( 'DIRECTION' ) = 'DESCENDING' ).
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
WHEN zif_abapgit_definitions=>c_action-repo_open_in_master_lang.
open_in_master_language( ).
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
WHEN c_actions-repo_switch_origin_to_pr.
lv_switched = switch_to_pr( ).
IF lv_switched = abap_true.
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
ELSE.
rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.
ENDIF.
WHEN c_actions-repo_reset_origin.
switch_to_pr( iv_revert = abap_true ).
rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
WHEN OTHERS.
rs_handled = super->zif_abapgit_gui_event_handler~on_event( ii_event ). " TODO refactor, move to HOC components
ENDCASE.
ENDMETHOD.
METHOD zif_abapgit_gui_hotkeys~get_hotkey_actions.
DATA: ls_hotkey_action LIKE LINE OF rt_hotkey_actions.
ls_hotkey_action-ui_component = 'Repo'.
ls_hotkey_action-description = |Stage changes|.
ls_hotkey_action-action = zif_abapgit_definitions=>c_action-go_stage.
ls_hotkey_action-hotkey = |s|.
INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.
ls_hotkey_action-description = |Switch branch|.
ls_hotkey_action-action = zif_abapgit_definitions=>c_action-git_branch_switch.
ls_hotkey_action-hotkey = |b|.
INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.
ls_hotkey_action-description = |Installed repo list|.
ls_hotkey_action-action = zif_abapgit_definitions=>c_action-abapgit_home.
ls_hotkey_action-hotkey = |o|.
INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.
ls_hotkey_action-description = |Refresh repository|.
ls_hotkey_action-action = zif_abapgit_definitions=>c_action-repo_refresh.
ls_hotkey_action-hotkey = |r|.
INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.
ls_hotkey_action-description = |Pull|.
ls_hotkey_action-action = zif_abapgit_definitions=>c_action-git_pull.
ls_hotkey_action-hotkey = |p|.
INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.
ls_hotkey_action-description = |Diff|.
ls_hotkey_action-action = zif_abapgit_definitions=>c_action-go_diff.
ls_hotkey_action-hotkey = |d|.
INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.
ls_hotkey_action-description = |Uninstall repository|.
ls_hotkey_action-action = zif_abapgit_definitions=>c_action-repo_purge.
ls_hotkey_action-hotkey = |u|.
INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.
ls_hotkey_action-description = |Run code inspector|.
ls_hotkey_action-action = zif_abapgit_definitions=>c_action-repo_code_inspector.
ls_hotkey_action-hotkey = |i|.
INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.
ls_hotkey_action-description = |Show log|.
ls_hotkey_action-action = zif_abapgit_definitions=>c_action-repo_log.
ls_hotkey_action-hotkey = |l|.
INSERT ls_hotkey_action INTO TABLE rt_hotkey_actions.
ENDMETHOD.
ENDCLASS.
CLASS zcl_abapgit_html_form DEFINITION
PUBLIC
FINAL
CREATE PRIVATE .
PUBLIC SECTION.
CLASS-METHODS create
IMPORTING
!iv_form_id TYPE string OPTIONAL
RETURNING
VALUE(ro_form) TYPE REF TO zcl_abapgit_html_form .
METHODS render
IMPORTING
!iv_form_class TYPE string
!io_values TYPE REF TO zcl_abapgit_string_map
!io_validation_log TYPE REF TO zcl_abapgit_string_map OPTIONAL
RETURNING
VALUE(ri_html) TYPE REF TO zif_abapgit_html .
METHODS command
IMPORTING
!iv_label TYPE string
!iv_action TYPE string
!iv_is_main TYPE abap_bool DEFAULT abap_false
!iv_as_a TYPE abap_bool DEFAULT abap_false
RETURNING
VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form .
METHODS text
IMPORTING
!iv_label TYPE string
!iv_name TYPE string
!iv_hint TYPE string OPTIONAL
!iv_required TYPE abap_bool DEFAULT abap_false
!iv_upper_case TYPE abap_bool DEFAULT abap_false
!iv_placeholder TYPE string OPTIONAL
!iv_side_action TYPE string OPTIONAL
!iv_password TYPE abap_bool DEFAULT abap_false
!iv_autofocus TYPE abap_bool DEFAULT abap_false
RETURNING
VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form .
METHODS checkbox
IMPORTING
!iv_label TYPE string
!iv_name TYPE string
!iv_hint TYPE string OPTIONAL
RETURNING
VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form .
METHODS radio
IMPORTING
!iv_label TYPE string
!iv_name TYPE string
!iv_default_value TYPE string OPTIONAL
!iv_hint TYPE string OPTIONAL
RETURNING
VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form .
METHODS option
IMPORTING
!iv_label TYPE string
!iv_value TYPE string
RETURNING
VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form .
METHODS start_group
IMPORTING
!iv_label TYPE string
!iv_name TYPE string
!iv_hint TYPE string OPTIONAL
RETURNING
VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form .
METHODS normalize_form_data
IMPORTING
!io_form_data TYPE REF TO zcl_abapgit_string_map
RETURNING
VALUE(ro_form_data) TYPE REF TO zcl_abapgit_string_map
RAISING
zcx_abapgit_exception .
METHODS validate_required_fields
IMPORTING
!io_form_data TYPE REF TO zcl_abapgit_string_map
RETURNING
VALUE(ro_validation_log) TYPE REF TO zcl_abapgit_string_map
RAISING
zcx_abapgit_exception .
PROTECTED SECTION.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_subitem,
label TYPE string,
value TYPE string,
END OF ty_subitem .
TYPES:
ty_subitems TYPE STANDARD TABLE OF ty_subitem WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_field,
type TYPE i,
name TYPE string,
label TYPE string,
hint TYPE string,
dblclick TYPE string,
placeholder TYPE string,
required TYPE string,
upper_case TYPE abap_bool,
password TYPE abap_bool,
autofocus TYPE abap_bool,
item_class TYPE string,
error TYPE string,
default_value TYPE string,
side_action TYPE string,
subitems TYPE ty_subitems,
* onclick ???
END OF ty_field .
TYPES:
BEGIN OF ty_command,
label TYPE string,
action TYPE string,
is_main TYPE abap_bool,
as_a TYPE abap_bool,
* onclick ???
END OF ty_command .
CONSTANTS:
BEGIN OF c_field_type,
text TYPE i VALUE 1,
radio TYPE i VALUE 2,
checkbox TYPE i VALUE 3,
field_group TYPE i VALUE 4,
END OF c_field_type .
DATA:
mt_fields TYPE STANDARD TABLE OF ty_field
WITH UNIQUE SORTED KEY by_name COMPONENTS name.
DATA:
mt_commands TYPE STANDARD TABLE OF ty_command.
DATA mv_form_id TYPE string .
METHODS render_field
IMPORTING
!ii_html TYPE REF TO zif_abapgit_html
!io_values TYPE REF TO zcl_abapgit_string_map
!io_validation_log TYPE REF TO zcl_abapgit_string_map
!is_field TYPE ty_field .
METHODS render_command
IMPORTING
!ii_html TYPE REF TO zif_abapgit_html
!is_cmd TYPE ty_command .
ENDCLASS.
CLASS zcl_abapgit_html_form IMPLEMENTATION.
METHOD checkbox.
DATA ls_field LIKE LINE OF mt_fields.
ls_field-type = c_field_type-checkbox.
ls_field-name = iv_name.
ls_field-label = iv_label.
IF iv_hint IS NOT INITIAL.
ls_field-hint = | title="{ iv_hint }"|.
ENDIF.
APPEND ls_field TO mt_fields.
ro_self = me.
ENDMETHOD.
METHOD command.
DATA ls_cmd LIKE LINE OF mt_commands.
ASSERT iv_as_a IS INITIAL OR iv_is_main IS INITIAL.
ls_cmd-label = iv_label.
ls_cmd-action = iv_action.
ls_cmd-is_main = iv_is_main.
ls_cmd-as_a = iv_as_a.
APPEND ls_cmd TO mt_commands.
ro_self = me.
ENDMETHOD.
METHOD create.
DATA lv_ts TYPE timestampl.
CREATE OBJECT ro_form.
ro_form->mv_form_id = iv_form_id.
IF ro_form->mv_form_id IS INITIAL.
GET TIME STAMP FIELD lv_ts.
ro_form->mv_form_id = |form_{ lv_ts }|.
ENDIF.
ENDMETHOD.
METHOD normalize_form_data.
DATA lv_value TYPE string.
FIELD-SYMBOLS <ls_field> LIKE LINE OF mt_fields.
CREATE OBJECT ro_form_data.
LOOP AT mt_fields ASSIGNING <ls_field>.
CLEAR lv_value.
lv_value = io_form_data->get( <ls_field>-name ).
IF <ls_field>-type = c_field_type-checkbox.
ro_form_data->set(
iv_key = <ls_field>-name
iv_val = boolc( lv_value = 'on' ) ).
ELSEIF <ls_field>-type = c_field_type-text AND <ls_field>-upper_case = abap_true.
ro_form_data->set(
iv_key = <ls_field>-name
iv_val = to_upper( lv_value ) ).
ELSE.
ro_form_data->set(
iv_key = <ls_field>-name
iv_val = lv_value ).
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD option.
FIELD-SYMBOLS <ls_last> LIKE LINE OF mt_fields.
DATA ls_option LIKE LINE OF <ls_last>-subitems.
DATA lv_size TYPE i.
lv_size = lines( mt_fields ).
ASSERT lv_size > 0. " Exception ? Maybe add zcx_no_check ?
READ TABLE mt_fields INDEX lv_size ASSIGNING <ls_last>.
ASSERT sy-subrc = 0.
ASSERT <ls_last>-type = c_field_type-radio. " Or dropdown - TODO in future
ls_option-label = iv_label.
ls_option-value = iv_value.
APPEND ls_option TO <ls_last>-subitems.
ro_self = me.
ENDMETHOD.
METHOD radio.
DATA ls_field LIKE LINE OF mt_fields.
ls_field-type = c_field_type-radio.
ls_field-name = iv_name.
ls_field-label = iv_label.
ls_field-default_value = iv_default_value.
IF iv_hint IS NOT INITIAL.
ls_field-hint = | title="{ iv_hint }"|.
ENDIF.
APPEND ls_field TO mt_fields.
ro_self = me.
ENDMETHOD.
METHOD render.
FIELD-SYMBOLS <ls_field> LIKE LINE OF mt_fields.
FIELD-SYMBOLS <ls_cmd> LIKE LINE OF mt_commands.
DATA ls_form_id TYPE string.
DATA lv_cur_group TYPE string.
IF mv_form_id IS NOT INITIAL.
ls_form_id = | id="{ mv_form_id }"|.
ENDIF.
CREATE OBJECT ri_html TYPE zcl_abapgit_html.
ri_html->add( |<div class="{ iv_form_class }">| ).
ri_html->add( |<form method="post"{ ls_form_id }>| ).
ri_html->add( |<ul>| ).
LOOP AT mt_fields ASSIGNING <ls_field>.
IF <ls_field>-type = c_field_type-field_group.
IF lv_cur_group IS NOT INITIAL AND lv_cur_group <> <ls_field>-name.
ri_html->add( '</fieldset>' ).
ENDIF.
lv_cur_group = <ls_field>-name.
ri_html->add( |<fieldset name="{ <ls_field>-name }">| ).
ri_html->add( |<legend{ <ls_field>-hint }>{ <ls_field>-label }</legend>| ).
CONTINUE.
ENDIF.
render_field(
ii_html = ri_html
io_values = io_values
io_validation_log = io_validation_log
is_field = <ls_field> ).
AT LAST.
IF lv_cur_group IS NOT INITIAL.
ri_html->add( '</fieldset>' ).
ENDIF.
ENDAT.
ENDLOOP.
ri_html->add( |<li class="dialog-commands">| ).
LOOP AT mt_commands ASSIGNING <ls_cmd>.
render_command(
ii_html = ri_html
is_cmd = <ls_cmd> ).
ENDLOOP.
ri_html->add( |</li>| ).
ri_html->add( |</ul>| ).
ri_html->add( |</form>| ).
ri_html->add( |</div>| ).
ENDMETHOD.
METHOD render_command.
DATA lv_main_submit TYPE string.
IF is_cmd-as_a = abap_true.
ii_html->add_a(
iv_txt = is_cmd-label
iv_act = is_cmd-action
iv_class = 'dialog-commands' ).
ELSE.
IF is_cmd-is_main = abap_true.
lv_main_submit = ' class="main"'.
ELSE.
CLEAR lv_main_submit.
ENDIF.
ii_html->add( |<input type="submit" value="{
is_cmd-label }"{ lv_main_submit } formaction="sapevent:{ is_cmd-action }">| ).
ENDIF.
ENDMETHOD.
METHOD render_field.
DATA lv_opt_id TYPE string.
DATA lv_error TYPE string.
DATA lv_value TYPE string.
DATA lv_type TYPE string.
DATA lv_focus TYPE string.
DATA lv_checked TYPE string.
DATA lv_item_class TYPE string.
FIELD-SYMBOLS <ls_opt> LIKE LINE OF is_field-subitems.
" Get value and validation error from maps
lv_value = io_values->get( is_field-name ).
IF io_validation_log IS BOUND.
lv_error = io_validation_log->get( is_field-name ).
ENDIF.
" Prepare item class
lv_item_class = is_field-item_class.
IF lv_error IS NOT INITIAL.
lv_item_class = condense( lv_item_class && ' error' ).
ENDIF.
IF lv_item_class IS NOT INITIAL.
lv_item_class = | class="{ lv_item_class }"|.
ENDIF.
" Render field
ii_html->add( |<li{ lv_item_class }>| ).
CASE is_field-type.
WHEN c_field_type-text.
ii_html->add( |<label for="{ is_field-name }"{ is_field-hint }>{
is_field-label }{ is_field-required }</label>| ).
IF lv_error IS NOT INITIAL.
ii_html->add( |<small>{ lv_error }</small>| ).
ENDIF.
IF is_field-side_action IS NOT INITIAL.
ii_html->add( '<div class="input-container">' ). " Ugly :(
ENDIF.
IF is_field-password = abap_true.
lv_type = 'password'.
ELSE.
lv_type = 'text'.
ENDIF.
IF is_field-autofocus = abap_true.
lv_focus = ' autofocus'.
ELSE.
lv_focus = ''.
ENDIF.
ii_html->add( |<input type="{ lv_type }" name="{ is_field-name }" id="{
is_field-name }"{ is_field-placeholder } value="{ lv_value }"{ is_field-dblclick }{ lv_focus }>| ).
IF is_field-side_action IS NOT INITIAL.
ii_html->add( '</div>' ).
ii_html->add( '<div class="command-container">' ).
ii_html->add( |<input type="submit" value="&#x2026;" formaction="sapevent:{ is_field-side_action }">| ).
ii_html->add( '</div>' ).
ENDIF.
WHEN c_field_type-checkbox.
IF lv_error IS NOT INITIAL.
ii_html->add( |<small>{ lv_error }</small>| ).
ENDIF.
IF lv_value = abap_true OR lv_value = 'on'. " boolc return ` ` which is not initial -> bug after 1st validation
lv_checked = ' checked'.
ENDIF.
ii_html->add( |<input type="checkbox" name="{ is_field-name }" id="{ is_field-name }"{ lv_checked }>| ).
ii_html->add( |<label for="{ is_field-name }"{ is_field-hint }>{
is_field-label }{ is_field-required }</label>| ).
WHEN c_field_type-radio.
ii_html->add( |<label{ is_field-hint }>{ is_field-label }{ is_field-required }</label>| ).
IF lv_error IS NOT INITIAL.
ii_html->add( |<small>{ lv_error }</small>| ).
ENDIF.
ii_html->add( |<div class="radio-container">| ).
LOOP AT is_field-subitems ASSIGNING <ls_opt>.
CLEAR lv_checked.
IF lv_value = <ls_opt>-value OR ( lv_value IS INITIAL AND <ls_opt>-value = is_field-default_value ).
lv_checked = ' checked'.
ENDIF.
lv_opt_id = |{ is_field-name }{ sy-tabix }|.
ii_html->add( |<input type="radio" name="{ is_field-name }" id="{
lv_opt_id }" value="{ <ls_opt>-value }"{ lv_checked }>| ).
ii_html->add( |<label for="{ lv_opt_id }">{ <ls_opt>-label }</label>| ).
ENDLOOP.
ii_html->add( '</div>' ).
WHEN OTHERS.
ASSERT 1 = 0.
ENDCASE.
ii_html->add( '</li>' ).
ENDMETHOD.
METHOD start_group.
DATA ls_field LIKE LINE OF mt_fields.
ls_field-type = c_field_type-field_group.
ls_field-label = iv_label.
ls_field-name = iv_name.
IF iv_hint IS NOT INITIAL.
ls_field-hint = | title="{ iv_hint }"|.
ENDIF.
APPEND ls_field TO mt_fields.
ro_self = me.
ENDMETHOD.
METHOD text.
DATA ls_field LIKE LINE OF mt_fields.
ls_field-type = c_field_type-text.
ls_field-name = iv_name.
ls_field-label = iv_label.
ls_field-upper_case = iv_upper_case.
ls_field-password = iv_password.
ls_field-autofocus = iv_autofocus.
IF iv_hint IS NOT INITIAL.
ls_field-hint = | title="{ iv_hint }"|.
ENDIF.
IF iv_side_action IS NOT INITIAL AND mv_form_id IS NOT INITIAL.
ls_field-item_class = 'with-command'.
ls_field-side_action = iv_side_action.
ls_field-dblclick = | ondblclick="document.getElementById('{ mv_form_id
}').action = 'sapevent:{ iv_side_action
}'; document.getElementById('{ mv_form_id
}').submit()"|.
ENDIF.
IF iv_required = abap_true.
ls_field-required = ' <em>*</em>'.
ENDIF.
IF iv_placeholder IS NOT INITIAL.
ls_field-placeholder = | placeholder="{ iv_placeholder }"|.
ENDIF.
APPEND ls_field TO mt_fields.
ro_self = me.
ENDMETHOD.
METHOD validate_required_fields.
DATA lv_value TYPE string.
FIELD-SYMBOLS <ls_field> LIKE LINE OF mt_fields.
CREATE OBJECT ro_validation_log.
LOOP AT mt_fields ASSIGNING <ls_field>.
lv_value = io_form_data->get( <ls_field>-name ).
IF <ls_field>-required IS NOT INITIAL AND lv_value IS INITIAL.
ro_validation_log->set(
iv_key = <ls_field>-name
iv_val = |{ <ls_field>-label } cannot be empty| ).
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
CLASS zcl_abapgit_http DEFINITION
PUBLIC
CREATE PUBLIC .
PUBLIC SECTION.
CLASS-METHODS get_agent
RETURNING
VALUE(rv_agent) TYPE string .
CLASS-METHODS create_by_url
IMPORTING
!iv_url TYPE string
!iv_service TYPE string
RETURNING
VALUE(ro_client) TYPE REF TO zcl_abapgit_http_client
RAISING
zcx_abapgit_exception .
PROTECTED SECTION.
CLASS-METHODS check_auth_requested
IMPORTING
!ii_client TYPE REF TO if_http_client
RETURNING
VALUE(rv_auth_requested) TYPE abap_bool
RAISING
zcx_abapgit_exception .
CLASS-METHODS is_local_system
IMPORTING
!iv_url TYPE string
RETURNING
VALUE(rv_bool) TYPE abap_bool .
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_abapgit_http IMPLEMENTATION.
METHOD check_auth_requested.
DATA: lv_code TYPE i.
ii_client->response->get_status( IMPORTING code = lv_code ).
IF lv_code = 401.
rv_auth_requested = abap_true.
ENDIF.
ENDMETHOD.
METHOD create_by_url.
DATA: lv_uri TYPE string,
lv_digest TYPE string,
li_client TYPE REF TO if_http_client,
lo_proxy_configuration TYPE REF TO zcl_abapgit_proxy_config,
lv_text TYPE string.
CREATE OBJECT lo_proxy_configuration.
li_client = zcl_abapgit_exit=>get_instance( )->create_http_client( iv_url ).
IF li_client IS NOT BOUND.
cl_http_client=>create_by_url(
EXPORTING
url = zcl_abapgit_url=>host( iv_url )
ssl_id = zcl_abapgit_exit=>get_instance( )->get_ssl_id( )
proxy_host = lo_proxy_configuration->get_proxy_url( iv_url )
proxy_service = lo_proxy_configuration->get_proxy_port( iv_url )
IMPORTING
client = li_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4 ).
IF sy-subrc <> 0.
CASE sy-subrc.
WHEN 1.
" make sure:
" a) SSL is setup properly in STRUST
lv_text = 'HTTPS ARGUMENT_NOT_FOUND | STRUST/SSL Setup correct?'.
WHEN OTHERS.
lv_text = 'While creating HTTP Client'.
ENDCASE.
zcx_abapgit_exception=>raise( lv_text ).
ENDIF.
ENDIF.
IF lo_proxy_configuration->get_proxy_authentication( iv_url ) = abap_true.
zcl_abapgit_proxy_auth=>run( li_client ).
ENDIF.
CREATE OBJECT ro_client
EXPORTING
ii_client = li_client.
IF is_local_system( iv_url ) = abap_true.
li_client->send_sap_logon_ticket( ).
ENDIF.
li_client->request->set_cdata( '' ).
li_client->request->set_header_field(
name = '~request_method'
value = 'GET' ).
li_client->request->set_header_field(
name = 'user-agent'
value = get_agent( ) ).
lv_uri = zcl_abapgit_url=>path_name( iv_url ) &&
'/info/refs?service=git-' &&
iv_service &&
'-pack'.
li_client->request->set_header_field(
name = '~request_uri'
value = lv_uri ).
" Disable internal auth dialog (due to its unclarity)
li_client->propertytype_logon_popup = if_http_client=>co_disabled.
zcl_abapgit_login_manager=>load(
iv_uri = iv_url
ii_client = li_client ).
zcl_abapgit_exit=>get_instance( )->http_client(
iv_url = iv_url
ii_client = li_client ).
ro_client->send_receive( ).
IF check_auth_requested( li_client ) = abap_true.
lv_digest = li_client->response->get_header_field( 'WWW-Authenticate' ).
" If authorization is not set, redirect to "Login Page"
zcl_abapgit_login_manager=>login(
iv_url = iv_url
iv_digest = lv_digest ).
ENDIF.
ro_client->check_http_200( ).
ENDMETHOD.
METHOD get_agent.
* bitbucket require agent prefix = "git/"
* also see https://github.com/abapGit/abapGit/issues/1432
rv_agent = |git/2.0 (abapGit { zif_abapgit_version=>gc_abap_version })|.
ENDMETHOD.
METHOD is_local_system.
DATA: lv_host TYPE string,
lt_list TYPE zif_abapgit_exit=>ty_icm_sinfo2_tt,
li_exit TYPE REF TO zif_abapgit_exit.
FIELD-SYMBOLS: <ls_list> LIKE LINE OF lt_list.
CALL FUNCTION 'ICM_GET_INFO2'
TABLES
servlist = lt_list
EXCEPTIONS
icm_error = 1
icm_timeout = 2
OTHERS = 3.
IF sy-subrc <> 0.
RETURN.
ENDIF.
APPEND INITIAL LINE TO lt_list ASSIGNING <ls_list>.
<ls_list>-hostname = 'localhost'.
li_exit = zcl_abapgit_exit=>get_instance( ).
li_exit->change_local_host( CHANGING ct_hosts = lt_list ).
FIND REGEX 'https?://([^/^:]*)' IN iv_url
SUBMATCHES lv_host.
READ TABLE lt_list WITH KEY hostname = lv_host TRANSPORTING NO FIELDS.
rv_bool = boolc( sy-subrc = 0 ).
ENDMETHOD.
ENDCLASS.
CLASS zcl_abapgit_http_digest DEFINITION
PUBLIC
CREATE PUBLIC .
PUBLIC SECTION.
METHODS constructor
IMPORTING
!ii_client TYPE REF TO if_http_client OPTIONAL
!iv_digest TYPE string OPTIONAL
!iv_username TYPE string
!iv_password TYPE string
RAISING
zcx_abapgit_exception.
METHODS run
IMPORTING
!ii_client TYPE REF TO if_http_client
RAISING
zcx_abapgit_exception.
PROTECTED SECTION.
PRIVATE SECTION.
DATA: mv_ha1 TYPE string,
mv_username TYPE string,
mv_realm TYPE string,
mv_qop TYPE string,
mv_nonce TYPE string.
CLASS-DATA: gv_nc TYPE n LENGTH 8.
CLASS-METHODS:
md5
IMPORTING
iv_data TYPE string
RETURNING
VALUE(rv_hash) TYPE string
RAISING zcx_abapgit_exception.
METHODS:
hash
IMPORTING
iv_qop TYPE string
iv_nonce TYPE string
iv_uri TYPE string
iv_method TYPE string
iv_cnonse TYPE string
RETURNING
VALUE(rv_response) TYPE string
RAISING zcx_abapgit_exception,
parse
IMPORTING
ii_client TYPE REF TO if_http_client
!iv_digest TYPE string.
ENDCLASS.
CLASS zcl_abapgit_http_digest IMPLEMENTATION.
METHOD constructor.
parse( ii_client = ii_client
iv_digest = iv_digest ).
mv_ha1 = md5( |{ iv_username }:{ mv_realm }:{ iv_password }| ).
mv_username = iv_username.
ENDMETHOD.
METHOD hash.
DATA: lv_ha2 TYPE string.
lv_ha2 = md5( |{ iv_method }:{ iv_uri }| ).
ASSERT NOT iv_cnonse IS INITIAL.
rv_response = md5( |{ mv_ha1 }:{ iv_nonce }:{ gv_nc }:{ iv_cnonse }:{ iv_qop }:{ lv_ha2 }| ).
ENDMETHOD.
METHOD md5.
DATA: lv_xstr TYPE xstring,
lv_hash TYPE xstring.
lv_xstr = zcl_abapgit_convert=>string_to_xstring_utf8( iv_data ).
CALL FUNCTION 'CALCULATE_HASH_FOR_RAW'
EXPORTING
alg = 'MD5'
data = lv_xstr
IMPORTING
hashxstring = lv_hash
EXCEPTIONS
unknown_alg = 1
param_error = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
zcx_abapgit_exception=>raise( 'error from CALCULATE_HASH_FOR_RAW' ).
ENDIF.
rv_hash = lv_hash.
TRANSLATE rv_hash TO LOWER CASE.
ENDMETHOD.
METHOD parse.
DATA: lv_value TYPE string.
IF iv_digest IS INITIAL.
lv_value = ii_client->response->get_header_field( 'WWW-Authenticate' ).
ELSE.
lv_value = iv_digest.
ENDIF.
FIND REGEX 'realm="([\w ]+)"' IN lv_value SUBMATCHES mv_realm.
FIND REGEX 'qop="(\w+)"' IN lv_value SUBMATCHES mv_qop.
FIND REGEX 'nonce="([\w=/+\$]+)"' IN lv_value SUBMATCHES mv_nonce.
ENDMETHOD.
METHOD run.
DATA: lv_response TYPE string,
lv_method TYPE string,
lv_cnonce TYPE string,
lv_uri TYPE string,
lv_auth TYPE string.
ASSERT NOT mv_nonce IS INITIAL.
lv_method = ii_client->request->get_header_field( '~request_method' ).
lv_uri = ii_client->request->get_header_field( '~request_uri' ).
CALL FUNCTION 'GENERAL_GET_RANDOM_STRING'
EXPORTING
number_chars = 24
IMPORTING
random_string = lv_cnonce.
lv_response = hash(
iv_qop = mv_qop
iv_nonce = mv_nonce
iv_uri = lv_uri
iv_method = lv_method
iv_cnonse = lv_cnonce ).
* client response
lv_auth = |Digest username="{ mv_username
}", realm="{ mv_realm
}", nonce="{ mv_nonce
}", uri="{ lv_uri
}", qop={ mv_qop
}, nc={ gv_nc
}, cnonce="{ lv_cnonce
}", response="{ lv_response }"|.
ii_client->request->set_header_field(
name = 'Authorization'
value = lv_auth ).
ENDMETHOD.
ENDCLASS.
CLASS zcl_abapgit_login_manager DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
CONSTANTS gc_proxy TYPE string VALUE 'http://proxy/' ##NO_TEXT. " Identifier for proxy
CLASS-METHODS login
IMPORTING
!iv_url TYPE string
!iv_digest TYPE string OPTIONAL
RAISING
zcx_abapgit_exception .
CLASS-METHODS load
IMPORTING
!iv_uri TYPE string
!ii_client TYPE REF TO if_http_client OPTIONAL
RETURNING
VALUE(rv_authorization) TYPE string
RAISING
zcx_abapgit_exception .
CLASS-METHODS save
IMPORTING
!iv_uri TYPE string
!ii_client TYPE REF TO if_http_client
RAISING
zcx_abapgit_exception .
CLASS-METHODS clear .
CLASS-METHODS set
IMPORTING
!iv_uri TYPE string
!iv_username TYPE string
!iv_password TYPE string
!iv_digest TYPE string OPTIONAL
RETURNING
VALUE(rv_auth) TYPE string
RAISING
zcx_abapgit_exception .
CLASS-METHODS get
IMPORTING
!iv_uri TYPE string
RETURNING
VALUE(rv_auth) TYPE string
RAISING
zcx_abapgit_exception .
CLASS-METHODS get_default_user
IMPORTING
!iv_uri TYPE string
RETURNING
VALUE(rv_username) TYPE string
RAISING
zcx_abapgit_exception .
CLASS-METHODS set_default_user
IMPORTING
!iv_uri TYPE string
!iv_username TYPE string
RAISING
zcx_abapgit_exception .
CLASS-METHODS get_host
IMPORTING
!iv_url TYPE string
RETURNING
VALUE(rv_host) TYPE string
RAISING
zcx_abapgit_exception .
CLASS-METHODS reset_count
IMPORTING
!iv_url TYPE string .
PROTECTED SECTION.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_auth,
uri TYPE string,
authorization TYPE string,
digest TYPE REF TO zcl_abapgit_http_digest,
END OF ty_auth .
TYPES:
BEGIN OF ty_login,
url TYPE string,
count TYPE i,
END OF ty_login .
CONSTANTS gc_max_logins TYPE i VALUE 3.
CLASS-DATA:
gt_auth TYPE HASHED TABLE OF ty_auth WITH UNIQUE KEY uri .
CLASS-DATA:
gt_logins TYPE HASHED TABLE OF ty_login WITH UNIQUE KEY url .
CLASS-METHODS increase_count
IMPORTING
!iv_url TYPE string
RETURNING
VALUE(rv_count) TYPE i.
CLASS-METHODS append
IMPORTING
!iv_uri TYPE string
!iv_auth TYPE string
!io_digest TYPE REF TO zcl_abapgit_http_digest OPTIONAL
RAISING
zcx_abapgit_exception .
ENDCLASS.
CLASS zcl_abapgit_login_manager IMPLEMENTATION.
METHOD append.
DATA ls_auth LIKE LINE OF gt_auth.
READ TABLE gt_auth WITH TABLE KEY uri = zcl_abapgit_url=>host( iv_uri )
TRANSPORTING NO FIELDS.
IF sy-subrc <> 0.
ls_auth-uri = zcl_abapgit_url=>host( iv_uri ).
ls_auth-authorization = iv_auth.
ls_auth-digest = io_digest.
INSERT ls_auth INTO TABLE gt_auth.
ENDIF.
ENDMETHOD.
METHOD clear.
CLEAR gt_auth.
ENDMETHOD.
METHOD get.
DATA ls_auth LIKE LINE OF gt_auth.
READ TABLE gt_auth INTO ls_auth WITH TABLE KEY uri = zcl_abapgit_url=>host( iv_uri ).
IF sy-subrc = 0.
rv_auth = ls_auth-authorization.
ENDIF.
ENDMETHOD.
METHOD get_default_user.
" No default user for proxy
IF iv_uri = gc_proxy.
RETURN.
ENDIF.
rv_username = zcl_abapgit_persistence_user=>get_instance( )->get_repo_login( iv_uri ).
ENDMETHOD.
METHOD get_host.
DATA lv_host TYPE string.
IF iv_url = gc_proxy.
rv_host = 'Proxy'.
ELSE.
lv_host = zcl_abapgit_url=>host( iv_url ).
SPLIT lv_host AT '//' INTO lv_host rv_host.
ENDIF.
ENDMETHOD.
METHOD increase_count.
DATA ls_login TYPE ty_login.
FIELD-SYMBOLS: <ls_login> TYPE ty_login.
" Keep track of how many login attempts have been made
READ TABLE gt_logins ASSIGNING <ls_login> WITH TABLE KEY url = iv_url.
IF sy-subrc = 0.
<ls_login>-count = <ls_login>-count + 1.
ELSE.
ls_login-url = iv_url.
ls_login-count = 1.
INSERT ls_login INTO TABLE gt_logins ASSIGNING <ls_login>.
ENDIF.
rv_count = <ls_login>-count.
ENDMETHOD.
METHOD load.
DATA: ls_auth LIKE LINE OF gt_auth.
READ TABLE gt_auth INTO ls_auth WITH TABLE KEY uri = zcl_abapgit_url=>host( iv_uri ).
IF sy-subrc = 0.
rv_authorization = ls_auth-authorization.
IF NOT ii_client IS INITIAL.
IF ls_auth-digest IS BOUND.
" Digest Authentication
" https://en.wikipedia.org/wiki/Digest_access_authentication
" e.g. used by https://www.gerritcodereview.com/
ls_auth-digest->run( ii_client ).
ELSE.
" Basic Authentication
" https://en.wikipedia.org/wiki/Basic_access_authentication
ii_client->request->set_header_field(
name = 'Authorization'
value = ls_auth-authorization ).
ENDIF.
ii_client->propertytype_logon_popup = ii_client->co_disabled.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD login.
DATA lv_count TYPE i.
lv_count = increase_count( iv_url ).
" Until maximum number of logins has been reached, trigger the login page
" by raising an exception with the URL parameter. The exception is caught
" in ZCL_ABAPGIT_GUI->HANDLE_ACTION which redirects to the login page.
IF lv_count BETWEEN 1 AND gc_max_logins.
zcx_abapgit_exception=>raise_login(
iv_url = iv_url
iv_digest = iv_digest
iv_count = lv_count ).
ENDIF.
" The previous logins were not successful. Reset the count and continue to
" process as usual. This will typically result in an error message
" on the target page
reset_count( iv_url ).
ENDMETHOD.
METHOD reset_count.
DELETE gt_logins WHERE url = iv_url.
ENDMETHOD.
METHOD save.
DATA: lv_auth TYPE string.
lv_auth = ii_client->request->get_header_field( 'Authorization' ).
IF NOT lv_auth IS INITIAL.
append( iv_uri = iv_uri
iv_auth = lv_auth ).
ENDIF.
ENDMETHOD.
METHOD set.
DATA: lv_concat TYPE string,
lo_digest TYPE REF TO zcl_abapgit_http_digest.
ASSERT NOT iv_uri IS INITIAL.
IF iv_username IS INITIAL OR iv_password IS INITIAL.
RETURN.
ENDIF.
CONCATENATE iv_username ':' iv_password INTO lv_concat.
IF iv_uri = gc_proxy.
rv_auth = lv_concat.
ELSE.
rv_auth = cl_http_utility=>if_http_utility~encode_base64( lv_concat ).
CONCATENATE 'Basic' rv_auth INTO rv_auth
SEPARATED BY space.
ENDIF.
IF iv_digest CP 'Digest *'.
CREATE OBJECT lo_digest
EXPORTING
iv_digest = iv_digest
iv_username = iv_username
iv_password = iv_password.
ENDIF.
append( iv_uri = iv_uri
iv_auth = rv_auth
io_digest = lo_digest ).
ENDMETHOD.
METHOD set_default_user.
" No default user for proxy
IF iv_uri = gc_proxy.
RETURN.
ENDIF.
zcl_abapgit_persistence_user=>get_instance( )->set_repo_login(
iv_url = iv_uri
iv_login = iv_username ).
ENDMETHOD.
ENDCLASS.
CLASS zcl_abapgit_proxy_auth DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
CLASS-METHODS:
run
IMPORTING ii_client TYPE REF TO if_http_client
RAISING zcx_abapgit_exception.
PRIVATE SECTION.
CLASS-DATA: gv_username TYPE string,
gv_password TYPE string.
ENDCLASS.
CLASS zcl_abapgit_proxy_auth IMPLEMENTATION.
METHOD run.
DATA lv_auth TYPE string.
IF gv_username IS INITIAL OR gv_password IS INITIAL.
lv_auth = zcl_abapgit_login_manager=>get( zcl_abapgit_login_manager=>gc_proxy ).
IF lv_auth IS INITIAL.
" If proxy authorization is not set, redirect to "Login Page"
zcl_abapgit_login_manager=>login( zcl_abapgit_login_manager=>gc_proxy ).
ELSE.
SPLIT lv_auth AT ':' INTO gv_username gv_password.
ENDIF.
ENDIF.
ii_client->authenticate(
proxy_authentication = abap_true
username = gv_username
password = gv_password ).
ENDMETHOD.
ENDCLASS.
CLASS zcl_abapgit_repo_srv DEFINITION
PUBLIC
FINAL
CREATE PRIVATE .
PUBLIC SECTION.
INTERFACES zif_abapgit_repo_srv .
INTERFACES zif_abapgit_repo_listener .
ALIASES get_repo_from_package
FOR zif_abapgit_repo_srv~get_repo_from_package .
CLASS-METHODS get_instance
RETURNING
VALUE(ri_srv) TYPE REF TO zif_abapgit_repo_srv .
PROTECTED SECTION.
PRIVATE SECTION.
ALIASES delete
FOR zif_abapgit_repo_srv~delete .
ALIASES get
FOR zif_abapgit_repo_srv~get .
ALIASES list
FOR zif_abapgit_repo_srv~list .
ALIASES validate_package
FOR zif_abapgit_repo_srv~validate_package .
CLASS-DATA gi_ref TYPE REF TO zif_abapgit_repo_srv .
DATA mv_init TYPE abap_bool VALUE abap_false ##NO_TEXT.
DATA mt_list TYPE zif_abapgit_definitions=>ty_repo_ref_tt .
METHODS determine_branch_name
IMPORTING
!iv_name TYPE string
!iv_url TYPE string
RETURNING
VALUE(rv_name) TYPE string
RAISING
zcx_abapgit_exception .
METHODS refresh
RAISING
zcx_abapgit_exception .
METHODS is_sap_object_allowed
RETURNING
VALUE(rv_allowed) TYPE abap_bool .
METHODS instantiate_and_add
IMPORTING
!is_repo_meta TYPE zif_abapgit_persistence=>ty_repo
RETURNING
VALUE(ro_repo) TYPE REF TO zcl_abapgit_repo
RAISING
zcx_abapgit_exception .
METHODS add
IMPORTING
!io_repo TYPE REF TO zcl_abapgit_repo
RAISING
zcx_abapgit_exception .
METHODS reinstantiate_repo
IMPORTING
!iv_key TYPE zif_abapgit_persistence=>ty_repo-key
!is_meta TYPE zif_abapgit_persistence=>ty_repo_xml
RAISING
zcx_abapgit_exception .
METHODS validate_sub_super_packages
IMPORTING
!iv_package TYPE devclass
!it_repos TYPE zif_abapgit_persistence=>ty_repos
!iv_ign_subpkg TYPE abap_bool DEFAULT abap_false
EXPORTING
VALUE(eo_repo) TYPE REF TO zcl_abapgit_repo
!ev_reason TYPE string
RAISING
zcx_abapgit_exception .
ENDCLASS.
CLASS zcl_abapgit_repo_srv IMPLEMENTATION.
METHOD add.
DATA: lo_repo LIKE LINE OF mt_list.
LOOP AT mt_list INTO lo_repo.
IF lo_repo->get_key( ) = io_repo->get_key( ).
IF lo_repo = io_repo.
RETURN.
ENDIF.
zcx_abapgit_exception=>raise( 'identical keys' ).
ENDIF.
ENDLOOP.
io_repo->bind_listener( me ).
APPEND io_repo TO mt_list.
ENDMETHOD.
METHOD determine_branch_name.
DATA lo_branch_list TYPE REF TO zcl_abapgit_git_branch_list.
rv_name = iv_name.
IF rv_name IS INITIAL.
ASSERT NOT iv_url IS INITIAL.
lo_branch_list = zcl_abapgit_git_transport=>branches( iv_url ).
rv_name = lo_branch_list->get_head_symref( ).
ELSEIF -1 = find(
val = rv_name
sub = zif_abapgit_definitions=>c_git_branch-heads_prefix ).
" Assume short branch name was received
rv_name = zif_abapgit_definitions=>c_git_branch-heads_prefix && rv_name.
ENDIF.
ENDMETHOD.
METHOD get_instance.
IF gi_ref IS INITIAL.
CREATE OBJECT gi_ref TYPE zcl_abapgit_repo_srv.
ENDIF.
ri_srv = gi_ref.
ENDMETHOD.
METHOD instantiate_and_add.
IF is_repo_meta-offline = abap_false.
CREATE OBJECT ro_repo TYPE zcl_abapgit_repo_online
EXPORTING
is_data = is_repo_meta.
ELSE.
CREATE OBJECT ro_repo TYPE zcl_abapgit_repo_offline
EXPORTING
is_data = is_repo_meta.
ENDIF.
add( ro_repo ).
ENDMETHOD.
METHOD is_sap_object_allowed.
rv_allowed = cl_enh_badi_def_utility=>is_sap_system( ).
IF rv_allowed = abap_true.
RETURN.
ENDIF.
rv_allowed = zcl_abapgit_exit=>get_instance( )->allow_sap_objects( ).
ENDMETHOD.
METHOD refresh.
DATA: lt_list TYPE zif_abapgit_persistence=>ty_repos.
FIELD-SYMBOLS: <ls_list> LIKE LINE OF lt_list.
CLEAR mt_list.
lt_list = zcl_abapgit_persist_factory=>get_repo( )->list( ).
LOOP AT lt_list ASSIGNING <ls_list>.
instantiate_and_add( <ls_list> ).
ENDLOOP.
mv_init = abap_true.
ENDMETHOD.
METHOD reinstantiate_repo.
DATA lo_repo TYPE REF TO zcl_abapgit_repo.
DATA ls_full_meta TYPE zif_abapgit_persistence=>ty_repo.
lo_repo = get( iv_key ).
DELETE TABLE mt_list FROM lo_repo.
ASSERT sy-subrc IS INITIAL.
MOVE-CORRESPONDING is_meta TO ls_full_meta.
ls_full_meta-key = iv_key.
instantiate_and_add( ls_full_meta ).
ENDMETHOD.
METHOD validate_sub_super_packages.
DATA:
ls_repo LIKE LINE OF it_repos,
li_package TYPE REF TO zif_abapgit_sap_package,
lt_packages TYPE zif_abapgit_sap_package=>ty_devclass_tt,
lo_repo TYPE REF TO zcl_abapgit_repo.
LOOP AT it_repos INTO ls_repo.
lo_repo = get( ls_repo-key ).
li_package = zcl_abapgit_factory=>get_sap_package( ls_repo-package ).
IF li_package->exists( ) = abap_false.
" Skip dangling repository
CONTINUE.
ENDIF.
CLEAR lt_packages.
IF lo_repo->get_local_settings( )-ignore_subpackages = abap_false.
APPEND LINES OF li_package->list_subpackages( ) TO lt_packages.
READ TABLE lt_packages TRANSPORTING NO FIELDS
WITH KEY table_line = iv_package.
IF sy-subrc = 0.
eo_repo = lo_repo.
ev_reason = |Repository { lo_repo->get_name( ) } already contains { iv_package } |.
RETURN.
ENDIF.
ENDIF.
IF iv_ign_subpkg = abap_false.
APPEND LINES OF li_package->list_superpackages( ) TO lt_packages.
READ TABLE lt_packages TRANSPORTING NO FIELDS
WITH KEY table_line = iv_package.
IF sy-subrc = 0.
eo_repo = lo_repo.
ev_reason = |Repository { lo_repo->get_name( ) } already contains subpackage of { iv_package } |.
RETURN.
ENDIF.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD zif_abapgit_repo_listener~on_meta_change.
DATA li_persistence TYPE REF TO zif_abapgit_persist_repo.
li_persistence = zcl_abapgit_persist_factory=>get_repo( ).
li_persistence->update_metadata(
iv_key = iv_key
is_meta = is_meta
is_change_mask = is_change_mask ).
" Recreate repo instance if type changed
" Instances in mt_list are of *_online and *_offline type
" If type is changed object should be recreated from the proper class
" TODO refactor, e.g. unify repo logic in one class
IF is_change_mask-offline = abap_true.
reinstantiate_repo(
iv_key = iv_key
is_meta = is_meta ).
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_repo_srv~delete.
zcl_abapgit_persist_factory=>get_repo( )->delete( io_repo->get_key( ) ).
" If favorite, remove it
IF zcl_abapgit_persistence_user=>get_instance( )->is_favorite_repo( io_repo->get_key( ) ) = abap_true.
zcl_abapgit_persistence_user=>get_instance( )->toggle_favorite( io_repo->get_key( ) ).
ENDIF.
DELETE TABLE mt_list FROM io_repo.
ASSERT sy-subrc = 0.
ENDMETHOD.
METHOD zif_abapgit_repo_srv~get.
FIELD-SYMBOLS: <lo_list> LIKE LINE OF mt_list.
IF mv_init = abap_false.
refresh( ).
ENDIF.
DO 2 TIMES.
" Repo might have been created in another session. Try again after refresh
IF sy-index = 2.
refresh( ).
ENDIF.
LOOP AT mt_list ASSIGNING <lo_list>.
IF <lo_list>->get_key( ) = iv_key.
ro_repo = <lo_list>.
RETURN.
ENDIF.
ENDLOOP.
ENDDO.
zcx_abapgit_exception=>raise( 'repo not found, get' ).
ENDMETHOD.
METHOD zif_abapgit_repo_srv~get_repo_from_package.
DATA:
lt_repos TYPE zif_abapgit_persistence=>ty_repos,
lv_name TYPE zif_abapgit_persistence=>ty_local_settings-display_name,
lv_owner TYPE zif_abapgit_persistence=>ty_local_settings-display_name.
FIELD-SYMBOLS:
<ls_repo> LIKE LINE OF lt_repos.
" check if package is already in use for a different repository
lt_repos = zcl_abapgit_persist_factory=>get_repo( )->list( ).
READ TABLE lt_repos WITH KEY package = iv_package ASSIGNING <ls_repo>.
IF sy-subrc = 0.
eo_repo = get_instance( )->get( <ls_repo>-key ).
lv_name = eo_repo->get_name( ).
lv_owner = <ls_repo>-created_by.
ev_reason = |Package { iv_package } already versioned as { lv_name } by { lv_owner }|.
ELSE.
" check if package is include as sub-package in a different repo
validate_sub_super_packages(
EXPORTING
iv_package = iv_package
it_repos = lt_repos
iv_ign_subpkg = iv_ign_subpkg
IMPORTING
eo_repo = eo_repo
ev_reason = ev_reason ).
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_repo_srv~get_repo_from_url.
DATA:
lt_repo TYPE zif_abapgit_definitions=>ty_repo_ref_tt,
lo_repo TYPE REF TO zcl_abapgit_repo,
lo_repo_online TYPE REF TO zcl_abapgit_repo_online.
lt_repo = list( ).
LOOP AT lt_repo INTO lo_repo.
CHECK lo_repo->is_offline( ) = abap_false.
lo_repo_online ?= lo_repo.
CHECK to_upper( lo_repo_online->get_url( ) ) = to_upper( iv_url ).
ro_repo ?= lo_repo.
RETURN.
ENDLOOP.
ENDMETHOD.
METHOD zif_abapgit_repo_srv~is_repo_installed.
DATA: lt_repo TYPE zif_abapgit_definitions=>ty_repo_ref_tt,
lo_repo TYPE REF TO zcl_abapgit_repo,
lv_url TYPE string,
lv_package TYPE devclass,
lo_repo_online TYPE REF TO zcl_abapgit_repo_online,
lv_err TYPE string.
lt_repo = list( ).
LOOP AT lt_repo INTO lo_repo.
CHECK lo_repo->is_offline( ) = abap_false.
lo_repo_online ?= lo_repo.
lv_url = lo_repo_online->get_url( ).
lv_package = lo_repo_online->get_package( ).
CHECK to_upper( lv_url ) = to_upper( iv_url ).
" Validate bindings
"TODO refactor: move this message out of this method
IF iv_target_package IS NOT INITIAL AND iv_target_package <> lv_package.
lv_err = |Installation to package { lv_package } detected. |
&& |Cancelling installation|.
zcx_abapgit_exception=>raise( lv_err ).
ENDIF.
rv_installed = abap_true.
EXIT.
ENDLOOP.
ENDMETHOD.
METHOD zif_abapgit_repo_srv~list.
IF mv_init = abap_false.
refresh( ).
ENDIF.
rt_list = mt_list.
ENDMETHOD.
METHOD zif_abapgit_repo_srv~new_offline.
DATA: ls_repo TYPE zif_abapgit_persistence=>ty_repo,
lv_key TYPE zif_abapgit_persistence=>ty_repo-key,
lo_dot_abapgit TYPE REF TO zcl_abapgit_dot_abapgit.
IF zcl_abapgit_auth=>is_allowed( zif_abapgit_auth=>gc_authorization-create_repo ) = abap_false.
zcx_abapgit_exception=>raise( 'Not authorized' ).
ENDIF.
validate_package( iv_package ).
IF iv_url IS INITIAL.
zcx_abapgit_exception=>raise( 'Missing display name for repo' ).
ENDIF.
lo_dot_abapgit = zcl_abapgit_dot_abapgit=>build_default( ).
lo_dot_abapgit->set_folder_logic( iv_folder_logic ).
lv_key = zcl_abapgit_persist_factory=>get_repo( )->add(
iv_url = iv_url
iv_branch_name = ''
iv_package = iv_package
iv_offline = abap_true
is_dot_abapgit = lo_dot_abapgit->get_data( ) ).
TRY.
ls_repo = zcl_abapgit_persist_factory=>get_repo( )->read( lv_key ).
CATCH zcx_abapgit_not_found.
zcx_abapgit_exception=>raise( 'new_offline not found' ).
ENDTRY.
ro_repo ?= instantiate_and_add( ls_repo ).
ls_repo-local_settings-serialize_master_lang_only = iv_master_lang_only.
ro_repo->set_local_settings( ls_repo-local_settings ).
ENDMETHOD.
METHOD zif_abapgit_repo_srv~new_online.
DATA: ls_repo TYPE zif_abapgit_persistence=>ty_repo,
lv_branch_name LIKE iv_branch_name,
lv_key TYPE zif_abapgit_persistence=>ty_repo-key,
ls_dot_abapgit TYPE zif_abapgit_dot_abapgit=>ty_dot_abapgit.
ASSERT NOT iv_url IS INITIAL
AND NOT iv_package IS INITIAL.
IF zcl_abapgit_auth=>is_allowed( zif_abapgit_auth=>gc_authorization-create_repo ) = abap_false.
zcx_abapgit_exception=>raise( 'Not authorized' ).
ENDIF.
validate_package( iv_package = iv_package
iv_ign_subpkg = iv_ign_subpkg ).
zcl_abapgit_url=>validate( iv_url ).
lv_branch_name = determine_branch_name(
iv_name = iv_branch_name
iv_url = iv_url ).
ls_dot_abapgit = zcl_abapgit_dot_abapgit=>build_default( )->get_data( ).
ls_dot_abapgit-folder_logic = iv_folder_logic.
lv_key = zcl_abapgit_persist_factory=>get_repo( )->add(
iv_url = iv_url
iv_branch_name = lv_branch_name " local !
iv_display_name = iv_display_name
iv_package = iv_package
iv_offline = abap_false
is_dot_abapgit = ls_dot_abapgit ).
TRY.
ls_repo = zcl_abapgit_persist_factory=>get_repo( )->read( lv_key ).
CATCH zcx_abapgit_not_found.
zcx_abapgit_exception=>raise( 'new_online not found' ).
ENDTRY.
ro_repo ?= instantiate_and_add( ls_repo ).
IF ls_repo-local_settings-ignore_subpackages <> iv_ign_subpkg.
ls_repo-local_settings-ignore_subpackages = iv_ign_subpkg.
ENDIF.
ls_repo-local_settings-serialize_master_lang_only = iv_master_lang_only.
ro_repo->set_local_settings( ls_repo-local_settings ).
ro_repo->refresh( ).
ro_repo->find_remote_dot_abapgit( ).
ENDMETHOD.
METHOD zif_abapgit_repo_srv~purge.
* todo, this should be a method on the repo instead
DATA: lt_tadir TYPE zif_abapgit_definitions=>ty_tadir_tt.
IF io_repo->get_local_settings( )-write_protected = abap_true.
zcx_abapgit_exception=>raise( 'Cannot purge. Local code is write-protected by repo config' ).
ELSEIF zcl_abapgit_auth=>is_allowed( zif_abapgit_auth=>gc_authorization-uninstall ) = abap_false.
zcx_abapgit_exception=>raise( 'Not authorized' ).
ENDIF.
lt_tadir = zcl_abapgit_factory=>get_tadir( )->read( io_repo->get_package( ) ).
zcl_abapgit_objects=>delete( it_tadir = lt_tadir
is_checks = is_checks ).
delete( io_repo ).
ENDMETHOD.
METHOD zif_abapgit_repo_srv~validate_package.
DATA: lv_as4user TYPE tdevc-as4user,
lo_repo TYPE REF TO zcl_abapgit_repo,
lv_reason TYPE string.
IF iv_package IS INITIAL.
zcx_abapgit_exception=>raise( 'add, package empty' ).
ENDIF.
IF iv_package = '$TMP'.
zcx_abapgit_exception=>raise( 'not possible to use $TMP, create new (local) package' ).
ENDIF.
SELECT SINGLE as4user FROM tdevc
INTO lv_as4user
WHERE devclass = iv_package. "#EC CI_GENBUFF
IF sy-subrc <> 0.
zcx_abapgit_exception=>raise( |Package { iv_package } not found| ).
ENDIF.
IF is_sap_object_allowed( ) = abap_false AND lv_as4user = 'SAP'.
zcx_abapgit_exception=>raise( |Package { iv_package } not allowed, responsible user = 'SAP'| ).
ENDIF.
IF iv_chk_exists = abap_true.
get_repo_from_package(
EXPORTING
iv_package = iv_package
iv_ign_subpkg = iv_ign_subpkg
IMPORTING
eo_repo = lo_repo
ev_reason = lv_reason ).
IF lo_repo IS BOUND.
zcx_abapgit_exception=>raise( lv_reason ).
ENDIF.
ENDIF.
ENDMETHOD.
ENDCLASS.
"! abapGit general error
CLASS zcx_abapgit_exception DEFINITION
PUBLIC
INHERITING FROM cx_static_check
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_t100_message .
CONSTANTS:
BEGIN OF gc_section_text,
cause TYPE string VALUE `Cause`,
system_response TYPE string VALUE `System response`,
what_to_do TYPE string VALUE `Procedure`,
sys_admin TYPE string VALUE `System administration`,
END OF gc_section_text .
CONSTANTS:
BEGIN OF gc_section_token,
cause TYPE string VALUE `&CAUSE&`,
system_response TYPE string VALUE `&SYSTEM_RESPONSE&`,
what_to_do TYPE string VALUE `&WHAT_TO_DO&`,
sys_admin TYPE string VALUE `&SYS_ADMIN&`,
END OF gc_section_token .
DATA msgv1 TYPE symsgv READ-ONLY .
DATA msgv2 TYPE symsgv READ-ONLY .
DATA msgv3 TYPE symsgv READ-ONLY .
DATA msgv4 TYPE symsgv READ-ONLY .
DATA mt_callstack TYPE abap_callstack READ-ONLY .
DATA url TYPE string READ-ONLY .
DATA count TYPE i READ-ONLY .
DATA digest TYPE string READ-ONLY .
"! Raise exception with text
"! @parameter iv_text | Text
"! @parameter ix_previous | Previous exception
"! @raising zcx_abapgit_exception | Exception
CLASS-METHODS raise
IMPORTING
!iv_text TYPE clike
!ix_previous TYPE REF TO cx_root OPTIONAL
RAISING
zcx_abapgit_exception .
"! Raise exception with T100 message
"! <p>
"! Will default to sy-msg* variables. These need to be set right before calling this method.
"! </p>
"! @parameter iv_msgid | Message ID
"! @parameter iv_msgno | Message number
"! @parameter iv_msgv1 | Message variable 1
"! @parameter iv_msgv2 | Message variable 2
"! @parameter iv_msgv3 | Message variable 3
"! @parameter iv_msgv4 | Message variable 4
"! @raising zcx_abapgit_exception | Exception
CLASS-METHODS raise_t100
IMPORTING
VALUE(iv_msgid) TYPE symsgid DEFAULT sy-msgid
VALUE(iv_msgno) TYPE symsgno DEFAULT sy-msgno
VALUE(iv_msgv1) TYPE symsgv DEFAULT sy-msgv1
VALUE(iv_msgv2) TYPE symsgv DEFAULT sy-msgv2
VALUE(iv_msgv3) TYPE symsgv DEFAULT sy-msgv3
VALUE(iv_msgv4) TYPE symsgv DEFAULT sy-msgv4
!ix_previous TYPE REF TO cx_root OPTIONAL
RAISING
zcx_abapgit_exception .
CLASS-METHODS raise_with_text
IMPORTING
!ix_previous TYPE REF TO cx_root
RAISING
zcx_abapgit_exception .
METHODS constructor
IMPORTING
!textid LIKE if_t100_message=>t100key OPTIONAL
!previous LIKE previous OPTIONAL
!msgv1 TYPE symsgv OPTIONAL
!msgv2 TYPE symsgv OPTIONAL
!msgv3 TYPE symsgv OPTIONAL
!msgv4 TYPE symsgv OPTIONAL
!url TYPE string OPTIONAL
!count TYPE i OPTIONAL
!digest TYPE string OPTIONAL .
CLASS-METHODS raise_login
IMPORTING
!iv_url TYPE string
!iv_count TYPE i
!iv_digest TYPE string
RAISING
zcx_abapgit_exception .
METHODS is_login
RETURNING
VALUE(rv_result) TYPE abap_bool .
METHODS get_source_position
REDEFINITION .
METHODS if_message~get_longtext
REDEFINITION .
PROTECTED SECTION.
PRIVATE SECTION.
CONSTANTS gc_generic_error_msg TYPE string VALUE `An error occured (ZCX_ABAPGIT_EXCEPTION)` ##NO_TEXT.
CLASS-METHODS split_text_to_symsg
IMPORTING
!iv_text TYPE string
RETURNING
VALUE(rs_msg) TYPE symsg .
METHODS save_callstack .
METHODS itf_to_string
IMPORTING
!it_itf TYPE tline_tab
RETURNING
VALUE(rv_result) TYPE string .
METHODS get_t100_longtext_itf
RETURNING
VALUE(rt_itf) TYPE tline_tab .
METHODS remove_empty_section
IMPORTING
!iv_tabix_from TYPE i
!iv_tabix_to TYPE i
CHANGING
!ct_itf TYPE tline_tab .
METHODS replace_section_head_with_text
CHANGING
!cs_itf TYPE tline .
ENDCLASS.
CLASS zcx_abapgit_exception IMPLEMENTATION.
METHOD constructor ##ADT_SUPPRESS_GENERATION.
super->constructor( previous = previous ).
me->msgv1 = msgv1.
me->msgv2 = msgv2.
me->msgv3 = msgv3.
me->msgv4 = msgv4.
me->url = url.
me->count = count.
me->digest = digest.
CLEAR me->textid.
IF textid IS INITIAL.
if_t100_message~t100key = if_t100_message=>default_textid.
ELSE.
if_t100_message~t100key = textid.
ENDIF.
save_callstack( ).
ENDMETHOD.
METHOD get_source_position.
FIELD-SYMBOLS: <ls_callstack> TYPE abap_callstack_line.
READ TABLE mt_callstack ASSIGNING <ls_callstack>
INDEX 1.
IF sy-subrc = 0.
program_name = <ls_callstack>-mainprogram.
include_name = <ls_callstack>-include.
source_line = <ls_callstack>-line.
ELSE.
super->get_source_position(
IMPORTING
program_name = program_name
include_name = include_name
source_line = source_line ).
ENDIF.
ENDMETHOD.
METHOD get_t100_longtext_itf.
DATA: lv_docu_key TYPE doku_obj.
FIELD-SYMBOLS <lv_msgv> TYPE any.
lv_docu_key = if_t100_message~t100key-msgid && if_t100_message~t100key-msgno.
CALL FUNCTION 'DOCU_GET'
EXPORTING
id = 'NA'
langu = sy-langu
object = lv_docu_key
typ = 'E'
TABLES
line = rt_itf
EXCEPTIONS
OTHERS = 1.
IF sy-subrc = 0.
ASSIGN me->(if_t100_message~t100key-attr1) TO <lv_msgv>.
IF sy-subrc = 0.
REPLACE ALL OCCURRENCES OF '&V1&' IN TABLE rt_itf WITH <lv_msgv>.
ENDIF.
ASSIGN me->(if_t100_message~t100key-attr2) TO <lv_msgv>.
IF sy-subrc = 0.
REPLACE ALL OCCURRENCES OF '&V2&' IN TABLE rt_itf WITH <lv_msgv>.
ENDIF.
ASSIGN me->(if_t100_message~t100key-attr3) TO <lv_msgv>.
IF sy-subrc = 0.
REPLACE ALL OCCURRENCES OF '&V3&' IN TABLE rt_itf WITH <lv_msgv>.
ENDIF.
ASSIGN me->(if_t100_message~t100key-attr4) TO <lv_msgv>.
IF sy-subrc = 0.
REPLACE ALL OCCURRENCES OF '&V4&' IN TABLE rt_itf WITH <lv_msgv>.
ENDIF.
ENDIF.
ENDMETHOD.
METHOD if_message~get_longtext.
result = super->get_longtext( ).
IF if_t100_message~t100key IS NOT INITIAL.
result = itf_to_string( get_t100_longtext_itf( ) ).
ENDIF.
ENDMETHOD.
METHOD is_login.
rv_result = boolc( url <> '' AND count > 0 ).
ENDMETHOD.
METHOD itf_to_string.
CONSTANTS: lc_format_section TYPE string VALUE 'U1'.
DATA:
lt_stream TYPE TABLE OF tdline,
lt_string TYPE TABLE OF string,
lv_string LIKE LINE OF lt_string,
lt_itf TYPE tline_tab,
lv_has_content TYPE abap_bool,
lv_tabix_from TYPE syst-tabix,
lv_tabix_to TYPE syst-tabix.
FIELD-SYMBOLS: <ls_itf_section> TYPE tline,
<ls_itf_section_item> TYPE tline.
lt_itf = it_itf.
" You should remember that we replace the U1 format because
" that preserves the section header of longtexts.
LOOP AT lt_itf ASSIGNING <ls_itf_section>
WHERE tdformat = lc_format_section.
CLEAR:
lv_has_content,
lv_tabix_to.
lv_tabix_from = sy-tabix.
LOOP AT lt_itf ASSIGNING <ls_itf_section_item>
FROM sy-tabix + 1.
IF <ls_itf_section_item>-tdformat = lc_format_section.
lv_tabix_to = sy-tabix.
EXIT.
ELSEIF <ls_itf_section_item>-tdline IS NOT INITIAL.
lv_has_content = abap_true.
ENDIF.
ENDLOOP.
IF lv_has_content = abap_false.
remove_empty_section(
EXPORTING
iv_tabix_from = lv_tabix_from
iv_tabix_to = lv_tabix_to
CHANGING
ct_itf = lt_itf ).
CONTINUE.
ENDIF.
replace_section_head_with_text( CHANGING cs_itf = <ls_itf_section> ).
ENDLOOP.
CALL FUNCTION 'CONVERT_ITF_TO_STREAM_TEXT'
EXPORTING
lf = 'X'
IMPORTING
stream_lines = lt_string
TABLES
itf_text = lt_itf
text_stream = lt_stream.
LOOP AT lt_string INTO lv_string.
IF sy-tabix = 1.
rv_result = lv_string.
ELSE.
CONCATENATE rv_result lv_string
INTO rv_result
SEPARATED BY cl_abap_char_utilities=>newline.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD raise.
DATA lv_text TYPE string.
IF iv_text IS INITIAL.
lv_text = gc_generic_error_msg.
ELSE.
lv_text = iv_text.
ENDIF.
split_text_to_symsg( lv_text ).
raise_t100( ix_previous = ix_previous ).
ENDMETHOD.
METHOD raise_login.
RAISE EXCEPTION TYPE zcx_abapgit_exception
EXPORTING
url = iv_url
count = iv_count
digest = iv_digest.
ENDMETHOD.
METHOD raise_t100.
DATA: ls_t100_key TYPE scx_t100key.
ls_t100_key-msgid = iv_msgid.
ls_t100_key-msgno = iv_msgno.
ls_t100_key-attr1 = 'MSGV1'.
ls_t100_key-attr2 = 'MSGV2'.
ls_t100_key-attr3 = 'MSGV3'.
ls_t100_key-attr4 = 'MSGV4'.
IF iv_msgid IS INITIAL.
CLEAR ls_t100_key.
ENDIF.
RAISE EXCEPTION TYPE zcx_abapgit_exception
EXPORTING
textid = ls_t100_key
msgv1 = iv_msgv1
msgv2 = iv_msgv2
msgv3 = iv_msgv3
msgv4 = iv_msgv4
previous = ix_previous.
ENDMETHOD.
METHOD raise_with_text.
raise(
iv_text = ix_previous->get_text( )
ix_previous = ix_previous ).
ENDMETHOD.
METHOD remove_empty_section.
IF iv_tabix_to BETWEEN iv_tabix_from AND lines( ct_itf ).
DELETE ct_itf FROM iv_tabix_from TO iv_tabix_to.
ELSE.
DELETE ct_itf FROM iv_tabix_from.
ENDIF.
ENDMETHOD.
METHOD replace_section_head_with_text.
CASE cs_itf-tdline.
WHEN gc_section_token-cause.
cs_itf-tdline = gc_section_text-cause.
WHEN gc_section_token-system_response.
cs_itf-tdline = gc_section_text-system_response.
WHEN gc_section_token-what_to_do.
cs_itf-tdline = gc_section_text-what_to_do.
WHEN gc_section_token-sys_admin.
cs_itf-tdline = gc_section_text-sys_admin.
ENDCASE.
ENDMETHOD.
METHOD save_callstack.
FIELD-SYMBOLS: <ls_callstack> TYPE abap_callstack_line.
CALL FUNCTION 'SYSTEM_CALLSTACK'
IMPORTING
callstack = mt_callstack.
" You should remember that the first lines are from zcx_abapgit_exception
" and are removed so that highest level in the callstack is the position where
" the exception is raised.
"
" For the merged report it's hard to do that, because zcx_abapgit_exception
" isn't visible in the callstack. Therefore we have to check the Events.
LOOP AT mt_callstack ASSIGNING <ls_callstack>.
IF <ls_callstack>-mainprogram CP |ZCX_ABAPGIT_EXCEPTION*| " full
OR <ls_callstack>-blockname = `SAVE_CALLSTACK` " merged
OR <ls_callstack>-blockname = `CONSTRUCTOR` " merged
OR <ls_callstack>-blockname CP `RAISE*`. "merged
DELETE TABLE mt_callstack FROM <ls_callstack>.
ELSE.
EXIT.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD split_text_to_symsg.
CONSTANTS:
lc_length_of_msgv TYPE i VALUE 50,
lc_offset_of_last_character TYPE i VALUE 49.
DATA:
lv_text TYPE c LENGTH 200,
lv_rest TYPE c LENGTH 200,
ls_msg TYPE symsg,
lv_msg_var TYPE c LENGTH lc_length_of_msgv,
lv_index TYPE sy-index.
lv_text = iv_text.
DO 4 TIMES.
lv_index = sy-index.
CALL FUNCTION 'TEXT_SPLIT'
EXPORTING
length = lc_length_of_msgv
text = lv_text
IMPORTING
line = lv_msg_var
rest = lv_rest.
IF lv_msg_var+lc_offset_of_last_character(1) = space OR
lv_text+lc_length_of_msgv(1) = space.
" keep the space at the beginning of the rest
" because otherwise it's lost
lv_rest = | { lv_rest }|.
ENDIF.
lv_text = lv_rest.
CASE lv_index.
WHEN 1.
ls_msg-msgv1 = lv_msg_var.
WHEN 2.
ls_msg-msgv2 = lv_msg_var.
WHEN 3.
ls_msg-msgv3 = lv_msg_var.
WHEN 4.
ls_msg-msgv4 = lv_msg_var.
ENDCASE.
ENDDO.
" Set syst using generic error message
MESSAGE e001(00) WITH ls_msg-msgv1 ls_msg-msgv2 ls_msg-msgv3 ls_msg-msgv4 INTO sy-lisel.
ENDMETHOD.
ENDCLASS.
INTERFACE zif_abapgit_definitions
PUBLIC .
TYPES:
ty_type TYPE c LENGTH 6 .
TYPES:
ty_bitbyte TYPE c LENGTH 8 .
TYPES:
ty_sha1 TYPE c LENGTH 40 .
TYPES: ty_sha1_tt TYPE STANDARD TABLE OF ty_sha1 WITH DEFAULT KEY .
TYPES:
ty_adler32 TYPE x LENGTH 4 .
TYPES:
BEGIN OF ty_file_signature,
path TYPE string,
filename TYPE string,
sha1 TYPE ty_sha1,
END OF ty_file_signature .
TYPES:
ty_file_signatures_tt TYPE STANDARD TABLE OF
ty_file_signature WITH DEFAULT KEY .
TYPES:
ty_file_signatures_ts TYPE SORTED TABLE OF
ty_file_signature WITH UNIQUE KEY path filename .
TYPES:
BEGIN OF ty_file.
INCLUDE TYPE ty_file_signature.
TYPES: data TYPE xstring,
END OF ty_file .
TYPES:
ty_files_tt TYPE STANDARD TABLE OF ty_file WITH DEFAULT KEY .
TYPES:
ty_string_tt TYPE STANDARD TABLE OF string WITH DEFAULT KEY .
TYPES:
ty_repo_ref_tt TYPE STANDARD TABLE OF REF TO zcl_abapgit_repo WITH DEFAULT KEY .
TYPES ty_git_branch_type TYPE c LENGTH 2 .
TYPES:
BEGIN OF ty_git_branch,
sha1 TYPE ty_sha1,
name TYPE string,
type TYPE ty_git_branch_type,
is_head TYPE abap_bool,
display_name TYPE string,
END OF ty_git_branch .
TYPES:
ty_git_branch_list_tt TYPE STANDARD TABLE OF ty_git_branch WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_git_tag,
sha1 TYPE ty_sha1,
object TYPE ty_sha1,
name TYPE string,
type TYPE ty_git_branch_type,
display_name TYPE string,
tagger_name TYPE string,
tagger_email TYPE string,
message TYPE string,
body TYPE string,
END OF ty_git_tag .
TYPES:
ty_git_tag_list_tt TYPE STANDARD TABLE OF ty_git_tag WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_hotkey,
ui_component TYPE string,
action TYPE string,
hotkey TYPE string,
END OF ty_hotkey .
TYPES:
ty_hotkey_tt TYPE STANDARD TABLE OF ty_hotkey
WITH NON-UNIQUE DEFAULT KEY
WITH NON-UNIQUE SORTED KEY action
COMPONENTS ui_component action.
TYPES:
BEGIN OF ty_git_user,
name TYPE string,
email TYPE string,
END OF ty_git_user .
TYPES:
BEGIN OF ty_comment,
committer TYPE ty_git_user,
author TYPE ty_git_user,
comment TYPE string,
END OF ty_comment .
TYPES:
BEGIN OF ty_item,
obj_type TYPE tadir-object,
obj_name TYPE tadir-obj_name,
devclass TYPE devclass,
inactive TYPE abap_bool,
END OF ty_item .
TYPES:
ty_items_tt TYPE STANDARD TABLE OF ty_item WITH DEFAULT KEY .
TYPES:
ty_items_ts TYPE SORTED TABLE OF ty_item WITH UNIQUE KEY obj_type obj_name .
TYPES:
BEGIN OF ty_file_item,
file TYPE ty_file,
item TYPE ty_item,
END OF ty_file_item .
TYPES:
ty_files_item_tt TYPE STANDARD TABLE OF ty_file_item WITH DEFAULT KEY .
TYPES:
ty_yes_no TYPE c LENGTH 1,
ty_yes_no_partial TYPE c LENGTH 1.
TYPES:
BEGIN OF ty_overwrite.
INCLUDE TYPE ty_item.
TYPES: decision TYPE ty_yes_no,
END OF ty_overwrite .
TYPES:
ty_overwrite_tt TYPE STANDARD TABLE OF ty_overwrite WITH DEFAULT KEY
WITH UNIQUE HASHED KEY object_type_and_name
COMPONENTS obj_type obj_name .
TYPES:
BEGIN OF ty_requirements,
met TYPE ty_yes_no,
decision TYPE ty_yes_no,
END OF ty_requirements .
TYPES:
BEGIN OF ty_dependencies,
met TYPE ty_yes_no,
END OF ty_dependencies .
TYPES:
BEGIN OF ty_transport_type,
request TYPE trfunction,
task TYPE trfunction,
END OF ty_transport_type .
TYPES:
BEGIN OF ty_transport,
required TYPE abap_bool,
transport TYPE trkorr,
type TYPE ty_transport_type,
END OF ty_transport .
TYPES:
BEGIN OF ty_deserialize_checks,
overwrite TYPE ty_overwrite_tt,
warning_package TYPE ty_overwrite_tt,
requirements TYPE ty_requirements,
dependencies TYPE ty_dependencies,
transport TYPE ty_transport,
END OF ty_deserialize_checks .
TYPES:
BEGIN OF ty_delete_checks,
transport TYPE ty_transport,
END OF ty_delete_checks .
TYPES:
BEGIN OF ty_metadata,
class TYPE string,
version TYPE string,
late_deser TYPE abap_bool, " refactor: can be removed later. replaced by steps
delete_tadir TYPE abap_bool,
ddic TYPE abap_bool,
END OF ty_metadata .
TYPES:
BEGIN OF ty_repo_file,
path TYPE string,
filename TYPE string,
is_changed TYPE abap_bool,
rstate TYPE c LENGTH 1,
lstate TYPE c LENGTH 1,
END OF ty_repo_file .
TYPES:
ty_repo_file_tt TYPE STANDARD TABLE OF ty_repo_file WITH DEFAULT KEY .
TYPES:
ty_chmod TYPE c LENGTH 6 .
TYPES:
BEGIN OF ty_object,
sha1 TYPE ty_sha1,
type TYPE ty_type,
data TYPE xstring,
adler32 TYPE ty_adler32,
index TYPE i,
END OF ty_object .
TYPES:
ty_objects_tt TYPE STANDARD TABLE OF ty_object WITH DEFAULT KEY
WITH NON-UNIQUE SORTED KEY sha COMPONENTS sha1
WITH NON-UNIQUE SORTED KEY type COMPONENTS type sha1 .
TYPES:
BEGIN OF ty_tadir,
pgmid TYPE tadir-pgmid,
object TYPE tadir-object,
obj_name TYPE tadir-obj_name,
devclass TYPE tadir-devclass,
korrnum TYPE tadir-korrnum,
delflag TYPE tadir-delflag,
genflag TYPE tadir-genflag,
path TYPE string,
END OF ty_tadir .
TYPES:
ty_tadir_tt TYPE STANDARD TABLE OF ty_tadir WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_result,
obj_type TYPE tadir-object,
obj_name TYPE tadir-obj_name,
inactive TYPE abap_bool,
path TYPE string,
filename TYPE string,
package TYPE devclass,
match TYPE abap_bool,
lstate TYPE c LENGTH 1,
rstate TYPE c LENGTH 1,
packmove TYPE abap_bool,
END OF ty_result .
TYPES:
ty_results_tt TYPE STANDARD TABLE OF ty_result WITH DEFAULT KEY .
TYPES:
ty_results_ts_path TYPE HASHED TABLE OF ty_result WITH UNIQUE KEY path filename .
TYPES:
BEGIN OF ty_stage_files,
local TYPE ty_files_item_tt,
remote TYPE ty_files_tt,
status TYPE ty_results_ts_path,
END OF ty_stage_files .
TYPES:
ty_sval_tt TYPE STANDARD TABLE OF sval WITH DEFAULT KEY .
TYPES:
ty_seocompotx_tt TYPE STANDARD TABLE OF seocompotx WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_tpool.
INCLUDE TYPE textpool.
TYPES: split TYPE c LENGTH 8.
TYPES: END OF ty_tpool .
TYPES:
ty_tpool_tt TYPE STANDARD TABLE OF ty_tpool WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_sotr,
header TYPE sotr_head,
entries TYPE sotr_text_tt,
END OF ty_sotr .
TYPES:
ty_sotr_tt TYPE STANDARD TABLE OF ty_sotr WITH DEFAULT KEY .
TYPES:
ty_sotr_use_tt TYPE STANDARD TABLE OF sotr_use WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_obj_attribute,
cmpname TYPE seocmpname,
attkeyfld TYPE seokeyfld,
attbusobj TYPE seobusobj,
END OF ty_obj_attribute .
TYPES:
ty_obj_attribute_tt TYPE STANDARD TABLE OF ty_obj_attribute WITH DEFAULT KEY
WITH NON-UNIQUE SORTED KEY cmpname COMPONENTS cmpname .
TYPES:
BEGIN OF ty_transport_to_branch,
branch_name TYPE string,
commit_text TYPE string,
END OF ty_transport_to_branch .
TYPES:
BEGIN OF ty_create,
name TYPE string,
parent TYPE string,
END OF ty_create .
TYPES:
BEGIN OF ty_commit,
sha1 TYPE ty_sha1,
parent1 TYPE ty_sha1,
parent2 TYPE ty_sha1,
author TYPE string,
email TYPE string,
time TYPE string,
message TYPE string,
body TYPE STANDARD TABLE OF string WITH DEFAULT KEY,
branch TYPE string,
merge TYPE string,
tags TYPE STANDARD TABLE OF string WITH DEFAULT KEY,
create TYPE STANDARD TABLE OF ty_create WITH DEFAULT KEY,
compressed TYPE abap_bool,
END OF ty_commit .
TYPES:
ty_commit_tt TYPE STANDARD TABLE OF ty_commit WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_diff,
patch_flag TYPE abap_bool,
new_num TYPE c LENGTH 6,
new TYPE string,
result TYPE c LENGTH 1,
old_num TYPE c LENGTH 6,
old TYPE string,
short TYPE abap_bool,
beacon TYPE i,
END OF ty_diff .
TYPES:
ty_diffs_tt TYPE STANDARD TABLE OF ty_diff WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_count,
insert TYPE i,
delete TYPE i,
update TYPE i,
END OF ty_count .
TYPES:
BEGIN OF ty_expanded,
path TYPE string,
name TYPE string,
sha1 TYPE ty_sha1,
chmod TYPE ty_chmod,
END OF ty_expanded .
TYPES:
ty_expanded_tt TYPE STANDARD TABLE OF ty_expanded WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_ancestor,
commit TYPE ty_sha1,
tree TYPE ty_sha1,
time TYPE string,
body TYPE string,
END OF ty_ancestor .
TYPES:
BEGIN OF ty_merge,
repo TYPE REF TO zcl_abapgit_repo_online,
source TYPE ty_git_branch,
target TYPE ty_git_branch,
common TYPE ty_ancestor,
stree TYPE ty_expanded_tt,
ttree TYPE ty_expanded_tt,
ctree TYPE ty_expanded_tt,
result TYPE ty_expanded_tt,
stage TYPE REF TO zcl_abapgit_stage,
conflict TYPE string,
END OF ty_merge .
TYPES:
BEGIN OF ty_merge_conflict,
path TYPE string,
filename TYPE string,
source_sha1 TYPE ty_sha1,
source_data TYPE xstring,
target_sha1 TYPE ty_sha1,
target_data TYPE xstring,
result_sha1 TYPE ty_sha1,
result_data TYPE xstring,
END OF ty_merge_conflict .
TYPES:
ty_merge_conflict_tt TYPE STANDARD TABLE OF ty_merge_conflict WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_repo_item,
obj_type TYPE tadir-object,
obj_name TYPE tadir-obj_name,
inactive TYPE abap_bool,
sortkey TYPE i,
path TYPE string,
is_dir TYPE abap_bool,
changes TYPE i,
lstate TYPE c LENGTH 1,
rstate TYPE c LENGTH 1,
files TYPE ty_repo_file_tt,
END OF ty_repo_item .
TYPES:
ty_repo_item_tt TYPE STANDARD TABLE OF ty_repo_item WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_s_user_settings,
max_lines TYPE i,
adt_jump_enabled TYPE abap_bool,
show_default_repo TYPE abap_bool,
link_hints_enabled TYPE abap_bool,
link_hint_key TYPE c LENGTH 1,
hotkeys TYPE ty_hotkey_tt,
parallel_proc_disabled TYPE abap_bool,
icon_scaling TYPE c LENGTH 1,
ui_theme TYPE string,
hide_sapgui_hint TYPE abap_bool,
activate_wo_popup TYPE abap_bool,
END OF ty_s_user_settings .
TYPES:
ty_dokil_tt TYPE STANDARD TABLE OF dokil
WITH NON-UNIQUE DEFAULT KEY .
TYPES:
BEGIN OF ty_col_spec,
tech_name TYPE string,
display_name TYPE string,
css_class TYPE string,
add_tz TYPE abap_bool,
title TYPE string,
END OF ty_col_spec,
ty_col_spec_tt TYPE STANDARD TABLE OF ty_col_spec
WITH NON-UNIQUE KEY tech_name.
TYPES:
ty_proxy_bypass_url TYPE c LENGTH 255,
ty_range_proxy_bypass_url TYPE RANGE OF ty_proxy_bypass_url.
TYPES:
BEGIN OF ty_version,
major TYPE i,
minor TYPE i,
patch TYPE i,
prerelase TYPE string,
prerelase_patch TYPE i,
END OF ty_version.
TYPES: BEGIN OF ty_alv_column,
name TYPE string,
text TYPE string,
length TYPE lvc_outlen,
END OF ty_alv_column,
ty_alv_column_tt TYPE TABLE OF ty_alv_column WITH DEFAULT KEY.
TYPES:
BEGIN OF ty_deserialization,
obj TYPE REF TO zif_abapgit_object,
xml TYPE REF TO zif_abapgit_xml_input,
package TYPE devclass,
item TYPE ty_item,
END OF ty_deserialization .
TYPES:
ty_deserialization_tt TYPE STANDARD TABLE OF ty_deserialization WITH DEFAULT KEY .
TYPES:
ty_deserialization_step TYPE string.
TYPES:
ty_deserialization_step_tt TYPE STANDARD TABLE OF ty_deserialization_step
WITH DEFAULT KEY .
TYPES:
BEGIN OF ty_step_data,
step_id TYPE ty_deserialization_step,
order TYPE i,
descr TYPE string,
is_ddic TYPE abap_bool,
syntax_check TYPE abap_bool,
objects TYPE ty_deserialization_tt,
END OF ty_step_data .
TYPES:
ty_step_data_tt TYPE STANDARD TABLE OF ty_step_data
WITH DEFAULT KEY .
TYPES:
ty_object_type_range TYPE RANGE OF trobjtype,
ty_object_name_range TYPE RANGE OF sobj_name.
CONSTANTS:
BEGIN OF c_git_branch_type,
branch TYPE ty_git_branch_type VALUE 'HD',
lightweight_tag TYPE ty_git_branch_type VALUE 'TG',
annotated_tag TYPE ty_git_branch_type VALUE 'AT',
other TYPE ty_git_branch_type VALUE 'ZZ',
END OF c_git_branch_type .
CONSTANTS c_head_name TYPE string VALUE 'HEAD' ##NO_TEXT.
CONSTANTS:
BEGIN OF c_git_branch,
master TYPE string VALUE 'refs/heads/master',
prefix TYPE string VALUE 'refs/',
heads_prefix TYPE string VALUE 'refs/heads/',
heads TYPE string VALUE 'refs/heads/*',
tags_prefix TYPE string VALUE 'refs/tags/',
tags TYPE string VALUE 'refs/tags/*',
END OF c_git_branch.
CONSTANTS:
BEGIN OF c_diff,
insert TYPE c LENGTH 1 VALUE 'I',
delete TYPE c LENGTH 1 VALUE 'D',
update TYPE c LENGTH 1 VALUE 'U',
END OF c_diff .
CONSTANTS:
BEGIN OF c_type,
commit TYPE ty_type VALUE 'commit', "#EC NOTEXT
tree TYPE ty_type VALUE 'tree', "#EC NOTEXT
ref_d TYPE ty_type VALUE 'ref_d', "#EC NOTEXT
tag TYPE ty_type VALUE 'tag', "#EC NOTEXT
blob TYPE ty_type VALUE 'blob', "#EC NOTEXT
END OF c_type .
CONSTANTS:
BEGIN OF c_state, " https://git-scm.com/docs/git-status
unchanged TYPE c LENGTH 1 VALUE '',
added TYPE c LENGTH 1 VALUE 'A',
modified TYPE c LENGTH 1 VALUE 'M',
deleted TYPE c LENGTH 1 VALUE 'D', "For future use
mixed TYPE c LENGTH 1 VALUE '*',
END OF c_state .
CONSTANTS:
BEGIN OF c_chmod,
file TYPE ty_chmod VALUE '100644',
executable TYPE ty_chmod VALUE '100755',
dir TYPE ty_chmod VALUE '40000 ',
END OF c_chmod .
CONSTANTS c_crlf TYPE c LENGTH 2 VALUE cl_abap_char_utilities=>cr_lf ##NO_TEXT.
CONSTANTS c_newline TYPE c LENGTH 1 VALUE cl_abap_char_utilities=>newline ##NO_TEXT.
CONSTANTS c_english TYPE spras VALUE 'E' ##NO_TEXT.
CONSTANTS c_root_dir TYPE string VALUE '/' ##NO_TEXT.
CONSTANTS c_dot_abapgit TYPE string VALUE '.abapgit.xml' ##NO_TEXT.
CONSTANTS c_author_regex TYPE string VALUE '^(.+) <(.*)> (\d{10})\s?.\d{4}$' ##NO_TEXT.
CONSTANTS:
BEGIN OF c_action,
repo_refresh TYPE string VALUE 'repo_refresh',
repo_remove TYPE string VALUE 'repo_remove',
repo_settings TYPE string VALUE 'repo_settings',
repo_purge TYPE string VALUE 'repo_purge',
repo_newonline TYPE string VALUE 'repo_newonline',
repo_newoffline TYPE string VALUE 'repo_newoffline',
repo_add_all_obj_to_trans_req TYPE string VALUE 'repo_add_all_obj_to_trans_req',
repo_remote_attach TYPE string VALUE 'repo_remote_attach',
repo_remote_detach TYPE string VALUE 'repo_remote_detach',
repo_remote_change TYPE string VALUE 'repo_remote_change',
repo_refresh_checksums TYPE string VALUE 'repo_refresh_checksums',
repo_toggle_fav TYPE string VALUE 'repo_toggle_fav',
repo_transport_to_branch TYPE string VALUE 'repo_transport_to_branch',
repo_syntax_check TYPE string VALUE 'repo_syntax_check',
repo_code_inspector TYPE string VALUE 'repo_code_inspector',
repo_open_in_master_lang TYPE string VALUE 'repo_open_in_master_lang',
repo_log TYPE string VALUE 'repo_log',
abapgit_home TYPE string VALUE 'abapgit_home',
abapgit_install TYPE string VALUE 'abapgit_install',
zip_import TYPE string VALUE 'zip_import',
zip_export TYPE string VALUE 'zip_export',
zip_package TYPE string VALUE 'zip_package',
zip_transport TYPE string VALUE 'zip_transport',
zip_object TYPE string VALUE 'zip_object',
performance_test TYPE string VALUE 'performance_test',
ie_devtools TYPE string VALUE 'ie_devtools',
git_pull TYPE string VALUE 'git_pull',
git_reset TYPE string VALUE 'git_reset',
git_branch_create TYPE string VALUE 'git_branch_create',
git_branch_switch TYPE string VALUE 'git_branch_switch',
git_branch_delete TYPE string VALUE 'git_branch_delete',
git_tag_create TYPE string VALUE 'git_tag_create',
git_tag_delete TYPE string VALUE 'git_tag_delete',
git_tag_switch TYPE string VALUE 'git_tag_switch',
git_commit TYPE string VALUE 'git_commit',
db_display TYPE string VALUE 'db_display',
db_edit TYPE string VALUE 'db_edit',
bg_update TYPE string VALUE 'bg_update',
go_explore TYPE string VALUE 'go_explore',
go_repo TYPE string VALUE 'go_repo',
go_db TYPE string VALUE 'go_db',
go_background TYPE string VALUE 'go_background',
go_background_run TYPE string VALUE 'go_background_run',
go_diff TYPE string VALUE 'go_diff',
go_stage TYPE string VALUE 'go_stage',
go_commit TYPE string VALUE 'go_commit',
go_branch_overview TYPE string VALUE 'go_branch_overview',
go_tag_overview TYPE string VALUE 'go_tag_overview',
go_debuginfo TYPE string VALUE 'go_debuginfo',
go_settings TYPE string VALUE 'go_settings',
go_tutorial TYPE string VALUE 'go_tutorial',
go_patch TYPE string VALUE 'go_patch',
jump TYPE string VALUE 'jump',
jump_transport TYPE string VALUE 'jump_transport',
url TYPE string VALUE 'url',
goto_source TYPE string VALUE 'goto_source',
show_callstack TYPE string VALUE 'show_callstack',
change_order_by TYPE string VALUE 'change_order_by',
goto_message TYPE string VALUE 'goto_message',
direction TYPE string VALUE 'direction',
changed_by TYPE string VALUE 'changed_by',
documentation TYPE string VALUE 'documentation',
changelog TYPE string VALUE 'changelog',
END OF c_action.
CONSTANTS c_spagpa_param_repo_key TYPE c LENGTH 20 VALUE 'REPO_KEY' ##NO_TEXT.
CONSTANTS c_spagpa_param_package TYPE c LENGTH 20 VALUE 'PACKAGE' ##NO_TEXT.
CONSTANTS gc_yes TYPE ty_yes_no VALUE 'Y'.
CONSTANTS gc_no TYPE ty_yes_no VALUE 'N'.
CONSTANTS gc_partial TYPE ty_yes_no_partial VALUE 'P'.
CONSTANTS gc_memoryid_title TYPE c LENGTH 60 VALUE 'ZABAPGIT_TITLE'.
TYPES:
ty_method TYPE c LENGTH 1 .
TYPES:
BEGIN OF ty_stage,
file TYPE ty_file,
method TYPE ty_method,
status TYPE ty_result,
END OF ty_stage .
TYPES:
ty_stage_tt TYPE SORTED TABLE OF ty_stage
WITH UNIQUE KEY file-path file-filename .
CONSTANTS:
BEGIN OF c_method,
add TYPE ty_method VALUE 'A',
rm TYPE ty_method VALUE 'R',
ignore TYPE ty_method VALUE 'I',
skip TYPE ty_method VALUE '?',
END OF c_method .
ENDINTERFACE.
INTERFACE zif_abapgit_repo_srv
PUBLIC .
METHODS delete
IMPORTING
!io_repo TYPE REF TO zcl_abapgit_repo
RAISING
zcx_abapgit_exception .
METHODS get
IMPORTING
!iv_key TYPE zif_abapgit_persistence=>ty_value
RETURNING
VALUE(ro_repo) TYPE REF TO zcl_abapgit_repo
RAISING
zcx_abapgit_exception .
METHODS is_repo_installed
IMPORTING
!iv_url TYPE string
!iv_target_package TYPE devclass OPTIONAL
RETURNING
VALUE(rv_installed) TYPE abap_bool
RAISING
zcx_abapgit_exception .
METHODS list
RETURNING
VALUE(rt_list) TYPE zif_abapgit_definitions=>ty_repo_ref_tt
RAISING
zcx_abapgit_exception .
METHODS new_offline
IMPORTING
!iv_url TYPE string
!iv_package TYPE devclass
!iv_folder_logic TYPE string DEFAULT zif_abapgit_dot_abapgit=>c_folder_logic-full
!iv_master_lang_only TYPE abap_bool DEFAULT abap_false
RETURNING
VALUE(ro_repo) TYPE REF TO zcl_abapgit_repo_offline
RAISING
zcx_abapgit_exception .
METHODS new_online
IMPORTING
!iv_url TYPE string
!iv_branch_name TYPE string
!iv_display_name TYPE string OPTIONAL
!iv_package TYPE devclass
!iv_folder_logic TYPE string DEFAULT 'PREFIX'
!iv_ign_subpkg TYPE abap_bool DEFAULT abap_false
!iv_master_lang_only TYPE abap_bool DEFAULT abap_false
RETURNING
VALUE(ro_repo) TYPE REF TO zcl_abapgit_repo_online
RAISING
zcx_abapgit_exception .
METHODS purge
IMPORTING
!io_repo TYPE REF TO zcl_abapgit_repo
!is_checks TYPE zif_abapgit_definitions=>ty_delete_checks
RAISING
zcx_abapgit_exception .
METHODS validate_package
IMPORTING
!iv_package TYPE devclass
!iv_ign_subpkg TYPE abap_bool DEFAULT abap_false
!iv_chk_exists TYPE abap_bool DEFAULT abap_true
RAISING
zcx_abapgit_exception .
METHODS get_repo_from_package
IMPORTING
!iv_package TYPE devclass
!iv_ign_subpkg TYPE abap_bool DEFAULT abap_false
EXPORTING
VALUE(eo_repo) TYPE REF TO zcl_abapgit_repo
!ev_reason TYPE string
RAISING
zcx_abapgit_exception .
METHODS get_repo_from_url
IMPORTING
!iv_url TYPE string
RETURNING
VALUE(ro_repo) TYPE REF TO zcl_abapgit_repo
RAISING
zcx_abapgit_exception .
ENDINTERFACE.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment