Skip to content

Conversation

@Prashant-thakur77
Copy link
Contributor

@Prashant-thakur77 Prashant-thakur77 commented Oct 21, 2025

Fixes #5425

Summary

This PR completes the removal of Vuetify from the Send Email dialog as part of the larger Vuetify migration effort (#5060). The dialog now uses Kolibri Design System components exclusively while maintaining all existing functionality.

Changes Made:

✅ Replaced VDialog and ConfirmationDialog with KModal

✅ Replaced VFlex and VLayout with custom CSS flex styles

✅ Replaced VForm with native form element

✅ Replaced VTextField and VTextarea with KTextbox

✅ Replaced VTooltip with KTooltip

✅ Implemented form validation using generateFormMixin

✅ Created new StudioChip component to replace VChip
Screenshot From 2025-10-21 11-23-43
image
Screenshot From 2025-10-21 11-30-37

References

Sub-issue of #5060.

Reviewer guidance

Login as [email protected] with password a
Go to Administration > Users
Select few users in the table
Click Email

Visual Changes:

Minor styling differences due to KDS vs Vuetify
Consistent with Kolibri Design System patterns
Maintains all existing functionality

@Prashant-thakur77 Prashant-thakur77 changed the title Remove vuetify email dialog [Remove Vuetify from Studio] Send e-mail dialog Oct 21, 2025
Copy link
Member

@LianaHarris360 LianaHarris360 left a comment

Choose a reason for hiding this comment

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

Thanks so much for updating the EmailUsersDialog component. This is a good start so far. There’s still a couple of Vuetify components that can be removed. The VBtn and VCardText can be replaced with KButton and a div. There’s also a few user-facing strings that still need to be translated. The KModal title, the From and To labels within the form, “Subject line”, “Email body”, and the phrase “Add placeholder to message”, and all of the placeholder labels.

</div>
<div class="email-textarea">
<KTextbox
ref="message"
Copy link
Member

Choose a reason for hiding this comment

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

Now that this "message" ref references KTextbox, on line 261, we need to update it to include $el to avoid this error in the console:
"TypeError: Cannot read properties of null (reading 'focus')"

<KTextbox
ref="message"
v-model="message"
:label="'Email body'"
Copy link
Member

Choose a reason for hiding this comment

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

The text for this label should be a translated string $tr

:submitText="$tr('sendButton')"
:cancelText="$tr('cancelButton')"
data-test="email-dialog"
@submit="submit"
Copy link
Member

Choose a reason for hiding this comment

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

The method to send the email is named onSubmit , it should be updated here and on line 15 in the <form> as well.

<KModal
v-if="show"
:size="600"
:title="'Send Email'"
Copy link
Member

Choose a reason for hiding this comment

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

This KModal title should be a translated string

Copy link
Member

Choose a reason for hiding this comment

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

Administration plugin is an exception. Since it's used internally, we don't translate strings. A general rule of thumb is to preserve the original approach: If there is a translated string - use it, if there is an untranslated string - use it :)

:showLabel="true"
:appearanceOverrides="getAppearanceOverrides(errors.subject)"
/>
<div class="caption grey--text">Add placeholder to message</div>
Copy link
Member

Choose a reason for hiding this comment

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

This phrase should be a translated string

expect(wrapper.vm.showWarning).toBe(true);
});

it('should not show warning when canceling with no draft content', async () => {
Copy link
Member

Choose a reason for hiding this comment

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

This a great addition to test for, thanks for including this!

},
handleClose() {
this.$emit('close');
this.$emit('input');
Copy link
Member

Choose a reason for hiding this comment

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

We shouldn't need to emit both close and input. I think in this case, only emitting close is more clear.

'studio-chip--active': isActive,
}"
:style="chipStyles"
@click="handleClick"
Copy link
Member

Choose a reason for hiding this comment

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

This div should be converted into a real button if it is meant to be interactive and clickable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks for the review @LianaHarris360 .I would like a suggestion on what to do here i think we can complelely get rid of the clickable feature . what are your thoughts on it .we will keep the kicon button clickable and the rest will be same?

Copy link
Contributor Author

@Prashant-thakur77 Prashant-thakur77 Oct 25, 2025

Choose a reason for hiding this comment

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

and if we want to make it interactive can u tell me how to apply hover and clickable effects to kbutton.This would be helpful in this and here

The VBtn and VCardText can be replaced with KButton and a div

I’ve replaced the VBtn and VCardText components with KButton and a div. However, I’m facing a bit of confusion while trying to apply the hover and clickable effects similar to those in VBtn. Could you please guide me through how to implement these interactions correctly or share a reference example where this has been done? It would be really helpful.

Copy link
Member

Choose a reason for hiding this comment

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

I will add a bit more nuance:

(1) Whole-area-clickable chips

Screenshot from 2025-10-28 12-16-36

These need to be <button> s. To ensure proper a11y-related behaviors.

KButton is not suitable for this purpose. It's quite a different component compared to a chip-like-button. You can use native <button>.

(2) Chips with clear X button

Screenshot from 2025-10-28 12-33-17

I think that these would be best <div>s with the inner clear <button>.

Here KIconButton for X could be good, but if there are any specific challenges, raise them here please and we can decide if there's something we need to update in KDS, or if the native <button> would be more suitable.

</slot>
</div>

<KIconButton
Copy link
Member

Choose a reason for hiding this comment

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

This icon button needs an accessible name attached to it, like ariaLabel ="Remove {username}", using the KIconButton ariaLabel prop.

@Prashant-thakur77
Copy link
Contributor Author

@LianaHarris360

There’s also a few user-facing strings that still need to be translated. The KModal title, the From and To labels within the form, “Subject line”, “Email body”, and the phrase “Add placeholder to message”, and all of the placeholder labels.

I have a doubt related #5426 (comment) this.Here i was told that wrapped strings are not to be used in administraion.So please do tell what i need to do here in this context

Copy link
Member

@MisRob MisRob left a comment

Choose a reason for hiding this comment

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

Chiming in with some additional notes.

Overall congratulations on your first more complex issue. Overall nice work. All main features seem to be preserved Thanks for examining the current experience carefully.

<KModal
v-if="show"
:size="600"
:title="'Send Email'"
Copy link
Member

Choose a reason for hiding this comment

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

Administration plugin is an exception. Since it's used internally, we don't translate strings. A general rule of thumb is to preserve the original approach: If there is a translated string - use it, if there is an untranslated string - use it :)

Copy link
Member

Choose a reason for hiding this comment

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

For this file, I would recommend to take the same approach that I suggested in your other PR. For the same reasons.

});
};

// Configure Testing Library to use data-test attributes
Copy link
Member

Choose a reason for hiding this comment

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

I appreciate that you were attentive to the current naming. This would better be done on the global configuration level though. And since we don't really yet have a pattern for VTL, you can remove it and use the default attribute. If I recall that's what most other VTL test suites use.

expect(screen.queryByTestId('remove-chip')).not.toBeInTheDocument();
});

test('applies small class when small prop is true', () => {
Copy link
Member

Choose a reason for hiding this comment

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

There is no need to test for the presence of a class. It won't say that much about the resulting experience. Typically we just test markup, content, and logic.

Same applies to other similar tests in this file.

'studio-chip--active': isActive,
}"
:style="chipStyles"
@click="handleClick"
Copy link
Member

Choose a reason for hiding this comment

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

I will add a bit more nuance:

(1) Whole-area-clickable chips

Screenshot from 2025-10-28 12-16-36

These need to be <button> s. To ensure proper a11y-related behaviors.

KButton is not suitable for this purpose. It's quite a different component compared to a chip-like-button. You can use native <button>.

(2) Chips with clear X button

Screenshot from 2025-10-28 12-33-17

I think that these would be best <div>s with the inner clear <button>.

Here KIconButton for X could be good, but if there are any specific challenges, raise them here please and we can decide if there's something we need to update in KDS, or if the native <button> would be more suitable.

},
},
mounted() {
document.addEventListener('click', this.handleClickOutside);
Copy link
Member

Choose a reason for hiding this comment

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

It is quite unusual to add event listener to style active/inactive state. What was the reason for doing it in this way? Have you tried to use common hover and focus styling approaches?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @MisRob — you’re right, typically hover/focus styling would handle active/inactive states more cleanly.

In this case, the event listener was added to detect clicks outside the component to toggle the isActive state off when the user clicks elsewhere on the page. This was mainly done to simulate a “chip selection”interaction where the chip remains active after being clicked, and only deactivates when the user clicks outside of it.

However, I agree that for purely visual feedback (like hover/focus), CSS pseudo-classes would be more appropriate. I can refactor it to use CSS states for hover/focus, and only keep the event listener if we still need outside-click detection for interaction purposes.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for explaining. @Prashant-thakur77. I think it'd be a bit more suitable to use state for what you're trying to achieve, but perhaps we don't even need it. For now let's just use CSS and remove the event listener completely. We will then preview and see.

margin: 2px;
}
/* Custom layout styles to replace Vuetify flex system */
Copy link
Member

Choose a reason for hiding this comment

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

It wouldn't be meaningful to have a copy of Vuetify utilities in this specific file. They are used across the whole Studio, and at some point, we may actually remove them. Please delete these copies and just apply styles to containing elements without using the utilities, in a similar way you do above this section.

:showLabel="true"
:appearanceOverrides="getAppearanceOverrides(errors.subject)"
/>
<div class="caption grey--text">Add placeholder to message</div>
Copy link
Member

Choose a reason for hiding this comment

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

Would you remove all these Vuetify helpers classes?

Relatedly, for color-related ones, such as here grey--text, KDS theme tokens and palette approach needs to be used instead.

Please revisit the whole file.

return {
...baseStyles,
focusBorderColor: this.$themeTokens.error,
focusBoxShadow: `0 0 0 2px ${this.$themeTokens.error}33`,
Copy link
Member

Choose a reason for hiding this comment

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

Do these focus... take effect actually?

Also, I think it'd be fine, and even better for consistency, to just go with the default error state for KTextbox.

Perhaps you can upload a screenshot of what you're trying to achieve and explain why, and then we can decide.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree it makes sense to stay consistent with the default KTextbox error state and avoid introducing separate handling unless absolutely necessary.Will update it

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Remove Vuetify from Studio] Send e-mail dialog

3 participants