From 7e9092429b41263bc90666609ac8f1bbd06b2839 Mon Sep 17 00:00:00 2001 From: marianfoo <13335743+marianfoo@users.noreply.github.com> Date: Thu, 11 Jun 2026 16:19:12 +0200 Subject: [PATCH 1/2] =?UTF-8?q?docs(abap):=20Fiori=20Elements=20page=20?= =?UTF-8?q?=E2=80=94=20verified=20sample,=20UI5=201.135=20minimum,=20sharp?= =?UTF-8?q?ened=20758=20finding?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backed by a live test (S/4HANA 2023 / 758, SAPUI5 1.136, real FE app from the samples repo): - State the frontend floor explicitly: file upload as an action parameter is a Fiori Elements OData V4 feature added in SAPUI5 1.135. - Replace the conceptual DDLX sketch with the real, runnable metadata extension from the samples (ZSSI_C_S_ORD) and link the new app/demo-orders Fiori Elements app incl. the custom 'API channel' action. - Add a verified channel matrix: on 758 the native importUpload dialog renders (labels included) but the gateway rejects the inline stream payload on submit (parser error) — previously the docs implied only mime/filename auto-binding was missing. The base64 importExcel channel works end-to-end, incl. per-row BO messages in the FE result dialog. - Troubleshooting: add the parser-error symptom row. Co-Authored-By: Claude Opus 4.8 --- docs/abap/fiori-elements.md | 103 +++++++++++++++++++++++------------ docs/abap/troubleshooting.md | 1 + 2 files changed, 70 insertions(+), 34 deletions(-) diff --git a/docs/abap/fiori-elements.md b/docs/abap/fiori-elements.md index 94de8fb..b7eb644 100644 --- a/docs/abap/fiori-elements.md +++ b/docs/abap/fiori-elements.md @@ -59,58 +59,93 @@ call). largeObject); the user picks the file and the rows import. The action is surfaced on the list report / object page through a **metadata extension** (see below). + !!! note "Frontend requirement: SAPUI5 ≥ 1.135" + File upload as an action parameter is a Fiori Elements (OData V4) feature **added in + SAPUI5 1.135** (April 2025). Older UI5 versions render the `FileContent` parameter as a + plain field. Backend requirement: see the release matrix below. + **Option fields** (on both parameters): `IsCsv` force CSV (else magic‑byte auto‑detect) · `IsDraft` create drafts · `ChunkSize` rows/LUW (0 = default 500) · `DecimalSeparator` `'.'`/`','` · `HeaderRow` 1‑based header row. See [Options & data types](options.md). ## Surfacing the action in Fiori Elements (metadata extension) -In a Fiori Elements app the import action becomes a **button in the table toolbar** (and the upload -parameter renders a file picker) via a CDS **metadata extension** (DDLX) on your projection view — no -custom UI code. Conceptually: +In a Fiori Elements app the import action becomes a **button in the table toolbar** via a CDS +**metadata extension** (DDLX) on your projection view — no custom UI code. This is the (verified, +runnable) annotation from the samples' demo BO: ```abap @Metadata.layer: #CORE -annotate entity ZC_YourProjection with +@UI: { + headerInfo: { typeName: 'Demo Order', typeNamePlural: 'Demo Orders', + title: { type: #STANDARD, value: 'OrderId' } } +} +annotate view ZSSI_C_S_ORD with { - @UI.lineItem: [ { position: 10 } ] // a column … - YourField; + // the #FOR_ACTION line items put the import buttons in the table toolbar + @UI: { lineItem: [ { position: 10, importance: #HIGH }, + { type: #FOR_ACTION, dataAction: 'importUpload', label: 'Import Spreadsheet (File Upload)' }, + { type: #FOR_ACTION, dataAction: 'importExcel', label: 'Import Spreadsheet (Base64)' } ], + identification: [ { position: 10 }, + { type: #FOR_ACTION, dataAction: 'importUpload', label: 'Import Spreadsheet (File Upload)' } ], + selectionField: [ { position: 10 } ] } + OrderId; + + @UI: { lineItem: [ { position: 20 } ], identification: [ { position: 20 } ] } + Customer; } - -// the action on the entity's toolbar: -@UI: { lineItem: [ { type: #FOR_ACTION, dataAction: 'importUpload', label: 'Import Excel' } ], - identification: [ { type: #FOR_ACTION, dataAction: 'importUpload', label: 'Import Excel' } ] } ``` -!!! info "A complete, runnable example is in the samples" - The [samples repo](https://github.com/spreadsheetimporter/abap-spreadsheetimporter-samples) wires the - demo BO end‑to‑end for Fiori Elements — projection view, behaviour projection, service definition, - OData V4 UI service binding, and the metadata extension that puts the import button on the list - report — so you can build a Fiori Elements app on top and upload Excel files. The exact objects + - DDLX are shown here once published. - -## The 758 on‑prem Fiori upload caveat +The full stack around it: projection view (`@Metadata.allowExtensions: true`, provider contract +`transactional_query`) → behavior projection (`use action importExcel; use action importUpload; +use function getCreateTemplate;`) → service definition → OData V4 UI service binding. -On **S/4HANA 2023 on‑prem**, the base64 **API channel is the universal, fully‑wired path**. The Fiori -`importUpload` control still renders a working `Edm.Stream` upload, but the mime‑type filter and file -name are not auto‑bound in the dialog — a confirmed **gateway framework‑version gap, not a modelling -bug**. The importer auto‑detects the file type from magic bytes regardless, so the import works either -way. +!!! info "A complete, runnable example is in the samples" + The [samples repo](https://github.com/spreadsheetimporter/abap-spreadsheetimporter-samples) ships the + whole thing — the wired demo BO (`ZSSI_R_S_ORD` + one‑line handlers), the projection stack with the + DDLX above, the published OData V4 service, **and a runnable Fiori Elements app** + (`app/demo-orders`) on top of it, including a custom "API channel" action + (`webapp/ext/ImportSpreadsheet.js`: file picker → base64 → `importExcel`) that works on every + supported release. + +## Which channel works where (verified) + +| | S/4HANA 2023 on‑prem (758) | BTP ABAP / S/4HANA Cloud (newer gateway) | +|---|---|---| +| **Native `importUpload` dialog** (needs SAPUI5 ≥ 1.135) | dialog **renders** — file‑upload control + the shipped field labels — but **submit fails**: the gateway cannot deserialize an inline `Edm.Stream` action parameter (`Parser error … while parsing an XML stream`) | ✅ works zero‑code (gateway emits the `Core.*` terms and accepts the stream payload) | +| **Base64 `importExcel`** — via API or an FE **custom action** | ✅ **works end‑to‑end** — verified live: per‑row BO messages (e.g. *"key value already in use"*) surface in the FE result dialog | ✅ works | + +So on 758 build the upload button as a small FE **custom action** that base64‑encodes the picked file +and calls `importExcel` (the sample's +[`ImportSpreadsheet.js`](https://github.com/spreadsheetimporter/abap-spreadsheetimporter-samples/blob/main/app/demo-orders/webapp/ext/ImportSpreadsheet.js) +is exactly that, ~60 lines). Keep `importUpload` modeled — it lights up with zero change once the +backend moves to a gateway that supports it. + +## The 758 on‑prem gateway gap (detail) + +On **S/4HANA 2023 on‑prem**, the base64 **API channel is the universal, fully‑wired path**. The native +Fiori upload is blocked by the gateway in two ways — both **framework‑version gaps, not modelling +bugs** (verified empirically against a live 758 system, from curl *and* from a real FE 1.136 app): + +1. `$metadata` carries **none** of the `Core.MediaType` / `Core.ContentDisposition` / + `Core.AcceptableMediaTypes` terms Fiori Elements uses to wire the mime filter and file name + (the `@EndUserText.label`s *do* arrive — the dialog fields are nicely labeled). +2. The action `POST` itself is rejected: the 758 gateway cannot deserialize an inline stream value in + the JSON action payload, in any representation (with/without `@odata.mediaContentType`, base64 or + base64url, OData 4.0 or 4.01 headers). ??? note "Why (the gateway detail)" `ZSSI_A_FILE` is modelled *verbatim* per SAP's documented "File Upload as an Action Parameter" recipe (`@Semantics.largeObject.mimeType/.fileName/.contentDispositionPreference:#INLINE` on `abap.rawstring`, - `@UI.hidden` on mime/filename). The live `$metadata` on 758 **does** render `FileContent` as - `Edm.Stream`, **but** the RAP→OData V4 gateway does **not** translate `@Semantics.largeObject` into the - `Core.MediaType` / `Core.ContentDisposition` / `Core.IsMediaType` / `Core.AcceptableMediaTypes` terms - that Fiori Elements needs to wire the mime filter and file name. The 758 `$metadata` carries **zero** of - those `Core.*` terms on the action‑parameter ComplexType. - - This translation is done by the gateway metadata generator on SAP BTP ABAP / S/4HANA Cloud (and newer - on‑prem gateway SPs); it is not expressible via DDLX, a raw `@Core.*` passthrough, or a SRVD - annotation — the only on‑prem path is a gateway SP/note upgrade. Because the modelling already matches - SAP's recipe byte‑for‑byte, the dialog **auto‑wires on Cloud / a newer on‑prem gateway with zero change** - to this component. + `@UI.hidden` on mime/filename, `acceptableMimeTypes`). The live `$metadata` on 758 **does** render + `FileContent` as `Edm.Stream` (which is why the 1.135+ dialog shows the upload control), **but** the + RAP→OData V4 gateway does **not** translate `@Semantics.largeObject` into the `Core.*` terms, and its + JSON deserializer predates inline stream values in action payloads. + + Neither half is expressible via DDLX, a raw `@Core.*` passthrough, or a SRVD annotation — the only + on‑prem path is a gateway SP/note upgrade. Because the modelling already matches SAP's recipe + byte‑for‑byte, the dialog **auto‑wires on Cloud / a newer on‑prem gateway with zero change** to this + component. ??? note "C1 API release (only for cross‑software‑component consumption on Cloud)" The "use of non‑released API" ATC finding only fires when a *restricted* (ABAP for Cloud Development) diff --git a/docs/abap/troubleshooting.md b/docs/abap/troubleshooting.md index 0f561b1..c70c3bc 100644 --- a/docs/abap/troubleshooting.md +++ b/docs/abap/troubleshooting.md @@ -14,6 +14,7 @@ | Drafts created as active rows | No draft adapter registered for the BO | Generate + register a draft adapter — the generic engine is active‑only | | Big file slow / memory | XCO holds the workbook in memory; one huge commit | Lower `rowThreshold`, tune `chunk_size`; consider splitting the file | | `COMMIT ENTITIES is not allowed with this status` dump | You called the engine from inside a RAP action/handler | The engine owns the commit — call it from your own job/controller (or set `defer_commit` so the framework commits at request end); the upload action must only *store* the file | +| Fiori `importUpload` dialog: `Parser error … while parsing an XML stream` on submit | S/4HANA 2023 (758) gateway can't deserialize an inline `Edm.Stream` action parameter | Use the base64 `importExcel` channel (e.g. an FE custom action) on 758; the native dialog works on BTP ABAP / S/4HANA Cloud — see [Fiori Elements & file upload](fiori-elements.md#which-channel-works-where-verified) | | Upload "succeeds", row has empty fields | A typed `CREATE FROM` without `%control` | Use `CREATE FIELDS ( … ) WITH` (auto‑sets control); the shipped handler / `fill_line` already do | ## Behaviour worth knowing From a5bef13b2ddd8b5a3accf492f1cccb523db62d2d Mon Sep 17 00:00:00 2001 From: marianfoo <13335743+marianfoo@users.noreply.github.com> Date: Fri, 10 Jul 2026 10:05:56 +0200 Subject: [PATCH 2/2] docs: correctness fixes from a full docs audit (ABAP + UI5) Every fix was cross-checked against the current source in a verify pass; the same ABAP-page fixes were applied to the library repo (source of truth) so the two copies stay consistent. ABAP pages: - public-api-contract: ZCL_SSI_PARSER's public utility is convexit_of, not the private resolve_field; gc_comp is not in ZIF_SSI_TYPES (internal ZCL_SSI_UTIL); no generated adapter (flat/deep/upsert) runs coerce_field/on_before_persist. - integration-guide: generate_deep is active-create only, so it does not set %is_draft (only flat/upsert do); is_draft is ignored on the deep path. - extension-hooks: engine runs only coerce_field + on_before_persist; the other three hooks live in the facade; no generated adapter runs the two today. - usage-cookbook: build_create_template returns an empty xstring for an unknown entity, it does not raise cx_static_check. - troubleshooting: dates must be text YYYYMMDD / YYYY-MM-DD (optional Txx); any other order or trailing junk fails closed (msg 002, row dropped), never stored corrupt. UI5 pages: - spreadsheetdownload: setDraftStatus and showOptions default to true (source + the page's own prose), the tables said false. - Wizard: the "openWizard with Options" sample now compiles (async) and calls this.spreadsheetUpload (was an undefined oComponent). - Configuration: repaired the corrupted nullMarker table row; directUploadConfig example uses useCsrf (not csrf) and drops the non-existent uploadTimeout. - HowItWorks: the table-count error triggers at more than ONE table (not two). - Checks: Nullable-Field check is available since 2.4.0 (was "[Next Release]"). - NullHandling: fixed a prose reference to a non-existent Phone column. - APIReference: "UI5 application" (was "UI Builder application"). - Events: closed an unclosed backtick on the MessageType link. Verified: mkdocs build --strict passes. Co-Authored-By: Claude Opus 4.8 --- docs/abap/extension-hooks.md | 9 +++++---- docs/abap/integration-guide.md | 4 +++- docs/abap/public-api-contract.md | 6 +++--- docs/abap/troubleshooting.md | 2 +- docs/abap/usage-cookbook.md | 2 +- docs/ui5/pages/APIReference.md | 2 +- docs/ui5/pages/Checks.md | 2 +- docs/ui5/pages/Configuration.md | 5 ++--- docs/ui5/pages/Events.md | 2 +- docs/ui5/pages/HowItWorks.md | 2 +- docs/ui5/pages/NullHandling.md | 2 +- docs/ui5/pages/Wizard.md | 8 ++++---- docs/ui5/pages/spreadsheetdownload.md | 4 ++-- 13 files changed, 26 insertions(+), 24 deletions(-) diff --git a/docs/abap/extension-hooks.md b/docs/abap/extension-hooks.md index a00d297..a75655b 100644 --- a/docs/abap/extension-hooks.md +++ b/docs/abap/extension-hooks.md @@ -48,10 +48,11 @@ ENDMETHOD. turns a thrown exception into an `E` message, so the never‑raises contract still holds. - A **wrong‑typed** `hooks` object (one that does not implement `ZIF_SSI_HOOKS`) **fails the import closed** — configured hooks are never silently skipped. -- **Coverage:** all five hooks run on the **generic engine** (flat active create) and the facade. A - generated **deep/draft/upsert adapter** runs `coerce_field` / `on_before_persist` only when - regenerated with a hook‑aware `ZCL_SSI_ADAPTER_GEN` (`on_rows_parsed` / `on_message` / `on_completed` - always run — they sit in the facade). +- **Coverage:** the **generic engine** runs `coerce_field` / `on_before_persist` only; `on_rows_parsed` + / `on_message` / `on_completed` run in the **facade** (`zcl_ssi_import`) — so a direct + `get_importer->import` call gets only the two engine hooks. **No** generated adapter — flat, deep, or + upsert — runs `coerce_field` / `on_before_persist` today; that would require regenerating with a + hook‑aware `ZCL_SSI_ADAPTER_GEN`. Full reference + a runnable example: the [public API contract](public-api-contract.md#extension-hooks-zif_ssi_hooks) and the diff --git a/docs/abap/integration-guide.md b/docs/abap/integration-guide.md index 8c6b54d..5d592b1 100644 --- a/docs/abap/integration-guide.md +++ b/docs/abap/integration-guide.md @@ -55,7 +55,9 @@ ENDINTERFACE. iv_assoc = '_Items' iv_child_alias = 'Item' iv_parent_key = 'ROOTKEY' ). ``` Create that class in your package (~50 lines of typed EML that fills the create lines via - `ZCL_SSI_UTIL=>fill_line`, sets `%is_draft`, and returns the result). + `ZCL_SSI_UTIL=>fill_line` and returns the result). The **flat** and **upsert** generators set + `%is_draft` when `is_options-is_draft = abap_true`; `generate_deep` emits **ACTIVE‑CREATE only** + (draft + deep/composition is out of scope), so `is_draft` is ignored on the deep path. 2. **Register** it once at startup so the factory routes your BO to it: ```abap diff --git a/docs/abap/public-api-contract.md b/docs/abap/public-api-contract.md index 4d002bf..0e71b9c 100644 --- a/docs/abap/public-api-contract.md +++ b/docs/abap/public-api-contract.md @@ -37,7 +37,7 @@ Every public API below has a **runnable, copy‑pasteable example**, each proven | Object | Role | How a consumer uses it | |---|---|---| -| **`ZIF_SSI_TYPES`** | Shared types: `ts_options` (incl. `mode`, `hooks`), `ts_row`/`ts_cell`, `ts_result`/`ts_message`/`ts_key`, `tt_map`, the `gc_mode`/`gc_comp` enums | Reference the types in your own code | +| **`ZIF_SSI_TYPES`** | Shared types: `ts_options` (incl. `mode`, `hooks`), `ts_row`/`ts_cell`, `ts_result`/`ts_message`/`ts_key`, `tt_map`, the `gc_mode` enum | Reference the types in your own code | | **`ZIF_SSI_IMPORTER`** | The `import( it_rows is_options ) RETURNING rs_result` contract | The seam to **mock** the library (see [`test doubles`](#testing-against-the-library)) | | **`ZIF_SSI_HOOKS`** | Optional developer **extension hooks** — `on_rows_parsed` / `coerce_field` / `on_before_persist` / `on_message` / `on_completed` (all `DEFAULT IGNORE`) | Implement the ones you need; inject via `ts_options-hooks` (see [Extension hooks](#extension-hooks-zif_ssi_hooks)) | | **`ZCL_SSI_IMPORT`** | Facade — `import_file` (auto-detect xlsx/CSV) / `import_rows`. **Never raises** (errors → `ts_message`) | The simplest entry point | @@ -46,7 +46,7 @@ Every public API below has a **runnable, copy‑pasteable example**, each proven | **`ZCL_SSI_TEMPLATE`** | `build_create_template( iv_entity, iv_sample_rows, it_mapping )` | Generate an `.xlsx` CREATE template | | **`ZCL_SSI_ADAPTER_GEN`** | Code generators: `generate_flat` / `generate_deep` / `generate_upsert` / `generate_action` / `generate_template_function` | You **run** these to emit a typed adapter for your BO | | **`ZCL_SSI_FACTORY`** | `register( iv_entity, iv_class )` — register your adapter | Wire a generated adapter for an entity | -| **`ZCL_SSI_PARSER`** | `parse_xlsx` / `parse_csv` / `coerce` / `resolve_field` — stateless parsing utilities (`parse_xlsx` raises `zcx_ssi_parse`, see [Exceptions](#exceptions)) | Advanced/standalone parsing | +| **`ZCL_SSI_PARSER`** | `parse_xlsx` / `parse_csv` / `coerce` / `convexit_of` — stateless parsing utilities (`parse_xlsx` raises `zcx_ssi_parse`, see [Exceptions](#exceptions)) | Advanced/standalone parsing | | **Abstract & custom entities** — `ZSSI_A_IMPORT` · `ZSSI_A_IMPORT_FILE` · `ZSSI_A_FILE` · `ZSSI_A_RESULT` · `ZSSI_A_TEMPLATE` · `ZSSI_A_TFILE` · `ZSSI_C_TEMPLATE` | The action/function parameter & result shapes | Reference them in your BDEF `action`/`function` signatures | | **`ZSSI_IMPORTER`** (message class) | The translatable messages | Surfaced in `ts_message`; reference numbers if you map them | @@ -90,7 +90,7 @@ one‑line RAP delegate, inject hooks via the optional `is_options`: `%param` format fields override the base where supplied. Calling the importer **directly** (`zcl_ssi_factory=>get_importer` → `import`) bypasses the facade, so only the engine‑level hooks run there. `coerce_field` and `on_before_persist` are live on the **generic engine** (flat active -create); a generated **deep/draft/upsert adapter** gets them once regenerated with a `ZCL_SSI_ADAPTER_GEN` +create); no generated adapter (**flat, deep or upsert**) runs them today — an adapter gets them once regenerated with a `ZCL_SSI_ADAPTER_GEN` version that emits the calls (follow‑on). On the engine path `on_before_persist`'s instances table is anonymous (RTTC‑built) — navigate it with `ASSIGN COMPONENT` (incl. the `%CONTROL` flags) and mutate **in place**; a typed adapter passes its typed table. Worked examples: `ZCL_SSI_UNIT_HOOKS` (the library's own hook tests) and diff --git a/docs/abap/troubleshooting.md b/docs/abap/troubleshooting.md index c70c3bc..1de99da 100644 --- a/docs/abap/troubleshooting.md +++ b/docs/abap/troubleshooting.md @@ -9,7 +9,7 @@ | Opaque short dump on import | Lower‑case `entity_name`/`sub_name` in the dynamic EML | The component upper‑cases them; if you pass a BO/association name, give it uppercase | | Your validations don't run | `IN LOCAL MODE` was used (bypasses validations/auth/prechecks) | The component calls EML **non‑local** against your BO; don't enable a "local/privileged" mode unless you mean to | | Determination loops / times out | Your determination issues `MODIFY` that re‑triggers itself | Guard your determination (don't re‑modify the trigger field set); not a component issue | -| Dates all blank / wrong | Native Excel date cells or wrong format | Use **text** dates in the template (see [Options & data types](options.md)) | +| Dates all blank / wrong | Dates must be **text** in `YYYYMMDD` or `YYYY‑MM‑DD` form (an optional `Txx` time suffix is stripped); any other order (e.g. `31.12.2024`) or trailing junk is rejected | Fails **closed** with a per‑row conversion error (msg `002`, severity `E`) and the row is dropped — the value is never silently stored corrupt. Only calendar‑**range** checks apply (month `01`‑`12`, day `01`‑`31`), so an impossible date like Feb‑30 still passes and stores as‑is. See [Options & data types](options.md) | | Number‑range error `BEHAVIOR_ILLEGAL_STATEMENT` | Your BO's custom number range does its own `COMMIT WORK` | Set the number‑range object to **main‑memory buffering** | | Drafts created as active rows | No draft adapter registered for the BO | Generate + register a draft adapter — the generic engine is active‑only | | Big file slow / memory | XCO holds the workbook in memory; one huge commit | Lower `rowThreshold`, tune `chunk_size`; consider splitting the file | diff --git a/docs/abap/usage-cookbook.md b/docs/abap/usage-cookbook.md index 80f5313..1ac9134 100644 --- a/docs/abap/usage-cookbook.md +++ b/docs/abap/usage-cookbook.md @@ -57,7 +57,7 @@ zcl_ssi_parser=>coerce( ```abap " .xlsx whose header row = the importer's accepted fields, so the filled file -" re-imports with zero config. Raises cx_static_check for an unknown entity. +" re-imports with zero config. Returns an empty xstring for an unknown entity / one with no importable fields (never raises); check xstrlen( ) > 0. DATA(lv_xlsx) = zcl_ssi_template=>build_create_template( iv_entity = 'ZSSI_R_S_ORD' iv_sample_rows = 1 ). " xstrlen( lv_xlsx ) > 0 -> a valid .xlsx diff --git a/docs/ui5/pages/APIReference.md b/docs/ui5/pages/APIReference.md index 52f8be4..88ee833 100644 --- a/docs/ui5/pages/APIReference.md +++ b/docs/ui5/pages/APIReference.md @@ -2,7 +2,7 @@ ### Overview -The `spreadsheetimporter` component provides a way to import data from a spreadsheet into a table in the UI Builder application. +The `spreadsheetimporter` component provides a way to import data from a spreadsheet into a table in the UI5 application. ### Constructor diff --git a/docs/ui5/pages/Checks.md b/docs/ui5/pages/Checks.md index 604c889..ff38db5 100644 --- a/docs/ui5/pages/Checks.md +++ b/docs/ui5/pages/Checks.md @@ -20,4 +20,4 @@ The following types of errors are handled by the UI5 Spreadsheet Upload Control: - **Empty Headers** _(Available since: 1.2.0)_: The control checks if the uploaded spreadsheet contains empty headers (columns labeled "**EMPTY", "**EMPTY_1", etc.). These typically occur when Excel adds empty columns during import. When an empty header is detected, the control displays a warning message indicating the presence of empty columns and providing guidance on the expected start position for data. This check helps ensure data is properly aligned with column headers, especially when using custom start coordinates. This check can be disabled using the `skipEmptyHeadersCheck` configuration option. -- **Nullable Field Violations** _(Available since: [Next Release])_: The control validates null values against OData metadata. When you use the `__NULL__` marker in a cell to explicitly set a field to NULL, the component checks the field's Nullable attribute in the OData metadata. If the field is non-nullable (Nullable="false"), an error is displayed. This validation ensures data integrity and prevents backend errors. Key fields and mandatory fields are typically non-nullable. See [Null & Empty Value Handling](NullHandling.md) for comprehensive guide. +- **Nullable Field Violations** _(Available since: 2.4.0)_: The control validates null values against OData metadata. When you use the `__NULL__` marker in a cell to explicitly set a field to NULL, the component checks the field's Nullable attribute in the OData metadata. If the field is non-nullable (Nullable="false"), an error is displayed. This validation ensures data integrity and prevents backend errors. Key fields and mandatory fields are typically non-nullable. See [Null & Empty Value Handling](NullHandling.md) for comprehensive guide. diff --git a/docs/ui5/pages/Configuration.md b/docs/ui5/pages/Configuration.md index aa71fde..6de5624 100644 --- a/docs/ui5/pages/Configuration.md +++ b/docs/ui5/pages/Configuration.md @@ -37,7 +37,7 @@ The table below summarizes the options available for the UI5 Spreadsheet Importe | [`batchSize`](#batchsize) | Controls the size of batches sent to the backend. | `1000` | 0.11.0 | `number` | | [`strict`](#strict) | Controls availability of the "Continue" button in error dialogs. | `false` | 0.16.0 | `boolean` | | [`decimalSeparator`](#decimalseparator) | Sets the decimal separator for numbers. | Browser default | 0.17.0 | `string` | -| docs: | [`nullMarker`](#nullmarker) | Marker string for NULL values in Excel cells. | `'__NULL__'` | 2.4.0 | `string` | +| [`nullMarker`](#nullmarker) | Marker string for NULL values in Excel cells. | `'__NULL__'` | 2.4.0 | `string` | | [`emptyStringMarker`](#emptystringmarker) | Marker string for empty strings (text fields only). | `'__EMPTY__'` | 2.4.0 | `string` | | [`mandatoryFields`](#mandatoryfields) | Specifies mandatory fields to check in the spreadsheet. | Not defined | 0.15.0 | `string[]` | | [`skipMandatoryFieldCheck`](#skipmandatoryfieldcheck) | Skips the check for mandatory fields. | `false` | 0.17.0 | `boolean` | @@ -96,8 +96,7 @@ The `directUploadConfig` option enables direct file upload to a CAP backend usin useCdsPlugin: true, localhostSupport: true, localhostPort: 4004, - csrf: true, - uploadTimeout: 30000 + useCsrf: true }, componentContainerData:{ buttonText:'Excel Upload with CDS Plugin', diff --git a/docs/ui5/pages/Events.md b/docs/ui5/pages/Events.md index 28b9454..3ef565c 100644 --- a/docs/ui5/pages/Events.md +++ b/docs/ui5/pages/Events.md @@ -76,7 +76,7 @@ You can add errors to the `messages` property of the `SpreadsheetUpload` control - `row` - the row number of the error - `group` - set to `true` or `false` to group the errors by title - `rawValue` - the raw value of the data from the spreadsheet -- `ui5type` - the type of the error, can be `Error`, `Warning`, `Success`, `Information` or `None` from the [`MessageType](https://ui5.sap.com/#/api/sap.ui.core.MessageType) enum +- `ui5type` - the type of the error, can be `Error`, `Warning`, `Success`, `Information` or `None` from the [`MessageType`](https://ui5.sap.com/#/api/sap.ui.core.MessageType) enum Errors with the same title will be grouped. diff --git a/docs/ui5/pages/HowItWorks.md b/docs/ui5/pages/HowItWorks.md index db59229..d137470 100644 --- a/docs/ui5/pages/HowItWorks.md +++ b/docs/ui5/pages/HowItWorks.md @@ -12,7 +12,7 @@ When the component is centrally deployed on an ABAP server, the setup is straigh ## Integration into UI5 Integrating the component is straightforward as long as the component has access to the context or the view, as without this access, it won't function. -Upon creation of the component, it searches for a table in the view to utilize the binding for the upload. Other necessary details, such as metadata and draft activation actions, are also derived from the table. If no table or more than two tables are found, the table must be defined in the options. +Upon creation of the component, it searches for a table in the view to utilize the binding for the upload. Other necessary details, such as metadata and draft activation actions, are also derived from the table. If no table or more than one table are found, the table must be defined in the options. ## Creating the Template File diff --git a/docs/ui5/pages/NullHandling.md b/docs/ui5/pages/NullHandling.md index 8a3e169..997f959 100644 --- a/docs/ui5/pages/NullHandling.md +++ b/docs/ui5/pages/NullHandling.md @@ -63,7 +63,7 @@ The component will send these requests to your backend: { "ID": "789", "email": "", "notes": null } ``` -Notice how empty cells in the Name and Phone columns don't appear in the JSON at all. This means those fields remain unchanged on the backend. +Notice how empty cells in the Name, Email, and Notes columns don't appear in the JSON at all. This means those fields remain unchanged on the backend. ## Validation Rules diff --git a/docs/ui5/pages/Wizard.md b/docs/ui5/pages/Wizard.md index e491755..c719035 100644 --- a/docs/ui5/pages/Wizard.md +++ b/docs/ui5/pages/Wizard.md @@ -115,7 +115,7 @@ openWizard: async function () { You can pass configuration options to override component settings: ```javascript -openWizard: function () { +openWizard: async function () { this.spreadsheetUpload = await this.getView() .getController() .getOwnerComponent() @@ -137,7 +137,7 @@ openWizard: function () { debug: true // Enable debug mode }; - oComponent.openWizard(wizardOptions) + this.spreadsheetUpload.openWizard(wizardOptions); } ``` @@ -147,13 +147,13 @@ The wizard supports all standard [events](Events.md): ```javascript // Attach events before opening wizard -oComponent.attachUploadButtonPress(function (event) { +this.spreadsheetUpload.attachUploadButtonPress(function (event) { // Handle upload completion const payload = event.getParameter('payload'); console.log('Data uploaded:', payload); }); -oComponent.attachCheckBeforeRead(function (event) { +this.spreadsheetUpload.attachCheckBeforeRead(function (event) { // Validate data before processing const sheetData = event.getParameter('sheetData'); // Add custom validation logic diff --git a/docs/ui5/pages/spreadsheetdownload.md b/docs/ui5/pages/spreadsheetdownload.md index fccc0c3..613bdec 100644 --- a/docs/ui5/pages/spreadsheetdownload.md +++ b/docs/ui5/pages/spreadsheetdownload.md @@ -24,11 +24,11 @@ This means that you can download all Orders, including the OrderItems, ShippingI | Option | Description | Default | Type | | ----------------- | ----------------------------------------------- | ----------- | --------------- | | `addKeysToExport` | Adds keys to the export file | `false` | boolean | -| `setDraftStatus` | Sets the draft status in `IsActiveEntity` | `false` | boolean | +| `setDraftStatus` | Sets the draft status in `IsActiveEntity` | `true` | boolean | | `filename` | Defines the filename for the export file | Entity Name | string | | `deepExport` | Turn on to export of sibling entities | `false` | boolean | | `deepLevel` | Defines the level of sibling entities to export | `0` | number | -| `showOptions` | Shows options dialog for users | `false` | boolean | +| `showOptions` | Shows options dialog for users | `true` | boolean | | `columns` | Defines the columns to export | `{}` | object or array | ### Sample Usage