Skip to content

Removed file upload hook's Ember dependency#26569

Draft
EvanHahn wants to merge 1 commit intomainfrom
useFetchApi-in-koenig-file-upload-http-request
Draft

Removed file upload hook's Ember dependency#26569
EvanHahn wants to merge 1 commit intomainfrom
useFetchApi-in-koenig-file-upload-http-request

Conversation

@EvanHahn
Copy link
Contributor

@EvanHahn EvanHahn commented Feb 24, 2026

towards https://linear.app/ghost/issue/NY-1097
ref #26591
ref #26593

This change should have limited user impact.

I want to move useFileUpload to a separate file. To do this, I need to remove its dependency on Ember's AJAX service. That meant exporting useFetchApi from admin-x-framework and depending on it there.

IMO, the "root" of the change is in koenig-lexical-editor.js. I'd start there if reviewing this patch.

useFetchApi is slightly different from Ember's AJAX service, but it's our closest analog in the React world.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

Walkthrough

This pull request refactors the module structure within the admin-x-framework package by reorganizing the useFetchApi hook imports. The hook is relocated from utils/api/fetch-api to hooks/use-fetch-api, with corresponding import path updates across multiple files in both the framework and ghost/admin packages. The hook is newly exported from the main hooks barrel file. In the koenig-lexical-editor component, the upload implementation is refactored to use the fetch-based useFetchApi hook, replacing the previous Ember AJAX approach. The admin-x-framework package is added as a dependency to ghost/admin with corresponding Nx build configuration updates.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main objective of the pull request: removing the Ember AJAX dependency from the file upload hook and replacing it with useFetchApi.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The PR description clearly relates to the changeset by explaining the motivation for moving useFileUpload to a separate file and exporting useFetchApi from admin-x-framework.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch useFetchApi-in-koenig-file-upload-http-request

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/admin-x-framework/src/hooks.ts (1)

1-1: LGTM — consider also exporting RequestOptions for TypeScript consumers.

The new useFetchApi export looks correct. Optionally, exporting RequestOptions alongside it would let TypeScript callers annotate their options without reaching into an internal module path.

♻️ Suggested addition
-export {useFetchApi} from './hooks/use-fetch-api';
+export {useFetchApi} from './hooks/use-fetch-api';
+export type {RequestOptions} from './hooks/use-fetch-api';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/admin-x-framework/src/hooks.ts` at line 1, Add a type-only re-export for
RequestOptions from the use-fetch-api module so consumers can import it from the
public barrel; specifically, in the file that currently exports useFetchApi
(export {useFetchApi} from './hooks/use-fetch-api';) add a type export like
export type { RequestOptions } from './hooks/use-fetch-api' (or combine into a
single export statement) to expose the RequestOptions TypeScript type alongside
useFetchApi.
ghost/admin/app/components/koenig-lexical-editor.js (1)

546-549: Upload progress is now binary (0 → 100) — XHR progress events removed.

The previous Ember AJAX implementation tracked incremental upload progress via XHR events and reflected it through progressTracker. With fetch, there are no upload progress events, so progressTracker is only updated to 100% upon completion. Large file uploads will show no progress until fully sent.

This is a known UX regression; flagging it for completeness given the progressTracker infrastructure is still in place.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/admin/app/components/koenig-lexical-editor.js` around lines 546 - 549,
The upload currently uses fetchApi (call around the upload: const uploadResponse
= await fetchApi(...)) which provides only terminal progress (0→100) because
fetch lacks upload progress events; replace this fetch-based upload with an
XMLHttpRequest-based upload that wires xhr.upload.onprogress to update the
existing progressTracker incrementally and resolves/rejects with the same
response handling as uploadResponse so downstream code is unchanged;
specifically, implement an XHR POST/PUT matching requestMethod, send
fileFormData, update progressTracker during xhr.upload.onprogress, and on
load/err parse the response so callers of the upload behave the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ghost/admin/app/components/koenig-lexical-editor.js`:
- Around line 575-576: Update the stale inline comment that reads "fall back to
EmberData/ember-ajax default message for error type" next to the conditional
checking for message (the if (!message) { block) to reference the current upload
implementation (useFetchApi) and the Fetch API/response default message instead;
locate the comment in koenig-lexical-editor.js near the if (!message) { branch
and replace the text to indicate fallback to the Fetch API/default response
message or the useFetchApi helper.

---

Nitpick comments:
In `@apps/admin-x-framework/src/hooks.ts`:
- Line 1: Add a type-only re-export for RequestOptions from the use-fetch-api
module so consumers can import it from the public barrel; specifically, in the
file that currently exports useFetchApi (export {useFetchApi} from
'./hooks/use-fetch-api';) add a type export like export type { RequestOptions }
from './hooks/use-fetch-api' (or combine into a single export statement) to
expose the RequestOptions TypeScript type alongside useFetchApi.

In `@ghost/admin/app/components/koenig-lexical-editor.js`:
- Around line 546-549: The upload currently uses fetchApi (call around the
upload: const uploadResponse = await fetchApi(...)) which provides only terminal
progress (0→100) because fetch lacks upload progress events; replace this
fetch-based upload with an XMLHttpRequest-based upload that wires
xhr.upload.onprogress to update the existing progressTracker incrementally and
resolves/rejects with the same response handling as uploadResponse so downstream
code is unchanged; specifically, implement an XHR POST/PUT matching
requestMethod, send fileFormData, update progressTracker during
xhr.upload.onprogress, and on load/err parse the response so callers of the
upload behave the same.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12c80cd and 3dadea5.

📒 Files selected for processing (9)
  • apps/admin-x-framework/src/api/current-user.ts
  • apps/admin-x-framework/src/hooks.ts
  • apps/admin-x-framework/src/hooks/use-fetch-api.ts
  • apps/admin-x-framework/src/hooks/use-filterable-api.ts
  • apps/admin-x-framework/src/utils/api/hooks.ts
  • apps/admin-x-framework/test/unit/hooks/use-fetch-api.test.tsx
  • apps/admin-x-framework/test/unit/hooks/use-filterable-api.test.ts
  • ghost/admin/app/components/koenig-lexical-editor.js
  • ghost/admin/package.json

Comment on lines 575 to 576
// fall back to EmberData/ember-ajax default message for error type
if (!message) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Stale comment references EmberData/ember-ajax.

The comment says "fall back to EmberData/ember-ajax default message for error type" but the upload now uses useFetchApi. Update to reflect the actual fallback source.

✏️ Proposed fix
-                    // fall back to EmberData/ember-ajax default message for error type
+                    // fall back to the error's own message (e.g. from fetchApi/APIError)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// fall back to EmberData/ember-ajax default message for error type
if (!message) {
// fall back to the error's own message (e.g. from fetchApi/APIError)
if (!message) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/admin/app/components/koenig-lexical-editor.js` around lines 575 - 576,
Update the stale inline comment that reads "fall back to EmberData/ember-ajax
default message for error type" next to the conditional checking for message
(the if (!message) { block) to reference the current upload implementation
(useFetchApi) and the Fetch API/response default message instead; locate the
comment in koenig-lexical-editor.js near the if (!message) { branch and replace
the text to indicate fallback to the Fetch API/default response message or the
useFetchApi helper.

@EvanHahn EvanHahn marked this pull request as draft February 24, 2026 19:40
@EvanHahn EvanHahn force-pushed the useFetchApi-in-koenig-file-upload-http-request branch from 3dadea5 to 368cc70 Compare February 25, 2026 17:53
towards https://linear.app/ghost/issue/NY-1075

This change should have limited user impact.

I want to move `useFileUpload` to a separate file. To do this, I need to
remove its dependency on Ember's AJAX service. That meant exporting
`useFetchApi` from `admin-x-framework`, depending on it there, and
adding a new progress feature it needs.

IMO, the "root" of the change is in `koenig-lexical-editor.js`. I'd
start there if reviewing this patch.
@EvanHahn EvanHahn force-pushed the useFetchApi-in-koenig-file-upload-http-request branch from 368cc70 to 872324f Compare February 25, 2026 19:13
@EvanHahn EvanHahn added ok to merge for me You can merge this on my behalf if you want. and removed ok to merge for me You can merge this on my behalf if you want. labels Feb 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant