-
Notifications
You must be signed in to change notification settings - Fork 138
Popover error message #2739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Popover error message #2739
Conversation
There was a problem hiding this 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 fixes the inconsistency in positions of popover error messages by modifying how error messages are displayed in the Popover component and how they are generated in the include panel processor.
- Adds local error handling and display functionality to the Popover Vue component
- Replaces error node creation with inline error slots in the popover content area
- Introduces error validation and DOM error capturing mechanisms
Reviewed Changes
Copilot reviewed 2 out of 66 changed files in this pull request and generated 6 comments.
File | Description |
---|---|
packages/vue-components/src/Popover.vue | Adds local error state, validation methods, and inline error message display |
packages/core/src/html/includePanelProcessor.ts | Replaces error node creation with inline error slots for consistent positioning |
}, | ||
isValidUrl(url) { | ||
try { | ||
(() => new URL(url))(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The immediately invoked function expression (IIFE) pattern (() => new URL(url))()
is unnecessarily complex. Replace with new URL(url)
directly since the constructor already throws on invalid URLs.
(() => new URL(url))(); | |
new URL(url); |
Copilot uses AI. Check for mistakes.
this.localError = errorEl.textContent; | ||
errorEl.remove(); | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Direct DOM querying with document.querySelectorAll
breaks Vue's component encapsulation and reactive data flow. Consider using Vue's ref system or emitting events to parent components instead of global DOM manipulation.
}); | |
// Check for error messages within this component only | |
const errorEl = this.$refs.popoverError; | |
if (errorEl && (errorEl.textContent.includes('popover') || errorEl.textContent.includes('src'))) { | |
// Optionally, further check if the error is related to this popover | |
if (errorEl.textContent.includes(this.src) || errorEl.textContent.includes(this.header)) { | |
this.localError = errorEl.textContent; | |
} | |
} |
Copilot uses AI. Check for mistakes.
if (errorEl.textContent.includes(this.src) | ||
|| errorEl.textContent.includes(this.header)) { | ||
this.localError = errorEl.textContent; | ||
errorEl.remove(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Directly removing DOM elements with errorEl.remove()
can cause memory leaks and break Vue's reactivity. If error elements need to be removed, use Vue's conditional rendering with v-if instead.
errorEl.remove(); | |
// Instead of removing the element, hide it to avoid breaking Vue's reactivity | |
errorEl.style.display = 'none'; |
Copilot uses AI. Check for mistakes.
} | ||
.popover-error-message { | ||
color: #f00; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The hardcoded color value #f00
is a magic number. Consider using a CSS custom property or a semantic color variable from your design system for better maintainability.
color: #f00; | |
color: var(--popover-error-color, #f00); |
Copilot uses AI. Check for mistakes.
{ | ||
type: 'tag', | ||
name: 'div', | ||
attribs: { style: 'color: red;' }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Inline styles with hardcoded colors should use CSS classes instead for consistency and maintainability. Consider using a CSS class like 'error-message' that can be styled centrally.
attribs: { style: 'color: red;' }, | |
attribs: { class: 'error-message' }, |
Copilot uses AI. Check for mistakes.
cheerio(node).replaceWith(createErrorNode(node, error)); | ||
const errorMsg | ||
= 'URLs are not allowed in the \'src\' attribute.<br>' | ||
+ `File: ${context.cwf}<br>` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using HTML <br>
tags in error messages couples the error content with presentation. Consider using \n
for line breaks and let the display layer handle formatting, or use an array of message parts.
+ `File: ${context.cwf}<br>` | |
= 'URLs are not allowed in the \'src\' attribute.\n' | |
+ `File: ${context.cwf}\n` |
Copilot uses AI. Check for mistakes.
Hi @Golddirio, just a preliminary test, will give a more detailed PR review. I noticed that the popover error message no longer shows for URLs in your branch, see: ![]() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Golddirio , thank you for your PR!
Firstly, just a small nit, do try to keep your PR clean by not committing the font files unless there are any specific font changes, and for the frontend bundles as well. Link.
I believe you are on the right track, do feel free to clarify any comments.
I would suggest refining the processing logic and minimizing any changes to the vue component to avoid introducing any unnecessary coupling between the two. Ideally, the vue popover component should not need to be too aware of how the src
attribute processing logic functions.
Think about why in one case, the error is generated at the location of the popover, and in the other case, it is not. There might already be a way to generate any similar error at the location of the popover then without modifying the logic or introducing if-else clauses in the vue component, with some slight tweaking.
I think with some refinement, you could achieve a simpler and more elegant fix. Great effort!
As a stretch goal, you could even consider adding a few testcases to verify that the popover appears at the desired location in the HTML dom.
node.children = createPopoverInlineErrorSlot(errorMsg); | ||
return context; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it would be helpful to understand how the original implementation displays the error message in-place without touching the logic in the separate vue UI components
}, | ||
findAndHandleGlobalErrors() { | ||
// Look for error messages that might have been injected elsewhere | ||
const popoverErrors = Array.from(document.querySelectorAll('.popover-error')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious, where do the elements with class popover-error originate from? I can't seem to find where such elements would be injected or modified upstream
type: String, | ||
default: 'top', | ||
}, | ||
src: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the popover expect this attribute?
markbind/packages/core/src/html/includePanelProcessor.ts
Lines 398 to 404 in f681976
const attributeSlotElement: NodeOrText[] = createSlotTemplateNode('content', actualContent); | |
node.children = node.children ? attributeSlotElement.concat(node.children) : attributeSlotElement; | |
delete node.attribs.src; | |
return childContext; | |
} |
Our processPopoverSrc upstream function deletes this attribute, would it be better that the vue component remains unaware of a potential src
attribute?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Golddirio, thanks for the contribution. I'd just like to follow up on @gerteck's comments.
Think about why in one case, the error is generated at the location of the popover, and in the other case, it is not. There might already be a way to generate any similar error at the location of the popover then without modifying the logic or introducing if-else clauses in the vue component, with some slight tweaking.
Just as gerteck mentioned, look at the original code to see why there is differing behavior between error locations for different errors. In particular, after some investigation there seems to be some strange behavior between cheerio's replaceWith
function and our createErrorNode
function.
createErrorNode
actually doesn't "create" a new node, it mutates the given element into an error node.- This leads to an issue when used with
replaceWith
, since we are accidentally replacing a node with itself. From my own testing, this often leads to strange behavior like placing the node at the end or deleting other nodes.
With this knowledge, think about a way to standardize error location behavior. Good luck!
What is the purpose of this pull request?
Fixes #2688
Overview of changes:
Popover error messages are placed in the content position which is consistent right now.
Anything you'd like to highlight/discuss:


Now the error messages are shown below:
Testing instructions:
NA
Proposed commit message: (wrap lines at 72 characters)
Fix the inconsistency in positions of popover error messages
Checklist: ☑️
Reviewer checklist:
Indicate the SEMVER impact of the PR:
At the end of the review, please label the PR with the appropriate label:
r.Major
,r.Minor
,r.Patch
.Breaking change release note preparation (if applicable):