Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[SAPUI5] Add your own Logout functionality to the Launchpad Sandbox

Use the attachLogoutEvent of the ushell container to trigger your approuter logout endpoint, that needs to be configured in your xs-app.json. The code in my launchpad.html looks like this:

    <script>
        sap.ui.getCore().attachInit(() => {

            sap.ushell.Container.createRenderer('fiori2', true).then(renderer => renderer.placeAt("content"))

            sap.ushell.Container.attachLogoutEvent(e => {
                e.preventDefault()
                window.location.replace('/do/logout')
            }, false)

        })
    </script>

This way, you can reuse the default logout dialog logic the launchpad provides.

For completeness, find also my approuter configuration and custom logout page below.

My xs-app.json:

{
  "welcomeFile": "index.html",
  "authenticationMethod": "route",
  "logout": {
    "logoutEndpoint": "/do/logout",
    "logoutPage": "/logged-out.html"
  },
  "sessionTimeout": 60,
  "routes": [
    {
      "source": "^/logged-out.html$",
      "localDir": ".",
      "authenticationType": "none"
    },
    {
      "source": "^/launchpad.html$",
      "localDir": ".",
      "authenticationType": "xsuaa",
      "cacheControl": "no-cache, no-store, must-revalidate"
    },
    {
      "source": "^/appconfig/(.*)$",
      "localDir": ".",
      "authenticationType": "xsuaa"
    },
    {
      "source": "^/user-api(.*)",
      "target": "$1",
      "service": "sap-approuter-userapi",
      "authenticationType": "xsuaa"
    },
...
  ]
}

My logged-out.html file, placed in the approuter folder next to the launchpad.html:

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Logged out</title>
    <style>
        h2 {
            font-family: "Arial", sans-serif;
        }
        .centered {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }
    </style>
</head>

<body>
    <div class="centered">
        <h2>You are now logged out</h2>
    </div>
</body>

</html>

[SAPUI5] Add custom header parameter to all oData queries

Simply go to your Component.js file and add this line to the init function:

this.getModel().setHeaders({"myCustomParameter": "test"})

In a CAP Backend, you get this parameter from the express req object, which can be accessed via the req.http property:

req.http.req.headers['myCustomParameter']

And here is a nice code snippet, on how to read this header parameter in an ABAP system: https://answers.sap.com/answers/425621/view.html

[SAPUI5] Suppress default oData error message / display meaningful error messages

Create a separate ErrorHandler.js file, like it is described here and either do your own error handler implementation, or take the sample from here. To avoid displaying multiple errors at once, follow this chapter.

Thanks to the provided dsag sample, this is takes only a few minutes and improves the user experience a lot!

[ABAP] xsdbool

Somehow I always forget that there is a boolean function in ABAP. That’s why I’m writing this post to hopefully remember it better. 🙂

If you just want to check something for truthiness, you can do it in the following three ways:

IF sy-subrc = 0.
  result = abap_true.
ELSE.
  result = abap_false.
ENDIF.
result = SWITCH #( sy-subrc WHEN 0 THEN abap_true
                                   ELSE abap_false ).
result = xsdbool( sy-subrc = 0 )

https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abenboole_functions.htm?file=abenboole_functions.htm

https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#use-xsdbool-to-set-boolean-variables

[CAP] Select max with group by

https://www.w3resource.com/sql/aggregate-functions/Max-with-group-by.php

https://answers.sap.com/questions/13081527/simple-count-aggregation-on-caps-cql.html?childToView=13079907&answerPublished=true

entity myEntity {
        key ID: Integer;
        key seqNr: Integer;
        key createdAt: DateTime;
        ...
    }

@readonly
entity myEntityMaxSeqNr 
        as select from myEntity {
            ID, 
            count(seqNr) as maxSeqNr: Integer
            createdAt,
            ...
            } 
        group by 
            ID,
            createdAt;

This can also be done using CQL like here.

[SAPUI5] Create date object in UTC YYYY-MM-ddTHH:mm:ss

https://sapui5.hana.ondemand.com/#/api/sap.ui.core.format.DateFormat%23methods/format

            const today = new Date()
            const oDateTimeFormat = sap.ui.core.format.DateFormat.getDateTimeInstance({
                pattern: "yyyy-MM-ddTHH:mm:ss",
                UTC: true
            })
            const todayISO = oDateTimeFormat.format(today)

The UTC flag can also be set, when calling the format function.

            const today = new Date()
            const oDateTimeFormat = sap.ui.core.format.DateFormat.getDateTimeInstance({
                pattern: "yyyy-MM-ddTHH:mm:ss",
                //UTC: true
            })
            const todayISO = oDateTimeFormat.format(today, true)