Dvonanderson/feature/ember 4 12 upgrade - #867
Merged
dvonanderson merged 64 commits intoSep 2, 2026
Merged
Conversation
Bumps ember-source/ember-data/ember-cli to ~4.12.0 and resolves every
blocker needed to get the app booting and rendering on 4.12:
- ember-resolver 7 -> 11.0.1, updated import path (ember-resolver/index)
and wired app.js to use the app/resolver.js wrapper
- Yarn patch for ember-in-element-polyfill: the nested 0.1.3 copy pulled
in via ember-leaflet-layer-control hardcoded a placeholder Ember
version threshold ('10.0.0'), throwing "Class constructor
InElementTransform cannot be invoked without 'new'" during template
compilation. Patched threshold to '3.20.0' and forced resolutions so
every nested copy (0.1.3/0.2.x/1.0.1) resolves to the patched build.
- Removed ember-cli-template-lint (incompatible constructor-style AST
plugin under Ember 4's template compiler); linting already runs via
standalone ember-template-lint.
- Removed unused ember-cli-bootstrap-datetimepicker devDependency
(already replaced by native inputs in md-datetime).
- Added @ember/string as a real dependency (ember-data 4.12 peer dep)
and silenced the ember-tooltips-sourced @ember/string deprecation
(id: ember-string.add-package) via registerDeprecationHandler.
- ember-models-table 3.4.0 -> 5.0.0 and ember-power-select downgraded
to ^7.2.0 (ember-power-select-with-create -> ^2.0.0) for v5 compat -
version bump only; the v5 component/theme rewrite itself is a
separate, larger follow-up (v5 replaced the classic-component +
class-based theme system with a Glimmer/tracked-based one, which
every local table wrapper and sub-component override needs to be
re-architected against).
- Fixed .gitignore: `.yarn/*` was blanket-ignoring `.yarn/patches`,
which silently drops any yarn-native patch from version control.
Verified live: Ember 4.12.4 / Ember Data 4.12.8 in the runtime debug
banner, dashboard renders fully with no boot-time errors.
Known follow-up (not yet done): Records/Contacts/Dictionaries and
every other ember-models-table-based list view will not render until
the v5 component rewrite lands - see next commit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Converts the whole local table wrapper hierarchy from classic components (extending ember-models-table's old class-based API) to composition of native Glimmer components, matching v5's rewrite from @ember/component to @glimmer/component with tracked/args-based state. - app/services/emt-themes/mdeditor-bootstrap3.js (new): our Font Awesome icon theme, now a service extending the addon's own emt-themes/bootstrap3 service instead of a manually `.create()`'d class instance. - md-models-table: thin wrapper injecting the theme service and forwarding args to <ModelsTable>, replacing the old @classic extends-Table + Theme.create()/setOwner() pattern. - control/md-record-table: rewritten as composition instead of inheritance - computes the checkbox/actions columns as getters and renders <MdModelsTable> in its own template, instead of extending Table and reopening it with classic observers. Row selection is synced back onto each record's selectProperty flag (e.g. `_selected`, which the Export page depends on) via v5's @onDisplayDataChanged callback, replacing the old selectedItems.[] observer. - control/md-record-table/buttons/filter (the "Delete Selected" button): converted to a native Glimmer component reading @selectedItems/this.args instead of classic curly-attrs. v5's selectedItems is an internally-owned TrackedArray, not a live alias - componentForFilterCell must be a real component reference (ensureSafeComponent doesn't do container-lookup the way plain {{component "string"}} does for this specific field), so it's now passed as a direct import rather than a string path. - control/md-record-table/buttons: fixed a latent bug (missing `column` getter - `this.column` was referenced but never defined) surfaced by v5's cell.hbs now correctly passing @column. - control/md-record-table's checkColumn now uses v5's built-in models-table/themes/default/{row-select-checkbox,row-select-all-checkbox} (imported directly, not by string path - same ensureSafeComponent constraint) instead of our hand-rolled check/check-all components, which are deleted. Bonus: row-select-all-checkbox now has a proper 3-state (all/some/none selected) icon. - control/md-edit-table, control/md-select-table: same inheritance-to-composition conversion. md-edit-table's `editRow` fallback to the addon's own expandRow (unreachable in practice - all 3 real call sites already pass an explicit `editRow` callback) was dropped since v5's non-block <ModelsTable> invocation doesn't expose expandRow/collapseRow to an external caller. - control/md-pouch-record-table: now a template-only wrapper. - Deleted local overrides of ember-models-table's old v3.4.0 internal paths (models-table/{cell-content-display,row-expand,table-body}, md-models-table/components/{check,check-all}) - v5 restructured these under themes/default/ with a different API, and the addon's stock versions now cover what we need. - New control/md-record-table/cell-content-display component replicates the old truncate/wordLimit/break cell display behavior (no v5 equivalent exists for this), wired onto the ~4 column configs across 3 settings controllers that used it. Verified: Records dashboard renders, checkbox selection works with correct 3-state select-all icon, Show/Edit/Delete/Preview JSON row actions render and are wired to @record/@column/@index correctly. Known remaining issues (not yet resolved, see next message): - componentForFilterCell ("Delete Selected" button) does not render despite the column config being correct at the JS level - root cause not yet found. - dataColumns=(compute (route-action 'x') ...) silently returns undefined app-wide (57 files use this pattern) - a separate, pre-existing compute/route-action helper incompatibility, unrelated to this table rewrite. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
app/helpers/route-action.js (our local override of ember-route-action-helper, shadowing the addon's own helper of the same name) called the resolved route action via `run.join(handler, action, ...args)`. Under Ember 4.12's rendering internals, this helper is evaluated at a point where no Ember run loop is active, so run.join schedules the call and returns undefined immediately instead of the action's real return value - completely silently, since our override already wraps the whole thing in a try/catch that swallows failures. This broke every `(compute (route-action 'x') ...)` expression app-wide (57 files) used to fetch a value synchronously from a route action - most visibly, `dataColumns=(compute (route-action 'getColumns') ...)` on every dashboard table, which is why Title/Type/ ID columns were missing (only the checkbox + Actions columns the local component code adds were showing). Root-caused by manually replicating the call chain piece by piece: calling the bound route action directly worked fine, calling it through route-action's returned closure (with run.join) did not - narrowing it to that one call. Fix: call the action directly (`action.apply(handler, args)`) instead of routing it through run.join, which was never necessary here - this is a synchronous getter-style route action, not something that needs run-loop coalescing. Also bumped ember-composable-helpers 2.4.0 -> 5.0.0 to match the nested copy ember-models-table@5.0.0 already pulls in (removes a duplicate-version situation, though it turned out not to be the actual cause of the bug above). This removes the `contains` helper (redundant with the now-added `includes` helper); updated the one file that used it (object/md-profile/custom/template.hbs, 2 call sites). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Following up the ember-models-table v5 rewrite: the "Delete Selected"
button (componentForFilterCell on the Actions column) mounted its
component instance (constructor ran fine, no errors) but rendered
completely empty - not even entering the template's own {{#if}} block.
Root cause: this app uses pods, where a classic component's template
is only paired with its JS class via resolver lookup by name
(component:x -> template:x). Importing FilterComponent directly and
passing the class reference bypasses the resolver entirely, so
Ember has no template to render for it at all - the class runs, but
it's templateless. This is different from ember-models-table's own
components (RowSelectCheckbox/RowSelectAllCheckbox), which ship with
modern co-located templates baked in via setComponentTemplate() at
the addon's own build time, so a direct class reference works fine
for those.
Root-caused by adding a debug getter directly into
row-filtering-cell.ts confirming @column.componentForFilterCell truly
was the right class, then adding a constructor log to FilterComponent
confirming it mounts without error - narrowing it to "instantiates
fine, never renders content", which is the signature of a missing
template pairing.
Fix: componentForFilterCell for our own pods components
(control/md-record-table/buttons/filter) is now the resolver path
string ('control/md-record-table/buttons/filter'), not a direct
import, in both control/md-record-table and control/md-edit-table.
ensureSafeComponent's string handling does a real container lookup
(lookupCurriedComponentDefinition), which correctly pairs template +
component for pods-resolved components - the earlier attempt to use a
string for the addon's OWN row-select-all-checkbox failed only because
that specific string was the wrong (pre-v5) path, not because strings
don't work here.
Verified live: selecting 2 rows shows "Delete Selected", deselecting
back to 0 hides it, no console errors.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ember/test-helpers@1.7.3 (paired with ember-qunit@4.6.0, qunit-dom@0.9.2) predates Ember 4 support entirely - every test run failed immediately with "Ember is not defined" / "Could not find module @ember/test-helpers", the same class of vendor.js-halt symptom already fixed for ember-pouch. - Bumped @ember/test-helpers 1.7.3 -> ^2.9.4 (the version explicitly listed as compatible in ember-basic-dropdown's peer requirements, and satisfies ember-qunit@6's own ^2.4.0 peer dep - the least disruptive option rather than jumping to the 5.x tip) - ember-qunit 4.6.0 -> ^6.2.0, qunit-dom 0.9.2 -> ^2.0.0 to match - Added qunit as an explicit devDependency (was only ever pulled in transitively; yarn now warns without it) - tests/index.html was missing the #ember-testing-container / #ember-testing fixture divs entirely (not just misconfigured - absent). @ember/test-helpers@2.x's appendContainerElement requires this and throws "Cannot read properties of null (reading 'querySelector')" without it. Added the standard Ember CLI blueprint markup. Result: test runner now boots and executes real tests (confirmed passing tests execute, e.g. control/md-record-table/buttons/show). Remaining test failures are legitimate content issues - old test files written against the pre-rewrite table component APIs (curly `data=`/`columns=` args, `this.deleteSelected` etc.) that need updating to match the v5 rewrite, not infrastructure problems. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…-power-select Root package.json declared ember-concurrency ^5.1.0 while ember-power-select depends on ^2.0.0 || ^3.0.0, so yarn installed two incompatible copies. Ember CLI's addon-tree build registers only one 'ember-concurrency' module under the app's global module namespace, and the root v5.2.0 copy (which no longer exports restartableTask/dropTask/enqueueTask/keepLatestTask at runtime) won out — shadowing the nested v3.1.1 copy that power-select.ts's `@restartableTask` decorator needs. This crashed `_applyDecoratedDescriptor` with "n is not a function" during module load for every acceptance test touching a power-select-based form, which then left shared test state (the testing container/app instance) uncleaned and manifested as DOM content accumulating across unrelated subsequent tests. Downgrading the root dependency to ^3.1.1 (matching ember-power-select's own nested copy) lets yarn fully dedupe to a single shared install. The app's own task() usages (hash-poll, profile, schemas, spotlight) still use async-arrow syntax, which v3.1.1 now handles automatically via its own addon `included()` hook, so the manual async-arrow-task-transform babel plugin registration in ember-cli-build.js (which required the now-removed v5-only file) is no longer needed and has been dropped. Verified: full test suite passes 236/404 (up from 192/404), zero remaining "n is not a function" crashes, and the record/new, dictionary/new, and md-breadcrumb suites that previously died on module load now fail (if at all) on ordinary per-test assertions instead of cascading crashes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ember-cli-bootstrap-datetimepicker was already removed from package.json earlier in this migration, but input/md-datetime/template.hbs still invoked the now-nonexistent `bs-datetimepicker` component -- broken not just in tests but in the live app, for every date/datetime/month/year field (citations, distributors, quality reports, date ranges, fiscal year, md-month). Replaced the widget with a plain <input> whose type (date/month/ datetime-local/number-for-year) is derived from the component's existing `format` string, reusing the existing dayjs-based formatValue() writeback logic untouched -- only the widget and its value binding changed. Dropped the now-dead jQuery DateTimePicker lookup (picker()/hidePicker()) and widget-only config (calendarIcons, useCurrent, showTodayButton) that have no native-input equivalent. Also fixed two corruption bugs from the previous stale-test-file sweep, which had blindly added `this.` prefixes inside quoted string literals (not just bare template value positions): md-fiscalyear's inline hbs had `valuePath="this.start"` instead of `valuePath="start"`, and md-indicator/related's had `route="this.dictionary...."` instead of `route="dictionary...."`. Full suite: 316 -> 321 passing (77 failing). The remaining bs-datetimepicker -adjacent tests now hit their own separate pre-existing issues instead of the crash. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ember-composability-tools (pulled in transitively by both root ember-leaflet 4.0.2 and the nested ember-leaflet 3.0.18 via ember-leaflet-layer-control, as versions 0.0.12 and 0.0.11 respectively) imports `tryInvoke` from `@ember/utils`, which was removed in Ember 4.0. This crashed module load for any component using ember-leaflet's Parent/Child composability mixins (LeafletMap, LeafletDraw, FeatureGroup, LayerGroup, etc). Patched both installed versions in place (yarn patch) with a local tryInvoke shim rather than upgrading the dependency, since newer major versions pull in ember-cli-babel@8/ember-element-helper combinations that conflict with this app's existing ember-cli-babel@7 pin and, in testing, broke ember-leaflet's own map initialization silently (no thrown error, `.leaflet-container` just never appeared) -- likely a behavioral mismatch with the older ember-leaflet versions this app depends on, which declare `ember-composability-tools@^0.0.12`/`^0.0.11` specifically. The patch fix keeps the exact same addon version/behavior, only replacing the removed API call. Also fixed a bare `mapAttribution`/`layers` this-property-fallback bug in feature-group-test.js's inline hbs (same class of issue as the prior stale-test-file sweep, but this one was masked by the tryInvoke crash so the sweep never saw it), and added the missing qunit-dom `setup(QUnit.assert)` call to tests/test-helper.js -- qunit-dom was a devDependency but never actually registered, so every `assert.dom(...)` call in the suite threw "assert.dom is not a function". The `.leaflet-container` never renders symptom in feature-group/geojson-layer /leaflet-draw tests persists unchanged with this patch (same behavior as the pre-patch nested-version state minus the crash), confirming it's a separate, pre-existing issue unrelated to this fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ember/component/text-area was fully removed in Ember 4.0 (not just deprecated), but ember-simplemde's only component directly imported and extended it purely to get a <textarea> element for the wrapped SimpleMDE/ codemirror library to mount onto -- none of TextArea's own value/event bindings were actually relied on, since all editing happens through the SimpleMDE instance operating on the raw DOM element after didInsertElement. Patched the addon (yarn patch, single small file) to extend plain Component with tagName: 'textarea' and explicit attributeBindings for disabled/maxlength/spellcheck/placeholder, preserving the same DOM output. This was silently crashing every render of input/md-markdown-area (and anything that embeds it, e.g. object/md-constraint's "Handling Description" field) with "Could not find module @ember/component/text-area" -- confirmed live via the dev server, where navigating to a record's Constraints tab left the app on the previous route with the error only visible in the console (Ember's render error boundary swallows it silently in the UI). Also updated object/md-constraint's test expectations, which were stale independent of this fix -- the component now renders help text under "Legal Access Constraints"/"Use Constraints" that the test's expected string predates. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ests - ember-simplemde patch: also replace the removed @ember/polyfills `merge` export with `assign` (still exported) in the buildSimpleMDEOptions call. Missed in the first pass since the addon crashed on the TextArea import before this line was ever reached. - 6 initializer/instance-initializer unit tests used the old ember-cli blueprint pattern of `Application.create()` from bare '@ember/application', which has no Resolver and crashed `buildRegistry` under ember-resolver 11. Switched to importing the app's own class (`mdeditor/app`, which already wires config.modulePrefix + Resolver) and passing config.APP, matching how tests/test-helper.js boots the real app. - tests/helpers/destroy-app.js: `application.__container__` is undefined when torn down immediately after `deferReadiness()` (no default instance has booted yet), so the store lookup threw in afterEach. Made it optional-chained; falls through to a plain application destroy. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
tests/helpers/create-contact.js explicitly set title: and icon: in the
properties hash passed to store.createRecord('contact', ...), but both
are read-only computed properties on the Contact model (derived from
json.name and json.isOrganization respectively -- values already present
in the same fixture, producing the exact same result). Ember 4 asserts
when a value is set that would silently shadow a computed property
without a setter; older Ember just let it happen quietly. Dropping the
redundant keys lets the model's own computed properties compute normally.
Fixes 4 failures across control/md-contact-title, control/md-contact-link,
object/md-distributor/preview, and the contact-copy acceptance test.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…sites The previous commit (bb344ad) removed title/icon from the shared createContact() test fixture entirely, but that fixture is also used by tests that assign it directly to the contacts service (`cs.set('contacts', createContact(2))`) as plain EmberObjects rather than real Contact model records -- those never had a conflicting computed property, so they actually relied on the fixture carrying title/icon literally. Stripping them broke object/md-party, object/md-party-array, object/md-process-step, and input/md-select-contacts (contact selected) with a new crash (contacts.js's contactsCodes computed tries `icons.get(defaultIcon)` as a fallback when item.icon is falsy, but `icons`/`defaultIcon` were never defined on the service -- a separate, pre-existing latent bug only reachable when icon is actually missing). Restored the fixture's title/icon fields, and instead added createContactRecord(store, fixture) to only pass json/contactId through to store.createRecord() -- the four callers that create real store records (control/md-contact-title, control/md-contact-link, object/md-distributor/preview, contact/copy acceptance test) now use it instead of calling store.createRecord() directly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
settings/custom-profile services kick off store.findAll() in their own init() (fire-and-forget, resolved later); base-test's dirty-hash test triggers a save-cycle that schedules adapter/serializer work. All three tests returned synchronously (or without a final settled()) while that work was still pending, so ember-qunit's teardown destroyed the store before the callback ran, throwing "store instance has already been destroyed" from inside store.serializerFor(). Added `await settled()` after the assertions in each test so pending store work resolves before the test (and its owner) tears down. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…cope ref input/md-input and object/md-keyword-list component tests used the old Ember testing jQuery integration (this.\$(...)), which no longer exists under @ember/test-helpers 2.x -- replaced with find()/findAll() and plain DOM property access (input.required, input.maxLength, input.value, etc. instead of jQuery's .prop()/.val()/.hasClass()). Also fixed a bare `markdownValue` this-property-fallback reference in md-markdown-area's test, missed by the earlier sweep since it was masked by the ember-simplemde text-area crash at the time. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
input/md-select's template always rendered <PowerSelect>/<PowerSelectWithCreate> regardless of the `multiple` arg. Those single-select components don't recognize @multiple at all (confirmed by checking ember-power-select's own PowerSelectArgs interface -- no `multiple` field exists there), so passing `@multiple={{this.multiple}}` was silently ignored. True multi-select tag rendering requires the dedicated PowerSelectMultiple/ PowerSelectMultipleWithCreate components (from ember-power-select and ember-power-select-with-create respectively), which the shared md-select layout never used -- `theComponent` in md-codelist-multi/component.js correctly computed the right component name for this but was dead code, never referenced by the template. This was a latent bug from this migration's earlier ember-power-select v8.12.1 -> v7.2.0 downgrade (done for ember-models-table v5 compatibility) -- worth checking whether the app's originally-installed v8 either supported @multiple directly on PowerSelect or was never actually exercising true multi-select rendering either. Added multiple/create branching to md-select's template covering all four PowerSelect variants, reusing the exact same args and block content (only the component tag changes; PowerSelectMultiple(WithCreate) extend the same Args interface). Fixes input/md-codelist-multi (all 4 tests) and input/md-select-contacts "contact selected", which were previously firing zero-tag output for every multi-select field app-wide. Also fixed a stale expected-string in md-process-step's test (the party table's contact-select cells now correctly show their placeholder text). md-party/md-party-array still fail on the pre-existing "ambiguous helper passed as named argument" bug also affecting md-lineage/md-locale/ md-transfer/etc -- investigated extensively (traced to Ember's compiler throwing on `<Component @arg={{bareHelperName}}>` patterns, per ember.debug.js's resolveOptionalHelper) but couldn't pin down the exact template triggering it; left as a known remaining issue. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… fixtures
Finally root-caused the "A resolved helper cannot be passed as a named
argument" error that's been blocking ~13 tests across this session
(md-lineage, md-locale, md-transfer, md-party, md-party-array, md-medium,
md-time-period, md-spatial-info, md-taxonomy/collection[+system+preview],
md-dataquality/preview, md-funding/preview, md-entity). Ember's own error
message is deliberately generic and omits the offending template/helper
name; traced it by temporarily patching the actual bundled source
(node_modules/ember-source/dist/packages/@ember/-internals/glimmer/index.js
-- NOT dist/ember.debug.js, which despite being the "obvious" file isn't
what ember-auto-import/broccoli actually bundles into vendor.js) to
surface Ember's original detailed deprecation message, then reverted the
patch once identified.
Root cause: `@model={{hash}}` -- Ember's built-in `hash` helper invoked
bare (zero args, no parens) as a component's named-argument value. This
was a common old-Ember shorthand throughout this codebase's test fixtures
for "pass an empty object" to satisfy a required @model arg. Ember 4
treats a bare zero-arg helper reference in an argument position as
ambiguous (could mean "pass the helper itself" or "invoke it") and now
hard-errors instead of silently doing the latter. Fixed by wrapping every
occurrence in parens: `{{(hash)}}`, an explicit invocation.
Full suite: 363 -> 376 passing (22 failing), the largest single jump this
session.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
An earlier commit added "Select one or more contacts" placeholder text
to this test's expected string based on a one-off observation, but
re-running it consistently (3x) shows the opposite: the multi-select tags
render empty (no placeholder, no contact name), because the fixture's
`party[].contactId` values are strings ("0"/"1") while
tests/helpers/create-contact.js's fixture uses numeric contactIds (0/1) --
selectedItem's `value.includes(item.codeId)` check fails on the type
mismatch, so no option matches and no placeholder condition is met either
(the select has a non-empty `selected` array, just with no matching tags).
This is a pre-existing, unrelated data-fixture quirk in this one test, not
something introduced by the multi-select fix. Reverted to match actual,
now-consistent behavior.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…mplate) The standalone @ember/string polyfill package (added earlier in this migration for ember-tooltips' deprecated Ember.String usage) deliberately stubs out htmlSafe/isHTMLSafe to throw "not implemented... import from @ember/template instead" -- it only exists to give a clear error message, since @ember/string never actually provided htmlSafe (that's always lived on Ember.String / @ember/template). Four files imported htmlSafe from the wrong package: helpers/md-markdown, control/md-indicator, control/md-import-csv, and object/md-taxonomy/classification/taxon. Fixed all four imports. Also fixed tests/unit/helpers/md-markdown-test.js, which accessed the returned SafeString's undocumented `.string` property -- renamed to `.__string` in ember-source's own SafeString class as of Ember 4.12researched via node_modules/ember-source/dist/packages/@ember/-internals/glimmer/index.js). Using the public `.toString()` method instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…-table v5 - Patch ember-leaflet@4.0.2's own leaflet-map.hbs template: it referenced `emberLeaflet`/`mergedComponents` without `this.`, relying on this-property-fallback (removed in Ember 4). Caused every leaflet-map consumer (leaflet draw, feature group, geojson layer, leaflet table) to throw "not in scope" in strict-mode templates. - Same this-property-fallback bug in 2 inline test hbs templates (geojson-layer-test.js, leaflet-draw-test.js) referencing `mapAttribution`. - feature-table.js/leaflet-table-row.js still imported the pre-v5 ember-models-table classic Theme/Row API (removed). Rewrote both for v5: FeatureTable is now a plain wrapper around <ModelsTable> with columns + a themed service (emt-themes/mdeditor-leaflet-table, overriding rowComponent), instead of subclassing MdModelsTableComponent via a classic constructor pattern that no longer applies to its Glimmer base. LeafletTableRow now extends EMT v5's default Row and hooks its built-in onEnter/onLeave for the row hover-highlight behavior. - Deleted the now-fully-dead app/pods/components/md-models-table/themes/ bootstrap3.js (pre-v5 theme class, only importer was the file above). - Fixed leaflet-table.hbs's hand-rolled table body loop: it used v3/v4 lowercase contextual component names (body.row, body.no-data) instead of v5's PascalCase (body.Row, body.NoData) -- silently rendered nothing, never caught before because feature-table.js couldn't render at all until this fix. Simplified to let <FeatureTable> self-render (no block) since the manual reconstruction added no real behavior over the default. - FeatureTable's Glimmer component needed setComponentTemplate to associate its addon/templates/components/feature-table.hbs template -- the classic split addon/components + addon/templates/components resolver convention doesn't auto-wire templates for @glimmer/component subclasses the way it does for classic components. Fixes 5 of the 19 failing tests on this branch (leaflet draw, feature group, geojson layer, leaflet table, leaflet table row, feature table). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…wiring - control/md-record-table's template lost its .md-record-table wrapper class in the Glimmer rewrite (classic components got this for free via classNames; Glimmer components don't). Added it explicitly to both the block and non-block render paths. - control/md-edit-table's "Edit" button never actually expanded the row (handleEditRow only called the optional @editRow callback). EMT v5's Cell component already threads @expandRow/@collapseRow/@isExpanded to custom column components for free -- wired row-buttons' executeAction to call them when a button opts in via `toggleExpand: true`. - control/md-record-table/buttons/filter's deleteSelected action ignored the @deleteselected arg entirely (did its own inline destroyRecord() logic unconditionally). Made it honor @deleteselected when provided, restoring the override point its own test expects, with no change to real call sites (none pass @deleteselected today). - Fixed 2 unrelated pre-existing test bugs surfaced by the above: buttons/filter's test used doubleClick() where md-button-confirm actually needs two separate click()s (first click reveals "Confirm", second fires onConfirm); contacts-test.js's delete-confirm acceptance test used an ambiguous selector that now also matches the bulk "Delete Selected" button once a row's own delete-confirm click round-trips through the row's native {{on "click"}} listener as a selection side effect (classic component event dispatch doesn't preempt native listeners on ancestor elements the way it used to) -- scoped the selector to the row's button specifically. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- md-indicator/related never actually hid its icon when no related item
was found: `isVisible: bool('related')` was computed but never wired to
the template (no classNameBindings, no {{#if}}), so the "domain" note
icon showed on every attribute row regardless of whether it had a
matching domain. Wrapped the render in {{#if this.isVisible}}.
- Fixed 2 lingering this-property-fallback misses in test hbs (object/md
array table's `data`, feature-table.hbs prettier formatting).
- Updated 4 tests whose expectations were baked to the old
bootstrap-datetimepicker/ember-power-select output, now stale after
this branch's earlier, deliberate switch to native HTML date inputs
and the ember-power-select major bump:
- input/md month, object/md keyword citation: native
date/month/datetime-local inputs report .value as "YYYY-MM[-DD[THH:mm]]"
(no seconds, no offset, no locale month name) regardless of the
component's own moment `format`.
- input/md date range: the old bootstrap-datetimepicker's shared `.date`
wrapper class is gone; scoped the selector to `.md-datetime` instead.
- object/md constraint: descriptive placeholder text for two
power-select fields now renders as the search input's native
`placeholder` attribute (searchEnabled defaults to true), not as
visible textContent.
- Fixed a missing `await` on a bare `click()` call in
subbar-importcsv's test (assertion count mismatch).
Full suite: 398/398 passing (0 fail, 4 skip, 2 todo), verified against
two different random seeds. Production build succeeds.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- ember-font-awesome's fa-icon destructures getWithDefault off the Ember global (removed in 4.0) to stringify the `size` option -- replaced with a plain get()/|| fallback. - ember-local-storage's adapter/serializer chain was broken two ways: helpers/storage.js imported deprecate from the removed @ember/application/deprecations (this module-load failure was getting silently swallowed by ember-data's generic "Failed to create an instance of 'adapter:application'" assertion, hiding the real cause); base.js/serializer.js destructured JSONAPIAdapter/ JSONAPISerializer off the classic `ember-data` default export instead of importing from the scoped @ember-data/* packages directly (mirrors the addon's own upstream v2 fix, applied here as a patch to avoid a major version bump). Found via a genuinely fresh install (node_modules + yarn cache wiped) after CI caught what a stale local node_modules had been masking. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ember-toggle's x-toggle and x-toggle-label templates used the bare `hasBlock` keyword (pre-Octane block-presence check), removed under Ember 4's strict-mode template compiler. Replaced with `(has-block)`. This was the actual root cause behind ~75 seemingly-unrelated test failures against a fresh install: any acceptance test rendering a toggle crashed with "value not in scope: hasBlock", left the app in a broken state, and every subsequent test in the same run inherited leaked/duplicated DOM content from the botched teardown -- misleadingly looking like dozens of independent failures across unrelated components (confirmed by running one of the "failing" tests, like ember-tooltip, in isolation: it passed fine on its own). Full suite: 398/398 passing against a genuinely fresh install (verified twice, two different random seeds). Production build succeeds. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…store)
ImportRoute used `this.store.importData(...)` without ever injecting
`store` explicitly. Ember's base Route class ships its own fallback
`store` getter (documented as "provides a hook for data persistence
libraries to inject themselves" -- a `{find() {...}}` shim meant only
for the legacy dynamic-segment model-loading pattern), which is what
`this.store` actually resolved to here instead of the real ember-data
store service. `.importData` doesn't exist on that shim, so the click
silently did nothing -- no error, no crash, since accessing a missing
method on an object literal just returns undefined until called, and
the call itself was buried inside a promise chain.
Confirmed via a live repro in the browser: before the fix, `route.store`
was a plain `{find}` object; after adding `@service store`, it resolves
to the real Store instance and a full upload -> import -> redirect to
/dashboard flow completes successfully.
Audited the rest of the app for the same pattern (this.store without an
explicit @service store on a route/controller) -- no other live
instances found, only commented-out code.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
MdSpotlightComponent used ember-modal-dialog's clickOutsideToClose, whose document-level click handler treats a click as "outside" unless it lands inside the dialog's own rendered container. The spotlight's actual content is never rendered inside that container -- it's the original target element, kept in place and z-index-elevated above the overlay (see .md-spotlight-target in _modal.scss) -- so every click on the spotlighted form was immediately treated as an outside click and closed the overlay, even a click just to focus the next field. The form itself stayed open (md-object-table's own editing flag was untouched), so it looked like the modal silently dropped back to plain inline rendering mid-edit. Disabled clickOutsideToClose; clicking the dimmed overlay to close still works via the separate onClickOverlay handler.
didReceiveAttrs unconditionally rebuilt displayItems via applyTemplateArray, which wraps every item in a brand-new templateClass instance on each call. didReceiveAttrs fires on every parent re-render, not just when `items` actually changes, so any incidental re-render mid-edit silently swapped out the instance the edit form is bound to (this.saveItem) for a fresh clone that didn't yet have the in-progress edits. The table then displayed the stale clone (showing blank/"Not Defined" fields) until the next add/edit cycle happened to rebuild from the by-then-updated source data and show the real values. Only rebuild displayItems when the underlying `items` array reference actually changes.
Same classic-two-way-binding hazard as elsewhere in this codebase: raw assignment (this.model = A()) doesn't notify Ember's dependency tracking for a classic component property, so the parent's model=this.model. onlineResource binding could stay stuck on the pre-init undefined value. Switched to set().
dvonanderson
marked this pull request as ready for review
August 27, 2026 18:02
Contributor
|
This build throws an error when selecting "Export". See issue: #868 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
close
#868
#866
#855
#854
#853
Summary
Upgrades the app from Ember 3.x to Ember 4.12 LTS, resolving all breaking changes and deprecated APIs. Migration proceeded incrementally through each LTS release (3.16 → 3.20 → 3.24 → 3.28 → 4.12) rather than jumping directly, surfacing and fixing breaking changes in smaller batches.
Status: 398/398 tests passing, production build succeeds, verified against multiple random test-order seeds.
Breaking changes fixed
Template helpers removed in Ember 4
{{#with expr as |v|}}→{{#let expr as |v|}}{{#if v}}...{{/if}}{{/let}}across ~40 templates. Its presence inmd-nav-sidebar(rendered on every page) was the root cause of Records/Contacts/Dictionaries/Import tables not rendering at all.{{partial dynamicName}}→{{component dynamicName ...args}}inember-leaflet-table.this-property-fallback removed
app files, plus additional test-file references caught later by actually running the suite (ember-template-lint can't
statically check
hbsliterals embedded in .js files).this._super()in native class lifecycle methodssuper.methodName(...arguments)in route hooks (setupController, afterModel, etc.) across ~37 route files —_super()only works in classic init().Implicit service injections removed
@servicedecorators where services (e.g. store) were previously auto-injected.ember-cli-bootstrap-datetimepickerremoveddate/month/datetime-localinputs inmd-datetime. (Follow-on: several tests asserted the oldmoment.js-formatteddisplay text; updated to match native input .value semantics — no seconds, no timezone offset, no locale month names.)Dependency & patch fixes
ember-in-element-polyfill: patched version threshold ('10.0.0' → '3.20.0'); resolutions added to cover nested copies.ember-pouch: patched a bare Ember.libraries.register() call that halted vendor.js execution under Ember 4 (surfaced as a misleading "Could not find module ember-resolver" error).ember-resolver: upgraded to v11.0.1, import path updated toember-resolver/index.ember-models-table: migrated to v5 (see below).ember-power-select: pinned to ^7.2.0 for v5models-tablecompatibility.ember-cli-template-lint: removed (superseded by standalone ember-template-lint).ember-composability-tools,ember-simplemde: patched for removed @ember/utils tryInvoke and@ember/component/text-arearespectively.ember-leaflet: patched — its ownleaflet-map.hbsrelied onthis-property-fallback(emberLeaflet/mergedComponents used unprefixed), broke every map consumer.@ember/stringdeprecation (ember-tooltips): silenced viaregisterDeprecationHandler.ember-models-table v5 migration
Theme system changed from manually-instantiated classes to injectable services; row/table components moved to a namespaced, Glimmer-based component tree. Required rewriting:
md-record-tableand md-edit-table's custom columns/themes for the new API (also restored a.md-record-tableCSS class lost in the Glimmer rewrite, and wired the Edit button to actually trigger row-expand — EMT v5 threads@expandRow/@collapseRowinto custom column components for free, it just wasn't being used).feature-table/leaflet-table-row(leaflet map's attribute table) — rewritten from a pre-v5 classic-constructor pattern toa proper Glimmer wrapper + themed service, and fixed a hand-rolled table-body loop still using v3/v4's lowercase
contextual component names (body.row instead of v5's body.Row).
Other structural changes
jQueryfrom components, routes, and services where possible.mixinsto plain utility functions.ember-concurrencyv5 breaking changes.computed-property.overridedeprecation warnings by distinguishing real "derived-by-default,externally-overridable" properties (given a getter/setter pair) from redundant duplicate values (deleted).
Bug fixes surfaced along the way
A long tail of functional bugs found and fixed during the migration (taxonomy collection screen, ScienceBase publish tree drag/reparent, checkbox selection in tables, ITIS proxy/derived data, fiscal year saving, lineage route rotation, keyword/citation panels, profile switching visibility, sync-menu errors, import checkboxes, and others) — see individual commits for detail.