Skip to content

Improve error handling and UX for image uploads in RichTextEditor#3359

Open
SxxAq wants to merge 5 commits intofossasia:devfrom
SxxAq:fix/error-handling-richtexteditor
Open

Improve error handling and UX for image uploads in RichTextEditor#3359
SxxAq wants to merge 5 commits intofossasia:devfrom
SxxAq:fix/error-handling-richtexteditor

Conversation

@SxxAq
Copy link
Copy Markdown
Contributor

@SxxAq SxxAq commented Apr 23, 2026

Replaced blocking alert() dialogs with proper error handling when image uploads fail in RichTextEditor. Errors now display inline in the toolbar with a user-friendly message.

Changes:

  • Added error state tracking for upload failures
  • Display translated error message in toolbar
  • Log errors to console for debugging
  • Removed blocking dialogs
image

Summary by Sourcery

Improve RichTextEditor image upload experience by surfacing non-blocking, localized error feedback and cleaning up editor event handling.

New Features:

  • Display inline, localized error messages in the RichTextEditor toolbar when image uploads fail.

Bug Fixes:

  • Prevent lingering Quill event listeners by unregistering text and selection change handlers on component unmount.

Enhancements:

  • Replace blocking alert dialogs with inline error messaging and console logging for image upload failures.
  • Add visual styling for upload error messages to clearly indicate failure states in the editor UI.

Copilot AI review requested due to automatic review settings April 23, 2026 19:33
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Apr 23, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Replaces blocking alert-based error handling for image uploads in RichTextEditor with reactive, inline error UI, adds proper lifecycle cleanup, and improves logging and styling for upload failures.

Sequence diagram for updated image upload error handling in RichTextEditor

sequenceDiagram
    actor User
    participant RichTextEditor
    participant QuillEditor
    participant FileInput
    participant ApiService
    participant I18n
    participant Console

    User->>RichTextEditor: Click image upload button
    RichTextEditor->>QuillEditor: Open image upload handler
    QuillEditor->>FileInput: Trigger file selection
    User->>FileInput: Select image file
    FileInput-->>QuillEditor: Return selected file
    QuillEditor->>RichTextEditor: Provide selected file

    RichTextEditor->>RichTextEditor: uploadError = null
    RichTextEditor->>RichTextEditor: uploading = true

    RichTextEditor->>ApiService: uploadFilePromise(file, fileName)

    alt Upload succeeds with no error
        ApiService-->>RichTextEditor: data (no error)
        RichTextEditor->>QuillEditor: Insert uploaded image
        RichTextEditor->>RichTextEditor: uploading = false
    else Upload returns error in response
        ApiService-->>RichTextEditor: data.error
        RichTextEditor->>I18n: t(RichTextEditor:upload:error)
        I18n-->>RichTextEditor: localized message
        RichTextEditor->>RichTextEditor: uploadError = localized message
        RichTextEditor->>Console: error(RichTextEditor image upload failed, data.error)
        RichTextEditor->>RichTextEditor: uploading = false
    else Upload request fails (network or other)
        ApiService--xRichTextEditor: throw error
        RichTextEditor->>I18n: t(RichTextEditor:upload:error)
        I18n-->>RichTextEditor: localized message
        RichTextEditor->>RichTextEditor: uploadError = localized message
        RichTextEditor->>Console: error(RichTextEditor image upload failed, error)
        RichTextEditor->>RichTextEditor: uploading = false
    end

    RichTextEditor-->>User: Inline error shown in toolbar if uploadError is set
Loading

Class diagram for updated RichTextEditor component state and dependencies

classDiagram
    class RichTextEditor {
        +ref outline
        +ref editor
        +ref quill
        +ref uploading
        +ref uploadError
        +onMounted()
        +onBeforeUnmount()
        +onTextchange(delta, oldContents, source)
        +onSelectionchange(range, oldRange, source)
    }

    class QuillEditor {
        +getContents()
        +setContents(contents)
        +updateContents(delta)
        +getSelection(focus)
        +on(eventName, handler)
        +off(eventName, handler)
    }

    class ApiService {
        +uploadFilePromise(file, fileName)
    }

    class I18n {
        +t(key)
    }

    class ConsoleLogger {
        +error(message, details)
    }

    RichTextEditor --> QuillEditor : uses
    RichTextEditor --> ApiService : calls
    RichTextEditor --> I18n : translates
    RichTextEditor --> ConsoleLogger : logs

    note for RichTextEditor "uploading controls bunt-progress-circular visibility; uploadError controls .upload-error inline message styling"
Loading

File-Level Changes

Change Details Files
Introduce reactive upload error state and inline error display in the RichTextEditor toolbar.
  • Add a reactive uploadError ref alongside the existing uploading state
  • Render an .upload-error element in the template when an upload error message is present
  • Reset uploadError to null when starting a new upload so old errors are cleared
app/eventyay/webapp/video/src/components/RichTextEditor.vue
Replace alert-based upload error handling with translated inline messaging and structured logging.
  • Import the i18n instance and use a RichTextEditor:upload:error translation key for failures
  • On upload API error or promise rejection, set uploadError instead of showing alert dialogs or clearing the editor contents
  • Log upload failures via console.error with contextual messages instead of console.log or alerts
app/eventyay/webapp/video/src/components/RichTextEditor.vue
app/eventyay/webapp/video/src/locales/en.json
Improve RichTextEditor lifecycle management and error styling.
  • Add onBeforeUnmount cleanup to detach Quill selection-change and text-change listeners
  • Style the .upload-error message with danger color, smaller font, and top margin to visually distinguish it from normal content
app/eventyay/webapp/video/src/components/RichTextEditor.vue

Assessment against linked issues

Issue Objective Addressed Explanation
#3358 Replace blocking alert() usage on image upload failure in RichTextEditor with a non-blocking error handling mechanism.
#3358 Surface image upload errors directly in the RichTextEditor UI so users see an inline error message and can retry from the same context.
#3358 Improve UX of failure handling by avoiding destructive side effects (like clearing editor contents) and integrating with the app’s i18n/notification approach.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The new i18n.t('RichTextEditor:upload:error') key should be added to en.json (and any other relevant locale files) to avoid runtime fallback or missing-translation behavior for the upload error message.
  • Consider including additional context (e.g., the file name or upload endpoint) in the console.error('RichTextEditor image upload failed', ...) logs to make debugging upload issues easier.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `i18n.t('RichTextEditor:upload:error')` key should be added to `en.json` (and any other relevant locale files) to avoid runtime fallback or missing-translation behavior for the upload error message.
- Consider including additional context (e.g., the file name or upload endpoint) in the `console.error('RichTextEditor image upload failed', ...)` logs to make debugging upload issues easier.

## Individual Comments

### Comment 1
<location path="app/eventyay/webapp/video/src/components/RichTextEditor.vue" line_range="104-110" />
<code_context>

+								uploadError.value = null
 								uploading.value = true
 								api.uploadFilePromise(file, file.name).then(data => {
 									if (data.error) {
-										alert(`Upload error: ${data.error}`)
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Consider using `finally` to centralize `uploading.value = false` cleanup.

Because `uploading.value = false` is in both `then` and `catch`, any error thrown before those lines run could leave `uploading.value` stuck at `true` and the spinner never clears. Moving the cleanup into `.finally(() => { uploading.value = false })` avoids duplication and ensures the flag is always reset, even if future changes add intermediate failures.

Suggested implementation:

```
								api.uploadFilePromise(file, file.name).then(data => {
									if (data.error) {
										uploadError.value = i18n.t('RichTextEditor:upload:error')
										console.error('RichTextEditor image upload failed', data.error)
									} else {
										const range = instance.getSelection(true)
										instance.updateContents(new Delta()
									}
								}).catch(error => {

```

You’ll also need to:

1. Locate the end of the `.catch(error => { ... })` block for this same promise chain.
2. Remove any existing `uploading.value = false` from inside the `catch` block.
3. Close the `catch` block and append a `finally` to centralize the cleanup, for example:

```js
								api.uploadFilePromise(file, file.name).then(data => {
									// existing success/error handling as above
								}).catch(error => {
									// existing error handling:
									// uploadError.value = ...
									// console.error(...)
								}).finally(() => {
									uploading.value = false
								})
```

This ensures `uploading.value` is always reset, even if errors occur before your existing `then`/`catch` cleanup paths.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread app/eventyay/webapp/video/src/components/RichTextEditor.vue
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the RichTextEditor image upload UX by replacing blocking alert() calls with an inline, translated error message and console error logging when uploads fail.

Changes:

  • Added uploadError state to track and display image upload failures inline.
  • Replaced alert()/console.log with translated error messaging and console.error logging.
  • Added styling for the inline upload error message.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
app/eventyay/webapp/video/src/locales/en.json Adds a new translation key for the image upload failure message.
app/eventyay/webapp/video/src/components/RichTextEditor.vue Tracks upload errors, shows an inline error message, and logs failures to the console.

Comment thread app/eventyay/webapp/video/src/components/RichTextEditor.vue
@sarafarajnasardi
Copy link
Copy Markdown
Member

@SxxAq Please Address the AI reviews

Copy link
Copy Markdown
Collaborator

@Saksham-Sirohi Saksham-Sirohi left a comment

Choose a reason for hiding this comment

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

i dont think displaying this message inside the editor is a good idea

@SxxAq
Copy link
Copy Markdown
Contributor Author

SxxAq commented Apr 26, 2026

i dont think displaying this message inside the editor is a good idea

I put the error in the editor from the UX perspective as the error will be close to the action area. where would you prefer the error?

  • Broader observation: The video webapp currently lacks a centralized error/message system like Django's messages framework. Components individually handle errors, which means each component reimplements error display logic. Should we implement a composable-based message center that could aggregate errors at the app level and provide a consistent pattern for the entire webapp?

@Rachit7168
Copy link
Copy Markdown
Contributor

Rachit7168 commented May 4, 2026

i dont think displaying this message inside the editor is a good idea

We show errors and success messages mostly everywhere in the above, with a red worng sign along with a rectangular box and an error inside it, and the same goes for success messages. I suggested that same layout for success or error message would be good but lets hear from @Saksham-Sirohi !

@Saksham-Sirohi
Copy link
Copy Markdown
Collaborator

hi @SxxAq you can use a popup dialog to inform within the textbox and allow edits further only after user has clicked ok or something

Copilot AI review requested due to automatic review settings May 4, 2026 17:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment thread app/eventyay/webapp/video/src/components/RichTextEditor.vue
Comment thread app/eventyay/webapp/video/src/locales/en.json
Comment thread app/eventyay/webapp/video/src/components/RichTextEditor.vue Outdated
@SxxAq
Copy link
Copy Markdown
Contributor Author

SxxAq commented May 4, 2026

@Saksham-Sirohi Implemented a popup error dialog in RichTextEditor and refactored it into a reusable ErrorDialog component, so we can reuse it for future error popups across the webapp.

Screenshot From 2026-05-05 00-32-52

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment on lines +33 to +39
error-dialog(
v-if="showErrorDialog"
:title="$t('RichTextEditor:upload:error-title')"
:message="uploadErrorMessage"
:button-text="$t('RichTextEditor:upload:error-ok')"
@close="closeErrorDialog"
)
Comment on lines +204 to +207
.upload-error
color: $clr-danger
font-size: 14px
margin-top: 8px
Comment on lines +13 to +21
<script setup>
import { ref } from 'vue'
import Prompt from 'components/Prompt'

const props = defineProps({
title: {
type: String,
default: 'Error'
},
Copy link
Copy Markdown
Collaborator

@Saksham-Sirohi Saksham-Sirohi left a comment

Choose a reason for hiding this comment

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

please get rid of nook being displayed on left of the dialog box

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

Improve error handling in RichTextEditor image uploads

5 participants