Skip to content

About

Every old system needs an Ark.

Resources

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

ARK - ABAP Render Kit

"Every old system needs an Ark."

ARK is a modern UI framework for ABAP, extracted and refined from the battle-tested abapGit project. It enables developers to build rich, interactive HTML-based user interfaces within SAP GUI using familiar ABAP patterns.

⚠️ Experimental Project

This is an experimental project. APIs, class names, and behavior may change without notice between releases. While ARK is derived from abapGit's source code, it is an independent project — not officially endorsed by or maintained by the abapGit team or SAP. No warranty is provided.

  • Do not use in production systems without thorough testing.
  • Expect breaking changes as the framework evolves.
  • Feedback, bug reports, and contributions are welcome, but treat current builds as alpha-quality.

Features

  • HTML Rendering Engine — Fluent API for building HTML with automatic indentation
  • Page Navigation — automatic page stack: navigation pushes history, go_back( ) pops one level (restoring the previous page instance with its state). Every non-home page gets a uniform ← 返回 control automatically; the reserved action ark_back is intercepted by the framework. F3/Back goes one level up and exits only at the top level — no more jumping straight to exit
  • Event System — Sapevent-based communication between frontend and ABAP backend
  • UI Components — Form, Table, Toolbar, and more ready-to-use components
  • JS Library Registry — zcl_ark_js_library=>register( iv_name iv_mime ) plugs any uploaded JS (three.js, dayjs, ...) into every page; include_for( lo_widget ) injects a widget's dependencies once per page
  • JS-ABAP Event Bridge — zcl_ark_js_bridge exposes window.arkEmit(action, params) so any component can fire sapevents without hand-rolled URL plumbing
  • Widget Plugin Interface — implement zif_ark_js_widget (get_assets + render) and your class is a first-class page capability, same as the built-in table/JSON/chart components
  • Generic Data Rendering — zcl_ark_html_table=>from_any_table( ) turns any internal table into an HTML table via RTTI; zcl_ark_json_tree renders any JSON string as a collapsible tree — no per-cell code in either direction
  • ECharts Component — Declarative charting with zcl_ark_echarts, mixable with any other HTML content; chart click events (drill-down) and GeoJSON maps (bundled China map) included
  • Text Templates — zcl_ark_template with {{PLACEHOLDER}} syntax, loadable from the MIME repository
  • JSON Serialization — zcl_ark_json=>to_json( ) for any ABAP data object (sXML-based, zero dependencies)
  • Theme Support — Fiori Quartz design tokens via zcl_ark_theme; override any token with set_token( )
  • Declarative State Pages — fill a typed ty_page_state (zif_ark_gui_state) and let zcl_ark_state_page render a Fiori-style page; no HTML in your ABAP code. Section kinds: KPI grid, table, form (framework read-back + required validation), chart, card grid, text, progress bars — plus one-call builders: table_section( ) (any internal table, RTTI-derived columns) and chart_section( ) (single bar/line series from ABAP data)
  • Convention Routing — no CASE in on_event: an action save_order is auto-dispatched to method on_action_save_order on your page class
  • Zero-Boilerplate Launcher — ZARK_LAUNCHER (transaction-code entry for any page class) removes the host-screen boilerplate from every app report
  • Extensible JS Pipeline — see docs/js-extensions.md: upload any JS (three.js, ...) as a W3MI asset, register it, and ship your own widget components
  • Zero External Dependencies — Runs entirely within SAP GUI using standard CL_GUI_HTML_VIEWER

Quick Start

Create one report (SE38/ADT, e.g. ZMY_ARK_APP), paste this, activate, run:

REPORT zmy_ark_app.

CLASS lcl_page DEFINITION INHERITING FROM zcl_ark_gui_page FINAL.
  PUBLIC SECTION.
    METHODS on_event REDEFINITION .
  PROTECTED SECTION.
    METHODS build_html REDEFINITION .
ENDCLASS.

CLASS lcl_page IMPLEMENTATION.
  METHOD build_html.
    mo_html->add( |<h1>Hello ARK!</h1>| ).

    " HTML rendering — fluent builder, any fragment in the page flow
    mo_html->div(
      iv_style   = |border:1px solid #ddd; border-radius:8px;|
                && | padding:12px; max-width:640px;|
                && | background:#f8fafc|
      iv_content = |<b>Plain HTML + styles</b>|
                && | mix freely with components.| ).

    " Sized, colorful chart
    DATA(lo_chart) = NEW zcl_ark_echarts(
      iv_div_id = 'sales'
      iv_width  = '640px'
      iv_height = 320 ).
    lo_chart->set_title( 'Weekly Sales' ).
    lo_chart->set_xaxis_categories( VALUE string_table(
      ( `Mon` ) ( `Tue` ) ( `Wed` ) ( `Thu` ) ( `Fri` ) ) ).
    lo_chart->add_series(
      iv_name          = 'Revenue'
      iv_type          = 'bar'
      iv_color_by_data = abap_true
      it_data          = VALUE zcl_ark_echarts=>ty_values(
        ( 120 ) ( 200 ) ( 150 ) ( 80 ) ( 270 ) ) ).
    mo_html->add( lo_chart->render( ) ).

    " sapevent link — handled in on_event below
    mo_html->add_a( iv_txt = 'Open the full examples'
                    iv_act = 'run_examples' ).
    ri_html = mo_html.
  ENDMETHOD.

  METHOD on_event.
    CASE ii_event->mv_action.
      WHEN 'run_examples'.
        " Jump-run the bundled demo hub (own screen and GUI);
        " returns here when the user exits it
        SUBMIT zark_example AND RETURN.
        TRY.
            zcl_ark_gui=>get_instance( )->render( ).
          CATCH zcx_ark_exception.
            " Full-screen takeover may invalidate the viewer: rebuild
            zcl_ark_gui=>get_instance( )->free( ).
            zcl_ark_gui=>create( )->set_page( NEW lcl_page( ) ).
        ENDTRY.
      WHEN OTHERS.
        rs_result = super->on_event( ii_event ).
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

" --- Launcher: the HTML viewer needs a host screen (like abapGit) ---
SELECTION-SCREEN BEGIN OF SCREEN 1001.
SELECTION-SCREEN END OF SCREEN 1001.

START-OF-SELECTION.
  TRY.
      " Offline ECharts asset; falls back to CDN if absent
      zcl_ark_echarts=>use_bundled_library( ).
    CATCH zcx_ark_exception.
  ENDTRY.
  TRY.
      zcl_ark_gui=>create( )->set_page( NEW lcl_page( ) ).
      CALL SELECTION-SCREEN 1001.
    CATCH zcx_ark_exception INTO DATA(lx_error).
      MESSAGE lx_error TYPE 'E'.
  ENDTRY.

AT SELECTION-SCREEN ON EXIT-COMMAND.
  " F3 / Back / Escape: one level up the page stack (same as the on-page
  " Back control); exit the program when already at the top level
  IF sy-dynnr = 1001.
    IF zcl_ark_gui=>get_instance( )->go_back( ) = abap_false.
      zcl_ark_gui=>get_instance( )->free( ).
      LEAVE PROGRAM.
    ENDIF.
  ENDIF.

To navigate between your own pages from on_event, return the new page in the result:

WHEN 'nav_detail'.
  rs_result-page  = NEW lcl_detail_page( ).
  rs_result-state = 1.

Beyond the basics — the bundled demos are the living documentation. Run ZARK_EXAMPLE (SE38/SA38, or ZCL_ARK_EXAMPLE_APP as an ABAP application in ADT): its home page navigates to the form, table, chart, data-viewer (RTTI table + JSON tree), and browser-info examples — the last one probes which rendering engine (IE/MSHTML vs Edge/Chromium) the SAP GUI HTML viewer actually uses on your machine — and jump-runs the standalone demo reports. ZARK_ECHARTS_DEMO shows every charting mode (declarative API, override hatch, full option structure, themes); ZARK_SFLIGHT_DEMO is a database-driven dashboard on SFLIGHT/SCARR.

Charts (ECharts)

zcl_ark_echarts renders a chart as a plain HTML fragment, so it mixes freely with headings, tables, toolbars, or a second chart on the same page. Three usage levels, from simplest to most powerful:

1. Declarative API — type-safe, covers the common chart options:

DATA(lo_chart) = NEW zcl_ark_echarts( iv_div_id = 'chart1' iv_height = 420 ).

lo_chart->set_title( 'Stacked Area Chart' ).
lo_chart->set_xaxis_categories( VALUE string_table( ( `Mon` ) ( `Tue` ) ( `Wed` ) ) ).
lo_chart->add_series(
  iv_name  = 'Email'
  it_data  = VALUE zcl_ark_echarts=>ty_values( ( 120 ) ( 132 ) ( 101 ) )
  iv_stack = 'Total'
  iv_area  = abap_true ).

mo_html->add( |<h1>Dashboard</h1>| ).
mo_html->add( lo_chart->render( ) ).   " just one chunk in the page flow

2. Override hatch — raw JSON shallow-merged (top-level keys) onto the generated option, for anything the declarative API does not cover yet (dataZoom, markLine, visualMap, ...):

lo_chart->set_option_override(
  `{ "dataZoom": [{ "type": "slider" }, { "type": "inside" }] }` ).

3. Full option structure — pass any ABAP structure as the complete ECharts option; serialized via /ui2/cl_json in camelCase mode (underscore field names become camelCase keys). Soft dependency: called dynamically, falls back to zcl_ark_json when /ui2/cl_json is not installed:

TYPES: BEGIN OF ty_pie_option,
         title  TYPE ty_title,        " text / left
         series TYPE tt_pie_series,   " name / type / radius / data
       END OF ty_pie_option.

lo_chart->set_option( ls_pie_option ).

4. Chart click events — drill into any chart element (bar, pie slice, map region):

lo_chart->set_on_click( 'chart_drill' ).

" ... in the page's on_event:
WHEN 'chart_drill'.
  DATA(lv_name)   = ii_event->query( 'name' ).    " category / datum name
  DATA(lv_series) = ii_event->query( 'series' ).  " series name
  DATA(lv_value)  = ii_event->query( 'value' ).   " number (objects arrive as JSON string)
  DATA(lv_idx)    = CONV i( ii_event->query( 'idx' ) ).

Query values are URL-decoded automatically (Chinese category names work). Single values are capped at 250 characters (percent-encoded Chinese ≈ 9 chars per character) — keep names short. On state pages, set chart_click_action on a chart section; its payload additionally carries chart (= section index) so multiple chart sections can share one action.

5. Maps (GeoJSON) — China map ships with the repository as MIME object ZARK_MAP_CHINA_JSON (abapGit W3MI, DataV 100000_full GeoJSON; use your own map data where licensing requires):

zcl_ark_echarts=>use_bundled_map( ).             " session-level load (once)

lo_chart->set_map( 'china' ).                    " registers the map
lo_chart->set_visual_map( iv_min = '0' iv_max = '1200' ).
lo_chart->add_map_series(
  iv_name = 'Sales'
  it_data = VALUE zcl_ark_echarts=>tt_map_data(
    ( name = '广东' value = 1180 )
    ( name = '江苏' value = 1050 ) ) ).          " names must match GeoJSON features
lo_chart->set_on_click( 'map_drill' ).           " click a province -> sapevent

Custom maps: upload any GeoJSON to SMW0 and load it with use_bundled_map( iv_map_name = 'usa' iv_mime_name = 'Z_USA_JSON' ), or pass the raw GeoJSON bytes directly: set_map( iv_name = 'usa' iv_xdata = zcl_ark_convert=>mime_to_xstring( 'Z_USA_JSON' ) ). The GeoJSON is served as a synchronous window.ARK_MAPS script through cache_asset; if the asset is missing the chart degrades to an empty map instead of a script error. State pages: set chart_map on a chart section and the map script is injected automatically.

Notes:

  • ECharts 6.1.0 ships with the repository as MIME object ZARK_ECHARTS_MIN_JS (abapGit W3MI, see src/assets/), so charts work offline out of the box; zcl_ark_echarts=>use_bundled_library( ) loads it once per session and serves it through cache_asset with automatic CDN fallback. Pass iv_include_lib = abap_false to any additional chart on the same page.
  • The China map GeoJSON ships as MIME object ZARK_MAP_CHINA_JSON the same way (use_bundled_map( ), no CDN fallback — a missing asset degrades to an empty map).
  • Series data and categories are serialized with zcl_ark_json=>to_json( ); pass plain ABAP internal tables, no string building required. add_series accepts any internal table with a numeric row type — zcl_ark_echarts=>ty_values is the integer convenience type, declare your own p/f table for decimal values such as amounts. iv_color_by_data = abap_true colors each datum from the palette (one color per bar/pie slice). iv_label = iv_label_thousands = abap_true renders thousands-separated data labels (1,630,000).
  • To use a different ECharts version, replace the file in src/assets/zark_echarts_min_js.w3mi.data.js or point c_cdn_url at another CDN build.
  • Series data and categories are serialized with zcl_ark_json=>to_json( ); pass plain ABAP internal tables, no string building required. add_series accepts any internal table with a numeric row type — zcl_ark_echarts=>ty_values is the integer convenience type, declare your own p/f table for decimal values such as amounts. iv_color_by_data = abap_true colors each datum from the palette (one color per bar/pie slice).
  • The constructor takes iv_height (px) and optional iv_width (e.g. '640px', '50%'; default full width, centered when narrower).
  • If the library fails to load, the chart container shows a visible error banner instead of failing silently.
  • See ZCL_ARK_EXAMPLE_CHART_PAGE (mixed content, click drill-down), report ZARK_ECHARTS_DEMO (declarative API, override hatch, full-structure pie chart, dark theme, China map choropleth with province click), and report ZARK_SFLIGHT_DEMO (database-driven dashboard on the classic SFLIGHT/SCARR flight model) for usage.

Data Rendering (any table / JSON)

Two generic components turn typed ABAP data into HTML without per-cell code. This is the answer to "I just want to show my data":

1. Any internal table → HTML table — RTTI-driven:

mo_html->add_table(
  zcl_ark_html_table=>from_any_table( lt_any )->zif_ark_gui_renderable~render( ) ).

Columns derive from the line type: components based on DDIC data elements contribute their medium/short/reptext label (field name as fallback), numeric columns are right-aligned, dates/times use the user format, deep table columns show their row count, .INCLUDE substructures are flattened. Values are HTML-escaped. The return value is the regular builder, so add_column( ), set_striped( ), ... still apply before render( ). Elementary line types render as a single TABLE_LINE column.

The generated table is interactive out of the box, entirely client-side (no sapevent round-trips): click a column header to sort ascending/descending — numeric and date columns sort by value, not by display text — and type into the filter bar above the table to match rows across all columns (the counter shows visible / total). Tables size to their content and scroll horizontally inside .ark-data-wrap instead of stretching the full page width. Manually built tables (plain add_column/add_cell) keep their previous behavior.

2. JSON string → collapsible tree — sXML-based, zero dependencies:

mo_html->add_table(
  zcl_ark_json_tree=>create( lv_json )->set_open( abap_true
                        )->zif_ark_gui_renderable~render( ) ).

Invalid JSON degrades to escaped plain text instead of a script error. set_open( ) controls the initial expand state of all nodes — flipping it and re-rendering is the expand-all/collapse-all pattern (a sapevent that sets rs_result-state = 1 without returning a new page re-renders in place). Styles come from zcl_ark_theme (ark-jt-* classes, token-driven); the tiny ES5 toggle script ships with the fragment and works on both MSHTML and Edge viewers.

See ZCL_ARK_EXAMPLE_DATA_PAGE (demo hub → Data Viewer) for both.

Declarative Pages (state)

The shortest path from ABAP data to a working app page: inherit from zcl_ark_state_page, fill a typed state in build_state( ), and the framework renders the whole Fiori-style page — no HTML, no JSON, no CASE dispatcher in your code. Tables get sorting/filtering/CSV download and forms get POST read-back + required validation built in.

CLASS zcl_sales_page DEFINITION INHERITING FROM zcl_ark_state_page FINAL.
  PUBLIC SECTION.
    " Convention routing: action 'pick_month' -> method below (≤20 chars)
    METHODS on_action_pick_month
      IMPORTING ii_event TYPE REF TO zif_ark_gui_event
      RETURNING VALUE(rs_result) TYPE zif_ark_gui_event_handler=>ty_handling_result
      RAISING   zcx_ark_exception .
  PROTECTED SECTION.
    METHODS build_state .
ENDCLASS.

CLASS zcl_sales_page IMPLEMENTATION.
  METHOD constructor.
    super->constructor( ).
    build_state( ).
  ENDMETHOD.

  METHOD build_state.
    DATA(ls_state) = VALUE zif_ark_gui_state=>ty_page_state(
      title = 'Sales Overview' subtitle = 'Typed state in, rendered page out' ).

    " KPI cards — semantic colors drive the delta styling
    ls_state-sections = VALUE #(
      ( kind = zif_ark_gui_state=>c_section_kind-kpi_grid
        kpi_cards = VALUE #(
          ( title = 'Revenue' value = '4,286,000'
            delta_text = '▲ 12.4% MoM'
            delta_semantic = zif_ark_gui_state=>c_semantic-positive ) ) ) ).

    " Chart — one call, single bar/line series from ABAP data
    APPEND zcl_ark_state_page=>chart_section(
             iv_title        = 'Monthly Revenue'
             iv_series_name  = 'Revenue'
             it_categories   = VALUE string_table( ( `Jan` ) ( `Feb` ) ( `Mar` ) )
             it_data         = VALUE zcl_ark_echarts=>ty_values( ( 420 ) ( 455 ) ( 490 ) )
             iv_click_action = 'pick_month' )
           TO ls_state-sections.

    " Table — any internal table; RTTI derives columns, DDIC labels, alignment
    SELECT carrid, connid, price FROM sflight INTO TABLE @DATA(lt_flights) UP TO 20 ROWS.
    APPEND zcl_ark_state_page=>table_section(
             iv_title = 'Flight Details' it_data = lt_flights )
           TO ls_state-sections.

    " Form — POST values are read back into the state before the handler runs
    ls_state-sections = VALUE #( BASE ls_state-sections
      ( kind = zif_ark_gui_state=>c_section_kind-form
        form_action = 'apply_filter'
        form_fields = VALUE #(
          ( input_type = 'text' label = 'Customer' name = 'customer' required = abap_true )
          ( input_type = 'submit' value = 'Apply' ) ) ) ).

    set_state( ls_state ).
  ENDMETHOD.

  METHOD on_action_pick_month.
    " ii_event->query( 'name' / 'value' / 'idx' ) — already URL-decoded
    build_state( ).            " rebuild state, e.g. with a filter applied
    rs_result-state = 1.       " re-render in place
  ENDMETHOD.
ENDCLASS.

Multi-series charts stay one call — pass a series table (per-series name/type/values; series without a type inherit iv_chart_type):

APPEND zcl_ark_state_page=>chart_section(
         iv_title      = 'Revenue vs Cost'
         it_categories = VALUE string_table( ( `Jan` ) ( `Feb` ) )
         it_series     = VALUE zcl_ark_state_page=>tt_chart_series(
                           ( name = 'Revenue' type = 'bar'  values = VALUE #( ( `420` ) ( `455` ) ) )
                           ( name = 'Cost'    type = 'line' values = VALUE #( ( `300` ) ( `280.5` ) ) ) ) )
       TO ls_state-sections.

Progress bars are a section kind too — label + right-aligned value text + semantic fill color (percent is clamped to 0-100 by the renderer):

" Progress — account validity with used/total days
APPEND VALUE zif_ark_gui_state=>ty_section(
  kind  = zif_ark_gui_state=>c_section_kind-progress
  title = 'Account Validity'
  progress_items = VALUE #(
    ( label      = '2025-01-01 ~ 2026-12-31'
      value_text = 'Used 620 / 730 days'
      percent    = 85
      semantic   = zif_ark_gui_state=>c_semantic-positive ) )
) TO ls_state-sections.

Advanced charts (stacked options, maps, pies) build their option with the zcl_ark_echarts declarative API and pass lo_chart->get_option_json( ) into the section's chart_option — see ZCL_ARK_EXAMPLE_STATE_PAGE (demo hub → State Page) for every section kind in one page.

Launch the page with zero boilerplate: create a transaction code pointing at report ZARK_LAUNCHER, set the start parameter P_PAGE = ZCL_SALES_PAGE ("skip initial screen"), and run it — no host-screen SELECTION-SCREEN copy-paste needed.

Templates

zcl_ark_template keeps HTML/JS skeletons out of your ABAP code. Placeholders use {{NAME}} syntax; unfilled placeholders are kept as-is so omissions are easy to spot:

mo_html->add(
  zcl_ark_template=>create( `<h1>{{TITLE}}</h1>`  " or =>from_mime( 'ZARK_MY_TEMPLATE' )
    )->set( iv_name = 'TITLE' iv_value = 'Hello'
    )->render( ) ).

Templates can be stored as text files in the MIME repository (SMW0) and loaded with zcl_ark_template=>from_mime( ).

Development Environment

The reference development base is the official SAP ABAP Platform 2023 developer trial, running as a local Docker container. On the client side, ARK targets the Edge (Chromium/WebView2) rendering engine of CL_GUI_HTML_VIEWER — SAP GUI 7.70+ with the Edge kernel enabled (see the browser-info example in ZARK_EXAMPLE to probe your actual engine). Legacy IE-engine clients are not supported.

Item Value
System Local Docker container a4h, official image sapse/abap-cloud-developer-trial:2023
Platform ABAP Platform 2023 (SAP_BASIS 7.57, 2023 trial, image tag VA_ABAP_PL_2023HDB)
Kernel 7.93 (793_REL, built 2024-08, SLES 15 x86_64)
Database SAP HANA (built into the container, port 30213)

Installation

  1. Install via abapGit — paste this repository URL
  2. Or manually copy all src/**/*.abap files into your SAP system
  3. Activate all classes and interfaces
  4. Run the demo program ZARK_EXAMPLE from SE38/SA38, or run class ZCL_ARK_EXAMPLE_APP as an ABAP application in ADT

Project Structure

src/
├── core/              # Tier 1: Core Engine
│   ├── zcl_ark_html              # HTML builder
│   ├── zcl_ark_gui               # GUI controller
│   ├── zcl_ark_html_viewer_gui   # HTML viewer wrapper
│   ├── zcl_ark_gui_event         # Event object
│   ├── zcl_ark_convert           # Conversion utilities
│   ├── zcl_ark_json              # JSON serializer (sXML based)
│   ├── zcl_ark_theme             # Fiori design tokens + default CSS
│   └── interfaces...
├── framework/         # Tier 2: Page Framework
│   ├── zcl_ark_gui_page          # Page base class
│   ├── zcl_ark_gui_component     # Component base class
│   ├── zcl_ark_state_page        # Declarative state page (renders ty_page_state)
│   └── zif_ark_gui_state         # Declarative page state schema (draft)
├── components/        # Tier 3: UI Components
│   ├── zcl_ark_html_form         # Form builder
│   ├── zcl_ark_html_table        # Table builder (+ from_any_table RTTI rendering)
│   ├── zcl_ark_html_toolbar      # Toolbar builder
│   ├── zcl_ark_echarts           # ECharts chart component
│   ├── zcl_ark_json_tree         # JSON string -> collapsible tree
│   └── zcl_ark_template          # Text template with placeholders
├── assets/            # Static assets (MIME objects)
│   ├── zark_echarts_min_js       # Apache ECharts 6.1.0 bundle
│   └── zark_map_china_json      # China map GeoJSON (DataV 100000_full)
└── examples/          # Demo applications

License

MIT License — same as abapGit.

Built with by extracting the best from abapGit.

About

Every old system needs an Ark.

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages