diff --git a/.claude/commands/upgrade-wijmo-version.md b/.claude/commands/upgrade-wijmo-version.md new file mode 100644 index 000000000..687f9b431 --- /dev/null +++ b/.claude/commands/upgrade-wijmo-version.md @@ -0,0 +1,18 @@ +--- +description: Upgrade Wijmo to a new build for the Reactive Data Grid, end to end — assets, OutSystems module refresh, ADR, Confluence, Jira, draft PR. +argument-hint: '[TASK_ID] [ARCHIVE_PATH]' +--- + +# Upgrade Wijmo Version + +Run the **`upgrade-wijmo-version` skill** (`.claude/skills/upgrade-wijmo-version/SKILL.md`) from its +Phase 0, passing the arguments below. + +| Argument | Required | Example | Notes | +| -------------- | -------- | -------------------------------- | -------------------------------------------------------------------------------------------------- | +| `TASK_ID` | Yes | `ROU-12860` | Jira task. Ask once if missing. The target build string and version description are read from it. | +| `ARCHIVE_PATH` | No | `C:/Downloads/wijmo-5.20261.52` | Extracted Wijmo distribution archive. If absent, the skill offers to download the ticket attachment. | + +The skill is the single source of truth for this procedure: the phase sequence, the safety +guardrails, the run-log format and the reference data all live there, and none of them are restated +here. Do not perform any upgrade step from this file. diff --git a/.claude/skills/upgrade-wijmo-version/SKILL.md b/.claude/skills/upgrade-wijmo-version/SKILL.md new file mode 100644 index 000000000..6b3d7ab24 --- /dev/null +++ b/.claude/skills/upgrade-wijmo-version/SKILL.md @@ -0,0 +1,712 @@ +--- +name: upgrade-wijmo-version +description: >- + Upgrades the Wijmo build behind the Reactive Data Grid end to end — distribution-archive gate, + vendored types and stylesheet, version constants, OutSystems module refresh via changeset, ADR and + run log, Confluence SBOM and record page, Jira enrichment, draft PR. Use when asked to update or + upgrade Wijmo, to adopt a new Wijmo build or release (e.g. "2026v1-Hotfix", "5.20261.52"), or when + running /upgrade-wijmo-version against a Wijmo upgrade ticket. +--- + +# Upgrade Wijmo Version + +The upgrade runbook for the **Reactive Data Grid**. Sixteen steps, numbered 0 to 14 with a gate at +8b, from the distribution archive through the draft PR to the documentation trail. Terms used here are fixed in +[`CONTEXT.md`](../../../CONTEXT.md) — *build string*, *version description*, *distribution archive*, +*vendored types*, *per-branch module*, *changeset*, *SBOM row*. + +This procedure covers more ground than ROU-12860's AC22 asked for. AC22 predates the discovery that +the OutSystems module must be refreshed before anything can be validated at all; phases 8, 8b and 9 +are that surplus, and it is deliberate. + +## When to Use + +- A ticket asks to update or upgrade Wijmo to a named build (`5.20261.52`) or release + (`2026v1-Hotfix`). +- A new Wijmo release should be adopted in this repository. +- A Wijmo asset in the `OutSystemsDataGrid` module has to be refreshed to match a build string. + +## When NOT to Use + +- The **Web Data Grid** (`outsystems-datagrid-web`, Traditional Web, its own much older build + string). Its assets, its module and its own SBOM row are outside this procedure entirely. +- Grid feature or bugfix work that leaves the Wijmo build string alone. +- Routine bumps of other dependencies, including dependabot PRs that do not touch `wijmo`. + +## Guardrails + +In force for the whole run, not only where a phase repeats them. + +**Staging and git** + +- Stage every path by name. `git add -A` is banned in this repository. `specs/` is permanently + untracked here and is never staged; `.claude/settings.local.json` is never staged. +- Branch from an up-to-date `dev` and commit only on the task branch. +- Sign every commit (`git commit -S`). Confirm a signing key in Phase 1 and abort there if none is + configured. +- `package-lock.json` and `dist/**` are gitignored, so neither appears in the diff and CI resolves + dependencies fresh from `package.json` on every install. That is why the dependency is pinned + exactly, with no caret. + +**Vendored files** + +- Copy vendored files from the distribution archive; never author or hand-edit one. The archive is + the only source for all three asset classes — the global-flavor `.d.ts` set, the unminified + stylesheet, and the module's minified runtime. +- The npm package ships the ES-module `.d.ts` flavor and no `.min.js` at all. When the archive is + missing, stop and ask for it. Copying `node_modules/wijmo/*.d.ts` breaks the build; hand-converting + module-flavor definitions to global flavor is forbidden. +- Expect a SonarQube finding on a refreshed vendored stylesheet — the `5.20261.50` refresh produced + one, raised with the vendor as WJM-37650. Treat it as a consequence of replacing a vendored file + and raise it upstream. Leave the vendored file exactly as the archive shipped it. + +**Version tooling** + +- `gulp updateVersion` / `gtaSetVersion` builds its search strings from + `gulp/DefaultSpecs.js: info.version` and calls `String.replace` with no match assertion. It + silently no-ops on `README.md`, and on `Constants.ts` whenever `OSDataGridVersion` has drifted from + `DefaultSpecs`. Grep both files after running it; never assume either was updated. +- Compute the ADR number as the **lowest free number**, from the set actually present in + `ls docs/adr/` — not the highest plus one, and never a file count. Both wrong answers are live here: + the directory holds two files numbered `ADR-0005`, so counting is off by one; and a number can be + *reserved* by being skipped when a later ADR is authored first, so highest-plus-one orphans the gap + permanently. ROU-12860 hit exactly that — `ADR-0007` was left free for the upgrade while `ADR-0008` + recorded the automation. Check the `Readme.md` log too: a number can have a file and no row, or a + row and no file. + +**Module work** + +- `oml apply-changeset` reads an input and writes a separate output. Run it against a scratchpad copy + and never write to the module owner's file. +- `addOrReplace` is full-replace: every `spec` echoes back the object's complete queried metadata. An + omitted property is wiped and the object silently renamed. +- Read every `GlobalKey` and `Folder` from a live `oml query` on this run's module. Recorded knowledge + is object *names* and *shapes*; a hardcoded key targets the wrong object or nothing at all. +- Verify file sets **by name**. The archive also ships `wijmo.angular*`, `wijmo.react*` and + `wijmo.vue*` bundles, so a count-based assertion mismeasures while reporting success. +- Reconcile the live module inventory against + [`references/module-inventory.md`](references/module-inventory.md) before generating anything, and + stop on any mismatch. A differently-cloned module can carry a renamed script or a missing language, + and the generator would cover it quietly. +- `GridAuxFeature` and `JsZIP` stay untouched, and the changeset asserts their absence explicitly. + `JsZIP` stays pinned at its own version; if the archive ships a newer JSZip, raise it as its own + ticket rather than upgrading a shared dependency inside a Wijmo upgrade. +- A protected OML fails at load with `Load is not allowed for this module` — the platform refusing, + not the CLI failing. Request an unprotected export from the module owner; retrying achieves nothing. +- **The unprotected export is a working copy, not the publish artifact.** The module that actually + ships is the protected one, so publishing the unprotected export wholesale would strip its + protection and carry across every incidental difference between the two, not just the upgrade. The + refreshed changes go back by **merge onto the protected module**, so only the intended diff lands. + +**Validation** + +- This repository cannot render a grid. `npm run dev` serves a landing page that lists + `dist/GridFramework.js` and loads no Wijmo runtime. Every behavioural check runs against a published + OutSystems module. +- Capture the pre-upgrade baseline before the publish. It is unrecoverable afterwards, and the + comparative checks are the ones runs skip. A comparative check with no recorded baseline is + reported `UNVERIFIED`, never "unchanged". + +**Outward-facing actions** + +- Hard gates, each needing explicit confirmation: the module publish (Phase 8b), the Confluence + runbook rewrite (Phase 12), any push, PR creation, and undraft. +- No credentials at any point. The publish is manual, so never request, echo, log or persist a + credential or token, and never place one in a command-line argument. +- Address Confluence by **page ID** only. The space keys quoted in tickets are unreliable; the page + IDs are not. + +**Bookkeeping** + +- Every phase emits its run-log line, including the ones that did nothing. +- On a failed step: stop the phase, report, and ask. Improvised recovery around a broken phase is the + one outcome this procedure exists to prevent. +- **Continuous improvement.** When a run finds this file wrong, incomplete, or silent about a failure + mode, edit it — and its reference files — in the same run: symptom, root cause, verified fix. Stage + that edit with the upgrade. +- **After any such edit, re-read the file from disk.** The copy the harness injected when the skill + was invoked is a snapshot and does not refresh, so a run that keeps following the injected text + silently ignores its own correction. The file on disk is authoritative. + +## Run Log + +One line per phase, emitted as the phase closes and appended to the upgrade's ADR in Phase 10: + +``` +Phase +``` + +| State | Meaning | +| ------------ | ----------------------------------------------------------------------------------- | +| `EXECUTED` | The exit assertion passed against evidence produced on this run. | +| `GATED` | Stopped at a hard gate awaiting a human. Name who was asked and for what. | +| `PARTIAL` | Some exit assertions passed, others did not. Name which, individually. | +| `SKIPPED` | Not run. State why, and who owns it now. | +| `UNVERIFIED` | Ran, but the evidence needed to judge the result does not exist. | + +The four non-`EXECUTED` states are the point of the log: they keep a skipped or vacuous phase visible +instead of letting a successful upgrade absorb it. Each one carries a reason and an owner by Phase 14. + +## Reference Files + +| File | Holds | +| ---------------------------------------------------------------- | --------------------------------------------------------------------------- | +| [`module-inventory.md`](references/module-inventory.md) | The 66 module objects by name and shape, and the two that are never touched. | +| [`changeset-recipe.md`](references/changeset-recipe.md) | The undocumented changeset schema, its three traps, and the validation gate. | +| [`workaround-inventory.md`](references/workaround-inventory.md) | The 6 Wijmo workaround sites — two of which no keyword grep finds. | +| [`confluence-and-jira.md`](references/confluence-and-jira.md) | Page IDs, SBOM rules, the child-page template, the Jira block shape. | + +--- + +## Phase 0 — Arguments + +**Entry**: invoked with zero to two positional arguments. + +- `TASK_ID` is required. Validate against `[A-Z][A-Z0-9]*-\d+`; ask once if missing. +- **Derive** the build string and the version description from the ticket rather than asking. Read + the ticket summary and description: `[DataGrid] - Update version - release 2026v1-Hotfix - Build + 5.20261.52` yields build string `5.20261.52` and version description + `2026v1-Hotfix Wijmo - Build 5.20261.52` — the ` Wijmo - Build ` shape + every predecessor used. Echo both and get confirmation before using either. +- `ARCHIVE_PATH` is optional. If absent, offer to download the ticket's `wijmo-.zip` + attachment (~165 MB) and ask before starting the download. +- Consistency: the build inside the version description equals the build string, and + `npm view wijmo@ version` resolves to that same build. + +**Exit**: `TASK_ID` valid; the build string and version description each quote the **ticket text they +were read from**, and the operator confirmed them; npm resolves; the archive path is known or the +download is agreed. Values the operator supplied instead of the ticket are marked as such — a value +that was asked for was not derived, and Phase 5 writes it into a shipped constant. + +**Log**: the four resolved values, each with its provenance. + +## Phase 1 — Prerequisites + +**Entry**: Phase 0 closed. + +Report anything missing rather than working around it: + +- `git`; `gh auth status` authenticated; `node` / `npm` (`package.json` pins the toolchain through + `volta`). +- Signed commits: `git config user.signingkey` and `git config commit.gpgsign`. **No key ⇒ abort + here**, before anything is edited. +- `dotnet --version` reports 8 or above. +- An `OutSystems.Cli` checkout. **Resolve its location; never assume one.** Nothing guarantees the + operator has it, or has it where a previous run did, so take the first hit of: + + 1. `$OUTSYSTEMS_CLI` or `$OUTSYSTEMS_CLI_HOME`, if either is already set in the environment; + 2. a directory named `OutSystems.Cli` **beside this repository's own checkout** — resolve the + parent from `git rev-parse --show-toplevel` rather than writing an absolute path; + 3. otherwise **ask the operator for the path** and stop until they answer. If they have no + checkout, it is cloned from `https://github.com/OutSystems/OutSystems.Cli` — a full clone with + LFS objects, which is a several-minute step and their call to make, not this run's. + + Verify the resolved directory is a real checkout (`$OUTSYSTEMS_CLI/src/OutSystems.AI.Cli` exists) + before accepting it, then **export it as `OUTSYSTEMS_CLI` for the rest of the run**. Every `oml` + command in this skill and its reference files is written against that variable; a literal path + pasted into a command is a defect, because it silently binds the procedure to one machine. + + Then check the checkout is **non-shallow** (`git rev-parse --is-shallow-repository` → `false`; + `git fetch --unshallow` first, because Nerdbank.GitVersioning rejects shallow clones), that its LFS + objects are **real rather than pointer stubs** (`git lfs ls-files` lists them and their on-disk + sizes are not ~130 B), and that it builds: + `dotnet build "$OUTSYSTEMS_CLI/src/OutSystems.AI.Cli/OutSystems.AI.Cli.csproj" -c Release`. + +**Exit**: every check reports a version or an explicit OK. `OUTSYSTEMS_CLI` points at a verified +checkout. Nothing is deferred to "later in the run". + +**Log**: the tool versions, the resolved `OUTSYSTEMS_CLI` path **and which of the three rules resolved +it**, and the CLI build result. + +## Phase 2 — Asset-source gate + +**Entry**: Phase 1 green. Nothing in the repository has been edited yet — and nothing is, until this +phase passes. + +The archive is the only source (see the vendored-files guardrails). Extract into the scratchpad only. + +**Layout, measured on `5.20261.52`.** The zip contains a single top-level `wijmo-/` +directory, so `$A` below is that inner directory, not the extraction target. Under it, the files this +procedure needs sit in **three** places, not one: + +| Needed | Archive path | +| ----------------------------------------- | ------------------------------- | +| 45 of the 47 vendored root `.d.ts`, all `.min.js`, `cultures/` | `$A/Dist/controls` | +| `wijmo.meta.d.ts` — global flavor | `$A/Dist/interop/meta` | +| unminified `wijmo.css` | `$A/Dist/styles` | + +`wijmo.interop.grid.d.ts` is the 47th and is **not in the archive in global flavor at all** — only +under `NpmImages/*`, in the same ES-module flavor npm ships. See Phase 4 step 3. + +**`unzip`'s `*` does not cross `/`** on Git Bash, so `"$A/Dist/controls/*"` silently omits +`cultures/`. Name each subdirectory explicitly: + +```bash +unzip -q -o "$Z" "wijmo-/Dist/controls/*" "wijmo-/Dist/controls/cultures/*" \ + "wijmo-/Dist/interop/meta/*" "wijmo-/Dist/styles/*" +``` + +Verify all three asset classes, **by name**, using the lists in +[`references/module-inventory.md`](references/module-inventory.md): + +```bash +A="/wijmo-" # the versioned dir INSIDE the zip +V=src/@types/wijmo- # the set currently vendored + +grep -rl "declare module wijmo" "$A/Dist/controls" | wc -l # global flavor, many files +grep -rl "^import .* from 'wijmo/" "$A/Dist/controls" | grep -v interop | wc -l # 0: no ES flavor + +# every vendored root .d.ts is accounted for, against the UNION of its three sources. +# One-way, because the archive ships far more than we vendor. This, not the count above, +# is the real global-flavor gate — and it must come back EMPTY, with no lines to +# "learn to ignore". +comm -23 <(ls -1 "$V"/*.d.ts | xargs -n1 basename | sort) \ + <( { ls -1 "$A/Dist/controls"/*.d.ts + ls -1 "$A/Dist/interop/meta"/*.d.ts + ls -1 node_modules/wijmo/wijmo.interop.grid.d.ts; } \ + | xargs -n1 basename | sort -u ) + +wc -l "$A/Dist/styles/wijmo.css" # thousands of lines, not ~13 (unminified) + +# the 13 runtime bundles, by name. Echo the count checked so the loop cannot pass +# silently on a short list. +NAMES="" +for f in $NAMES; do + test -f "$A/Dist/controls/$f.min.js" || echo "MISSING: $f.min.js" +done +echo "names checked: $(echo $NAMES | wc -w)" # must be 13 + +# the release's new properties are declared in the ARCHIVE's own types, not only in npm's +grep -n "" "$A/Dist/controls/wijmo.grid.d.ts" + +# culture-language parity, both directions — must print nothing +comm -3 <(ls -1 "$V"/cultures/*.d.ts | xargs -n1 basename \ + | sed 's/wijmo\.culture\.//; s/\.d\.ts//' | sort) \ + <(ls -1 "$A/Dist/controls/cultures"/*.min.js | xargs -n1 basename \ + | sed 's/wijmo\.culture\.//; s/\.min\.js//' | sort) + +find "$A" -iname "*jszip*" | head # does the archive carry its own JSZip? +``` + +**Exit**: 13 runtime names checked and all located; the vendored root `.d.ts` diff empty; both culture +diffs empty; the unminified stylesheet found; every new property the ticket names declared in the +archive's own `.d.ts`; the JSZip question answered either way. Any gap stops the run and escalates to +the ticket reporter. + +**Log**: the three asset classes with the assertion that located each, the property declarations +confirmed, plus the JSZip answer. + +## Phase 3 — Branch + +**Entry**: Phase 2 green. + +`git fetch origin`, then create `` from `origin/dev`. Never commit on `dev`. + +**Exit**: `git rev-parse --abbrev-ref HEAD` is ``, and its merge-base is the current +`origin/dev`. + +**Log**: branch name and base commit. + +## Phase 4 — Dependency and vendored assets + +**Entry**: Phase 3 green. + +1. `npm install wijmo@ --save-exact --save-dev` — exact, no caret. Then + `rm -rf node_modules && npm install` and read the installed manifest back. On Windows `npm install` + can die with a libuv assertion leaving `node_modules` empty: rerun and re-verify the printed + version. +2. Create `src/@types/wijmo-/` from the archive, copying **only what is currently + vendored** — the same root `.d.ts` set plus `cultures/`, not the whole archive. The root set comes + from **two** archive directories: `Dist/controls` for 45 of them, and `Dist/interop/meta` for + `wijmo.meta.d.ts`. Copying only from `Dist/controls` drops `wijmo.meta.d.ts` and breaks the + entry-set parity. Remove the old directory with `git rm` so the rename is reviewable. +3. `wijmo.interop.grid.d.ts` — the 47th root file, and the exception. **The archive carries no + global-flavor copy**: its only copies live under `NpmImages/*` in the same ES-module flavor as npm. + So take `node_modules/wijmo/wijmo.interop.grid.d.ts`, verbatim, no hand edits, and record in the + ADR that it stays ES-module flavor. That is not a defect: a `.d.ts` with top-level + `import`/`export` is a module, contributes no globals, and this file is referenced nowhere in + `src/` — it compiles and goes unused. Do not go looking for a global version; there isn't one. +4. Replace `styles/wijmo.css` with the archive's unminified `Dist/styles/wijmo.css`, formatted with + the repo's own Prettier config so the diff is reviewable, and with the leading UTF-8 BOM dropped to + match the previous file. `styles/Grid.css` is not touched here. +5. **Fail fast**: `npx tsc --noEmit -p tsconfig.json`. + +**Exit**: installed manifest reports the build string; a **two-way name diff** of the new vendored +directory against its predecessor is empty, root files and `cultures/` alike — a count would pass on a +set that swapped one file for another; every root `.d.ts` header names the new build string; all but +`wijmo.interop.grid.d.ts` are global flavor; the old directory is gone; `styles/wijmo.css` header +names the new build string; `tsc --noEmit` is clean. A flood of `Cannot find namespace 'wijmo'` here +means step 2 copied the wrong flavor — fix the source, never the call sites. + +**Log**: the pinned version, the vendored entry count, the interop source chosen, the `tsc` result. + +## Phase 5 — Version strings + +**Entry**: Phase 4 green. + +- `src/OSFramework/DataGrid/Constants.ts`: `WijmoFlexGridVersion` = the version description, keeping + the established `' Wijmo - Build '` shape. +- Same file: `OSDataGridVersion` = `gulp/DefaultSpecs.js: info.version` (which equals + `package.json: version`). This closes a drift, it does not increment a release — and it restores the + release bot's ability to find and replace that literal (see the version-tooling guardrails). +- Sweep the old build string across, and only across: `CLAUDE.md`, `ARCHITECTURE.md` (including its + `Last Updated` line), `package.json`, `Constants.ts`, `styles/wijmo.css`, `src/@types/`. + **Historical documents are excluded by design** — `docs/adr/**` records past decisions, its + `Readme.md` rows name the builds they were about, and `specs/**` is a record of past tickets. + Rewriting any of them would falsify the history. + +**Exit**: a grep for the old build string over the swept files prints nothing; a grep for the new one +finds it in each; `docs/adr/` and prior `specs/` are unchanged. + +**Log**: both constants, and the swept file list. + +## Phase 6 — Release review + +**Entry**: Phase 5 green. Offline analysis; independent of Phase 4. + +**Both lists are enumerated from a source outside this run** — otherwise a run that enumerates nothing +gives a verdict on nothing and the exit passes. Write both counts down before deciding anything: the +number of entries in the ticket's *API Updates* and *Breaking Changes* sections, and the number of +workaround sites the grep returns. + +1. **New-release opt-in / opt-out.** For every property the release's *API Updates* section adds to + a control this component uses, record an explicit adopt-or-decline decision with its reason. A + fixed provider option lands in `FlexGridConfig.getProviderConfig()` with a one-line rationale + comment beside its siblings, and its scalar type on `Types.IGridProviderConfigs` — members + alphabetical, which lint enforces. Prefer a literal over a computed value: the assembly loop + strips `undefined`. + `_getProviderConfig()` returns `unknown` and the bag is never checked against Wijmo's types, so a + green build says nothing about whether the option exists or is honoured. Its evidence is Phase 9. +2. **Workaround inventory.** Take the site list from + [`references/workaround-inventory.md`](references/workaround-inventory.md) — **not** from a keyword + grep, which finds only 4 of the 6 sites and misses the two most upgrade-sensitive ones. Cross-check + each against the release's changelog ids and give it a kept-or-removed verdict with a written + justification. Removing a workaround is its own ticket unless this one says otherwise; a verdict + that depends on the refreshed DOM stays provisional until Phase 9. + +**Exit**: the verdict count **equals** the *API Updates* entry count, and every *Breaking Changes* +entry has an impact assessment — including the ones assessed as not applicable, named rather than +omitted. Every site in `workaround-inventory.md` has a verdict, and +`grep -rn "workaround\|Workaround" src --include=*.ts` — run as a *supplement*, to catch sites the +inventory does not yet list — surfaces nothing new. Nothing under `src/Providers/` changed and no +`OutSystems.GridAPI` surface was added (NFR2, NFR5) — `git diff --name-only` proves it. + +**Log**: the two source counts, the adopted / declined and kept / removed splits against them, and any +provisional verdict by name. + +## Phase 7 — Build gate + +**Entry**: Phases 4-6 green. + +`npm run build` exits 0 with **no errors and no warnings at all** — `CONTRIBUTING.md` sets that +absolute bar, and it is the checkable one: "no *new* diagnostics" needs a pre-change build nobody +captured. Then `git status --short` to confirm the `lintfix` step touched nothing outside this +upgrade's paths. + +Two things this gate does **not** cover, so neither is evidence of anything: + +- **`styles/`** — `createProduction` is `cleanOldFiles` + `transpileProd`, and nothing in the build + reads the stylesheet. +- **the provider option bag** — untyped at the boundary (Phase 6). + +Expect the SonarQube stylesheet finding (see the vendored-files guardrails). For `5.20261.52`, Mescius +marks WJM-37650 as fixed in `2026v1-HF`: check whether the finding is gone and carry the answer into +Phase 12. + +**The exit code is not evidence the bundle exists — assert the artifact.** This gate used to pass on a +build that emitted nothing: `cleanOldFiles` piped `gulp.src('./dist/*')` into `gulp-clean` without +returning the stream and called `cb()` at once, so gulp started the transpile with the delete still +pending. The TypeScript compile is synchronous and blocks the event loop for seconds, starving the +glob's `readdir`; when it finally ran it listed `dist/` *after* the compile had written the bundle and +unlinked exactly the fresh files. Not a flaky race — reliably scheduled after the write, which is why +it looked like the build simply produced nothing. + +Fixed in ROU-12860 by returning the stream. If a future run finds `dist/` empty behind a green build, +check that `cleanOldFiles` still returns it: that one missing `return` is the regression tell, and the +symptom is indistinguishable from a compile failure until you notice `npx tsc --noEmit` is clean. +A `cleanOldFiles` that completes in well under a millisecond did not wait for its stream. + +**Exit**: exit code 0 with an empty error and warning list; **`dist/GridFramework.js` exists**, is +within a plausible size of its recorded value, and contains both version strings written in Phase 5; +working tree shows only intended paths. + +**Log**: the exit code, and whether the SonarQube stylesheet finding appeared. + +## Phase 8 — Module script refresh + +**Entry**: Phase 7 green, `dist/GridFramework.js` built. Read +[`references/module-inventory.md`](references/module-inventory.md) and +[`references/changeset-recipe.md`](references/changeset-recipe.md) before starting. + +1. **Request the per-branch module.** `OutSystemsDataGrid_`, created by a + hand clone of the base module, exported **unprotected**. Nothing in the pipeline produces it. +2. **Copy it into the scratchpad and check the copy is faithful** (`sha256sum` both). All later work + runs on the copy. +3. **Reconcile the live inventory.** `oml query` the module's `Scripts` and its `MobileFlows` / + `Nodes`, and diff the names two-way against the recorded inventory. **Any mismatch stops the + phase.** +4. **Generate one changeset** covering the **64 scripts** — 13 runtime, 50 cultures, `GridFramework` — + each `spec` echoing all six queried properties, **`RequiredScripts` included**, each `Description` + rewritten to name the new build string, and **the archive's UTF-8 BOM stripped from every file**. + Two traps here, both silent: omitting `RequiredScripts` costs `GridFramework` its 15 dependencies on + the Wijmo runtime, and keeping the BOM leaves a stray `U+FEFF` at the head of all 63 scripts. Neither + shows up in `oml validate`; both break the grid at load. Assert that no change targets `GridAuxFeature` or `JsZIP`. **The two block stylesheets + are not in the changeset**: `addOrReplace` on a block wipes its widgets, resets `Public` and nulls + its `Description` with zero validation errors to show for it. They are a manual Service Studio step + (Phase 14). +5. **Apply to a copy and validate.** `oml apply-changeset `, then the assertion + set in `changeset-recipe.md`, written as a re-runnable script — the generator will need iterations + and each one must be re-checked in full. If the single pass fails on a parse or size error, split + the changeset: `apply-changeset` chains, because one run's output is a valid input to the next. + Never respond by trimming the object set. +6. **Deliver the output where the operator can reach it.** `apply-changeset` writes a *separate* file, + so the module owner's export is never modified — which also means **the refreshed module is not the + file they handed over**, and saying "done" while the only copy sits in a session scratchpad hands + them nothing. Copy the validated output next to their original under a name that carries the new + build (`OutSystemsDataGrid__.oml`), verify the copy by hash, and re-run + `oml validate` **on the delivered file** rather than trusting the one you validated upstream. Then + name both paths explicitly when reporting. + +**Exit**: every assertion below. Two things they are built to defeat: an **empty changeset**, which +satisfies validate, unchanged counts and byte-identity perfectly by doing nothing; and **collateral +damage to a property nobody thought to check**, which is how this phase shipped a gutted block and a +dependency-less `GridFramework` on its first real run. + +- **`oml diff` between input and output reports only the intended change** — 64 `(Object Script)` + entries, `JavaScript` ×64, `Description` ×63, and no block, no `Required Script`, no other property. + Run this first: it is the only assertion that reports what you did not think to look for. +- `GridFramework.RequiredScripts` still holds its 15 entries, resolving to the same names as the input, + and the module's total `RequiredScripts` count is unchanged. +- **No stored script begins with `U+FEFF`**, and the runtime scripts equal the archive files *with the + archive's BOM stripped*. Comparing against the archive as-read passes with the BOM on both sides, + which is how it got in. +- `changes` length **is** 64, and its target names diff empty against the reconciled inventory. +- **63** objects in the output name the new build string in their `Description` — a count, not a + "for each", which is vacuous over an empty set. +- Exactly 64 scripts differ from the input **by content hash**, and no others. +- `oml validate` reports `errors == 0` and **no warning whose `(Type, Id, OwnerPath)` is absent from + the baseline set** — set-based, because a count both fails a run that removed a stale warning and + passes a swap. Disappeared warnings are reported, not ignored. +- The module's own script count is unchanged; per-flow node counts are unchanged. +- `GridAuxFeature` and `JsZIP` hash identical to the input. +- **Every block keeps its `Public`, its widget count and its `Description`** — `Structures/Grid` still + `Public=true` with 4 widgets. Nothing in the changeset targets a block, which is exactly why this is + asserted rather than assumed. +- `GridFramework` in the output carries both new version strings from Phase 5. +- The delivered file sits outside the scratchpad, hashes equal to the validated output, and passes + `oml validate` in place. The owner's original is byte-unchanged. + +**Log**: the `changes` count and the 63-description count as measured, the validate result against its +measured baseline, and the two untouched objects confirmed identical. + +## Phase 8b — Baseline capture and publish handoff + +**Entry**: Phase 8 green. **Nothing is published before step 1.** + +1. **Capture the pre-upgrade baseline.** It is unrecoverable once the module is republished, and the + comparative checks in Phase 9 are void without it. Record, into a named evidence folder: the + metadata a spreadsheet export writes, a decimal column's rendering of a typed and a pasted + excess-precision value, the filter panel's button DOM and appearance, plus one observation per + comparative item in the release's *Breaking Changes* section. + A live "before" beats snapshots: the public sample runs the released build, and the predecessor + record page used exactly that for its side-by-side. Confirm with the module owner which is + available. +2. **Hard gate — merge onto the protected module, then publish.** Do not publish the validated + unprotected OML directly (see the module-work guardrails). Hand it over as the *source of the + change*, to be merged onto the protected module so protection survives and only the upgrade's diff + lands. A three-way merge is the mechanism — Service Studio's, or `oml merge + -o `, which writes an output only when there are no conflicts; the common ancestor is the + pre-upgrade export the run started from. Then a Service Studio 1-Click Publish. **Stop until the + owner confirms it succeeded.** No API publish, therefore no credentials at any point. +3. **Refresh the per-branch sample apps** so they consume the republished module, and confirm which + sample and screen Phase 9 will use, with its URL. Their conventional names are in + `confluence-and-jira.md`. A sample still bound to the previous module makes every Phase 9 result + meaningless in an unknown direction — which is what the runtime gate exists to catch. + +**Exit**: the evidence folder covers every comparative item; explicit publish confirmation received; +the environment URL and sample-screen path are known. + +**Log**: `GATED` until the publish is confirmed; then the evidence-folder path and the sample URL. If +the baseline was missed, say so here — Phase 9 will report `UNVERIFIED`, not "unchanged". + +## Phase 9 — Manual validation + +**Entry**: Phase 8b confirmed. Everything here runs in a browser against the refreshed module. + +**Runtime gate, first and non-negotiable.** In the browser console on the sample screen: + +```js +OSFramework.DataGrid.Constants.WijmoFlexGridVersion; // the version description +wijmo.grid.FlexGrid.prototype.hasOwnProperty(''); // must be true +``` + +The second line is the only reliable proof the **Wijmo runtime itself** is on the new build — for +`5.20261.52` the property is `preventCut`. On `false`, stop: the module is partially refreshed and +every result below would be meaningless in an unknown direction. + +**Do the offline half first — much of this phase does not need a browser.** Two classes of check are +provable by comparing the old and new runtime scripts, which are both in hand (the pre-upgrade export +and the refreshed module): + +- **A breaking change that removes a default** shows up as the literal disappearing. On `5.20261.52`, + `WijmoXlsxJS` went from one occurrence of `…(e.company || "GrapeCity, Inc.")` to zero — + which proves the before *and* the after from the vendor's own code, more firmly than a screenshot, + and needs no captured baseline at all. +- **A workaround that hooks a vendor internal** is only as safe as that internal. Grep both runtimes + for each hook and compare counts: `_eTip` (tooltip), `getClipString` (CSV export), + `reApplyFilterOnUpdate`, `cloneFrozenCells`, `itemsEdited`. Equal counts mean the hook survived; a + count dropping to zero means a workaround has gone quietly inert, since most are guarded by an + `if` that simply stops firing. + +Then the browser half. **Every item names an action, an observable, and the exact expected string where +one exists** — a checklist that says "check tooltips" cannot be executed or disputed: + +| AC | Action | Expected observable | +| ---- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | +| AC13 | Click a column header twice; open a column filter and Apply; drag a column into the group panel; double-click a cell, type, Enter | Sorts ascending then descending; rows filter; rows group under headers; the value commits and `OnCellValueChange` fires | +| AC14 | Bind a source containing a `null` or primitive row | Valid rows render, and the console reads exactly `[DataGrid] Dropped N non-object row(s) from data source.` | +| AC15 | Group a text column, export CSV, open the file in a text editor | No `` or `` anywhere; group header rows read as plain text | +| AC16 | Hover a cell with a tooltip; then hover a cell failing validation | Tooltip appears with the standard class; the invalid one carries the error-validation styling | + +Add one row per intent-specific change this upgrade made on purpose, phrased the same way. + +Write each result into the evidence folder as it happens; re-running browser checks is expensive and +Phase 10 consumes them. + +Any comparative item whose Phase 8b baseline is missing is reported `UNVERIFIED`. + +**Loop back if this phase edits `styles/Grid.css`.** The refreshed stylesheet can move the DOM under +our own overrides, so this is the phase that changes them — and the moment it does, the module's `Grid` +block stylesheet is stale and every result gathered after that point was measured against the old CSS. +Re-run Phase 8 for that single object, republish, and re-check whatever the change could affect. +Shipping the repository's `Grid.css` against a module carrying the previous one is the silent failure +this loopback exists to stop. + +**Exit**: the runtime gate returned `true`; every checklist item has a recorded result; every +provisional Phase 6 verdict is now final; if `styles/Grid.css` changed, the module carries the changed +copy and the affected checks were re-run against it. + +**Log**: the gate result, and the pass / `UNVERIFIED` split with each `UNVERIFIED` item named. + +## Phase 10 — ADR and run log + +**Entry**: Phase 9 closed. The ADR records verified outcomes, not intentions. + +- Compute the next ADR number (see the version-tooling guardrails) and author + `docs/adr/ADR--Wijmo-Upgrade-.md` from `ADR-0000-Title-of-ADR.md`, status + `Accepted`. Cover: the build move and its ticket; the exact-pin rationale; each new-property + decision from Phase 6; the archive-sourcing constraint; the module refresh with its inventory, + schema traps and validation gate; the `wijmo.interop.grid.d.ts` disposition; the breaking-change + assessment with Phase 9 evidence; the workaround table with verdicts; and what was **not** run + here, named. +- Add one row to `docs/adr/Readme.md`, columns padded to the surrounding table. Do not renumber or + edit existing rows. +- Append the complete run log under an execution-record heading. + +**Exit**: the ADR exists and is `Accepted`; the log row is present and aligned; the run log has one +line per phase 0-14 with no unexplained non-`EXECUTED` state. + +**Log**: the ADR number and the run-log line count. + +## Phase 11 — Commit and PR + +**Entry**: Phases 4-10 closed. This runs **before** the two documentation phases, which both need +the PR link. + +- Stage by name: `package.json`, the new `src/@types/wijmo-/`, the old directory's + deletion, `Constants.ts`, any provider-config files Phase 6 changed, `styles/wijmo.css`, + `styles/Grid.css` if Phase 9 changed it, `ARCHITECTURE.md`, `CLAUDE.md`, `docs/adr/`, any + build-tooling fix the run had to make to get a green gate, and any edit the continuous-improvement + clause made to this skill or its references. Never `.claude/settings.local.json`; never `specs/`. +- Signed commit, `: `. +- **Hard gate** before pushing. +- Draft PR against `dev`: same title, satisfying `^([A-Z][A-Z0-9]*-\d+(:)?\s\w)`, with at least one of + `feature` / `bug` / `bugfix` / `dependencies` / `dependency` / `chore`; body following + `.github/pull_request_template.md` and naming the module refresh, the archive-sourcing constraint, + each new-property decision, and the out-of-scope items. Tick *requires changes in OutSystems*. +- **Hard gate** before creating the PR, and again before undrafting. It stays a draft until + validation is confirmed green. + +**Exit**: `git status --short` shows nothing unintended; `git log -1 --show-signature` confirms the +signature; `gh pr view --json isDraft,title,labels` matches the rules above. + +**Log**: the commit SHA, the PR number, and its draft state. + +## Phase 12 — Confluence + +**Entry**: Phase 11 closed, so the PR link exists. All targets, rules and templates are in +[`references/confluence-and-jira.md`](references/confluence-and-jira.md). Page IDs only. + +- **SBOM row**: the Data Grid **Reactive** row of the two; **replace** the value with the version + description. The Web Data Grid row is untouched. +- **Child page**: create `Wijmo update v to v` under the runbook, following the + precedent template. Fill the derivable sections; leave the operator's sections as visible + placeholders rather than guesses. + The PR link comes from Phase 11, which is why that phase now runs first: an earlier ordering had + this page written before the PR existed, leaving a placeholder someone had to remember to fill. +- **Reported issues**: derive the candidate list — rows whose status names this release, intersected + with the release's changelog ids — and hand it to the operator. Do not write verdicts. +- **First run only, hard gate**: replace the runbook body with a pointer to this skill, keeping the + child-page index. It is a shared team page whose original author has left. Confirm before editing. + +**Exit**: the child page renders; the Reactive SBOM value is the version description and the Web row +is unchanged; no page carries a procedure that competes with this skill. + +**Log**: page IDs written, and every section left to the operator, by name. + +## Phase 13 — Jira enrichment + +**Entry**: Phase 12 green, and the PR from Phase 11 exists — `/enrich-jira-task` needs its link. + +**Delegate to `/enrich-jira-task`.** That command already owns this job and does it better than a +hand-rolled write: it locates the ticket's existing **What I Did** slots by heading text and injects +into them as ADF via `acli jira workitem edit --from-json`, so the Context, Changelog, Acceptance +Criteria and DoD panels — and their smartlinks — are untouched. It also gates on assignee and +`In Progress` status, marks the section as generated, and is idempotent on re-runs. + +``` +/enrich-jira-task +``` + +Two of its defaults assume a different repository and need overriding here: it diffs against +`origin/main` where this repo uses **`origin/dev`**, and it derives *Points of Impact* from +`src/scripts/Components/**`, which does not exist here — for a Wijmo upgrade the honest value is +`All Grid functionalities`, as every predecessor page has said. + +Automated-test runs and test-case outcomes belong to the operator; leave them as placeholders rather +than filling them from assumption. Do not hand-write the block, and do not settle for a comment: the +MCP `editJiraIssue` replaces the whole `description` field, which is why the surgical ADF route exists. + +**Exit**: every derivable bullet carries a real link or value; every non-derivable one is a visible +placeholder. + +**Log**: which bullets were filled and which were left. + +## Phase 14 — Final checklist + +**Entry**: Phase 13 closed. + +Report these as named manual follow-ups, each with an owner — they are outside this skill and are +lost if they are not said out loud: + +- **The two block stylesheets, by hand in Service Studio.** `Styles/WijmoCSS` takes the refreshed + `styles/wijmo.css`; `Structures/Grid` takes `styles/Grid.css` **only if this upgrade changed it**. + Not scriptable — see `changeset-recipe.md`. Until this is done the module carries the previous + Wijmo stylesheet, so Phase 9's filter-panel and rendering checks are measuring the old CSS. +- **Sample-app refresh**, if Phase 8b step 3 did not already cover it. Validation runs against the + per-branch sample apps, which this skill does not touch. URLs in `confluence-and-jira.md`. +- **RPM board** entries, if the release fixed anything a customer reported. +- **Third-Party Tools registry** (`engineering.outsystems.net/ThirdPartyTools/`) once the component + reaches production. +- **External regression suite** — the WebdriverIO/Cucumber suite in `outsystems-datagrid-tests`, and + its test-case spreadsheet. Not run here; its outcome gates the PR undraft. +- **Release notes** draft, calling out any breaking change. +- **The child page's operator sections** — fixed issues, new issues found, RPMs, automated-test runs. +- **The module release publish**, as distinct from the per-branch publish in Phase 8b. + +Then restate the run log in full, and for each non-`EXECUTED` line give its reason and its owner. + +**Exit**: every follow-up has an owner; no run-log line is unexplained. + +**Log**: `Phase 14 Final checklist EXECUTED follow-ups reported, non-EXECUTED lines +explained`. diff --git a/.claude/skills/upgrade-wijmo-version/references/changeset-recipe.md b/.claude/skills/upgrade-wijmo-version/references/changeset-recipe.md new file mode 100644 index 000000000..a75e0ab24 --- /dev/null +++ b/.claude/skills/upgrade-wijmo-version/references/changeset-recipe.md @@ -0,0 +1,254 @@ +# Changeset Recipe + +How to refresh module objects offline with `OutSystems.Cli`. The schema is **undocumented** — +`ParseChangeSet` lives in the external `OutSystems.ModelExtensions.ChangeSet` assembly, and what is +written here was derived from its error messages and then probed end to end against a real OML. + +A reader should be able to construct a valid changeset from this file alone. + +## The three verbs + +```bash +# $OUTSYSTEMS_CLI is the checkout path resolved in Phase 1 — an environment variable, never a +# literal. No machine is guaranteed to hold the clone at any particular path. +# A function, not a string: the resolved path can contain spaces, and quotes inside an expanded +# variable reach dotnet as literal characters instead of grouping the argument. +cli() { dotnet run --project "$OUTSYSTEMS_CLI/src/OutSystems.AI.Cli" -c Release -- "$@"; } + +printf 'Root { Scripts { Name Description } }' | cli oml query "" - +cli oml apply-changeset "" "" "" +cli oml validate "" +``` + +If `$OUTSYSTEMS_CLI` is empty, Phase 1 was skipped: go back and resolve it there rather than guessing +a path here. + +`apply-changeset` takes a **separate output path**, so it is inherently non-destructive to its input. +That is what makes "run against a copy" cheap: keep the module owner's export untouched, apply onto a +new file, and re-apply from scratch on every generator iteration. + +## Schema + +```json +{ + "version": "1", + "changes": [ + { + "action": "addOrReplace", + "target": "", + "add": { "collection": "" }, + "spec": { "key": "", "type_": "", "...": "..." } + } + ] +} +``` + +Both `GlobalKey` values come from the run's own `oml query`. Never from this file, never from a +previous run. + +## Three traps + +Each was found by hitting it: + +1. **`version` is required, and must be a string.** A JSON number throws + `requires an element of type 'String'`. +2. **`action` is required.** Omitting it throws `Invalid ChangeSet format: missing action element`. +3. **`add` is required even for a pure property change** — a change that replaces only a + `Description` or a `StyleSheet` still needs the `add` element naming the collection. + +And a fourth thing that is not a parse error but a data-loss bug: **`addOrReplace` is full-replace.** +Every property the object had and the `spec` omits is wiped, which for a Script means it comes back +renamed (`Script1`) with no `RuntimePath` and no `Folder`. Echo back the object's complete queried +metadata in every `spec`. + +## Scripts: safe **only with `RequiredScripts` echoed**. Block stylesheets: DESTRUCTIVE. + +Full-replace reaches child collections on **both** object types. It bit twice in one run: once on the +blocks, and once on Scripts, where a spec of six scalar fields silently dropped +`GridFramework`'s 15 `RequiredScripts`. The grid then failed at runtime because the Wijmo files no +longer loaded before it, and `oml validate` reported nothing at all — load order is not a model +constraint. + +`RequiredScripts` is a **plain array of script `GlobalKey` strings**. Note that two key spaces coexist: +`GlobalKey` is the `*` form used for every cross-reference, while `Key` returns +a plain GUID. Query `GlobalKey` when resolving a reference and `Key` when addressing the object itself. +Echo the queried array verbatim: the refresh replaces content, never identity, so the keys stay valid. + +**The lesson that generalises past this one field:** do not verify a replace against a hand-picked list +of properties you happened to think of — that is what missed the blocks and then missed this. Verify +with `oml diff` (below), which reports everything that moved. + +| Probe | `target` | `add.collection` | `spec.type_` | Result | +| ------------------ | --------------------------------- | ---------------- | -------------- | ---------------------------------------------------------------------------------------------------------- | +| Script property | the **eSpace** `GlobalKey` | `Scripts` | `IScript` | Applied over all 64. Script count still 66, no rename, dependencies preserved — with `Name`, `Public`, `RuntimePath`, `Folder`, `Description` **and `RequiredScripts`** all echoed back. Omit `RequiredScripts` and `GridFramework` silently loses its 15 dependencies. | +| Block `StyleSheet` | the **flow** `GlobalKey` | `Nodes` | `IMobileBlock` | Applied. `WijmoCSS.StyleSheet` replaced; every flow's node count unchanged. | + +**The block row above is a trap, and the probe that produced it asked the wrong question.** "Every +flow's node count unchanged" measures the container, not the payload: the block survives, its contents +do not. Measured on `5.20261.52`, applying `addOrReplace` to both blocks with a spec of +`{ key, type_, Name, StyleSheet }`: + +| Block | Before | After | +| ----------------- | ----------------------------------------- | ------------------------------------------------- | +| `Structures/Grid` | `Public=true`, 4 widgets, description set | `Public=false`, **0 widgets**, description `null` | +| `Styles/WijmoCSS` | `Public=false`, 1 widget, description set | `Public=false`, **0 widgets**, description `null` | + +`Grid` losing `Public=true` alone breaks the component — that flag is what lets consumers drop the +block on a screen. And `oml validate` reports **zero errors** on the wreckage; the only signal is 12 +new `UnusedUserAction` warnings (`CreateDataGrid`, `InitGrid`, `SetGridData`, `DestroyDataGrid`, …), +because the actions the gutted block used to call are now referenced by nothing. + +This is full-replace reaching one level deeper than the Script case. For a Script, echoing four scalar +properties *is* a complete spec. A block's state includes **child collections** that a flat spec cannot +carry, so echoing `Public` and `Description` as well would not save it — the widgets would still go. + +**Therefore the changeset covers 64 objects, not 66.** Refreshing `WijmoCSS.StyleSheet` — and `Grid` +if the upgrade changed `styles/Grid.css` — is a **manual Service Studio step**, reported as a named +follow-up. Include a block change only if a future run finds a non-destructive mechanism (a different +`action` verb, or a spec that carries `Widgets`) *and* proves it against the block-integrity +assertions below. + +The asymmetry, still true for Scripts: a Script's `target` is the **eSpace**. A block's would be the +**flow that contains it**, with the block as the `spec`. + +## What each object's `spec` carries + +Per `module-inventory.md`: + +Every Script spec echoes **six** properties from the live query — `Name`, `Public`, `RuntimePath`, +`Folder`, `Description`, `RequiredScripts` — plus the new `JavaScript`. All six, every object, always. + +**Strip the UTF-8 BOM from every file copied out of the archive.** All 63 archive `.min.js` files start +with one; the module's script content has never carried any. Copying it in leaves a stray `U+FEFF` at +the head of all 63 scripts — the only content-level difference between a scripted refresh and the +hand-made upgrades that preceded it, and a plausible cause of runtime failures once the platform +concatenates the scripts, because a `U+FEFF` between two IIFEs can suppress the statement boundary and +change what the next function's parameter binds to. `plan.md` already knew to drop the BOM when copying +`wijmo.css`; the rule is the same for every vendored copy. One line: +`s.charCodeAt(0) === 0xFEFF ? s.slice(1) : s`. + +Note the consequence for assertions: comparing module content against the archive *as read* passes +happily with the BOM on both sides. Compare against the archive **with its BOM stripped**, and assert +separately that no stored script begins with `U+FEFF`. + +- **13 runtime scripts** — `JavaScript` = the matching `*.min.js` from the archive; `Description` = + `File: - Version: `. +- **50 culture scripts** — `JavaScript` = the matching `cultures/*.min.js`; `Description` = + `Script with the culture files - Wijmo library version `. +- **1 wrapper script** — `GridFramework` = `dist/GridFramework.js`; `Description` unchanged. This is the + one object with a non-empty `RequiredScripts`: **15 entries** — the 13 Wijmo runtime scripts plus + `JsZIP` and `GridAuxFeature`. (`GridAuxFeature` itself requires `WijmoJS`, but it is never replaced, + so its dependency is never at risk.) +- **0 block stylesheets** — excluded by the section above. `WijmoCSS` and `Grid` are refreshed by hand. + +Runtime source filenames need no hardcoded table: **the module's own `Description` names its source +file** (`File: wijmo.grid.grouppanel.min.js - Version: `), so parse it rather than maintaining a +mapping. Culture object names are de-hyphenated — see `module-inventory.md`. + +## Validation gate + +`oml validate` prints a JSON array of messages, each with `Type`, `Id` and `OwnerPath`. It is not a +summary line — count it yourself. + +The gate is **set-based**, not count-based: + +``` +errors == 0 && no warning in the output whose (Type, Id, OwnerPath) is absent from the baseline +``` + +**Compare the set, never the total.** Two ways a count gate gets it wrong, both observed: + +- **It fails a clean run.** On `5.20261.52` the baseline was 10 warnings and the output had 9: the + refresh *removed* a pre-existing `Script_SyntaxErrors` on `GridFramework` ("has syntax errors. Using + it in your app might cause runtime errors"), because the newly built bundle parses where the module's + old copy did not. `warnings == baseline` would have rejected a strictly better module. +- **It passes a swap.** One warning gone and one new leaves the total unchanged, which is exactly the + regression the gate exists to catch. + +Report disappeared warnings too — they are evidence for the ADR, not noise. + +**Re-measure the baseline on this run's input OML.** Do not carry a recorded number or set forward: it +belongs to one specific export, and a different clone can legitimately differ. And a plain "0 errors" +check is no substitute at all — the block-stylesheet damage above produced **zero errors**. + +The reference baseline, for orientation only: `{Error: 0, Warning: 10}` = 7 `UnusedElement`, +2 `InvalidResourceURL_Offline` (base64 image URLs in `Structures/Grid`'s stylesheet), and +1 `Script_SyntaxErrors` on `GridFramework`. + +## Full assertion set after apply + +Write these as a re-runnable script, not a checklist walked by hand. The generator will need more than +one iteration and every iteration must be re-checked in full. + +### `oml diff` first — it is the only assertion that sees what you forgot + +```bash +cli oml diff # the `cli` function from "The three verbs" +``` + +It prints a structural tree of everything that moved, property by property and child object by child +object. On a correct 64-script refresh it reports exactly: 64 `(Object Script)` entries, `JavaScript` +changed 64 times, `Description` changed 63 times, `HasSyntaxErrors` once, and — besides container +folders — **nothing else**. No blocks. No `Required Script` lines. + +Run it before the property assertions, not after. Both destructive defects found in ROU-12860 were +invisible to a hand-picked field list and glaring here: the block damage showed as changed +`(Object MobileBlock)` nodes, and the lost dependencies as +`(Object Required Script) WijmoJS [RemovedFromForeign]` and fourteen siblings. A field list can only +check what its author thought of; `diff` reports what actually happened. + +| Assertion | Expected | +| -------------------------------- | ------------------------------------------------------------------------ | +| **`oml diff` input → output** | **64 Scripts; `JavaScript` ×64, `Description` ×63; no block, no `Required Script`, no other property** | +| `GridFramework.RequiredScripts` | **15 entries, resolving to the same names as the input** | +| total `RequiredScripts` in module | **unchanged** (16 on the reference module) | +| `changes` length | **64** | +| no change targets | `GridAuxFeature` or `JsZIP` | +| `oml validate` | `errors == 0` and **no warning absent from the baseline set** | +| module `Scripts` count | unchanged (the module's own count, not the changeset's) | +| scripts whose content changed | exactly 64, by content hash — an empty changeset passes every other row | +| the 63 Wijmo `Description`s | all name the new build string | +| `GridAuxFeature`, `JsZIP` | content hash identical to the input | +| `GridFramework` | contains **both** version strings written in Phase 5 | +| node count per flow | unchanged, flow by flow | +| **every block: `Public`** | **unchanged** — `Structures/Grid` in particular must stay `true` | +| **every block: widget count** | **unchanged** — `Grid` 4, `WijmoCSS` 1 | +| **every block: `Description`** | **unchanged and non-`null`** | +| **every block: `StyleSheet`** | hash unchanged, since the changeset no longer touches them | + +The four block rows are the ones that were missing when this route was believed safe. Assert them even +though the changeset does not target blocks — they are cheap, and they are what turns "I did not touch +it" from an intention into a measurement. + +Compare maps **order-independently**. `oml query` does not return flows in a stable order, so a naive +`JSON.stringify` comparison of two per-flow maps reports a difference that is not there. Sort the keys +first. + +Also worth knowing when writing these: **8 blocks carry a `StyleSheet` property**, not 2 — +`Structures/Grid`, `Styles/WijmoCSS`, `Pagination/ButtonList` and the five `Grid_Events/*` blocks. Only +the first two are upgrade targets; the rest must come through unchanged. + +## If one changeset is too large + +The probes proved the mechanism for one Script and one block stylesheet; they did not prove it for 66 +objects carrying roughly 1.5 MB of minified JavaScript embedded in JSON. No size or encoding limit on +`ParseChangeSet` is known. + +If the single pass fails, the symptom tells you where to go. A parse or size error means **split the +changeset**: `apply-changeset` chains cleanly, because one run's output is a valid input to the next, +so N smaller runs are equivalent to one large one. Never respond by trimming the object set — a +partially refreshed module produces false results in Phase 9, in whichever direction. + +And never hand-edit the OML. Fix the generator and re-run. + +## Ruled out, so no run retries them + +- `OutSystems.Cli` has **no** command that fetches a module from an environment. Every `oml` verb takes + a local file. +- It has **no** O11 support: its README targets ODC, and its `odc publish` is a stub with the one + working line commented out. The publish half is manual by necessity, which is also why this + procedure needs no credentials. +- A **protected** export cannot be loaded at all — the platform refuses in + `CheckOpenPermissions` with `Load is not allowed for this module`, and the CLI supplies no key. + Protection is key-based rather than absolute, so the fix is to ask the module owner (this team) for + an unprotected export. Retrying is futile. diff --git a/.claude/skills/upgrade-wijmo-version/references/confluence-and-jira.md b/.claude/skills/upgrade-wijmo-version/references/confluence-and-jira.md new file mode 100644 index 000000000..b258de61f --- /dev/null +++ b/.claude/skills/upgrade-wijmo-version/references/confluence-and-jira.md @@ -0,0 +1,183 @@ +# Confluence and Jira Targets + +## Address pages by ID only + +| Page ID | Title | Role | +| ------------ | ---------------------------------------- | -------------------------------------------------------- | +| `3058631508` | Wijmo Updates | The upgrade runbook **and** the index of per-upgrade pages | +| `2745598610` | External Libraries in UI Components | The SBOM | +| `3353313306` | Issues reported to the provider libs | Issues raised with the vendor, with a status per issue | + +All three live in space **`RDMBLVS`** ("R&D - Web & Mobile Apps - Value Stream"). + +**The space keys quoted in tickets are wrong.** ROU-12860 places the SBOM in `RDOO` and the +reported-issues page in both `RDOO` and `RDMBVS`. Those links resolve only because Confluence +tolerates a stale space key in the path. Look pages up by ID; never construct a URL from a +ticket-quoted space key, and never search by title expecting one space. + +--- + +## SBOM row (`2745598610`) + +The page's main table has columns **Asset | Library | Version | Licence | Components**. Two rows name +Wijmo: + +| Asset | Touch it? | +| ----------------------------------------- | -------------------------------------------- | +| `OutSystems Data Grid (Reactive)` | **Yes** — this is the row an upgrade updates. | +| `OutSystems Data Grid Web (Traditional)` | **No.** Different component, its own build. | + +**The update API takes the whole page body, so a one-cell edit is a full-body rewrite.** This page +carries 28 rows owned by other teams, plus a Team Forks table, inline-comment annotations, a user +mention and per-column widths. Fetch with `contentFormat: "html"` — it round-trips faithfully, verified +— change only the target value, and **re-fetch and diff afterwards** to prove exactly one cell moved. +Page history is the recovery route if it did not. Never edit this page through `markdown`, which is +lossy. + +Rules: + +- **Replace** the Version value with the version description, e.g. + `2026v1-Hotfix Wijmo - Build 5.20261.52`. One value, not a history. +- **Do not copy the Charts rows' behaviour.** `OutSystems Charts (Reactive)` accumulates one line per + release in a single cell. The Data Grid rows never have, and matching Charts here would silently + change what the row means. +- Leave `Licence` and `Components` alone. The library link points at the vendor's download page and + carries no build string. +- The page's own note ("once the new components are released into production we need to update this + information at `engineering.outsystems.net/ThirdPartyTools/`") is a **separate, manual** follow-up. + It is reported in Phase 14, not performed. + +## Reported issues (`3353313306`) + +Section **"Wijmo Flexgrid - Reported Issues/Requests"**, a table of +**Issue ID | Title | Description | Status**, where Status names the release a fix landed in +(`2026v1-HF`, `Solved in v5.20251.34`, `Closed`, …). + +Derive a **candidate list** and stop there: rows whose Status names the release being adopted, +intersected with the release's changelog ids. Hand that list to the operator. Deciding whether a +reported issue is genuinely fixed needs the reproduction sample, and a wrong verdict here removes a +workaround that customers depend on — so this skill never writes a status. + +One row is worth knowing about in advance: **WJM-37650** ("Compilation issue with an SCSS file", the +SonarQube duplicated-CSS finding on `wijmo.css`) is marked fixed in `2026v1-HF`. Phase 7 records +whether the finding actually disappeared; that answer belongs in this row. + +## Child page (under `3058631508`) + +Ten predecessors, back to 2023, titled `Wijmo update v to v` — most recently +`Wijmo update v5.20252.44 to v5.20261.50` (page `6242140231`, ROU-12689), which is the template +source. Nothing needs inventing. + +### Section-by-section split + +Every section of the precedent page, and who fills it: + +| Section | Source | +| ---------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| `Jira Task → ` | **Auto** — from `TASK_ID`. | +| *Updated the page 3353313306…* | **Operator** — the candidate list above is provided; the verdicts are theirs. | +| *Updated the page 2745598610* | **Auto** — the SBOM row, done in Phase 12. | +| *Updated the RPMs* | **Operator** — the RPM board is outside this skill. `N/A` is a legitimate answer and the precedent's. | +| **Code** → PR | **Auto** — the draft PR from Phase 11. | +| **Code** → OutSystems → Module | **Auto** — the module refreshed, and what changed in it, from the Phase 8 log. | +| **Points of Impact** | **Auto** — `All Grid functionalities`, as every predecessor. Narrow it only on evidence. | +| **Samples** → Screens | **Auto** — the conventional URLs below. | +| **Automated Tests** → PR + pipeline runs | **Operator** — a different repository and pipeline; not run here. | +| **Test Cases** | **Auto template, operator outcome** — the regression walk below; pass/fail is theirs. | +| `### ✅ Fixed Issues` | **Operator, always.** `_None_` is the precedent's answer and a valid one. | +| `### ⚠️ New issues found:` | **Operator, always** — needs screenshots and vendor ticket ids. Phase 7's SonarQube answer feeds it. | + +Leave every operator section present as a visible placeholder. An absent section reads as "nothing to +report"; a placeholder reads as "not yet done". + +### Test-case template + +The precedent's single test case, which generalises: + +> **Test Case 1 — Regression** +> - Open the automation sample app, exercise its screens, confirm everything is as expected. +> - Open the `Overview` screen of the sample app, exercise its screens, confirm everything is as +> expected. + +## Sample-app URL conventions + +Validation runs against two **per-branch sample apps**, both hand-made clones. This skill does not +touch either — they are a named manual follow-up (Phase 14) — but it emits their URLs into the child +page so the gap is explicit rather than discovered during validation. + +With `` = the task id with its hyphen removed (`ROU-12860` → `ROU12860`): + +``` +https://outsystemsui-dev.outsystemsenterprise.com/OSDataGridAutomation_ +https://outsystemsui-dev.outsystemsenterprise.com/OutSystemsDataGridSample_/Overview +``` + +And the **pre-upgrade baseline** for Phase 8b — the public sample, which runs the released build and +therefore stays on the old one for the length of the upgrade: + +``` +https://outsystemsui.outsystems.com/OutSystemsDataGridSample/ +``` + +The precedent page used exactly that for its before/after comparison, and ROU-12860 chose it over +snapshots. A live "before" beats a folder of screenshots, and it survives the republish that destroys +a snapshot-based baseline. Confirm it is still on the old build before relying on it — its version is +readable from `OSFramework.DataGrid.Constants.WijmoFlexGridVersion` in the browser console, which is +the same one-liner Phase 9 uses on the refreshed side. + +## Runbook rewrite (`3058631508`) — first run only + +The parent page is both a runbook and the child index. Its body is a seven-step manual procedure last +touched in October 2024: its author has left, its download link points at a retired domain, and its +asset step describes a module folder layout that no longer matches the module. + +Replace the body with a pointer to this skill, keeping the child-page index intact and keeping the +License Update links at the foot. Leave the child pages themselves untouched — they are the historical +record. + +**Hard gate.** This is a write to a shared team page whose original author has left. Confirm before +editing, and do it once — later runs only add a child page. + +## Jira "What I Did" block + +The ticket ships this block empty in its description. Fill it in place, keeping its exact shape: + +```markdown +**What I Did** + +* **Code**: + * PR → + * OutSystems → +* **Points of Impact**: +* **Samples**: + * Screens → +* **Automated Tests**: + * PR → +* **Test Cases**: + * Test Case 1 + * Test Case N +``` + +Auto: `Code` (the PR link, and the module refreshed), `Points of Impact`, `Samples` (the two URLs +above). Operator: `Automated Tests` and the `Test Cases` outcomes — leave them as placeholders rather +than filling them from assumption. + +**Fill it with `/enrich-jira-task`, which injects into these slots surgically.** It finds the panel by +its `What I Did` heading, walks to each slot by heading text, and writes ADF through +`acli jira workitem edit --from-json`. Every other panel survives, smartlinks included. + +The wrong turns, both taken on the first run and both recorded so they are not taken again: + +- **Do not rewrite the `description` field.** The MCP `editJiraIssue` accepts only the whole field, and + a markdown round trip degrades the ticket's smartlinks to plain URLs — damaging the reporter's text + to add your own. +- **Do not settle for a comment either.** It is lossless and additive, which makes it tempting, but it + leaves the template empty and the convention unmet. The constraint that makes a full rewrite + unacceptable does not make a comment correct; it makes surgical ADF injection correct. + +The PR link exists by the time this phase runs: Phase 11 creates it, ahead of both documentation +phases, precisely so neither has to leave a placeholder. + +The ticket's own acceptance criteria also name the RPM board, the Third-Party Tools registry, the +test-case spreadsheet and the release-notes draft. None is performed here; all four are reported in +Phase 14. diff --git a/.claude/skills/upgrade-wijmo-version/references/module-inventory.md b/.claude/skills/upgrade-wijmo-version/references/module-inventory.md new file mode 100644 index 000000000..02d141c7b --- /dev/null +++ b/.claude/skills/upgrade-wijmo-version/references/module-inventory.md @@ -0,0 +1,162 @@ +# Module Asset Inventory — `OutSystemsDataGrid` + +The objects a Wijmo upgrade replaces inside the OutSystems module, by **name and shape**. Measured +with `oml query` against a real unprotected export at build `5.20261.50`. + +**No `GlobalKey` or `Folder` value appears in this file, and none may be added.** Those identifiers +are per-module: a value recorded from one export would silently target the wrong object — or nothing +at all — in the next per-branch module. Read them from a live `oml query` on every run, and use this +file only to know *what to look for* and *what to assert*. + +Reconcile this list against the live module before generating a changeset, and stop on any mismatch. +A differently-cloned module can legitimately carry a renamed script or a missing language, and a +generator that is not reconciled first would cover 49 cultures and report success. + +--- + +## Wijmo runtime scripts — 13 + +All in one folder, all **minified**. `Description` format: +`File: - Version: `. + +All 63 archive `.min.js` files carry a UTF-8 BOM that the module's stored content never has. Strip it +on copy — see `changeset-recipe.md`. + +The sizes are the `5.20261.50` values, recorded as a **pre-flight magnitude check only** — if the +archive's replacement for one of these is wildly off (`wijmo.grid.min.js` at 40 KB rather than +~366 KB), the wrong file was picked. They are **not** expected to match after an upgrade, and no +assertion compares them for equality. + +| Script (`Scripts` collection) | Source file | Size at `5.20261.50` | +| ----------------------------- | ------------------------------ | -------------------- | +| `WijmoJS` | `wijmo.min.js` | 168 066 B | +| `WijmoGridJS` | `wijmo.grid.min.js` | 366 455 B | +| `WijmoInputJS` | `wijmo.input.min.js` | 278 538 B | +| `WijmoXlsxJS` | `wijmo.xlsx.min.js` | 199 831 B | +| `WijmoNavJS` | `wijmo.nav.min.js` | 69 156 B | +| `WijmoGridFilterJS` | `wijmo.grid.filter.min.js` | 67 271 B | +| `WijmoGridXlsxJS` | `wijmo.grid.xlsx.min.js` | 33 289 B | +| `WijmoUndoStackJS` | `wijmo.undo.min.js` | 27 668 B | +| `WijmoGroupPanelJS` | `wijmo.grid.grouppanel.min.js` | 18 227 B | +| `WijmoGridSelectorJS` | `wijmo.grid.selector.min.js` | 11 432 B | +| `WijmoGridSearchJS` | `wijmo.grid.search.min.js` | 9 077 B | +| `WijmoTouchJS` | `wijmo.touch.min.js` | 6 558 B | +| `WijmoGridCellMakerJS` | `wijmo.grid.cellmaker.min.js` | 6 217 B | + +**Why a code-derived list is wrong.** `WijmoTouchJS` and `WijmoNavJS` are not derivable from this +repository's source. A namespace census over `src/OSFramework`, `src/Providers` and `src/OutSystems` +yields ten bundles and misses both: they are transitive dependencies of `wijmo.input`'s dropdowns and +menus, referenced by the runtime and never by our code. This inventory is authoritative; a census is +not. + +## Culture scripts — 50 + +Named `wijmo_culture__min` with **the hyphen removed from the language tag**, one folder, +~11-17 KB each. `Description` format: +`Script with the culture files - Wijmo library version `. + +The de-hyphenation is the mapping trap: the archive file is `wijmo.culture.en-CA.min.js` but the module +object is `wijmo_culture_enCA_min`, so a generator that substitutes the language tag verbatim finds +nothing for the 11 hyphenated languages (`ar-AE`, `ar-SA`, `de-CH`, `en-CA`, `en-GB`, `es-419`, +`es-MX`, `fr-CA`, `mn-MN`, `zh-HK`, `zh-TW`) and silently covers only the other 39. Map with +`'wijmo_culture_' + lang.replace(/-/g, '') + '_min'`, and reconcile by name before generating. + +`ar-AE`, `ar-SA`, `bg`, `ca`, `cs`, `da`, `de`, `de-CH`, `el`, `en`, `en-CA`, `en-GB`, `es`, `es-419`, +`es-MX`, `et`, `eu`, `fi`, `fr`, `fr-CA`, `gl`, `he`, `hi`, `hr`, `hu`, `id`, `it`, `ja`, `kk`, `ko`, +`lt`, `lv`, `mn-MN`, `nl`, `no`, `pl`, `pt`, `ro`, `ru`, `sk`, `sl`, `sr`, `sv`, `th`, `tr`, `uk`, +`vi`, `zh`, `zh-HK`, `zh-TW`. + +**This set is exactly the set vendored under `src/@types/wijmo-/cultures/`** — 50 in +each, verified with a two-way set difference that came back empty in both directions. So there are no +per-language mapping decisions to make: the module's culture scripts and the repository's culture +types cover the same languages, and the archive must supply both for all 50. Assert the parity +against the archive (Phase 2), re-assert it against the live module (Phase 8), and **fail loudly** +rather than skipping if any single language is absent from either side. + +## Wrapper script — 1 + +`GridFramework` — `dist/GridFramework.js`, non-minified, 583 562 B at `5.20261.50`. Its `Description` +carries no build string and is left as it is. In scope because nothing delivers it automatically: the +pipeline's Deploy stage only runs on PR builds and posts to an endpoint that may no longer exist. + +It is also a free cross-check on the repository work — after the changeset, the output copy must +contain **both** version strings Phase 5 wrote. If only one changed, that isolates which edit was +missed. + +**It is the one replaced object with dependencies: `RequiredScripts` holds 15 entries** — the 13 Wijmo +runtime scripts plus `JsZIP` and `GridAuxFeature`. They declare the load order the grid needs, and a +changeset that does not echo them wipes the list, breaking the component at runtime with no validation +signal. See `changeset-recipe.md`. (`GridAuxFeature` requires `WijmoJS`, but it is never replaced, so +its dependency is never at risk.) + +## Block stylesheets — 2 + +Neither CSS file is a resource or a theme: `WebThemes` and `Resources` are both empty. Both are the +`StyleSheet` property of a `MobileBlock`, and the changeset targets the **flow**, not the block (see +`changeset-recipe.md`). + +| Block | Flow | Content | Size at `5.20261.50` | +| ---------- | ------------ | ----------- | -------------------- | +| `WijmoCSS` | `Styles` | `wijmo.css` | 102 549 chars | +| `Grid` | `Structures` | `Grid.css` | 53 977 chars | + +`WijmoCSS` takes the archive's refreshed stylesheet. `Grid` takes this repository's `styles/Grid.css` +— ours, not the vendor's, and it only needs replacing when the upgrade changed it. + +**Neither can be refreshed by changeset.** `addOrReplace` on a block wipes its widgets, resets +`Public` and nulls its `Description`, with zero validation errors to show for it — measured, see +`changeset-recipe.md`. Both are **manual Service Studio steps**, and `Grid` is usually not needed at +all: it only changes when the upgrade edited `styles/Grid.css`, which most upgrades do not. + +Their integrity is still asserted after every changeset, precisely because nothing is supposed to touch +them: `Grid` stays `Public=true` with 4 widgets, `WijmoCSS` has 1 widget, and both keep their +descriptions. + +## Never touched — 2 + +| Script | What it is | +| --------------- | ------------------------------------------------------------------------------------------ | +| `GridAuxFeature` | Obfuscated. `Description`: "OutSystems Data Grid license script." | +| `JsZIP` | `File: jszip.js version 3.10.1` — a dependency of `wijmo.xlsx`, carrying its own version. | + +Both must be **byte-identical** in the changeset output, and the generator asserts that no change +targets either — explicitly, not merely by omitting them. + +**The risk in leaving `JsZIP` alone, stated so it is not rediscovered.** `wijmo.xlsx.min.js` uses +JSZip. An upgrade replaces the former while pinning the latter, so if a new Wijmo build expects a +newer JSZip API, spreadsheet export breaks at runtime — not at build time, and not in `oml validate`. +Only the manual export check in Phase 9 would catch it. Phase 2 therefore asks whether the archive +ships its own JSZip and how its version compares; a newer one is raised as its own ticket, never +adopted quietly inside a Wijmo upgrade. + +**Measured on `5.20261.52`: the archive ships no JSZip at all** — a case-insensitive search of the +whole 165 MB zip for `*jszip*` returns nothing. So there is no version to compare and nothing to +raise; `JsZIP` stays at `3.10.1` because the vendor never offered an alternative. Re-run the search +each upgrade rather than carrying this answer forward. + +--- + +## Two counts of 66, asserted separately + +These collide confusingly and are not evidence of each other: + +| Bucket | Count | +| ----------------------------------------------------------------- | ----- | +| Scripts in the module, total | 66 | +| — replaced (13 runtime + 50 cultures + `GridFramework`) | 64 | +| — never touched (`GridAuxFeature`, `JsZIP`) | 2 | +| **Objects the changeset carries** | **64** | +| Block stylesheets, refreshed **by hand** | 2 | + +So the module holds **66** Scripts while the changeset carries **64** objects. Assert each +independently: the module's script count must be **unchanged** at 66 after the apply, while the +changeset's change count must **be** 64, and exactly 64 scripts must differ by content hash. Treating +any one as proof of another hides a whole class of generator bug — an empty changeset satisfies +"count unchanged" perfectly. + +An earlier version of this file said the changeset carries 66, counting the two block stylesheets. That +route turned out to destroy the blocks; the 64/66 split above is the measured one. + +And per the guardrails: verify every set **by name**, never by count. The archive ships +`wijmo.angular*`, `wijmo.react*` and `wijmo.vue*` bundles that inflate any count while every name +above could still be missing. diff --git a/.claude/skills/upgrade-wijmo-version/references/workaround-inventory.md b/.claude/skills/upgrade-wijmo-version/references/workaround-inventory.md new file mode 100644 index 000000000..0e53d1315 --- /dev/null +++ b/.claude/skills/upgrade-wijmo-version/references/workaround-inventory.md @@ -0,0 +1,72 @@ +# Workaround Inventory + +Every place this repository works around Wijmo behaviour. An upgrade re-validates each one against +the new release's changelog and records a kept-or-removed verdict with a justification. + +**A keyword grep does not find this list, and must not be used to build it.** Measured on +`5.20261.50`: `grep -rn "workaround\|Workaround" src --include=*.ts` returns 6 lines covering only +**4** of the 6 sites. The two it misses are the two most sensitive to a Wijmo upgrade — the +`CollectionView` proxy guard and the filter-button CSS override — because both are described in prose +without ever using the word. Same lesson as the module inventory: a code-derived list is wrong, and +this file is authoritative. + +Re-derive the list by reading these locations, then check for genuinely new sites with the grep as a +*supplement*, never as the source. + +| # | Site | Guards against | Vendor id / origin | +| - | ----------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------ | +| 1 | `Providers/.../Features/ToolTip.ts` (~:118) | Tooltip rendering; the workaround Wijmo supplied for our report | ROU-4207 | +| 2 | `Providers/.../Features/GroupPanel.ts` (~:119) | HTML tags and encoded symbols in CSV export with grouped columns | WJM-35579 | +| 3 | `Providers/.../Features/Export.ts` (~:61) | Same family — HTML tags exported in CSV with grouped columns (`_stripHtmlBoldTag`) | WJM-35579 | +| 4 | `Providers/.../Grid/FlexGrid.ts` (`_safari14workaround`) | Safari 14 rendering defect. Three grep hits — doc comment, method, call site — but **one** workaround | Safari 14 | +| 5 | `OSFramework/.../Grid/AbstractDataSource.ts` (~:341-347) | **No keyword.** `CollectionView` proxy-wraps every bound item since Wijmo 2026v1, so a `null`/primitive row throws `Cannot create proxy with a non-object as target or handler` at bind time. Filters them out to keep the pre-2026v1 forgiving contract | ROU-12689 | +| 6 | `styles/Grid.css` (~:921-958) | **No keyword.** Filter panel's Apply/Clear/Cancel buttons gained an extra wrapper `
` in Wijmo 5.2026v1 for a11y; the override restores their size and spacing | Wijmo 5.2026v1 a11y change | + +## Static evidence: does the hook still exist? + +Sites 1-5 hook a vendor internal or API. Each verdict gains real evidence — not just "absent from the +changelog" — by grepping the old and new runtime scripts and comparing occurrence counts. A count +falling to zero means the workaround has gone quietly inert, because most are guarded by an `if` that +simply stops firing. + +| Hook | Lives in | `5.20261.50` | `5.20261.52` | +| ----------------------- | ------------------- | ------------ | ------------ | +| `_eTip` | `WijmoJS` | 14 | 14 | +| `getClipString` | `WijmoGridJS` | 6 | 6 | +| `reApplyFilterOnUpdate` | `WijmoGridFilterJS` | 2 | 2 | +| `cloneFrozenCells` | `WijmoGridJS` | 1 | 1 | +| `itemsEdited` | `WijmoJS` | 1 | 1 | + +Run this before the browser work. It costs nothing, it is repeatable, and it catches the failure mode +a behavioural check misses: a workaround that no longer does anything while everything still *looks* +fine. + +## How each verdict is reached + +- **1-3** are behavioural workarounds with a vendor id. Check that id against the release's changelog: + a fix means the workaround is a removal candidate, and its removal is its own ticket unless this one + says otherwise. +- **4** is a browser defect, not a Wijmo one. It changes only if the supported-browser matrix changes, + so a Wijmo upgrade keeps it by default and says so rather than staying silent. +- **5** is version-coupled in the direction that matters: it exists *because* of a 2026v1 change, so a + later build could either keep that proxy behaviour (keep the guard) or revert it (the guard becomes + dead code that still costs a `filter` on every bind). Neither is visible from a build — check the + changelog for `CollectionView`, and confirm on the refreshed module in Phase 9. +- **6** is the only verdict that **cannot** be settled offline. Whether the selector still matches + depends on the refreshed stylesheet's DOM, so it stays provisional through Phase 6 and is decided in + Phase 9 with before/after evidence. If Phase 9 edits this file, the module's `Grid` block stylesheet + goes stale — see Phase 9's loopback. + +## Verdicts recorded on `5.20261.52` (ROU-12860) + +Changelog ids in that release: WJM-37517, 35377, 37691, 37615, 37215, 37596, 37523, 37524, 35181, +37533, 33508, 37518, 22911, 37515, 37633. + +| # | Verdict | Justification | +| - | ---------------------- | ------------------------------------------------------------------------------------ | +| 1 | **Kept** | ROU-4207 / no tooltip entry in the changelog. | +| 2 | **Kept** | WJM-35579 is absent from the changelog, and its tracker row reads `Closed (Nothing will be done)`. | +| 3 | **Kept** | Same id, same reason. | +| 4 | **Kept** | Browser defect; the supported-browser matrix did not change in this ticket. | +| 5 | **Kept** | No `CollectionView` proxy change in the changelog. The one `CollectionView` entry (WJM-37533, `newItemIndex` / `insertAt`) is unrelated to item proxying. | +| 6 | **Provisional → Phase 9** | Needs the refreshed filter-panel DOM. Note the predecessor upgrade *introduced* this override for the same reason. | diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index b23fc7c66..964a1ba3f 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2,7 +2,7 @@ > **Repository:** outsystems-datagrid > **Runtime Environment:** User Browser (TypeScript/JavaScript) + OutSystems Server (.NET Extension) -> **Last Updated:** 2026-04-19 +> **Last Updated:** 2026-08-25 ## Overview @@ -17,7 +17,7 @@ graph TB Extension["DataGridUtils Extension
Runs on: OutSystems Server"] %% External services - WijmoLib[Wijmo FlexGrid v5.20261.50
EXTERNAL] + WijmoLib[Wijmo FlexGrid v5.20261.52
EXTERNAL] OSApp[OutSystems Reactive App
EXTERNAL] %% Communication flows @@ -39,7 +39,7 @@ graph TB | External Service | Communication Type | Purpose | |---|---|---| -| Wijmo FlexGrid v5.20261.50 | Sync (JavaScript API) | Third-party grid provider offering data virtualization, editing, filtering, sorting, grouping, export, and multi-panel architecture | +| Wijmo FlexGrid v5.20261.52 | Sync (JavaScript API) | Third-party grid provider offering data virtualization, editing, filtering, sorting, grouping, export, and multi-panel architecture | | OutSystems Reactive App | Sync (JavaScript API) | Consumer application instantiating and controlling grid instances via the `OutSystems.GridAPI` public API | | OutSystems Platform | Sync (Server Actions) | Host platform executing the .NET extension server-side and loading the compiled JS module client-side | | outsystems-datagrid-tests | Sync (WebDriver HTTP) | External test repository validating grid behavior across browsers via WebdriverIO + Cucumber | diff --git a/CLAUDE.md b/CLAUDE.md index 2bbc7af37..1e3cbc2d7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Overview -OutSystems Data Grid wraps Wijmo FlexGrid v5.20261.50 to deliver enterprise-grade spreadsheet functionality in OutSystems Reactive Web applications. The repository contains TypeScript (browser-side grid wrapper) and a .NET extension (server-side data preparation). +OutSystems Data Grid wraps Wijmo FlexGrid v5.20261.52 to deliver enterprise-grade spreadsheet functionality in OutSystems Reactive Web applications. The repository contains TypeScript (browser-side grid wrapper) and a .NET extension (server-side data preparation). ## Foundation Documents @@ -32,7 +32,7 @@ See [CONTRIBUTING.md](./.github/CONTRIBUTING.md) for CI expectations (`npm run b - `src/OSFramework/DataGrid/` -- provider-agnostic interfaces and base classes - `src/Providers/DataGrid/Wijmo/` -- Wijmo FlexGrid implementation of framework contracts - `src/OutSystems/GridAPI/` -- public JavaScript API consumed by OutSystems apps -- `src/@types/wijmo-5.20261.50/` -- vendored Wijmo type definitions +- `src/@types/wijmo-5.20261.52/` -- vendored Wijmo type definitions - `extension/DataGridUtils/Source/NET/` -- .NET extension implementation - `extension/DataGridUtils/Templates/NET/` -- auto-generated Integration Studio stubs - `extension/tests/` -- .NET console test project @@ -80,7 +80,7 @@ Runtime toggles: `OutSystems.GridAPI.Security.EnableCellDataSanitizer(gridID)` / ## Do Not Modify - `extension/DataGridUtils/Templates/NET/` -- auto-generated by Integration Studio -- `src/@types/wijmo-5.20261.50/` -- vendored Wijmo type definitions +- `src/@types/wijmo-5.20261.52/` -- vendored Wijmo type definitions ## ADRs diff --git a/CONTEXT.md b/CONTEXT.md new file mode 100644 index 000000000..4348c7299 --- /dev/null +++ b/CONTEXT.md @@ -0,0 +1,86 @@ +# OutSystems Data Grid + +The browser-side grid wrapper around the Wijmo FlexGrid library, plus the .NET extension that +prepares server-side data for it. This glossary fixes the terms used when talking about the grid, its +third-party library, and the artifacts an upgrade touches. + +## Language + +### The third-party library + +**Wijmo**: +The third-party FlexGrid library the provider layer wraps. Vendor is MESCIUS (formerly GrapeCity). +_Avoid_: FlexGrid on its own (that is one control within Wijmo), GrapeCity + +**Build string**: +The exact Wijmo build identifier, e.g. `5.20261.52`. The only value that uniquely identifies a +release; every asset carries it in a file header. +_Avoid_: version, version number + +**Version description**: +The human-readable release label that pairs a marketing name with a build string, e.g. +`2026v1-Hotfix Wijmo - Build 5.20261.52`. +_Avoid_: version name, release name + +**Wijmo bundle**: +One distributable unit of the Wijmo library, e.g. `wijmo.grid`, `wijmo.xlsx`, `wijmo.input`. Ships as +a `.min.js` runtime file and a matching `.d.ts`. +_Avoid_: module, Wijmo module, script + +**Culture script**: +The per-language localization file for a Wijmo bundle, e.g. `wijmo.culture.pt.min.js`. There are 50. +_Avoid_: language file, locale file, translation + +### Where assets come from + +**Distribution archive**: +The Wijmo release ZIP obtained from the vendor or the Jira ticket attachment. The only source for the +global-flavor type definitions, the unminified stylesheet, and the minified runtime. +_Avoid_: zip, download, release package + +**npm package**: +The `wijmo` entry in `package.json`. Declares the dependency so tooling and SCA scans can see it; it +is not a source for any file the repository or the OutSystems module carries. +_Avoid_: module, npm module, dependency package + +**Vendored types**: +The global-namespace `.d.ts` set tracked under `src/@types/wijmo-/`. Copied verbatim +from the distribution archive, never authored. +_Avoid_: typings, type defs, @types + +### The OutSystems side + +**OutSystems module**: +An OutSystems eSpace, exported as an `.oml` file. The one that carries the grid's runtime assets is +`OutSystemsDataGrid`. +_Avoid_: module on its own, espace, app + +**Per-branch module**: +A hand-made clone of the OutSystems module, named after a task branch, used to validate a change +before it reaches the released module. +_Avoid_: branch module, test module, dev module + +**Changeset**: +A JSON document describing object replacements to apply to an OutSystems module offline, via the +OutSystems CLI. +_Avoid_: patch, diff, migration + +**Reactive Data Grid**: +The Data Grid component for Reactive Web, built from this repository. +_Avoid_: Data Grid on its own when Web is also in play, DataGrid Reactive + +**Web Data Grid**: +The separate Data Grid component for Traditional Web, built from `outsystems-datagrid-web`. Tracks +its own, much older Wijmo build string. +_Avoid_: DataGrid Web, Traditional Grid + +### Documentation targets + +**SBOM row**: +The row naming this component's Wijmo build string in the Confluence software bill of materials for +external libraries. +_Avoid_: version table, libraries page entry + +**Upgrade runbook**: +The team-facing procedure for performing a Wijmo upgrade. There must be exactly one. +_Avoid_: upgrade page, how-to, guide diff --git a/docs/adr/ADR-0007-Wijmo-Upgrade-2026v1-Hotfix.md b/docs/adr/ADR-0007-Wijmo-Upgrade-2026v1-Hotfix.md new file mode 100644 index 000000000..c692012c7 --- /dev/null +++ b/docs/adr/ADR-0007-Wijmo-Upgrade-2026v1-Hotfix.md @@ -0,0 +1,283 @@ +# ADR-0007: Wijmo Upgrade to 2026v1-Hotfix (Build 5.20261.52) + +## Status + +Accepted + +## Context + +ROU-12860 moves the Wijmo FlexGrid provider from `2026v1` (Build `5.20261.50`, ADR-0002) to +`2026v1-Hotfix` (Build `5.20261.52`). The release carries nine new API properties, three breaking +changes, and one property this component wants: `preventCut`, which opts out of Wijmo's new +Ctrl+X handling. + +This is also the first upgrade performed through the `upgrade-wijmo-version` skill rather than by +hand (ADR-0008). That matters here because the run exposed defects in what the procedure believed +about the OutSystems module, and this record carries them. + +## Decision Drivers + +- The declared dependency and the vendored types had already diverged silently, and nothing in the + build detects it. +- The repository cannot render a grid, so every behavioural claim must come from a published module + or from the runtime files themselves. +- `oml validate` reporting zero errors is not evidence that a module refresh worked. +- Behaviour must be unchanged except where the ticket intends otherwise. + +## Considered Options + +- **Caret range (`^5.20261.50`), as ADR-0002 chose** + - Pros: picks up patch releases without a code change. + - Cons: `package-lock.json` is gitignored, so CI resolves fresh on every install. Under the + caret, CI was *already* installing `5.20261.52` against vendored `5.20261.50` types — the + divergence this ADR exists to close. +- **Exact pin (`5.20261.52`)** — chosen. + - Pros: the declared dependency, the vendored types and the module runtime name one build. + - Cons: patch releases need a deliberate change, which is the point. +- **Adopt the release's new properties** — rejected except `preventCut`; see below. +- **Enable Wijmo's new cut handling** — rejected. The grid has no cut hook, so cut-cleared cells + would bypass validation marks, `OnCellValueChange` and undo/redo. + +## Decision Outcome + +**Exact-pin `wijmo` at `5.20261.52`**, refresh the vendored types and stylesheet from the +distribution archive, correct both version constants, opt out of cut handling with `preventCut: true`, +and refresh the module's 64 Wijmo scripts by changeset with the two block stylesheets done by hand. + +### Asset sourcing — the archive is the only source + +The npm package ships the ES-module `.d.ts` flavour and no `.min.js` at all, so it is evidence for the +declared dependency and the source of nothing. Three asset classes come from the archive, and they sit +in **three** directories, not one: + +| Asset | Source | +| --------------------------------------- | ----------------------------------------------- | +| 45 of the 47 vendored root `.d.ts` | `Dist/controls` | +| `wijmo.meta.d.ts` (global flavour) | `Dist/interop/meta` | +| 50 culture `.d.ts` | `Dist/controls/cultures` | +| unminified `wijmo.css` | `Dist/styles` | +| 13 + 50 `.min.js` for the module | `Dist/controls` and `Dist/controls/cultures` | + +`wijmo.interop.grid.d.ts` is the exception: the archive carries **no global-flavour copy anywhere**, +only ES-module copies under `NpmImages/*`. It was taken from npm verbatim and stays ES-module flavour. +That is not a defect — a `.d.ts` with top-level `import`/`export` is a module, contributes no globals, +and this file is referenced nowhere in `src/`. It compiles and goes unused. + +**The archive's 63 `.min.js` files carry a UTF-8 BOM; the module's script content never has.** Copying +it in left a stray `U+FEFF` at the head of all 63 scripts and the grid failed at load with +`e._registerModule is not a function`. Strip the BOM on copy. `_registerModule` exists in both builds, +so this was never an API change. + +### Version constants + +`WijmoFlexGridVersion` becomes `2026v1-Hotfix Wijmo - Build 5.20261.52`. `OSDataGridVersion` is +corrected from `2.23.1` to `2.24.0`, closing a drift against `package.json` and `gulp/DefaultSpecs.js`. +That drift was not cosmetic: `gulp gtaSetVersion` builds its search string from `DefaultSpecs` and calls +`String.replace` with no match assertion, so it had been silently failing to update `Constants.ts` on +every release and would have continued to. + +### New-release review — nine properties, one adopted + +`preventCut: true` is set in `FlexGridConfig.getProviderConfig()` with `preventCut: boolean` on +`IGridProviderConfigs`. The other eight are declined on codebase evidence: `stickyGroupHeaders` and +`newItemIndex`/`insertAt` are behavioural changes the ticket does not ask for, and +`searchDuringComposition`, `customFilter`, `customHighlight`, `boxPlotData`, `treeColumnIndex` and +`truncate` touch controls this component does not use — a reference census returns zero for +AutoComplete, MultiSelect, MultiSelectListBox, TreeGrid, BoxWhisker and ComboBox. + +`truncate` deserves its own line: leaving it unset is what keeps AC11's rounding behaviour, and setting +it would have adopted the breaking change rather than absorbing it. + +### Breaking changes + +| Change | Assessment | +| ------------------------------------------------------- | ----------------------------------------------------------------------------- | +| XLSX default `company` removed (WJM-37633) | **Observable, no code change.** `Export.ts` never sets `company`. Proven from the runtimes: `WijmoXlsxJS` at `.50` carries `…(e.company \|\| "GrapeCity, Inc.")` once, at `.52` zero times. Exports now leave Company empty. | +| `InputNumber` truncation unified for typing and paste (WJM-22911) | **No impact.** `truncate` is set nowhere in `src/`, so default rounding applies; typed and pasted `1.2345` both render `1.23`. | +| Angular minimum raised to `20.3.18` (WJM-37615) | **Not applicable.** Plain TypeScript with Gulp; no Angular wrapper anywhere in the build. | + +### Module refresh — what the procedure got wrong + +The changeset covers **64 scripts**, not the 66 objects originally planned, and every `spec` echoes six +properties plus the new content. Three defects surfaced, and all three passed `oml validate` with zero +errors: + +1. **`addOrReplace` on a block destroys it.** Applied to `Styles/WijmoCSS` and `Structures/Grid`, it + wiped every widget, reset `Public` to false and nulled `Description` — `Grid` losing `Public=true` + is what stops consumers placing it on a screen. The only signal was 12 new `UnusedUserAction` + warnings, because the gutted block no longer called `CreateDataGrid`, `InitGrid` and the rest. Both + block stylesheets are therefore **manual Service Studio steps**. +2. **`addOrReplace` on a Script wipes `RequiredScripts`.** `GridFramework` declares 15 dependencies — + the 13 Wijmo runtime scripts plus `JsZIP` and `GridAuxFeature` — and losing them broke load order at + runtime with nothing in validation to show for it. Echo the array; it is a plain list of script + `GlobalKey` strings. +3. **The BOM**, above. + +The lesson generalises past all three: **a replace verified against a hand-picked list of properties +only checks what its author thought of.** `oml diff` between input and output reports what actually +moved, and both destructive defects would have been glaring in it — the blocks as changed +`(Object MobileBlock)` nodes, the dependencies as `(Object Required Script) … [RemovedFromForeign]`. +It is now the first assertion of the module phase. + +Two further rules the run established. The validation gate compares the warning **set**, not the count: +the refresh legitimately *removed* a pre-existing `Script_SyntaxErrors` on `GridFramework`, so +`warnings == baseline` would have rejected a better module, and a count also passes a one-out-one-in +swap. And the unprotected export is a working copy, not the publish artifact — the shipping module is +protected, so the refreshed changes go back by three-way merge onto it. + +### Workaround review — six sites, six kept + +| Site | Verdict | Justification | +| ----------------------------------------------- | ------- | ----------------------------------------------------------------------------- | +| `ToolTip.ts` (~:118), ROU-4207 | Kept | No tooltip entry in the changelog. Hook `_eTip` present in both builds, 14 occurrences each. | +| `GroupPanel.ts` (~:119), WJM-35579 | Kept | Absent from the changelog; tracker row reads `Closed (Nothing will be done)`. | +| `Export.ts` (~:61), same family | Kept | Same id. `getClipString` present in both, 6 occurrences each. | +| `FlexGrid.ts` `_safari14workaround` | Kept | Browser defect, not a Wijmo one. Supported-browser matrix unchanged. | +| `AbstractDataSource.ts` (~:341), ROU-12689 | Kept | No `CollectionView` proxy change in the changelog; the one `CollectionView` entry (WJM-37533) is unrelated to item proxying. | +| `styles/Grid.css` (~:921-958) | Kept | Filter-panel wrapper selector still matches the refreshed DOM. `styles/Grid.css` unchanged, so the module's `Grid` block needed no refresh. | + +Two of these six are invisible to a keyword grep — the `CollectionView` guard and the CSS override +describe themselves in prose without the word "workaround" — so the inventory is a named list, not a +search result. + +### Validation + +The runtime gate passed: `wijmo.grid.FlexGrid.prototype.hasOwnProperty('preventCut')` returned `true`, +which is the only reliable proof the Wijmo runtime itself is on the new build rather than just our +wrapper. `GetActiveGrid().provider.preventCut` returned `true` — the only available proof the option +reached the constructor, since `_getProviderConfig()` returns `unknown` and the option bag is never +type-checked, so a green build says nothing about it. + +Ctrl+X is inert; Ctrl+C/Ctrl+V still raise validation marks and `OnCellValueChange`; decimal columns +round as before; filter buttons render correctly; and the regression surface — render, sort, filter, +group, edit, non-object rows, grouped CSV export, tooltips — behaved as expected. + +The pre-upgrade baseline was the live public sample, which stays on the released build for the length +of the upgrade. Two comparative checks turned out not to need it: a removed default and a vendor +internal are both provable by diffing the two runtime files. + +### Not done here + +The external WebdriverIO/Cucumber suite in `outsystems-datagrid-tests` and its test-case spreadsheet +were not run. The Third-Party Tools registry, the RPM board and the release-notes draft are outside +this change. The module's *release* publish is a follow-up; what happened here was a per-branch merge +and publish for validation. + +## Links + +- [ADR-0002](./ADR-0002-Wijmo-Upgrade-2026v1.md) — the `5.20261.50` upgrade, and the caret this one + reverses +- [ADR-0006](./ADR-0006-Roll-Back-Incompatible-TypeDoc-Dependency-Bump.md) — the absent-lockfile + consequence behind the exact pin +- [ADR-0008](./ADR-0008-Wijmo-Upgrade-Automation-Shape.md) — the shape of the automation this run + exercised +- WJM-37524 (`preventCut`), WJM-37633 (XLSX `company`), WJM-22911 (`InputNumber` truncation), + WJM-37615 (Angular minimum), WJM-37650 (the SonarQube stylesheet finding, marked fixed in + `2026v1-HF`) +- Wijmo FlexGrid API: + +## Date + +2026-08-26 + +--- + +## Execution record + +First run of the `upgrade-wijmo-version` skill (ADR-0008). One line per phase, with the evidence that +closed it. The four non-`EXECUTED` states exist so a skipped or vacuous phase stays visible instead of +being absorbed into a successful upgrade. + +``` +Phase 0 Arguments EXECUTED Build 5.20261.52 and "2026v1-Hotfix Wijmo - Build 5.20261.52" + read from the ticket summary; npm resolves; archive already on + disk, byte-identical in size to Jira attachment 714103. +Phase 1 Prerequisites EXECUTED git 2.49.0; node 24.13.1 / npm 11.18.0 (= volta pins); dotnet + 9.0.317; signing key set; gh authenticated; OutSystems.Cli + non-shallow, LFS real, Release build runs. +Phase 2 Asset-source gate EXECUTED 47 vendored root .d.ts accounted for across three sources; + 13 runtime bundles located by name; culture parity empty both + ways (50/50); preventCut declared in the archive's own + wijmo.grid.d.ts:3222; archive ships no JSZip. +Phase 3 Branch EXECUTED ROU-12860, 0 ahead / 0 behind origin/dev (50c1224). +Phase 4 Dependency + assets EXECUTED Exact pin; two-way name diff old->new empty (47 root + 50 + cultures); every root header on 5.20261.52; 46/47 global + flavour; wijmo.css 4394 lines; tsc --noEmit clean. +Phase 5 Version strings EXECUTED Both constants corrected; swept CLAUDE.md (3) and + ARCHITECTURE.md (2); docs/adr and specs untouched. +Phase 6 Release review EXECUTED 9 API Updates -> 1 adopted, 8 declined on codebase evidence; + 3 breaking changes assessed; 6 workaround sites, 5 kept and 1 + provisional; NFR2/NFR5 clean. +Phase 7 Build gate EXECUTED npm run build exit 0, zero diagnostics. Required fixing + gulpfile.js first: cleanOldFiles deleted the bundle it had + just built (commit 966b102). +Phase 8 Module refresh EXECUTED Inventory reconciled exactly (66 scripts, 0 missing, 0 extra). + 64-script changeset applied to a copy; oml diff reports only + JavaScript x64, Description x63, HasSyntaxErrors x1. + Scope corrected from 66 to 64 mid-phase. +Phase 8m Manual stylesheet EXECUTED Styles/WijmoCSS refreshed by hand; full re-verification after + the Service Studio round trip. +Phase 8b Baseline + publish EXECUTED Baseline = the live public sample. Delivered by three-way + merge onto the protected module, not by publishing the + unprotected export; both sample apps refreshed. +Phase 9 Manual validation EXECUTED Two failed attempts first, both root-caused (RequiredScripts, + BOM). Runtime gate true; provider.preventCut true; AC7-AC11 + and AC13-AC16 as expected; AC10 proven from the runtime files; + all six workaround verdicts final. +Phase 10 ADR + run log EXECUTED ADR-0007 (lowest free number, not highest+1); Readme row + added and aligned; this record appended. +Phase 11 Commit + PR EXECUTED Two signed commits (966b102 gulpfile fix, 9391a9a upgrade), + 114 paths staged by name. Draft PR #528 against dev, labels + dependencies + chore, title matching the required regex. + Neither .claude/settings.local.json nor specs/ was staged. +Phase 12 Confluence EXECUTED SBOM row replaced on 2745598610 (Reactive row only; verified + by re-fetch that exactly one cell moved). Child page 6719996097 + created. Runbook 3058631508 body replaced by a pointer to the + skill after an explicit hard-gate confirmation, child index and + License Update links kept, previous procedure preserved in page + history. Reported-issues candidate list handed over, not + decided: WJM-37650 only, and its id is absent from the release + changelog even though its Status names 2026v1-HF. +Phase 13 Jira enrichment PARTIAL Content posted as comment 1601169 and later updated with the + PR link. The description's "What I Did" template is still + empty: it should have been filled with /enrich-jira-task, + which injects ADF surgically. Owner: task owner. Finding 20. +Phase 14 Final checklist EXECUTED Follow-ups below, each with an owner. +``` + +### What the run changed in the procedure + +Seventeen corrections, made in the same run rather than deferred. Three share a root and are the ones +worth remembering, because in every case `oml validate` stayed green while the module was broken: +`addOrReplace` destroying blocks, the same verb wiping `RequiredScripts`, and the archive's BOM riding +into all 63 scripts. What they have in common is that each was verified against a hand-picked list of +properties rather than against the previous state. `oml diff` is now the first assertion of the module +phase, and it would have caught all three. + +A second theme recurred four times: **compare by name or set, never by count** — archive file sets, +the workaround inventory, the validation warning gate, and the ADR numbering rule that would have +orphaned `ADR-0007` by taking highest-plus-one. + +The full record, including the two findings that were operator-reported rather than self-detected, +is in the ticket's working notes. + +### Manual follow-ups, with owners + +Not done by this change. Each is named here because a follow-up that is not written down is a +follow-up that does not happen. + +| # | Follow-up | Owner | Status | +| - | -------------------------------------------------------------------------------------------------- | ------------ | ------ | +| 1 | **External regression suite** — the WebdriverIO/Cucumber suite in `outsystems-datagrid-tests`, and its test-case spreadsheet. Its outcome is what takes PR #528 out of draft. | Task owner | Done | +| 2 | **The Jira description's "What I Did" template** — content is in comment 1601169; fill the block itself with `/enrich-jira-task`. | Task owner | Done | +| 3 | **The child page's operator sections** — `Fixed Issues`, `New issues found`, the RPMs and the automated-test runs, all left as visible placeholders. | Task owner | Done | +| 4 | **Reported-issues page (3353313306)** — WJM-37650 is the only candidate. | Task owner | Done | +| 5 | **RPM board** — likely N/A, since no reported issue was fixed in this release. | Task owner | Done | +| 6 | **Third-Party Tools registry** (`engineering.outsystems.net/ThirdPartyTools/`) — once the component reaches production. | Task owner | Open | +| 7 | **Release-notes draft**, calling out the XLSX `Company` change as the one user-visible difference. | Task owner | Done | +| 8 | **The module's release publish**, as distinct from the per-branch merge and publish done for validation. | Module owner | Done | +| 9 | **Does CI lose the gulp race?** `azure-pipelines.yml` publishes `dist/GridFramework.js`; before the `cleanOldFiles` fix it may have been publishing an empty directory. Open a past build's artifact and check. **Not investigated.** | Unassigned | Open | +| 10 | **Duplicate `ADR-0005`** — two files carry that number, and `ADR-0005-Remove-Lodash-Dependency.md` has no row in the ADR log. Pre-existing; flagged in PR #528, worth a separate chore. | Unassigned | Open | + +Items 9 and 10 are the two with no owner. Item 9 is the one worth chasing: it is a live question about +what CI has been publishing, raised by this ticket and not answered by it. diff --git a/docs/adr/ADR-0008-Wijmo-Upgrade-Automation-Shape.md b/docs/adr/ADR-0008-Wijmo-Upgrade-Automation-Shape.md new file mode 100644 index 000000000..4774c0b68 --- /dev/null +++ b/docs/adr/ADR-0008-Wijmo-Upgrade-Automation-Shape.md @@ -0,0 +1,172 @@ +# ADR-0008: Shape of the Wijmo Upgrade Automation + +## Status + +Accepted + +## Context + +Wijmo upgrades happen three or four times a year and touch assets that live in four different places: +this repository (npm dependency, vendored types, stylesheet, version constants), the +`OutSystemsDataGrid` OutSystems module (63 Wijmo scripts plus two block stylesheets), Confluence (a +software bill of materials row and a per-upgrade record page), and Jira. The procedure has never been +encoded anywhere executable. What existed instead was a Confluence upgrade runbook last touched in +October 2024, whose author has left, whose download link points at a retired domain, and whose asset +step describes a module folder layout that no longer matches the module. + +ROU-12860 asked for "a command similar to the one created for OS Charts to handle future updates". +The Charts repository is therefore the reference implementation, and it turned out to carry two +overlapping artifacts: a 759-line slash command (`.claude/commands/upgrade-highcharts-version.md`) +covering code, OML, docs PRs, Confluence and Jira, and a 77-line skill +(`.claude/skills/update-highcharts-version/SKILL.md`) covering a narrower code-only process. Neither +references the other, and they have diverged. Porting that structure without deciding what to keep +would import the divergence along with the useful parts. + +Two measurements constrain what "parity with Charts" can mean here: + +- The public documentation repositories carry no Wijmo build string. `docs-product-internal` + (`src/ref/ui-patterns/mobile/data-grid-api-ref.md`) and `docs-next` + (`src/eap/reference/data-grid-ref.md`) describe the component as "built on top of Mescius Data + Grid" behind an unversioned link. The Charts equivalents do carry versions + (`OutSystems uses Highcharts 12.6.0…` in two files, three occurrences). +- Full asset manipulation is scriptable, but validation is not: this repository cannot render a grid, + so every behavioural check runs against a published OutSystems module. + +## Decision Drivers + +- One source of truth for the procedure — the failure this repository is already living with, twice + over (a stale Confluence runbook, and the Charts command/skill split). +- A phase that cannot do anything must not be able to report success. +- Guardrails must be in force without anyone choosing to load them. +- Long-lived reference data (a 66-object inventory, an undocumented changeset schema) must not + consume context on runs that never reach the phase needing it. +- `AC21` requires a file at `.claude/commands/upgrade-wijmo-version.md` with YAML frontmatter. + +## Considered Options + +- **Option 1 — Single slash command, structurally a copy of the Charts command** + - Pros: satisfies AC21 literally with no indirection; one file to read; closest to the letter + of the Jira request. + - Cons: a ~15-phase procedure in one file loads the module inventory and changeset schema on + every run, including runs that stop at the asset gate; invites the same blind port of the two + docs-PR phases. +- **Option 2 — Skill only, with reference files** + - Pros: progressive disclosure; model-invocable; the natural home for a long procedure. + - Cons: leaves AC21 unsatisfied; no discoverable typed entry point for a procedure people + invoke deliberately rather than incidentally. +- **Option 3 — Skill as the single source of truth, plus a thin delegating command** + - Pros: satisfies AC21; keeps one procedure definition; gives both a typed entry point + (`/upgrade-wijmo-version`) and on-demand loading of bulk reference data. + - Cons: two files where a reader might expect one; the indirection needs explaining — which is + what this record is for. +- **Option 4 — Port the Charts phase list wholesale, including the two documentation PRs** + - Pros: literal parity; nothing to justify. + - Cons: two phases that clone a repository, search for a build string that does not exist, + change nothing, and pass. + +## Decision Outcome + +Chosen option: **Option 3**, with the Charts documentation-PR phases deliberately omitted +(Option 4 rejected on the measurement above). + +Concretely: + +- `.claude/skills/upgrade-wijmo-version/SKILL.md` holds the phase sequence, the safety guardrails, + and the run-log format. Guardrails live here, never in a reference file: a guardrail that is only + read when someone goes looking for it does not guard. +- `.claude/skills/upgrade-wijmo-version/references/` holds bulk invariant *data* only — the module + asset inventory, the changeset recipe, and the Confluence/Jira targets and templates. +- `.claude/commands/upgrade-wijmo-version.md` carries frontmatter and delegates. It defines no + procedure of its own. +- Scope covers the Reactive Data Grid only. The Web Data Grid (`outsystems-datagrid-web`, + Traditional Web, maintenance only, four years behind on Wijmo) is named in the skill's + "when not to use" so a run neither adopts it silently nor edits its adjacent SBOM row by mistake. +- The Confluence upgrade runbook becomes a pointer to this skill, and each upgrade adds a child + page following the convention already established by ten predecessor pages. Sections that cannot + be derived — RPMs, automated-test runs, `Fixed Issues`, `New issues found` — are left as + placeholders for the task owner. +- Every phase emits a run-log line (`EXECUTED` / `GATED` / `PARTIAL` / `SKIPPED` / `UNVERIFIED`) + with its evidence, appended to the upgrade's own ADR. + +Positive consequences: + +- The procedure exists in exactly one place, and the two documents that previously competed to be + that place now point at it. +- A skipped or vacuous phase is visible in the run log instead of being absorbed into a successful + upgrade, which is what gives the continuous-improvement clause something to act on. +- Runs that fail at the asset-source gate never load the module inventory or changeset schema. +- The omitted documentation phases are omitted on record. If Data Grid documentation ever starts + naming a build string, the reason to add them back is written down. + +Negative consequences: + +- Two files must stay in sync in one narrow respect: the command's `argument-hint` and the skill's + Phase 0. This is the residual cost of satisfying AC21 without duplicating the procedure. +- The skill is authored before it has ever run. It is written from findings that were measured + rather than assumed, and ROU-12860 is its first execution, but until that run completes the + procedure is unexercised. +- Reference data recorded here — object names, the validation warning baseline, page identifiers — + can drift from the systems it describes. The skill mitigates this by reconciling the live module + inventory against the recorded one and stopping on mismatch, but no such check exists for the + Confluence targets. + +## Execution note — ROU-12860, the first run + +Added after the fact. This record's decisions held; three of its details did not, and one of its stated +risks landed harder than written. + +**What held.** The skill/command split (Option 3) caused no friction: the command's `argument-hint` and +the skill's Phase 0 stayed in sync, and no run loaded the module inventory before reaching the phase +that needs it. Omitting the two documentation-PR phases (Option 4 rejected) was never regretted — +neither documentation repository names a Wijmo build string, and nothing in the run wanted them. +Guardrails-in-`SKILL.md` earned itself: several were consulted in phases that do not repeat them. + +**What changed.** + +- **`references/` holds one more file than this record anticipated.** It said the directory carries + the module inventory, the changeset recipe, and the Confluence/Jira targets. The run added + `workaround-inventory.md`, because a keyword grep finds only four of the six workaround sites and + the two it misses are the two most sensitive to a Wijmo upgrade. Same principle, one more instance: + a code-derived list is wrong. +- **The phase order changed.** Commit-and-PR moved ahead of the two documentation phases, which both + need the PR link. The original order left them holding a placeholder for a later phase to fill — + correct only if someone remembers. +- **Jira enrichment delegates rather than implementing.** Phase 13 now calls `/enrich-jira-task`, + which injects into the ticket's existing slots as ADF. Writing that step by hand was a mistake: + one procedure per job is this record's own principle, and it applies to neighbouring procedures too. + +**The risk that landed.** This record's second negative consequence — "the skill is authored before it +has ever run... until that run completes the procedure is unexercised" — was the accurate one. The run +produced twenty corrections. Three were destructive and shared a root: the recorded changeset recipe +called the block-stylesheet route *verified*, on a probe whose assertion could not tell success from +destruction. `addOrReplace` gutted both blocks, wiped `GridFramework`'s 15 required-script +dependencies, and carried the archive's UTF-8 BOM into all 63 scripts — each with `oml validate` +reporting zero errors. + +That sharpens the third negative consequence too. Reference data does not only *drift*; it can be +wrong on the day it is written, when the measurement that produced it was too weak to see the failure. +The mitigation is now `oml diff` against the previous state as the module phase's first assertion, +rather than a longer list of properties to check. + +**Verdict.** Option 3 was right, and authoring-before-running cost twenty corrections that a +hand-performed upgrade would have absorbed silently. The trade was worth it, but the cost belongs on +the record: this shape is only as good as the first real run is honest. + +## Links + +- [ROU-12860](https://outsystemsrd.atlassian.net/browse/ROU-12860) — the ticket requesting the + automation; predecessor [ROU-12689](https://outsystemsrd.atlassian.net/browse/ROU-12689) +- [ADR-0002](./ADR-0002-Wijmo-Upgrade-2026v1.md) — the previous Wijmo upgrade, performed manually +- [ADR-0006](./ADR-0006-Roll-Back-Incompatible-TypeDoc-Dependency-Bump.md) — the absent-lockfile + consequence behind the exact-pin step +- [CONTEXT.md](../../CONTEXT.md) — vocabulary this skill is written in +- Reference implementation: `outsystems-charts` — `.claude/commands/upgrade-highcharts-version.md` + and `.claude/skills/update-highcharts-version/SKILL.md` +- Confluence: [Wijmo Updates](https://outsystemsrd.atlassian.net/wiki/spaces/RDMBLVS/pages/3058631508/Wijmo+Updates) + (upgrade runbook and per-upgrade index), + [External Libraries in UI Components](https://outsystemsrd.atlassian.net/wiki/spaces/RDMBLVS/pages/2745598610/External+Libraries+in+UI+Components) + (SBOM) + +## Date + +2026-08-25 diff --git a/docs/adr/Readme.md b/docs/adr/Readme.md index 73da57e0c..b955cc6ab 100644 --- a/docs/adr/Readme.md +++ b/docs/adr/Readme.md @@ -33,3 +33,5 @@ Each ADR should follow the template in `ADR-0000-Title-of-ADR.md`. | ADR-0004 | Fix Column-Group Index Collision in ValidationMark Cell Edit Handler | Accepted | 2026-05-12 | | ADR-0005 | Fix Broken ARIA Reference on Column Headers (describedById Misuse) | Accepted | 2026-06-06 | | ADR-0006 | Roll Back Incompatible TypeDoc Dependency Bump | Accepted | 2026-06-06 | +| ADR-0007 | Wijmo Upgrade to 2026v1-Hotfix (Build 5.20261.52) | Accepted | 2026-08-26 | +| ADR-0008 | Shape of the Wijmo Upgrade Automation | Accepted | 2026-08-25 | diff --git a/gulpfile.js b/gulpfile.js index fe32224fb..ba14c8a4c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -17,7 +17,11 @@ const watchTsFiles = 'src/**/*.ts'; // Clean Dist Folder function cleanOldFiles(cb) { if (fs.existsSync(distFolder)) { - gulp.src(distFolder + '/*', { read: false }).pipe(clean()); + // Return the stream so gulp waits for the delete to finish. Without this, cb() completes the + // task immediately and the synchronous TypeScript compile that follows blocks the event loop, + // starving the glob's readdir. It then lists dist/ *after* the compile wrote the bundle and + // deletes it -- leaving a build that exits 0 with an empty dist/. + return gulp.src(distFolder + '/*', { read: false }).pipe(clean()); } cb(); } diff --git a/package.json b/package.json index 716d3a3e3..fe7f3cd7e 100644 --- a/package.json +++ b/package.json @@ -54,10 +54,10 @@ "typedoc-plugin-merge-modules": "^7.0.0", "typedoc-umlclass": "^0.10.2", "typescript": "~5.9.3", - "wijmo": "^5.20261.50" + "wijmo": "5.20261.52" }, "volta": { "node": "24.13.1", "npm": "11.18.0" } -} \ No newline at end of file +} diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ar-AE.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ar-AE.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ar-AE.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ar-AE.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ar-SA.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ar-SA.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ar-SA.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ar-SA.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.bg.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.bg.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.bg.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.bg.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ca.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ca.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ca.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ca.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.cs.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.cs.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.cs.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.cs.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.da.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.da.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.da.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.da.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.de-CH.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.de-CH.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.de-CH.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.de-CH.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.de.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.de.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.de.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.de.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.el.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.el.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.el.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.el.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.en-CA.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.en-CA.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.en-CA.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.en-CA.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.en-GB.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.en-GB.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.en-GB.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.en-GB.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.en.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.en.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.en.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.en.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.es-419.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.es-419.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.es-419.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.es-419.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.es-MX.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.es-MX.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.es-MX.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.es-MX.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.es.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.es.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.es.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.es.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.et.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.et.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.et.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.et.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.eu.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.eu.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.eu.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.eu.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.fi.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.fi.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.fi.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.fi.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.fr-CA.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.fr-CA.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.fr-CA.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.fr-CA.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.fr.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.fr.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.fr.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.fr.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.gl.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.gl.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.gl.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.gl.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.he.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.he.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.he.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.he.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.hi.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.hi.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.hi.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.hi.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.hr.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.hr.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.hr.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.hr.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.hu.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.hu.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.hu.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.hu.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.id.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.id.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.id.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.id.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.it.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.it.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.it.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.it.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ja.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ja.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ja.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ja.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.kk.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.kk.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.kk.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.kk.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ko.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ko.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ko.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ko.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.lt.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.lt.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.lt.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.lt.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.lv.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.lv.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.lv.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.lv.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.mn-MN.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.mn-MN.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.mn-MN.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.mn-MN.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.nl.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.nl.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.nl.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.nl.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.no.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.no.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.no.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.no.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.pl.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.pl.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.pl.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.pl.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.pt.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.pt.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.pt.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.pt.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ro.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ro.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ro.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ro.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ru.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ru.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.ru.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.ru.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.sk.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.sk.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.sk.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.sk.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.sl.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.sl.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.sl.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.sl.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.sr.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.sr.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.sr.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.sr.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.sv.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.sv.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.sv.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.sv.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.th.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.th.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.th.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.th.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.tr.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.tr.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.tr.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.tr.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.uk.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.uk.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.uk.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.uk.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.vi.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.vi.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.vi.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.vi.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.zh-HK.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.zh-HK.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.zh-HK.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.zh-HK.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.zh-TW.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.zh-TW.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.zh-TW.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.zh-TW.d.ts diff --git a/src/@types/wijmo-5.20261.50/cultures/wijmo.culture.zh.d.ts b/src/@types/wijmo-5.20261.52/cultures/wijmo.culture.zh.d.ts similarity index 100% rename from src/@types/wijmo-5.20261.50/cultures/wijmo.culture.zh.d.ts rename to src/@types/wijmo-5.20261.52/cultures/wijmo.culture.zh.d.ts diff --git a/src/@types/wijmo-5.20261.50/wijmo.barcode.common.d.ts b/src/@types/wijmo-5.20261.52/wijmo.barcode.common.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.barcode.common.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.barcode.common.d.ts index bd101a5a5..8b9c5c5f7 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.barcode.common.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.barcode.common.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.barcode.composite.d.ts b/src/@types/wijmo-5.20261.52/wijmo.barcode.composite.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.barcode.composite.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.barcode.composite.d.ts index aeb16fd57..366df4f84 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.barcode.composite.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.barcode.composite.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.barcode.d.ts b/src/@types/wijmo-5.20261.52/wijmo.barcode.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.barcode.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.barcode.d.ts index 2d894b82c..ca5e6d7b4 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.barcode.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.barcode.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.barcode.specialized.d.ts b/src/@types/wijmo-5.20261.52/wijmo.barcode.specialized.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.barcode.specialized.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.barcode.specialized.d.ts index af3236ae6..65ab2bbf1 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.barcode.specialized.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.barcode.specialized.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.analytics.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.analytics.d.ts similarity index 90% rename from src/@types/wijmo-5.20261.50/wijmo.chart.analytics.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.analytics.d.ts index a89b657c5..5f5fb8ea1 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.analytics.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.analytics.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -638,6 +638,32 @@ declare module wijmo.chart.analytics { /** Exclude median value when calculating quartile. */ ExclusiveMedian = 1 } + /** + * Represents the final statistics for one rendered box in a + * {@link BoxWhisker} series. + * + * When the box plot values have already been calculated and + * should be used directly by the chart instead of being derived from the raw + * sample array. + */ + interface IBoxPlotData { + /** Gets the lower whisker value to render for the box. */ + min: number; + /** Gets the upper whisker value to render for the box. */ + max: number; + /** Gets the mean value. If omitted, the median is used as the fallback mean. */ + mean?: number; + /** Gets the first quartile (Q1). */ + firstQuartile: number; + /** Gets the third quartile (Q3). */ + thirdQuartile: number; + /** Gets the median value. */ + median: number; + /** Gets the outlier points to render for the box. */ + outlierPoints?: number[]; + /** Gets the inner points to render for the box. */ + innerPoints?: number[]; + } /** * Represents a Box&Whisker chart series. * @@ -654,6 +680,8 @@ declare module wijmo.chart.analytics { private _showInnerPoints; private _showOutliers; private _quartileCalculation; + private _boxPlotData; + private _boxPlotDataMap; hitTester: wijmo.chart._HitTester; /** * Initializes a new instance of the {@link BoxWhisker} class. @@ -707,10 +735,39 @@ declare module wijmo.chart.analytics { * and third quartiles. */ showOutliers: boolean; + /** + * Gets or sets an array of pre-processed box plot statistics. + * + * Use this property when the min/max/quartile/median/mean values for each + * box have already been calculated in advance, for example by a backend + * service or during an earlier preprocessing step. + * + * Each entry corresponds to the point at the same index in the bound raw + * array data. When a valid {@link IBoxPlotData} entry is provided, the + * series renders that box from the supplied statistics instead of + * recalculating them from the raw sample array. When an entry is missing + * or invalid, the series falls back to the default calculation path for + * that point. + * + * The supplied values are treated as the final box plot result for that + * point. In particular, min/max/outlierPoints/innerPoints are used as-is + * and are not recomputed from the raw sample array. + * + * When the series uses CollectionView-backed data, including arrays that + * are internally wrapped as a {@link CollectionView}, the processed + * statistics are associated with the original source items by item identity + * and resolved against the current view items during rendering. This keeps + * the processed values aligned when the view order changes because of + * sorting, filtering, or paging. + */ + boxPlotData: IBoxPlotData[]; private _rendering; _convertPoints(points: number[], axis: wijmo.chart._IAxis): number[]; _drawBoxWhisker(engine: wijmo.chart.IRenderEngine, xs: any, ys: any, prevXS: any, prevYS: any, series: wijmo.chart._ISeries): void; _renderLabels(engine: wijmo.chart.IRenderEngine, smap: wijmo.chart._IHitArea[], chart: wijmo.chart.FlexChartCore, lblAreas: wijmo.chart._RectArea[]): void; + private _getProcessedBoxPlotData; + private _getBoxPlotDataSourceItems; + private _getBoxPlotDataViewItems; } class _BoxPlot { private _data; @@ -725,7 +782,7 @@ declare module wijmo.chart.analytics { private _outlierPoints; private _innerPoints; private _showOutliers; - constructor(data: number[], quartileCalculation: QuartileCalculation, showOutliers: boolean); + constructor(data: number[] | IBoxPlotData, quartileCalculation: QuartileCalculation, showOutliers: boolean); readonly showOutliers: boolean; readonly min: number; readonly max: number; @@ -736,6 +793,7 @@ declare module wijmo.chart.analytics { readonly outlierPoints: number[]; readonly innerPoints: number[]; _parse(): void; + private _applyProcessedData; _quartileInc(data: number[], percent: number): number; _quartileExc(data: number[], percent: number): number; } diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.animation.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.animation.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.chart.animation.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.animation.d.ts index 1a4de87de..1856814fe 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.animation.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.animation.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.annotation.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.annotation.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.chart.annotation.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.annotation.d.ts index 917666630..28889359f 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.annotation.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.annotation.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.chart.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.d.ts index b9c4d0f99..54eb51e2b 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -3023,7 +3023,7 @@ declare module wijmo.chart { /** * Gets or sets a value indicating whether the axis line is visible. * - * The default value for this property is true. + * The default value for this property is true for the x-axis and is false for the y-axis. */ axisLine: boolean; /** diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.finance.analytics.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.finance.analytics.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.chart.finance.analytics.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.finance.analytics.d.ts index deee88f70..48f139a72 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.finance.analytics.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.finance.analytics.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.finance.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.finance.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.chart.finance.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.finance.d.ts index 3eb8c91cf..1d92e6e9a 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.finance.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.finance.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.hierarchical.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.hierarchical.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.chart.hierarchical.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.hierarchical.d.ts index c5810d4e9..634d45af2 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.hierarchical.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.hierarchical.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.interaction.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.interaction.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.chart.interaction.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.interaction.d.ts index 68b8f2295..119869dc9 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.interaction.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.interaction.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.map.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.map.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.chart.map.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.map.d.ts index 99bcd8260..76b81fd50 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.map.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.map.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.radar.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.radar.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.chart.radar.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.radar.d.ts index ddc60dbf1..fe7f0178c 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.radar.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.radar.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.render.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.render.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.chart.render.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.render.d.ts index 464902643..91fd3dd11 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.render.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.render.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.chart.webgl.d.ts b/src/@types/wijmo-5.20261.52/wijmo.chart.webgl.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.chart.webgl.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.chart.webgl.d.ts index 9fd4074bf..392e82b83 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.chart.webgl.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.chart.webgl.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.cloud.d.ts b/src/@types/wijmo-5.20261.52/wijmo.cloud.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.cloud.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.cloud.d.ts index 01265819f..55d4d9374 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.cloud.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.cloud.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -339,6 +339,8 @@ declare module wijmo.cloud { * Raises the {@link hasPendingChangesChanged} event. */ onHasPendingChangesChanged(e?: wijmo.EventArgs): void; + newItemIndex: number; + insertAt(): void; /** * Override {@link commitNew} to add the new item to the database. */ @@ -472,6 +474,8 @@ declare module wijmo.cloud { * @param e {@link RequestErrorEventArgs} that contains information about the error. */ onError(e: wijmo.RequestErrorEventArgs): boolean; + newItemIndex: number; + insertAt(): void; /** * Override {@link commitNew} to add the new item to the database. */ @@ -1150,6 +1154,8 @@ declare module wijmo.cloud { * @param e {@link PageChangingEventArgs} that contains the event data. */ onPageChanging(e: wijmo.collections.PageChangingEventArgs): boolean; + newItemIndex: number; + insertAt(): void; /** * Override {@link commitNew} to add the new item to the database. */ diff --git a/src/@types/wijmo-5.20261.50/wijmo.d.ts b/src/@types/wijmo-5.20261.52/wijmo.d.ts similarity index 97% rename from src/@types/wijmo-5.20261.50/wijmo.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.d.ts index 4bb6b09a8..2b7804ee1 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -10,6 +10,9 @@ * https://developer.mescius.com/wijmo/licensing * */ +declare module wijmo { + const ipaddr: any; +} declare module wijmo { interface _IMap { clear(): void; @@ -36,9 +39,6 @@ declare module wijmo { set(key: K, value: V): this; } } -declare module wijmo { - const ipaddr: any; -} declare module wijmo { /** * Provides binding to complex properties (e.g. 'customer.address.city') @@ -552,12 +552,43 @@ declare module wijmo.collections { * Gets a value that indicates whether an edit transaction is in progress. */ isEditingItem: boolean; + /** + * Gets or sets the zero-based index that the new row template uses when + * inserting items. + * + * When paging is enabled, values in the range `0..pageSize - 1` map to + * positions within the current page. Values less than zero or greater than + * or equal to the current page size keep the original add-new behavior and + * append items to the end of the source collection. When paging is disabled, + * non-negative values are treated as positions within the full source + * collection. + */ + newItemIndex: number; /** * Adds a new item to the collection. * * @return The item that was added to the collection. */ addNew(): any; + /** + * Adds a new item to the collection at the specified position. + * + * + * Similar to removeAt, the index is relative to the view, not to the source collection. + * When paging is enabled, values in the range `0..pageSize - 1` map to + * positions within the current page. Values less than zero or greater than + * or equal to the current page size are ignored. When sorting , filtering or grouping + * is active, valid indexes fall back to the original add-new behavior and + * append items to the end of the source collection. When paging is disabled, + * non-negative values are treated as positions within the full source + * collection. + * + * @param index Zero-based position where the new item should be inserted. + * @param item Optional item to add. + * @param commit Whether to commit the new item immediately. + * @return The item that was added to the collection, or null if the operation failed. + */ + insertAt(index: number, item?: any, commit?: boolean): any; /** * Ends the current edit transaction and, if possible, * restores the original value to the item. @@ -2146,6 +2177,7 @@ declare module wijmo { function _getTextDecorations(font: any): string; function _getDevicePixelTolerance(base: number, roundFn?: (value: number) => number): number; function _getElementBorderWidth(element: HTMLElement | null, side: 'left' | 'right' | 'top' | 'bottom'): number; + function _copyProps(src: any, dst: any, dstProps: string[], excludeProps?: string[]): void; } declare module wijmo { /** @@ -2572,7 +2604,7 @@ declare module wijmo { */ static parseDate(value: string, format: string, refDate?: Date): Date; static getFullFormat(format: string): string; - static _CJK: string; + static _CJKT: string; /** * Gets the first day of the week according to the current culture. * @@ -2583,6 +2615,7 @@ declare module wijmo { * Gets the symbol used as a decimal separator in numbers. */ static getNumberDecimalSeparator(): string; + private static _toExponentialStr; private static _toFixedStr; private static _unquote; private static _numFormatInfo; @@ -3067,6 +3100,7 @@ declare module wijmo.collections { _srtDsc: ObservableArray; _grpDesc: ObservableArray; _newItem: (Partial | T) | null; + _newItemIdx: number; _edtItem: T | null; _edtClone: any; _committing: boolean; @@ -3099,6 +3133,11 @@ declare module wijmo.collections { _initializing: boolean; _calcFields: any; _storeTrackChanges: boolean; + _insertItems: Array<{ + insertPos: number; + item: Partial | T; + insertId: number; + }>; static _collator: Intl.Collator; /** * Initializes a new instance of the {@link CollectionView} class. @@ -3677,6 +3716,29 @@ declare module wijmo.collections { * Gets a value that indicates whether an edit transaction is in progress. */ readonly isEditingItem: boolean; + /** + * Gets or sets the zero-based index that {@link FlexGrid}'s new row template + * uses when inserting new items. + * + * The index is honored only when sorting, filtering, and grouping are inactive. + * With paging enabled, values in the range `0..pageSize - 1` map to positions + * within the current page; values less than zero or greater than or equal to the + * current {@link pageSize} keep the original {@link addNew} behavior and append + * the item to the end of the {@link sourceCollection}. When paging is disabled, + * non-negative values are treated as positions within the full + * {@link sourceCollection}. + * + * @example + * // Use the original addNew behavior (append to sourceCollection) + * cv.newItemIndex = -1; + * + * // Insert at the top of the current page + * cv.newItemIndex = 0; + * + * // Insert at the bottom of the current page + * cv.newItemIndex = cv.pageSize - 1; + */ + newItemIndex: number; /** * Begins an edit transaction of the specified item. * @@ -3737,6 +3799,34 @@ declare module wijmo.collections { * failed. */ addNew(item?: Partial | T, commit?: boolean): Partial | T; + /** + * Adds a new item to the collection at the specified position. + * + * This method is similar to {@link addNew}, but allows you to control where the new + * item is inserted. With paging enabled, values in the range `0..pageSize - 1` + * map to positions within the current page. Values less than zero or greater than + * or equal to the current {@link pageSize} are ignored. When sorting, filtering, + * or grouping is active, valid indexes fall back to the original {@link addNew} + * behavior and append items to the end of the {@link sourceCollection}. When paging is disabled, + * non-negative values are treated as positions within the full + * {@link sourceCollection}. + * + * @param index Zero-based position where the new item should be inserted. + * @param item Item to be added to the collection (optional). + * @param commit Whether to commit the new item immediately. + * @return The item that was added to the collection, or null if the transaction failed. + */ + insertAt(index: number, item?: Partial | T, commit?: boolean): Partial | T; + _insertNewItem(index: number, item?: Partial | T, commit?: boolean, addNewFallback?: boolean): Partial | T; + _createNewItem(item?: Partial | T): Partial | T; + _isValidInsertIndex(index: number): boolean; + _isPaged(): boolean; + _hasActiveViewTransform(): boolean; + _isSort(): boolean; + _isFilter(): boolean; + _isGroup(): boolean; + _getInsertAtPosition(index: number): number; + _finalizeNewItem(item: Partial | T, commit: boolean): void; /** * Ends the current add transaction and saves the pending new item. */ @@ -3914,6 +4004,13 @@ declare module wijmo.collections { */ _clone(): CollectionViewGroup; } + class _CollectionViewItemMap { + private _map; + readonly hasValues: boolean; + clear(): void; + reset(items: any[], values: TValue[], validator?: (value: TValue) => boolean): void; + getValue(item: any): TValue; + } class _NullValue { _id: number; constructor(id: number); @@ -4839,12 +4936,13 @@ declare module wijmo { content: string; } } +declare module wijmo { +} declare module wijmo { function _updateWme(ctl: Control, key: string): void; + function _checkLicenseVersion(vLc: string, vWj: string, nVP: string): boolean; function _ckHT(host: any, domain: any): any; function _isBeforeVersion(vLc: any): boolean; function _isOldLicense(lic: any): boolean; function isSameOrigin(loc1: any, loc2: any): boolean; } -declare module wijmo { -} diff --git a/src/@types/wijmo-5.20261.50/wijmo.gauge.d.ts b/src/@types/wijmo-5.20261.52/wijmo.gauge.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.gauge.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.gauge.d.ts index da5c94e33..ea2194879 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.gauge.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.gauge.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.cellmaker.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.cellmaker.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.cellmaker.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.cellmaker.d.ts index c87b5badf..e4f9d6b5e 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.cellmaker.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.cellmaker.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.d.ts similarity index 97% rename from src/@types/wijmo-5.20261.50/wijmo.grid.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.d.ts index 2c7aac3d2..0d648e2dd 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -67,6 +67,9 @@ declare module wijmo.grid { sortAsc: string; sortDesc: string; sortIndex: string; + stickyGroupCell: string; + stickyGroupHeaders: string; + stickyGroupRow: string; topLeft: string; whiteSpacePre: string; wrap: string; @@ -766,6 +769,7 @@ declare module wijmo.grid { function softMultirow(): any; function softTransposed(): any; function softTransposedMultirow(): any; + function softSheet(): any; function softRestCV(): any; function softODataCV(): any; function softGridInteropBase(): any; @@ -2484,6 +2488,7 @@ declare module wijmo.grid { * EnterExit editing mode and move the selection to the cell below the current one (by default, can be overridden using the {@link keyActionEnter} property) * Delete, BackspaceDelete the currently selected rows (if the {@link allowDelete} property is set to true), or clear the content of the selected cells (if the values are not required). * Control + C or Control + InsertCopy the selection to the clipboard (if the {@link autoClipboard} property is set to true) + * Control + XCopy the selection to the clipboard and clear or delete any selected content that can be modified (if the {@link autoClipboard} property is set to true and the {@link preventCut} property is set to false) * Control + V or Shift + InsertPaste the content of the clipboard into the selected area (if the {@link autoClipboard} property is set to true) * Control + +When {@link allowAddNew} is true, insert a new blank row above the current active cell. (+ key on numpad) * Control + -When {@link allowDelete} is true, delete the row where the active cell is located. (- key on numpad). @@ -2600,6 +2605,7 @@ declare module wijmo.grid { protected _caseSensitive: boolean; protected _readOnly: boolean; protected _indent: number; + protected _treeColIdx: number; protected _autoSizeMode: AutoSizeMode; protected _autoHeights: boolean; protected _quickSize: boolean; @@ -2645,6 +2651,14 @@ declare module wijmo.grid { protected _pOutline: boolean; protected _collapsedGroups: any; protected _stickyHdr: boolean; + protected _stickyGrpHdr: boolean; + private _eStickyGroups; + private _eStickyGroupRowHeaders; + private _stickyGroupPath; + private _stickyGroupTransitionAnchor; + private _stickyGroupReveal; + private _stickyGroupScrollY; + private _stickyGroupKeyboardArrowUp; protected _anchorCursor: boolean; protected _copyHeaders: HeadersVisibility; protected _bigChecks: boolean; @@ -2687,6 +2701,7 @@ declare module wijmo.grid { private _startEditingTimer; _canOverRuleCtrlPress: boolean; _isShiftTab: boolean; + _preventCut: boolean; static _ctrlTemplate: string; private _updateContentAnim; /** @@ -2726,6 +2741,17 @@ declare module wijmo.grid { * The default value for this property is **false**. */ stickyHeaders: boolean; + /** + * Gets or sets a value that determines whether row group headers should remain + * visible when the user scrolls the flexgrid. + * + * This feature is not supported together with frozen rows or columns. + * Keep {@link frozenRows}, {@link frozenColumns}, and {@link frozenCells} + * disabled when using sticky group headers. + * + * The default value for this property is **false**. + */ + stickyGroupHeaders: boolean; /** * Gets or sets a value that determines whether the grid should adjust its size * to fit the maximum content width and available height. @@ -2879,6 +2905,7 @@ declare module wijmo.grid { * *
*
ctrl+C, ctrl+Ins
Copy grid selection to clipboard.
+ *
ctrl+X
Cut grid selection to clipboard.
*
ctrl+V, shift+Ins
Paste clipboard text to grid selection.
*
* @@ -3181,6 +3208,18 @@ declare module wijmo.grid { * The default value for this property is **false**. */ allowDelete: boolean; + /** + * Gets or sets a value that determines whether the grid disables its + * built-in handling for the standard clipboard cut shortcut key. + * + * When this property is set to true, the grid will not copy, clear, + * or delete selected content in response to the cut shortcut. + * The keyboard event is left untouched so the browser and any external + * event listeners may continue to handle it. + * + * This value is a boolean value; you need to pass in a boolean value. The default value for this property is **false**. + */ + preventCut: boolean; /** * Gets or sets which parts of the grid provide cell merging. * @@ -3543,6 +3582,8 @@ declare module wijmo.grid { * Frozen rows/columns do not scroll vertically/horizontally, but the cells they contain * may be selected and edited. * + * Frozen panes are not supported together with {@link stickyGroupHeaders}. + * */ frozenCells: IGridFreezeOptions; /** @@ -3550,6 +3591,8 @@ declare module wijmo.grid { * * Frozen rows do not scroll vertically, but the cells they contain * may be selected and edited. + + * Frozen panes are not supported together with {@link stickyGroupHeaders}. * * The default value for this property is **0**. */ @@ -3560,6 +3603,8 @@ declare module wijmo.grid { * Frozen columns do not scroll horizontally, but the cells they contain * may be selected and edited. * + * Frozen panes are not supported together with {@link stickyGroupHeaders}. + * * The default value for this property is **0**. */ frozenColumns: number; @@ -3886,6 +3931,24 @@ declare module wijmo.grid { * {@link FlexGrid} control, and **32** pixels for the **PivotGrid**. */ treeIndent: number; + /** + * Gets or sets the index of the column that displays the tree outline + * (expand/collapse buttons and indentation) in Treegrid. + * + * By default (value = -1), the tree outline is shown in the first visible column. + * Set this property to display the tree outline in a specific column. + * + * Example: + *
+         * // show tree buttons and indentation in the second column (index 1)
+         * grid.treeColumnIndex = 1;
+         * 
+ * + * The default value for this property is **-1** (first visible column). + * This API only works in TreeGrid, not in Group. + */ + treeColumnIndex: number; + _getTreeColIndex(): number; _grpClpsChng: boolean; /** * Collapses all the group rows to a given level. @@ -4967,6 +5030,70 @@ declare module wijmo.grid { protected handleLoad(): void; private _applyOverflow; private _updateStickyHeaders; + private _shouldShowStickyGroupHeaders; + private _createStickyGroupOverlayElement; + private _ensureStickyGroupOverlay; + private _ensureStickyGroupRowHeaderOverlay; + private _disposeStickyGroupContainerContent; + private _ensureStickyGroupOverlaySlot; + private _trimStickyGroupOverlaySlots; + private _clearStickyGroupOverlay; + private _hideStickyGroupOverlay; + private _resetStickyGroupState; + private _resetStickyGroupRevealTransition; + private _getStickyGroupBaseTop; + private _getStickyGroupBaseNaturalTop; + private _getStickyGroupViewportWidth; + private _getStickyGroupViewportHeight; + private _getStickyGroupSlotNaturalTop; + private _findStickyGroupBranchEnd; + private _findStickyGroupSlotRow; + private _collectStickyGroupPath; + private _isStickyGroupPathPrefix; + private _getStickyGroupSharedPrefixLength; + private _isSameStickyGroupPath; + private _findVisibleGroupRow; + private _findLastVisibleGroupRowInBranch; + private _getStickyGroupDriverTop; + private _getStickyGroupCellGeometry; + private _getStickyGroupBottomSlotTop; + private _findStickyGroupDriverRow; + private _useLiveStickyGroupPath; + private _getStickyGroupIncomingPathAbove; + private _armStickyGroupRevealTransition; + private _continueStickyGroupRevealTransition; + private _resolveStickyGroupPathWhileScrollingUp; + private _trimReleasedStickyGroupRows; + private _tryStartStickyGroupTransition; + private _continueStickyGroupTransition; + private _createStickyGroupPathResolution; + private _resolveStickyGroupPath; + private _buildStickyGroupSlots; + private _applyStickyGroupReveal; + private _getStickyGroupOverlayBottom; + private _getStickyGroupPathBottom; + private _getStickyGroupKeyboardRevealBottom; + _setStickyGroupKeyboardArrowUp(value: boolean): void; + private _scrollIntoViewStickyGroupBoundary; + private _applyStickyGroupPushOff; + private _updateStickyGroupOverlayBounds; + private _renderStickyGroupCell; + private _renderStickyGroupCellForColumn; + private _renderStickyGroupPanelCells; + private _createStickyGroupSlotRow; + private _renderStickyGroupOverlaySlot; + private _updateStickyGroupHeaders; + private _resolveStickyGroupSlots; + private _createStickyGroupOverlayLayout; + private _prepareStickyGroupOverlays; + private _renderStickyGroupOverlays; + _hitStickyGroupCell(pt: wijmo.Point): { + cell: HTMLElement; + row: number; + col: number; + panel: GridPanel; + rng: CellRange | null; + } | null; private _updateScrollHandler; _getClipToScreen(): boolean; private _scroll; @@ -5252,11 +5379,17 @@ declare module wijmo.grid { private _ieKeypressTimer; private _ieActivateEditorTimer; private _setSelectionRangeTimer; + private _imeEditInput; + private _imeEditInputState; + private _imeCompositionFinalizeTimer; + private _imeEditInputCleanup; + private _imeCompositionHandOffCleanup; private _displayMonthChangingHandler; private _displayMonthChangedHandler; private _savedGridWidth; private _isDroppedDownChangingHandler; private _isDroppedDownChangedHandler; + private static readonly _IME_COMPOSITION_SETTLE_DELAY; /** * Initializes a new instance of a {@link _CustomEditor}. * @@ -5289,14 +5422,32 @@ declare module wijmo.grid { private _cmpstart; private _keydown; private _checkColumn; + private _handoffImeCompositionOnAutoCompleteDropDownKey; + private _isAutoCompleteDropDownNavigationKey; private _mousedown; private _activateEditor; private showEditor; private _hideEditor; _resetTabIndex(): void; private _updateFocus; + private _matchesColumn; private _onHostBlur; + private _cancelImeCompositionFinalize; + private _cancelImeCompositionHandOff; + private _scheduleImeCompositionFinalize; + private _setEditorInputValue; + private _dispatchEditorInput; + private _clearImeEditInputState; + private _finalizeImeEditInputValue; private _initImeEditInput; + private _createImeEditInputState; + private _attachImeEditInput; + private _syncImeEditInput; + private _detachImeEditInput; + private _restoreImeEditInputOwner; + private _finalizeImeComposition; + private _onImeEditInputGotFocus; + private _applyImeEditInputValue; private static _setSelectionRange; private _imeEditor; private _ensureEditorsContainer; @@ -5711,6 +5862,7 @@ declare module wijmo.grid { private _getFrozenRowSide; private _isMouseOutsideGrid; private _isMouseInHeaderArea; + private _isFrozenScrollHeaderSelection; private _isDraggingFromFrozenColWithHiddenContent; private _isDraggingFromFrozenRowWithHiddenContent; private _isDraggingFromFrozenWithHiddenContent; @@ -5737,6 +5889,8 @@ declare module wijmo.grid { private _handleBottomFrozenScroll; private _handleFrozenRowScroll; private _handleFrozenToNonFrozenRowScroll; + private _getFrozenScrollRefreshTarget; + private _refreshSelectionAfterFrozenScroll; private _handleResizing; private _dragstart; private _dragend; @@ -5786,6 +5940,7 @@ declare module wijmo.grid { _isHeadersHandled: boolean; private _finishEditingTimer; private _kbResizing; + _isCut: boolean; /** * Initializes a new instance of the {@link _KeyboardHandler} class. * diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.detail.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.detail.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.detail.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.detail.d.ts index 4c27b24e0..8b369f311 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.detail.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.detail.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -183,6 +183,7 @@ declare module wijmo.grid.detail { _mode: DetailVisibilityMode; _animated: boolean; _toSel: any; + _toFmt: any; _createDetailCellFn: ICreateDetailCell; _disposeDetailCellFn: IDisposeDetailCell; _rowHasDetailFn: IRowHasDetail; diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.filter.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.filter.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.filter.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.filter.d.ts index 9ef6ae786..f7608842f 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.filter.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.filter.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.grouppanel.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.grouppanel.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.grouppanel.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.grouppanel.d.ts index e831e12ca..13c72c96a 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.grouppanel.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.grouppanel.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.immutable.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.immutable.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.immutable.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.immutable.d.ts index 19036e64c..7ce468e22 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.immutable.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.immutable.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.multirow.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.multirow.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.multirow.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.multirow.d.ts index 173ce0b5c..227f76abf 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.multirow.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.multirow.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -246,6 +246,7 @@ declare module wijmo.grid.multirow { _multiRowGroupHeaders: boolean; _collapsedHeadersWasNull: boolean; _btnCollapse: HTMLElement; + protected _isFrozenObjectAllowed(): boolean; _rowHdrCnt: number; _toDimensionCheck: any; static _ctrlTemplate: string; @@ -470,6 +471,8 @@ declare module wijmo.grid.multirow { onCollapsedHeadersChanged(e?: wijmo.EventArgs): void; _allowKeyboardDragging(): boolean; allowPinning: boolean; + treeColumnIndex: number; + stickyGroupHeaders: boolean; onSelectionChanging(e: wijmo.grid.CellRangeEventArgs): boolean; protected _createSelHdl(): wijmo.grid._SelectionHandler; _getDeleteColumnIndex(): number; diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.pdf.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.pdf.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.pdf.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.pdf.d.ts index e06150739..6e9201c96 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.pdf.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.pdf.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -369,6 +369,7 @@ declare module wijmo.grid.pdf { rowHeaders: _IGridPanel; topLeftCells: _IGridPanel; treeIndent: number; + treeColumnIndex: number; getSelection(): _ICellRange[]; getComputedStyle(panel: _IGridPanel, cell: HTMLElement): CSSStyleDeclaration; getComputedDefBorderColor(): string; diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.search.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.search.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.search.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.search.d.ts index dd764dfb5..4b94cdf96 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.search.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.search.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.selector.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.selector.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.selector.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.selector.d.ts index 4da39afd3..9bfb4c2c4 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.selector.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.selector.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.sheet.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.sheet.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.sheet.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.sheet.d.ts index e6fad1a03..b846ecb4e 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.sheet.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.sheet.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -845,6 +845,7 @@ declare module wijmo.grid.sheet { private _sheets; private _selectedSheetIndex; _tabHolder: _TabHolder; + protected _isFrozenObjectAllowed(): boolean; private _isTabHolderVisibleCache; private _contextMenu; private _divContainer; @@ -930,6 +931,7 @@ declare module wijmo.grid.sheet { */ constructor(element: any, options?: any); _getProductInfo(): string; + preventCut: boolean; /** * Gets the collection of {@link Sheet} objects representing workbook sheets. */ @@ -962,6 +964,7 @@ declare module wijmo.grid.sheet { * Gets the {@link FlexSheetFilter} instance that controls FlexSheet filtering. */ readonly filter: FlexSheetFilter; + stickyGroupHeaders: boolean; /** * Gets or sets the visiblity of the filter icon. */ @@ -992,6 +995,7 @@ declare module wijmo.grid.sheet { * a pattern by dragging the bottom right corner of the cell. */ allowAutoFill: boolean; + treeColumnIndex: number; _lastSelMovePos: wijmo.grid.CellRange; _setvalidateEdits(value: boolean): void; /** diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.style.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.style.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.style.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.style.d.ts index b49e2482f..6a029647c 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.style.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.style.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.transposed.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.transposed.d.ts similarity index 97% rename from src/@types/wijmo-5.20261.50/wijmo.grid.transposed.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.transposed.d.ts index f2246750f..ad15b6292 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.transposed.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.transposed.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -58,8 +58,7 @@ declare module wijmo.grid.transposed { * The list of disabled properties includes the following: * {@link FlexGrid.allowAddNew}, {@link FlexGrid.allowDelete}, * {@link FlexGrid.allowSorting}, {@link Column.cellTemplate}, - * {@link Column.editor}, {@link FlexGridFilter}, - * {@link Selector}. + * {@link FlexGridFilter}, {@link Selector}. */ class TransposedGrid extends wijmo.grid.FlexGrid { protected _sourceItems: any; @@ -68,6 +67,7 @@ declare module wijmo.grid.transposed { protected _toRowInfo: any; _rowInfo: wijmo.grid.ColumnCollection; static _ctrlTemplate: string; + protected _isFrozenObjectAllowed(): boolean; /** * Gets or sets the template used to instantiate {@link TransposedGrid} control. */ @@ -136,10 +136,16 @@ declare module wijmo.grid.transposed { allowAddNew: boolean; allowDelete: boolean; allowSorting: wijmo.grid.AllowSorting; + treeColumnIndex: number; + stickyGroupHeaders: boolean; /** * Not supported. Use {@link rowGroups} instead. */ columnGroups: any[]; + /** + * Disposes of the control by removing its association with the host element. + */ + dispose(): void; onRowEditEnded(e: wijmo.grid.CellRangeEventArgs): void; protected _getCollectionView(value: any): wijmo.collections.ICollectionView; _getColumnTypes(arr: any[]): wijmo.IBindingInfo[]; @@ -148,7 +154,6 @@ declare module wijmo.grid.transposed { _getBindingColumn(p: wijmo.grid.GridPanel, r: number, c: wijmo.grid.Column): wijmo.grid.Column; _isTransposed(): boolean; _autoSizeRows(): void; - private _copyProps; private _updateRowHeaders; _rowInfoChanged(): void; _sourceViewChanged(_sender: wijmo.collections.ICollectionView, _e: wijmo.collections.NotifyCollectionChangedEventArgs): void; diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.transposedmultirow.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.transposedmultirow.d.ts similarity index 98% rename from src/@types/wijmo-5.20261.50/wijmo.grid.transposedmultirow.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.transposedmultirow.d.ts index 22164834b..cb6549923 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.transposedmultirow.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.transposedmultirow.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -164,6 +164,7 @@ declare module wijmo.grid.transposedmultirow { _layout: _MultiRowLayout; _bindingColumns: any; protected _view: wijmo.collections.ICollectionView; + protected _isFrozenObjectAllowed(): boolean; protected _keyPrefix: string; _rowInfo: wijmo.grid.ColumnCollection; static _ctrlTemplate: string; @@ -229,6 +230,8 @@ declare module wijmo.grid.transposedmultirow { allowDragging: wijmo.grid.AllowDragging; allowPinning: boolean; allowSorting: wijmo.grid.AllowSorting; + treeColumnIndex: number; + stickyGroupHeaders: boolean; columnLayout: string; refresh(fullUpdate?: boolean): void; onLoadedRows(e?: wijmo.EventArgs): void; diff --git a/src/@types/wijmo-5.20261.50/wijmo.grid.xlsx.d.ts b/src/@types/wijmo-5.20261.52/wijmo.grid.xlsx.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.grid.xlsx.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.grid.xlsx.d.ts index 151bb54db..a1a4b7249 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.grid.xlsx.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.grid.xlsx.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.input.d.ts b/src/@types/wijmo-5.20261.52/wijmo.input.d.ts similarity index 97% rename from src/@types/wijmo-5.20261.50/wijmo.input.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.input.d.ts index cc23e967a..8bb3606a7 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.input.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.input.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -151,6 +151,7 @@ declare module wijmo.input { _min: number; _max: number; _format: string; + _truncate: boolean; _step: number; _showBtn: boolean; _readOnly: boolean; @@ -171,7 +172,6 @@ declare module wijmo.input { _delKey: boolean; _rptUp: wijmo._ClickRepeater; _rptDn: wijmo._ClickRepeater; - _fromKb: boolean; static _ctrlTemplate: string; _inputElementAriaLabel: string; _ariaLabelledby: string; @@ -264,6 +264,16 @@ declare module wijmo.input { * standard numeric format string. */ format: string; + /** + * Gets or sets whether the control truncates numeric values that exceed + * the decimal precision defined by {@link format}, instead of applying rounding. + * + * For example, if {@link format} = 'n2' and the value is 99.999, + * setting {@link truncate} to true will store 99.99 rather than rounding to 100. + * + * Default is **false**, which preserves the standard rounding behavior. + */ + truncate: boolean; /** * Gets or sets the text shown in the control. */ @@ -1248,206 +1258,6 @@ declare module wijmo.input { readonly item: HTMLElement; } } -declare module wijmo.input { - /** - * The {@link MultiSelectListBox} control contains a {@link ListBox} with - * a "Select All" button and a "Filter" input. - * - * The "Select All" and "Filter" elements can be shown or hidden using - * the {@link showSelectAllCheckbox} and {@link showFilterInput} properties. - * - * The {@link MultiSelectListBox} control is used as a drop-down by the - * {@link MultiSelect} control. - */ - class MultiSelectListBox extends wijmo.Control { - _selectAll: HTMLElement; - _filter: HTMLInputElement; - _lbHost: HTMLElement; - _lbx: ListBox; - _cbSelectAll: HTMLInputElement; - _spSelectAll: HTMLSpanElement; - _ariaLabel: string; - _selectAllLabel: string; - _filterPlaceholder: string; - _filterText: string; - _checkOnFilter: boolean; - _delay: number; - _toSearch: any; - static _DEF_CHECKED_PATH: string; - static _ctrlTemplate: string; - /** - * Gets or sets the template used to instantiate {@link MultiSelectListBox} controls. - */ - static controlTemplate: string; - /** - * Initializes a new instance of the {@link MultiSelectListBox} class. - * - * @param element The DOM element that hosts the control, or a CSS selector for the host element (e.g. '#theCtrl'). - * @param options The JavaScript object containing initialization data for the control. - */ - constructor(element: any, options?: any); - /** - * Gets or sets the array or {@link ICollectionView} object that contains - * the list items. - */ - itemsSource: any; - /** - * Gets the {@link ICollectionView} object used as the item source. - */ - readonly collectionView: wijmo.collections.ICollectionView; - /** - * Gets or sets the minimum number of rows and/or columns required to enable - * virtualization in the drop-down {@link ListBox}. - * - * The default value for this property is a very big number, meaning virtualization is - * disabled. To enable virtualization, set its value to 0 or a positive number. - * - * For more detals, please see the {@link ListBox.virtualizationThreshold} - * property. - */ - virtualizationThreshold: number; - /** - * Gets or sets the name of the property to use as the visual - * representation of the items. - */ - displayMemberPath: string; - /** - * Gets or sets a value indicating whether items contain plain - * text or HTML. - * - * The default value for this property is **false**. - */ - isContentHtml: boolean; - /** - * Gets or sets a value that determines whether searches performed - * while the user types should case-sensitive. - * - * The default value for this property is **false**. - */ - caseSensitiveSearch: boolean; - /** - * Gets or sets the delay, in milliseconds, between when a keystroke occurs - * and when the search is performed to update the filter. - * - * This property is relevant only when the {@link showFilterInput} - * property is set to **true**. - * - * The default value for this property is **500** milliseconds. - */ - delay: number; - /** - * Gets or sets a value that determines whether the {@link MultiSelectListBox} should - * include group header items to delimit data groups. - * - * Data groups are created by modifying the {@link ICollectionView.groupDescriptions} - * property of the {@link ICollectionView} object used as an {@link itemsSource}. - * - * The {@link MultiSelectListBox} only shows the first level of grouping. - * - * The default value for this property is **false**. - */ - showGroups: boolean; - /** - * Gets or sets a value that determines whether the {@link MultiSelectListBox} - * should automatically check all filtered items when the filter text changes. - * - * The default value for this property is **true**, which causes the control - * to behave like Excel and check all visible items when the filter is applied. - * - * For example, in a control with three items "Alice", "Bob", and "Mary", - * typing "a" into the filter would cause the control to show items "Alice" - * and "Mary", and both would be checked. - * - * Setting this property to **false** prevents the control from automatically - * checking filtered items, and to keep checked items visible regardless of the - * filter value. - * - * For example, in a control with three items "Alice", "Bob", and "Mary", - * typing "a" into the filter would cause the control to show items "Alice" - * and "Mary", but neither would be checked. - * If the user then checked "Mary", and typed "b" into the filter, the list - * would show items "Mary" (still checked) and "Bob" (unchecked). - */ - checkOnFilter: boolean; - /** - * Gets or sets the index of the currently selected item. - */ - selectedIndex: number; - /** - * Gets a reference to the {@link ListBox} control hosted by this - * {@link MultiSelectListBox}. - */ - readonly listBox: ListBox; - /** - * Gets or sets whether the control should display a "filter" input - * above the items to filter the items displayed. - * - * The default value for this property is **false**. - */ - showFilterInput: boolean; - /** - * Gets or sets the string used as a placeholder for the filter input element. - * - * The default value for this property is **null**, which causes the control - * to show a localized version of the string "Filter". - */ - filterInputPlaceholder: string; - /** - * Gets or sets whether the control should display a "Select All" checkbox - * above the items to select or de-select all items. - * - * The default value for this property is **false**. - */ - showSelectAllCheckbox: boolean; - /** - * Gets or sets the string to be used as a label for the "Select All" - * checkbox that is displayed when the {@link showSelectAllCheckbox} - * property is set to true. - * - * The default value for this property is **null**, which causes the control - * to show a localized version of the string "Select All". - */ - selectAllLabel: string; - /** - * Gets or sets the name of the property used to control the checkboxes - * placed next to each item. - */ - checkedMemberPath: string; - /** - * Gets or sets an array containing the items that are currently checked. - */ - checkedItems: any[]; - /** - * Gets or sets the aria-labelledby attribute of {@link MultiSelectListBox} input element. - */ - ariaLabelledBy: string; - _updateAriaLabel(): void; - /** - * Occurs when the value of the {@link checkedItems} property changes. - */ - readonly checkedItemsChanged: Event, EventArgs>; - /** - * Raises the {@link checkedItemsChanged} event. - */ - onCheckedItemsChanged(e?: any): void; - /** - * Occurs when the value of the {@link selectedIndex} property changes. - */ - readonly selectedIndexChanged: Event, EventArgs>; - /** - * Raises the {@link selectedIndexChanged} event. - */ - onSelectedIndexChanged(e?: wijmo.EventArgs): void; - refresh(fullUpdate?: boolean): void; - dispose(): void; - _applyFilter(): void; - _updateCheckAllCheckbox(): void; - _setIsDisabled(value: boolean): void; - _setTabOrder(value: number): void; - tryForceClearDelayAndFilter(): void; - onLostFocus(): void; - } -} declare module wijmo.input { interface _IDateRange { from: Date | null; @@ -3915,12 +3725,14 @@ declare module wijmo.input { _findNextWhenIsEditableFalse(search: string, step: number, start?: number): number; protected _keydown(e: KeyboardEvent): void; _afterOpenDropdownByDownArrow(): void; - _input(_e: wijmo.Event): void; + _input(e: wijmo.Event): void; _handleDragTextState(): void; _shouldOpenDropdown(): boolean; _handleIsEditableFalseInput(): void; _updateSelection(index: number, editStart: number): void; - _updateComponentText(): void; + _updateComponentText(e?: wijmo.Event): void; + private _getInputTextForUpdate; + private _shouldUseCurrentTextAfterComposition; _updateEmptyValueFlag(): void; _controlDropdownVisibility(): void; _resetDragState(): void; @@ -3934,226 +3746,39 @@ declare module wijmo.input { } declare module wijmo.input { /** - * Represents a method that returns a string used as a header for a - * {@link MultiSelect} control. + * Interface implemented by command objects. + * + * For details, please see the {@link Menu.command} property. */ - interface IHeaderFormatter { + interface ICommand { /** - * @param sender {@link MultiSelect} whose header is being formatted. - * @returns The text to show in the control's header element. + * Executes the command with a given parameter. + * + * The parameter passed to the command is defined by the value of the + * {@link Menu.commandParameterPath} property of the current item. + * If the {@link Menu.commandParameterPath} property is not specified, + * the parameter passed is the item itself. */ - (sender: MultiSelect): string; + executeCommand(parameter: any): void; + /** + * Returns true if the command can be executed in the current app state. + * + * If this method returns false, the corresponding menu option is + * disabled. + */ + canExecuteCommand?(parameter: any): boolean; } /** - * The {@link MultiSelect} control allows users to select multiple items from - * drop-down lists that contain custom objects or simple strings. - * - * The {@link MultiSelect} control extends {@link ComboBox}, with all the usual - * properties, including {@link MultiSelect.itemsSource} and - * {@link MultiSelect.displayMemberPath}. - * - * Like the {@link ListBox} control, it has a {@link MultiSelect.checkedMemberPath} - * property that defines the name of the property that determines whether an - * item is checked or not. + * The {@link Menu} control shows a text element with a drop-down list of commands that + * the user can invoke by click or touch. * - * The items currently checked (selected) can be obtained using the - * {@link MultiSelect.checkedItems} property. + * The {@link Menu} control inherits from {@link ComboBox}, so you populate and style it + * in the same way that you do the {@link ComboBox} (see the {@link Menu.itemsSource} + * property). * - * The control header is fully customizable. By default, it shows up to two items - * selected and the item count after that. You can change the maximum number of - * items to display ({@link MultiSelect.maxHeaderItems}), the message shown when no - * items are selected ({@link MultiSelect.placeholder}), and the format string used to - * show the item count ({@link MultiSelect.headerFormat}). - * - * Alternatively, you can provide a function to generate the header content based - * on whatever criteria your application requires ({@link MultiSelect.headerFormatter}). - * - * The example below shows how you can use a {@link MultiSelect} control to select - * multiple items from a drop-down list: - * - * {@sample Input/MultiSelect/Overview Example} - */ - class MultiSelect extends ComboBox { - private _maxHdrItems; - private _readOnly; - private _hdrFmt; - private _hdrFormatter; - private _msLbx; - static _DEF_CHECKED_PATH: string; - static _ctrlTemplate: string; - _inputElementAriaLabel: string; - /** - * Gets or sets the template used to instantiate {@link MultiSelect} control. - */ - static controlTemplate: string; - /** - * Initializes a new instance of the {@link MultiSelect} class. - * - * @param element The DOM element that hosts the control, or a CSS selector for the host element (e.g. '#theCtrl'). - * @param options The JavaScript object containing initialization data for the control. - */ - constructor(element: any, options?: any); - /** - * Gets or sets whether the control should display a "Select All" checkbox - * above the items to select or de-select all items. - * - * The default value for this property is **false**. - */ - showSelectAllCheckbox: boolean; - /** - * Gets or sets whether the control should display a "filter" input - * above the items to filter the items displayed. - * - * The default value for this property is **false**. - */ - showFilterInput: boolean; - /** - * Gets or sets the delay, in milliseconds, between when a keystroke occurs - * and when the search is performed to update the filter. - * - * This property is relevant only when the {@link showFilterInput} - * property is set to **true**. - * - * The default value for this property is **500** milliseconds. - */ - delay: number; - /** - * Gets or sets a value that determines whether searches performed - * while the user types should case-sensitive. - * - * The default value for this property is **false**. - */ - caseSensitiveSearch: boolean; - /** - * Gets or sets the string used as a placeholder for the filter input - * element on the {@link MultiSelectListBox} drop-down. - * - * The default value for this property is **null**, which causes the - * control to use a localized version of the string "Filter". - */ - filterInputPlaceholder: string | null; - /** - * Gets or sets a value that determines whether the {@link MultiSelectListBox} - * in the drop-down should automatically select all the filtered items when the - * filter text changes. - * - * The default value for this property is **true**. - */ - checkOnFilter: boolean; - /** - * Gets or sets the string to be used as a label for the "Select All" - * checkbox that is displayed when the {@link showSelectAllCheckbox} - * property is set to true. - * - * The default value for this property is **null**, which causes the - * control to use a localized version of the string "Select All". - */ - selectAllLabel: string | null; - /** - * Gets or sets the name of the property used to control the checkboxes - * placed next to each item. - */ - checkedMemberPath: string; - /** - * Gets or sets the maximum number of items to display on the control header. - * - * If no items are selected, the header displays the text specified by the - * {@link placeholder} property. - * - * If the number of selected items is smaller than or equal to the value of the - * {@link maxHeaderItems} property, the selected items are shown in the header. - * - * If the number of selected items is greater than {@link maxHeaderItems}, the - * header displays the selected item count instead. - * - * The default value for this property is **2**. - */ - maxHeaderItems: number; - /** - * Gets or sets the format string used to create the header content - * when the control has more than {@link maxHeaderItems} items checked. - * - * The format string may contain the '{count}' replacement string - * which gets replaced with the number of items currently checked. - * - * The default value for this property is **null**, which causes the - * control to use a localized version of the string "{count:n0} items selected". - */ - headerFormat: string | null; - /** - * Gets or sets a function that gets the text displayed in the control - * header. - * - * By default, the control header content is determined based on the - * {@link placeholder}, {@link maxHeaderItems}, and on the current selection. - * - * You may customize the header content by specifying a function that - * returns a custom string based on whatever criteria your application - * requires. - */ - headerFormatter: IHeaderFormatter | null; - /** - * Gets or sets an array containing the items that are currently checked. - */ - checkedItems: any[]; - /** - * Occurs when the value of the {@link checkedItems} property changes. - */ - readonly checkedItemsChanged: Event; - /** - * Raises the {@link checkedItemsChanged} event. - */ - onCheckedItemsChanged(e?: wijmo.EventArgs): void; - dispose(): void; - onIsDroppedDownChanged(e?: wijmo.EventArgs): void; - onLostFocus(): void; - protected _createDropDown(): void; - _updateBtnAria(): void; - _updateTbxAria(): void; - isReadOnly: boolean; - refresh(fullUpdate?: boolean): void; - protected _setText(_text: string, _fullMatch: boolean): void; - protected _keydown(e: KeyboardEvent): void; - protected _hasItems(): boolean; - private _updateHeader; - getAriaLabelForScreenReader(): any; - } -} -declare module wijmo.input { - /** - * Interface implemented by command objects. - * - * For details, please see the {@link Menu.command} property. - */ - interface ICommand { - /** - * Executes the command with a given parameter. - * - * The parameter passed to the command is defined by the value of the - * {@link Menu.commandParameterPath} property of the current item. - * If the {@link Menu.commandParameterPath} property is not specified, - * the parameter passed is the item itself. - */ - executeCommand(parameter: any): void; - /** - * Returns true if the command can be executed in the current app state. - * - * If this method returns false, the corresponding menu option is - * disabled. - */ - canExecuteCommand?(parameter: any): boolean; - } - /** - * The {@link Menu} control shows a text element with a drop-down list of commands that - * the user can invoke by click or touch. - * - * The {@link Menu} control inherits from {@link ComboBox}, so you populate and style it - * in the same way that you do the {@link ComboBox} (see the {@link Menu.itemsSource} - * property). - * - * The {@link Menu} control adds an {@link Menu.itemClicked} event that fires when the user - * selects an item from the menu. The event handler can inspect the {@link Menu} control - * to determine which item was clicked. For example: + * The {@link Menu} control adds an {@link Menu.itemClicked} event that fires when the user + * selects an item from the menu. The event handler can inspect the {@link Menu} control + * to determine which item was clicked. For example: * * ```typescript * import { Menu } from '@mescius/wijmo.input'; @@ -4751,6 +4376,26 @@ declare module wijmo.input { * */ (items: any[]): void; } + /** + * Represents a custom filter function used by {@link AutoComplete} and {@link MultiSelectListBox}. + * + * @param item The data item to test. + * @param query The current search query string. + * @param text The display text (after displayMemberPath processing). + * @returns **true** to include the item in the filtered results, **false** to exclude it. + */ + type CustomFilterCallback = (item: any, query: string, text: string) => boolean; + /** + * Represents a custom highlight function used by {@link AutoComplete}. + * + * @param item The data item being displayed. + * @param query The current search query string. + * @param text The display text (after displayMemberPath processing). + * @returns An HTML string with highlighted portions wrapped in highlight spans. + * + * **Security Note**: Escape user input with {@link escapeHtml} to prevent XSS attacks. + */ + type CustomHighlightCallback = (item: any, query: string, text: string) => string; /** * The {@link AutoComplete} control is an input control that allows callers * to customize the item list as the user types. @@ -4775,6 +4420,9 @@ declare module wijmo.input { private _itemCount; private _beginsWith; private _delay; + private _searchDuringComposition; + private _customFilter; + private _customHighlight; _selItems: any; private _toSearch; private _query; @@ -4825,6 +4473,18 @@ declare module wijmo.input { * The default value for this property is **500** milliseconds. */ delay: number; + /** + * Gets or sets whether AutoComplete should search while IME composition is active. + * + * The default value for this property is **false**. + * + * When set to **false**, search timing stays unchanged and filtering starts + * only after the composition is committed. + * + * When set to **true**, the control may filter immediately from the current + * composing text while composition is still active. + */ + searchDuringComposition: boolean; /** * Gets or sets a string containing a comma-separated list of properties to use * when searching for items. @@ -4887,6 +4547,43 @@ declare module wijmo.input { * The default value for this property is **wj-state-match**. */ cssMatch: string; + /** + * Gets or sets a custom filter function for filtering items. + * + * When set, this function is used instead of the default filtering logic. + * The function receives the item, the current query string, and the display text, + * and should return true to include the item or false to exclude it. + * + * Set to null to restore default filtering behavior. + * + * @remarks + * When customFilter is set, these properties are ignored: + * - {@link caseSensitiveSearch}, {@link beginsWithSearch}, {@link isContentHtml} + * + * These properties are still honored: + * - {@link maxItems}, {@link minLength} + */ + customFilter: CustomFilterCallback; + /** + * Gets or sets a custom highlight function for highlighting matched text. + * + * When set, this function is called for each filtered item to generate + * the HTML to display in the drop-down list. The function receives the + * item, query, and display text, and should return HTML with highlighted + * portions wrapped in <span class="wj-state-match">. + * + * Set to null to restore default highlighting behavior. + * + * @remarks + * **Security**: Always use {@link escapeHtml} on user content to prevent XSS. + * + * The highlight function is called before formatItem event handlers, + * allowing handlers to override the result. + * + * If the function throws an exception, the error is logged and the + * original text is displayed without highlighting. + */ + customHighlight: CustomHighlightCallback; /** * Raises the {@link selectedIndexChanged} event. */ @@ -4894,6 +4591,13 @@ declare module wijmo.input { _updateTbxAria(): void; _keydown(e: KeyboardEvent): void; _input(_e: wijmo.Event): void; + /** + * Sets the focus to the control and selects all its content. + */ + selectAll(): void; + private _canSearchWhileComposing; + private _hasExternalCompositionFocus; + private _isLegacyImeGuardBrowser; private _isBlurInput; protected _commitText(noFocus?: boolean): void; _setText(text: string | null): void; @@ -5010,5 +4714,421 @@ declare module wijmo.input { _updateTabIndex(): void; } } +declare module wijmo.input { + /** + * The {@link MultiSelectListBox} control contains a {@link ListBox} with + * a "Select All" button and a "Filter" input. + * + * The "Select All" and "Filter" elements can be shown or hidden using + * the {@link showSelectAllCheckbox} and {@link showFilterInput} properties. + * + * The {@link MultiSelectListBox} control is used as a drop-down by the + * {@link MultiSelect} control. + */ + class MultiSelectListBox extends wijmo.Control { + _selectAll: HTMLElement; + _filter: HTMLInputElement; + _lbHost: HTMLElement; + _lbx: ListBox; + _cbSelectAll: HTMLInputElement; + _spSelectAll: HTMLSpanElement; + _ariaLabel: string; + _selectAllLabel: string; + _filterPlaceholder: string; + _filterText: string; + _checkOnFilter: boolean; + _delay: number; + _toSearch: any; + _customFilter: CustomFilterCallback; + static _DEF_CHECKED_PATH: string; + static _ctrlTemplate: string; + /** + * Gets or sets the template used to instantiate {@link MultiSelectListBox} controls. + */ + static controlTemplate: string; + /** + * Initializes a new instance of the {@link MultiSelectListBox} class. + * + * @param element The DOM element that hosts the control, or a CSS selector for the host element (e.g. '#theCtrl'). + * @param options The JavaScript object containing initialization data for the control. + */ + constructor(element: any, options?: any); + /** + * Gets or sets the array or {@link ICollectionView} object that contains + * the list items. + */ + itemsSource: any; + /** + * Gets the {@link ICollectionView} object used as the item source. + */ + readonly collectionView: wijmo.collections.ICollectionView; + /** + * Gets or sets the minimum number of rows and/or columns required to enable + * virtualization in the drop-down {@link ListBox}. + * + * The default value for this property is a very big number, meaning virtualization is + * disabled. To enable virtualization, set its value to 0 or a positive number. + * + * For more detals, please see the {@link ListBox.virtualizationThreshold} + * property. + */ + virtualizationThreshold: number; + /** + * Gets or sets the name of the property to use as the visual + * representation of the items. + */ + displayMemberPath: string; + /** + * Gets or sets a value indicating whether items contain plain + * text or HTML. + * + * The default value for this property is **false**. + */ + isContentHtml: boolean; + /** + * Gets or sets a value that determines whether searches performed + * while the user types should case-sensitive. + * + * The default value for this property is **false**. + */ + caseSensitiveSearch: boolean; + /** + * Gets or sets the delay, in milliseconds, between when a keystroke occurs + * and when the search is performed to update the filter. + * + * This property is relevant only when the {@link showFilterInput} + * property is set to **true**. + * + * The default value for this property is **500** milliseconds. + */ + delay: number; + /** + * Gets or sets a custom filter function for filtering items. + * + * When set, this function is used instead of the default regex-based filtering. + * + * @param item The data item to test. + * @param query The current filter text. + * @param text The display text (after displayMemberPath processing). + * @returns **true** to include the item, **false** to exclude it. + * + * Setting to null restores default filtering. Requires {@link showFilterInput} to be true. + */ + customFilter: CustomFilterCallback; + /** + * Gets or sets a value that determines whether the {@link MultiSelectListBox} should + * include group header items to delimit data groups. + * + * Data groups are created by modifying the {@link ICollectionView.groupDescriptions} + * property of the {@link ICollectionView} object used as an {@link itemsSource}. + * + * The {@link MultiSelectListBox} only shows the first level of grouping. + * + * The default value for this property is **false**. + */ + showGroups: boolean; + /** + * Gets or sets a value that determines whether the {@link MultiSelectListBox} + * should automatically check all filtered items when the filter text changes. + * + * The default value for this property is **true**, which causes the control + * to behave like Excel and check all visible items when the filter is applied. + * + * For example, in a control with three items "Alice", "Bob", and "Mary", + * typing "a" into the filter would cause the control to show items "Alice" + * and "Mary", and both would be checked. + * + * Setting this property to **false** prevents the control from automatically + * checking filtered items, and to keep checked items visible regardless of the + * filter value. + * + * For example, in a control with three items "Alice", "Bob", and "Mary", + * typing "a" into the filter would cause the control to show items "Alice" + * and "Mary", but neither would be checked. + * If the user then checked "Mary", and typed "b" into the filter, the list + * would show items "Mary" (still checked) and "Bob" (unchecked). + */ + checkOnFilter: boolean; + /** + * Gets or sets the index of the currently selected item. + */ + selectedIndex: number; + /** + * Gets a reference to the {@link ListBox} control hosted by this + * {@link MultiSelectListBox}. + */ + readonly listBox: ListBox; + /** + * Gets or sets whether the control should display a "filter" input + * above the items to filter the items displayed. + * + * The default value for this property is **false**. + */ + showFilterInput: boolean; + /** + * Gets or sets the string used as a placeholder for the filter input element. + * + * The default value for this property is **null**, which causes the control + * to show a localized version of the string "Filter". + */ + filterInputPlaceholder: string; + /** + * Gets or sets whether the control should display a "Select All" checkbox + * above the items to select or de-select all items. + * + * The default value for this property is **false**. + */ + showSelectAllCheckbox: boolean; + /** + * Gets or sets the string to be used as a label for the "Select All" + * checkbox that is displayed when the {@link showSelectAllCheckbox} + * property is set to true. + * + * The default value for this property is **null**, which causes the control + * to show a localized version of the string "Select All". + */ + selectAllLabel: string; + /** + * Gets or sets the name of the property used to control the checkboxes + * placed next to each item. + */ + checkedMemberPath: string; + /** + * Gets or sets an array containing the items that are currently checked. + */ + checkedItems: any[]; + /** + * Gets or sets the aria-labelledby attribute of {@link MultiSelectListBox} input element. + */ + ariaLabelledBy: string; + _updateAriaLabel(): void; + /** + * Occurs when the value of the {@link checkedItems} property changes. + */ + readonly checkedItemsChanged: Event, EventArgs>; + /** + * Raises the {@link checkedItemsChanged} event. + */ + onCheckedItemsChanged(e?: any): void; + /** + * Occurs when the value of the {@link selectedIndex} property changes. + */ + readonly selectedIndexChanged: Event, EventArgs>; + /** + * Raises the {@link selectedIndexChanged} event. + */ + onSelectedIndexChanged(e?: wijmo.EventArgs): void; + refresh(fullUpdate?: boolean): void; + dispose(): void; + _applyFilter(): void; + protected _getItemText(item: any, binding?: wijmo.Binding): string; + _updateCheckAllCheckbox(): void; + _setIsDisabled(value: boolean): void; + _setTabOrder(value: number): void; + tryForceClearDelayAndFilter(): void; + onLostFocus(): void; + } +} +declare module wijmo.input { + /** + * Represents a method that returns a string used as a header for a + * {@link MultiSelect} control. + */ + interface IHeaderFormatter { + /** + * @param sender {@link MultiSelect} whose header is being formatted. + * @returns The text to show in the control's header element. + */ + (sender: MultiSelect): string; + } + /** + * The {@link MultiSelect} control allows users to select multiple items from + * drop-down lists that contain custom objects or simple strings. + * + * The {@link MultiSelect} control extends {@link ComboBox}, with all the usual + * properties, including {@link MultiSelect.itemsSource} and + * {@link MultiSelect.displayMemberPath}. + * + * Like the {@link ListBox} control, it has a {@link MultiSelect.checkedMemberPath} + * property that defines the name of the property that determines whether an + * item is checked or not. + * + * The items currently checked (selected) can be obtained using the + * {@link MultiSelect.checkedItems} property. + * + * The control header is fully customizable. By default, it shows up to two items + * selected and the item count after that. You can change the maximum number of + * items to display ({@link MultiSelect.maxHeaderItems}), the message shown when no + * items are selected ({@link MultiSelect.placeholder}), and the format string used to + * show the item count ({@link MultiSelect.headerFormat}). + * + * Alternatively, you can provide a function to generate the header content based + * on whatever criteria your application requires ({@link MultiSelect.headerFormatter}). + * + * The example below shows how you can use a {@link MultiSelect} control to select + * multiple items from a drop-down list: + * + * {@sample Input/MultiSelect/Overview Example} + */ + class MultiSelect extends ComboBox { + private _maxHdrItems; + private _readOnly; + private _hdrFmt; + private _hdrFormatter; + private _msLbx; + static _DEF_CHECKED_PATH: string; + static _ctrlTemplate: string; + _inputElementAriaLabel: string; + /** + * Gets or sets the template used to instantiate {@link MultiSelect} control. + */ + static controlTemplate: string; + /** + * Initializes a new instance of the {@link MultiSelect} class. + * + * @param element The DOM element that hosts the control, or a CSS selector for the host element (e.g. '#theCtrl'). + * @param options The JavaScript object containing initialization data for the control. + */ + constructor(element: any, options?: any); + /** + * Gets or sets whether the control should display a "Select All" checkbox + * above the items to select or de-select all items. + * + * The default value for this property is **false**. + */ + showSelectAllCheckbox: boolean; + /** + * Gets or sets whether the control should display a "filter" input + * above the items to filter the items displayed. + * + * The default value for this property is **false**. + */ + showFilterInput: boolean; + /** + * Gets or sets the delay, in milliseconds, between when a keystroke occurs + * and when the search is performed to update the filter. + * + * This property is relevant only when the {@link showFilterInput} + * property is set to **true**. + * + * The default value for this property is **500** milliseconds. + */ + delay: number; + /** + * Gets or sets a value that determines whether searches performed + * while the user types should case-sensitive. + * + * The default value for this property is **false**. + */ + caseSensitiveSearch: boolean; + /** + * Gets or sets the string used as a placeholder for the filter input + * element on the {@link MultiSelectListBox} drop-down. + * + * The default value for this property is **null**, which causes the + * control to use a localized version of the string "Filter". + */ + filterInputPlaceholder: string | null; + /** + * Gets or sets a value that determines whether the {@link MultiSelectListBox} + * in the drop-down should automatically select all the filtered items when the + * filter text changes. + * + * The default value for this property is **true**. + */ + checkOnFilter: boolean; + /** + * Gets or sets a custom filter function for filtering items. + * + * When set, this function is used instead of the default regex-based filtering + * in the filter input. Requires {@link showFilterInput} to be true. + * + * @param item The data item to test. + * @param query The current filter text. + * @param text The display text (after displayMemberPath processing). + * @returns **true** to include the item, **false** to exclude it. + * + * Setting to null restores default filtering. + */ + customFilter: CustomFilterCallback; + /** + * Gets or sets the string to be used as a label for the "Select All" + * checkbox that is displayed when the {@link showSelectAllCheckbox} + * property is set to true. + * + * The default value for this property is **null**, which causes the + * control to use a localized version of the string "Select All". + */ + selectAllLabel: string | null; + /** + * Gets or sets the name of the property used to control the checkboxes + * placed next to each item. + */ + checkedMemberPath: string; + /** + * Gets or sets the maximum number of items to display on the control header. + * + * If no items are selected, the header displays the text specified by the + * {@link placeholder} property. + * + * If the number of selected items is smaller than or equal to the value of the + * {@link maxHeaderItems} property, the selected items are shown in the header. + * + * If the number of selected items is greater than {@link maxHeaderItems}, the + * header displays the selected item count instead. + * + * The default value for this property is **2**. + */ + maxHeaderItems: number; + /** + * Gets or sets the format string used to create the header content + * when the control has more than {@link maxHeaderItems} items checked. + * + * The format string may contain the '{count}' replacement string + * which gets replaced with the number of items currently checked. + * + * The default value for this property is **null**, which causes the + * control to use a localized version of the string "{count:n0} items selected". + */ + headerFormat: string | null; + /** + * Gets or sets a function that gets the text displayed in the control + * header. + * + * By default, the control header content is determined based on the + * {@link placeholder}, {@link maxHeaderItems}, and on the current selection. + * + * You may customize the header content by specifying a function that + * returns a custom string based on whatever criteria your application + * requires. + */ + headerFormatter: IHeaderFormatter | null; + /** + * Gets or sets an array containing the items that are currently checked. + */ + checkedItems: any[]; + /** + * Occurs when the value of the {@link checkedItems} property changes. + */ + readonly checkedItemsChanged: Event; + /** + * Raises the {@link checkedItemsChanged} event. + */ + onCheckedItemsChanged(e?: wijmo.EventArgs): void; + dispose(): void; + onIsDroppedDownChanged(e?: wijmo.EventArgs): void; + onLostFocus(): void; + protected _createDropDown(): void; + _updateBtnAria(): void; + _updateTbxAria(): void; + isReadOnly: boolean; + refresh(fullUpdate?: boolean): void; + protected _setText(_text: string, _fullMatch: boolean): void; + protected _keydown(e: KeyboardEvent): void; + protected _hasItems(): boolean; + private _updateHeader; + getAriaLabelForScreenReader(): any; + } +} declare module wijmo.input { } diff --git a/src/@types/wijmo-5.20261.50/wijmo.interop.grid.d.ts b/src/@types/wijmo-5.20261.52/wijmo.interop.grid.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.interop.grid.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.interop.grid.d.ts index 0c78f13ef..546086ff5 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.interop.grid.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.interop.grid.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.meta.d.ts b/src/@types/wijmo-5.20261.52/wijmo.meta.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.meta.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.meta.d.ts index eb7e9aefe..a22fa79a9 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.meta.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.meta.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.nav.d.ts b/src/@types/wijmo-5.20261.52/wijmo.nav.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.nav.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.nav.d.ts index 5d82cfbf6..f0febe611 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.nav.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.nav.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.odata.d.ts b/src/@types/wijmo-5.20261.52/wijmo.odata.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.odata.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.odata.d.ts index f858bdc12..289125787 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.odata.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.odata.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -518,6 +518,8 @@ declare module wijmo.odata { * @param interfaceName Name of the interface to look for. */ implementsInterface(interfaceName: string): boolean; + newItemIndex: number; + insertAt(): void; /** * Override {@link commitNew} to add the new item to the database. */ diff --git a/src/@types/wijmo-5.20261.50/wijmo.olap.d.ts b/src/@types/wijmo-5.20261.52/wijmo.olap.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.olap.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.olap.d.ts index bf955c8e1..9124fb355 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.olap.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.olap.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -241,9 +241,11 @@ declare module wijmo.olap { * Gets a reference to the {@link PivotEngine} that owns this view. */ readonly engine: PivotEngine; + newItemIndex: number; implementsInterface(interfaceName: string): boolean; editItem(_item: any): void; addNew(): void; + insertAt(): void; _performSort(items: any[]): void; _performFilter(items: any[]): any[]; _getGroupRange(items: any[], item: any): number[]; @@ -1609,6 +1611,7 @@ declare module wijmo.olap { private _updateFieldValues; _getAggregateObject(item: any, binding: string): any; private _getColTotal; + private _sameParentKeyPath; private _getRunningTotal; private _getLastValueInRowGroup; private _getRowDifference; @@ -1919,6 +1922,7 @@ declare module wijmo.olap { private _showRowFldSort; private _showRowFldHdrs; private _showColFldHdrs; + protected _isFrozenObjectAllowed(): boolean; private _showValFldHdrs; private _centerVert; private _collapsedKeys; @@ -2059,6 +2063,7 @@ declare module wijmo.olap { * ``` */ outlineMode: boolean; + treeColumnIndex: number; /** * Gets an object with information about the fields and values * being used to summarize a given cell. @@ -2107,6 +2112,7 @@ declare module wijmo.olap { * levels expand all columns. */ collapseColumnsToLevel(level: number): void; + stickyGroupHeaders: boolean; _getQuickAutoSize(): boolean; _bindGrid(full: boolean): void; protected _getCollectionView(value: any): wijmo.collections.ICollectionView; diff --git a/src/@types/wijmo-5.20261.50/wijmo.pdf.d.ts b/src/@types/wijmo-5.20261.52/wijmo.pdf.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.pdf.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.pdf.d.ts index 01de63212..5e278c652 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.pdf.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.pdf.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.pdf.security.d.ts b/src/@types/wijmo-5.20261.52/wijmo.pdf.security.d.ts similarity index 98% rename from src/@types/wijmo-5.20261.50/wijmo.pdf.security.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.pdf.security.d.ts index 9430b12a0..f82b40d55 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.pdf.security.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.pdf.security.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.rest.d.ts b/src/@types/wijmo-5.20261.52/wijmo.rest.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.rest.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.rest.d.ts index 59e83aad9..07e8fd3e1 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.rest.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.rest.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -245,6 +245,8 @@ declare module wijmo.rest { * @param e {{@link PageChangingEventArgs} that contains the event data. */ onPageChanging(e: wijmo.collections.PageChangingEventArgs): boolean; + newItemIndex: number; + insertAt(): void; /** * Override {{@link commitNew} to add the new item to the database. */ diff --git a/src/@types/wijmo-5.20261.50/wijmo.touch.d.ts b/src/@types/wijmo-5.20261.52/wijmo.touch.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.touch.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.touch.d.ts index 9fd77aabb..f05992249 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.touch.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.touch.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.undo.d.ts b/src/@types/wijmo-5.20261.52/wijmo.undo.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.undo.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.undo.d.ts index 37823a0c0..398844f7f 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.undo.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.undo.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.viewer.d.ts b/src/@types/wijmo-5.20261.52/wijmo.viewer.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.viewer.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.viewer.d.ts index 193ce64ef..7b66bf3a8 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.viewer.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.viewer.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/@types/wijmo-5.20261.50/wijmo.xlsx.d.ts b/src/@types/wijmo-5.20261.52/wijmo.xlsx.d.ts similarity index 99% rename from src/@types/wijmo-5.20261.50/wijmo.xlsx.d.ts rename to src/@types/wijmo-5.20261.52/wijmo.xlsx.d.ts index 4db366b53..46dbd72ee 100644 --- a/src/@types/wijmo-5.20261.50/wijmo.xlsx.d.ts +++ b/src/@types/wijmo-5.20261.52/wijmo.xlsx.d.ts @@ -1,6 +1,6 @@ /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. diff --git a/src/OSFramework/DataGrid/Configuration/Grid/FlexGridConfig.ts b/src/OSFramework/DataGrid/Configuration/Grid/FlexGridConfig.ts index 441a87697..d818d4fe6 100644 --- a/src/OSFramework/DataGrid/Configuration/Grid/FlexGridConfig.ts +++ b/src/OSFramework/DataGrid/Configuration/Grid/FlexGridConfig.ts @@ -37,6 +37,10 @@ namespace OSFramework.DataGrid.Configuration.Grid { allowMerging: 'Cells', // allow mergeCells API. This option does nothing, without the proper column config. headersFocusability: wijmo.grid.HeadersFocusability.All, // by default, Row and Column headers are focusable via keyboard. isReadOnly: this.allowEdit === false, + // Wijmo 5.20261.52 (WJM-37524) handles Ctrl+X while autoClipboard is on. + // Opt out to preserve the pre-upgrade contract to maintain the same behavior + // before the upgrade; the key event still reaches the browser. + preventCut: true, validateEdits: this.validateEdits, showSelectedHeaders: 'All', // highlight row/column header }; diff --git a/src/OSFramework/DataGrid/Constants.ts b/src/OSFramework/DataGrid/Constants.ts index 3b0924df2..bf802d1ad 100644 --- a/src/OSFramework/DataGrid/Constants.ts +++ b/src/OSFramework/DataGrid/Constants.ts @@ -1,7 +1,7 @@ // eslint-disable-next-line @typescript-eslint/no-unused-vars namespace OSFramework.DataGrid.Constants { /* OutSystems Data Grid Version */ - export const OSDataGridVersion = '2.23.1'; + export const OSDataGridVersion = '2.24.0'; /* OutSystems null values */ export const OSNullDate = '1900-01-01'; export const OSNullDateTime = '1900-01-01T00:00:00'; @@ -12,5 +12,5 @@ namespace OSFramework.DataGrid.Constants { */ export const OSPlatform = '<->platformType<->'; /*Wijmo FlexGrid Version */ - export const WijmoFlexGridVersion = '2026v1 Wijmo - Build 5.20261.50'; + export const WijmoFlexGridVersion = '2026v1-Hotfix Wijmo - Build 5.20261.52'; } diff --git a/src/OSFramework/DataGrid/Types/index.ts b/src/OSFramework/DataGrid/Types/index.ts index ba525b22b..36757e464 100644 --- a/src/OSFramework/DataGrid/Types/index.ts +++ b/src/OSFramework/DataGrid/Types/index.ts @@ -58,6 +58,7 @@ namespace OSFramework.DataGrid.Types { autoGenerateColumns: boolean; headersFocusability: wijmo.grid.HeadersFocusability; isReadOnly: boolean; + preventCut: boolean; showSelectedHeaders: string; validateEdits: boolean; } diff --git a/styles/wijmo.css b/styles/wijmo.css index cedeb6c46..29ba952ca 100644 --- a/styles/wijmo.css +++ b/styles/wijmo.css @@ -1,7 +1,7 @@ @charset "UTF-8"; /*! * - * Wijmo Library 5.20261.50 + * Wijmo Library 5.20261.52 * https://developer.mescius.com/wijmo * * Copyright(c) MESCIUS inc. All rights reserved. @@ -232,7 +232,7 @@ border-top: 0.4em solid transparent; border-right: 0.5em solid; border-bottom: 0.4em solid transparent; - top: 0.12em; + top: 1px; } .wj-glyph-step-backward:after { position: absolute; @@ -247,6 +247,7 @@ } .wj-glyph-step-forward { + top: 1px; border-top: 0.4em solid transparent; border-bottom: 0.4em solid transparent; border-left: 0.5em solid; @@ -1049,6 +1050,7 @@ justify-content: flex-end; } .wj-inputdate-dropdown .wj-calendar-confirmation-button-container .wj-btn { + margin-left: 10px; background: #eee; cursor: pointer; color: black; @@ -1071,9 +1073,6 @@ pointer-events: none; opacity: 0.6; } -.wj-inputdate-dropdown .wj-calendar-confirmation-button-container .wj-btn { - margin-left: 10px; -} .wj-inputdate-dropdown .wj-calendar-confirmation-button-container :focus { outline: none; } @@ -1462,7 +1461,7 @@ } .wj-labeled-input input[type=checkbox]:checked + label:after, .wj-labeled-input input[type=radio]:checked + label:after { - content: "✔"; + content: "✔︎"; background: #007cbe; } .wj-labeled-input input[type=radio] + label:after { @@ -1844,6 +1843,53 @@ .wj-flexgrid .wj-state-sticky .wj-header { opacity: 0.8; } +.wj-flexgrid .wj-sticky-group-headers { + position: absolute; + left: 0; + top: 0; + width: 0; + height: 0; + z-index: 6; + pointer-events: none; +} +.wj-flexgrid .wj-sticky-group-row { + position: absolute; + left: 0; + width: 100%; + pointer-events: none; +} +.wj-flexgrid .wj-sticky-group-cell { + position: absolute; + box-sizing: border-box; + background: inherit; + border-bottom: 1px solid rgba(0, 0, 0, 0.2); + pointer-events: auto; +} +.wj-flexgrid .wj-sticky-group-cell.wj-state-active { + box-shadow: 0 0 0 1px #007cbe, inset 0 0 0 1px #007cbe; +} +.wj-flexgrid .wj-sticky-group-cell.wj-state-selected { + background: #007cbe; + color: white; +} +.wj-flexgrid .wj-sticky-group-cell.wj-state-multi-selected { + background: #4e7b8d; + color: white; +} +@media (forced-colors: active) { + .wj-flexgrid .wj-sticky-group-cell.wj-state-active { + outline: 2px solid Highlight; + outline-offset: -1px; + } + .wj-flexgrid .wj-sticky-group-cell.wj-state-selected { + background-color: Highlight; + color: ActiveText; + } + .wj-flexgrid .wj-sticky-group-cell.wj-state-multi-selected { + background-color: Canvas; + color: ActiveText; + } +} .wj-flexgrid .wj-grid-editor { width: 100%; height: 100%; @@ -3228,6 +3274,25 @@ div[wj-part=div-exceeds] { margin-bottom: 6px; width: 100%; } +.wj-pivotfiltereditor .wj-input-group { + align-items: center; +} +.wj-pivotfiltereditor .wj-glyph-search { + top: 0; + transform: translate(6px, 0); +} +.wj-pivotfiltereditor .wj-valuefilter-editor [wj-part=div-options] { + margin-bottom: 3px; +} +.wj-pivotfiltereditor .wj-valuefilter-editor label[wj-part=lbl-include-sel], +.wj-pivotfiltereditor .wj-valuefilter-editor label[wj-part=select-all-container] { + display: inline-flex; + align-items: center; +} +.wj-pivotfiltereditor .wj-valuefilter-editor label[wj-part=lbl-include-sel] > input[type=checkbox], +.wj-pivotfiltereditor .wj-valuefilter-editor label[wj-part=select-all-container] > input[type=checkbox] { + margin: 0 2px 0 0; +} .wj-pivotfiltereditor .wj-listbox { max-height: 150px; }