Home Applications bi-export-plus

bi-export-plus

Community Project
This project is maintained by its author and is not officially supported by InterSystems. For technical support, please contact the project developer.
4
1 reviews
1
Awards
80
Views
14
IPM installs
0
Add to bundle
Details
Releases (5)
Reviews (1)
Awards (1)
Issues
Adding support for IRIS BI Export to Excel (and JSON)

What's new in this version

  1. Dashboard export support — multi-sheet workbook export, per-widget buttons, openpyxl availability detection with graceful degradation
  2. Docker support — Dockerfile, docker-compose.yml, iris.script, .dockerignore
  3. REST API auth fix + version bump to 1.1.5 — the AutheEnabled bitmask fix for the real blocking bug
  4. Docs — README/QUICKSTART updates (Dashboard export usage + Docker quick-start) and the new docs/ architecture writeups

bi-export-plus

bi-export-plus logo

Real, binary .xlsx (and typed JSON) exports for the InterSystems IRIS BI/DeepSee
Analyzer — no more opening “Export to Excel” and getting an HTML table wearing an
.xls extension.

  • Excel Workbook and JSON buttons appear right in the Analyzer’s own Export
    dropdown, next to the stock Excel/CSV options.
  • A standalone REST API (/csp/bi-export/xlsx, /csp/bi-export/json) too, for
    pulling the same exports from scripts/automation without opening the Analyzer.

Try it now - no install, no existing IRIS needed

docker run -d -p 52773:52773 -p 1972:1972 ghcr.io/asinay/bi-export-plus:latest

Pre-loaded with Samples-BI and this
module - openpyxl included - so there’s real data to export immediately:

Demo page, no pivot needed http://localhost:52773/csp/user/BIExport.UI.DemoPage.cls
Analyzer, on the sample HoleFoods cube http://localhost:52773/csp/user/BIExport.UI.Analyzer.cls?CUBE=HOLEFOODS
Management Portal (login _SYSTEM / SYS) http://localhost:52773/csp/sys/UtilHome.csp

Building it yourself instead of pulling: docker compose up --build (see
https://github.com/asinay/bi-export-plus/blob/master/Dockerfile). Already running IRIS elsewhere? →
Try it in 2 minutes instead, or keep reading for the full
reference below.

Excel Workbook and JSON in the Analyzer's Export dropdown

The new buttons, right next to the stock Excel/CSV ones.

Real Excel Table with autofilter and a Totals row
A genuine Excel Table - autofilter, sortable headers, a native Totals row.
Styled Info sheet with report metadata
An Info sheet with title/cube/filters, not squeezed above the data.

Requirements

  • InterSystems IRIS with Embedded Python enabled.
  • The Python package openpyxl importable
    from IRIS’s embedded Python (needed for the .xlsx path only; JSON export
    needs neither Python nor openpyxl).

Install openpyxl into IRIS’s embedded Python environment, e.g.:

/bin/irispython -m pip install openpyxl

Verify it from an IRIS terminal in any namespace:

Do ##class(%SYS.Python).Import("openpyxl")

If that errors, fix the Python/openpyxl setup before installing this module -
the xlsx export will fail at runtime otherwise.

If openpyxl turns out not to be importable at runtime anyway, every export surface
(Analyzer buttons, dashboard widget buttons, demo page, REST API) detects it and degrades
gracefully instead of producing a broken download - buttons gray out with an explanation
in their tooltip, and the REST API returns 503 with a plain-text reason. JSON export is
never affected either way, since it needs no Python.

Installation

Just want to try it out rather than add it to a real instance? See
Try it now with Docker above instead -
nothing below is needed for that.

Recommended: InterSystems Package Manager (IPM/ZPM). If this module has been
published to the IPM registry:

zpm "install bi-export-plus"

To install straight from a local clone of this repository instead (e.g. before
it’s published, or to run a modified copy):

git clone 
zpm "load /path/to/bi-export-plus"

Point this at the directory that contains https://github.com/asinay/bi-export-plus/blob/master/module.xml, not at the
https://github.com/asinay/bi-export-plus/blob/master/module.xml file itself - e.g. on Windows:

zpm:USER>load C:\path\to\bi-export-plus

IPM reads https://github.com/asinay/bi-export-plus/blob/master/module.xml, loads the classes under https://github.com/asinay/bi-export-plus/blob/master/src/, and
registers the /csp/bi-export web application for you. Take note of the
AfterInstallMessage it prints at the end - it points you at the two usage
options below.

Other ways to install (no IPM, or just the packaged classes XML)

Option B: Manual install (no IPM)

  1. Load the classes into your target namespace from an IRIS terminal:

    Set path = "/path/to/bi-export-plus/https://github.com/asinay/bi-export-plus/blob/master/src/cls"
    Do $system.OBJ.LoadDir(path, "ck", , 1)
    

    ("ck" = compile, keep the source-controlled state consistent; the trailing
    1 recompiles even if the class already exists.)

  2. Create the REST web application manually (IPM normally does this from the
    <WebApplication> block in https://github.com/asinay/bi-export-plus/blob/master/module.xml) - in the Management
    Portal: System Administration > Security > Applications > Web
    Applications > New Web Application
    , with:

    Setting Value
    Name /csp/bi-export
    Namespace your target namespace
    Dispatch class BIExport.REST
    Enable Password authentication Yes
    Enable Unauthenticated access No

    This step is only needed for the standalone REST API (Option B under
    “Usage” below); the in-Analyzer export buttons work without it.

  3. Confirm the openpyxl import (see Requirements above) - manual installs skip
    IPM’s install-time checks, so this is easy to miss.

Option C: Import the packaged classes XML

https://github.com/asinay/bi-export-plus/blob/master/dist/BIExport-classes.xml is a single IRIS class
export containing every class in this module - the quickest way to get it
into an existing instance without cloning the repo or using IPM.

Either drag-and-drop it onto Management Portal > System Explorer >
Classes > Import
, or from an IRIS terminal in your target namespace:

Do $system.OBJ.Load("/path/to/bi-export-plus/https://github.com/asinay/bi-export-plus/blob/master/dist/BIExport-classes.xml", "ck")

This does not create the /csp/bi-export web application - it’s just the
classes. That’s enough for the in-Analyzer export buttons (Option A under
“Usage” below), but if you also want the standalone REST API, create the web
application manually per step 2 of Option B above.

Usage

Just want to see it work? Try the demo page

No pivot needed - BIExport.UI.DemoPage.cls is a self-contained form with a few
canned MDX queries and totals/aggregation toggles. Pick one, click a button, get a
real .xlsx/.json download, using the exact same code path as the buttons below:

/csp/<namespace>/BIExport.UI.DemoPage.cls

Standalone demo page with sample queries and totals toggles

Option A: In-Analyzer export buttons

Open your pivots via BIExport.UI.Analyzer.cls instead of the stock
_DeepSee.UI.Analyzer.zen - same query params, just a different class name:

/csp/<namespace>/BIExport.UI.Analyzer.cls?CUBE=...

The page’s Export dropdown gains Excel Workbook and JSON entries next
to the stock Excel/CSV ones.

Add a Favorites bookmark instead of changing a link's URL

Rather than changing an existing link/shortcut’s URL, add a normal Portal
Favorite that opens a saved pivot through BIExport.UI.Analyzer.cls
directly - it shows up in the User Portal’s Favorites sidebar/cover shelf
like any other bookmark:

Do ##class(BIExport.Favorites).AddAnalyzerFavorite("/.pivot")

The one required argument is the pivot’s full library path (fullName in
the Portal’s pivot list). Optional second/third arguments choose the
bookmark’s folder (default "BIExport") and display title (defaults to the
pivot’s own name). Run once per pivot, per user - Favorites are personal to
each user, there’s no bulk/all-users mode. RemoveAnalyzerFavorite(pFolderName, pTitle) undoes it.

Option B: Standalone REST API

POST an MDX query to /csp/bi-export/xlsx or /csp/bi-export/json:

curl -u _system:PASSWORD -X POST \
  http://host:port/csp/bi-export/xlsx \
  -H "Content-Type: application/json" \
  -d '{
    "mdx": "SELECT [Measures].[Amount] ON 0 FROM [HoleFoods Sales]",
    "title": "Sales Report",
    "cube": "HoleFoods Sales"
  }' \
  -o report.xlsx

Supported request body fields:

Field Required Description
mdx yes MDX query text
filename no Defaults to <title>.xlsx/.json, or <cube>_<timestamp> if no title
title, subtitle no Shown on the Info sheet
cube no Shown on the Info sheet, used in the default filename
listing no Listing name, for drillthrough/listing MDX
rowTotals no true to include a “Total” column (one value per row, summed across columns). Independent of columnTotals — a pivot can have either, both, or neither.
columnTotals no true to include a “Total” row (one value per column, summed down rows). Independent of rowTotals.
rowTotalAgg no Aggregation for rowTotals"sum" (default), "count", "min", "max", "avg", "pct" (% of total)
columnTotalAgg no Aggregation for columnTotals, same values as rowTotalAgg
filters no [{"name": "...", "value": "..."}] recap block on the Info sheet
rowCaptions no Row axis dimension captions (outermost first), for the row-header columns

Pivot Options dialog's Summary aggregation dropdown

rowTotalAgg/columnTotalAgg take the same values as this dropdown - no translation needed.

See sample output in https://github.com/asinay/bi-export-plus/blob/master/samples/.

Option C: Dashboard export

Two related pieces, for saved Dashboards rather than ad-hoc pivots:

Per-widget buttons. Same Excel Workbook/JSON buttons as the Analyzer, but on an
individual dashboard widget’s own Export dropdown. Existing widgets need to be converted
to the export-capable widget class once:

Do ##class(BIExport.DashboardTools).ConvertWidget("/.dashboard", "")

or, to convert every pivot-family widget on a dashboard in one call:

Do ##class(BIExport.DashboardTools).ConvertAllWidgets("/.dashboard")

RevertWidget(pDashboardFullName, pWidgetName) undoes a single conversion. New
dashboards can also just set a widget’s type to BIExport.UI.Widget.pivot directly in
the Dashboard Editor’s widget definition, instead of converting after the fact.

Whole-dashboard export. Open the dashboard via BIExport.UI.DashboardViewer.cls
instead of the stock _DeepSee.UserPortal.DashboardViewer.zen (same query params):

/csp/<namespace>/BIExport.UI.DashboardViewer.cls?DASHBOARD=...

then use Export Dashboard, in the small text-menu row at the bottom of the page
(next to Home/About/Logout) - it downloads one .xlsx workbook with one sheet per pivot
widget on that dashboard.

Try it against a real dashboard, using the Docker image’s
preloaded Samples-BI data - no conversion needed first, since whole-dashboard export
reads any pivot-family widget, stock type included:

http://localhost:52773/csp/user/BIExport.UI.DashboardViewer.cls?DASHBOARD=Basic%20Dashboard%20Demo.dashboard

Click Export Dashboard at the bottom - downloads a 3-sheet workbook (Info sheet plus
one sheet per pivot widget on that dashboard).

Known limitations

  • Totals across mixed measures. If a row/column axis mixes different
    measures (e.g. “Amount Sold” and “Units Sold” side by side), rowTotals/
    columnTotals aggregate across them regardless of measure, mixing dollars
    and units - this matches the stock Analyzer’s own CSV/Excel exports, which
    call the same underlying IRIS API. Totals are only meaningful when an axis
    is entirely one measure.
  • Nested column headers aren’t Excel Tables. A pivot with a dimension on
    Columns (e.g. Channel x measure) needs a true 2+ row merged header, which
    Excel’s Table feature can’t have (exactly one header row allowed) - that
    export keeps the merged header and skips the Table (no autofilter/banded
    rows), with a note on the Info sheet explaining why.
  • Whole-dashboard export uses each widget’s SAVED state. It resolves every widget
    from its saved pivot definition, not whatever the dashboard viewer session currently
    has on-screen (unsaved filter changes, unsaved widget tweaks) - there’s no browser
    session available to the server-side export code. Save the dashboard first if you want
    those reflected. The per-widget export buttons don’t have this limitation - they run
    against the widget’s live, on-screen state.
  • Whole-dashboard export uses generic row-header labels. With no live pivot table
    widget to query for row-axis captions in that path, every sheet’s row headers fall back
    to generic “Row 1”/“Row 2” labels rather than the dimension names a per-widget or
    Analyzer export shows.

License

MIT - see https://github.com/asinay/bi-export-plus/blob/master/LICENSE.

Last checked by moderator
03 Sep, 2026Works on IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2026.1 (Build 234U) Fri Mar 27 2026 14:07:14 EDT
Made with
Install
zpm install bi-export-plus download archive
Version
1.1.506 Sep, 2026
Ideas to the app
Category
Analytics
Works with
InterSystems IRIS BI
First published
31 Aug, 2026
Last edited
06 Sep, 2026