Skip to content

Conversation

@Ajit-Mehrotra
Copy link
Collaborator

@Ajit-Mehrotra Ajit-Mehrotra commented Dec 2, 2025

Purpose

Migrate Notification-related Components from Shadcn to Nuxtui

Summary of changes and notable additions:

  • converted notification components (including the notification toast) to NuxtUI
  • connected app.config.ts to the vite.config.ts
  • connected toast app themes to mount-engine.ts
  • a new async generator method in the notifications api
  • added a system for "risky" notifications that use the legacy notify script for email/agents, but handle unread file creation ourselves. By default though, we're using the legacy notify script in webgui/emhttp/webGui/scripts/notify (and no this script did not check for the title size...see bug fixes below :/)
  • added NotificationSettings to the graphql api model so we can sync toast position with legacy settings
  • removed vue-sommer (did not remove dependency, nor dependency for non-nuxtui icons )
  • replaced loading spinner with nuxtui skeleton instead
  • added ssh retry logic to the deploy script (got unlucky first time I ran the script)

Bug Fixes

  • fixed api's filtering logic (alert, info, warning). Before, data was being paginated and then filtered. This led to missing notifications when sorting by chosen filter.
  • fixed bug where notifications silently failed (api thought they succeeded) when the title of the notification was greater than 255 bytes.
  • fixed bug where when scrolled all the way down in the notification pane (when api is down), unraid infinitely sends network requests, obv not good.
  • fixed issue where error messages in the notification pane were inaccurate (ex. when api is disconnected, etc).
    • Now errors are more graceful ux on failure. Errors now look at non-standard locations as well.

Some Notes

  • make sure to make these webgui css changes before trying to run this yourself.
  • I haven't removed vue-sonner or any dependencies we use for icons from package.json or anything. Not sure if they're used elsewhere or what the future plans are.
  • UButtons need to use window.location.assign not the :to prop as there is no vue router in a standalone component enviornment.

Unfixed Bugs (issues need to be created)

  • Also, I haven't checked for accessibility yet.
  • webgui & notification styles look weird on gray mode (black looks fine)
  • there's something fishy going on with the notification counts but it doesn't impact the user much (it's fine on refresh) and i fixed the bigger bugs. That being said, there are a bug or two that I found out yesterday and already forgot, so it's more robust but still some work to be done.
  • adding a bunch of notifications at once hangs the UI temporarily
  • need to upgrade to lastest version of Nuxtui in order to take advantage of newer styling/theming options for the toast

- update VSCode settings for Tailwind CSS support
…rror messages

commit addresses the following two bugs/issues:
1. infinite network requests
2. make error messages more accurate

bug details:
- when scrolled all the way down in the notification pane (when api is down), unraid infinitely sends network requests.
- must be scrolled all the way to the bottom and stay at the bottom of the pane while the api is down

technical details:
- for infinite loop, added try/catch that sets a canLoadMore flag to false when it encounters an error, preventing infinite loop
- errors now look at non-standard locations as well

impact:
- performance benefits
- more graceful ux on failure
… improved consistency

- replaced Heroicons components with UIcon for better integration
- refactored Sidebar.vue to utilize USlideover and UButton for a cleaner UI
- removed unused imports and styles in main.css for better maintainability

NOTES:
- had to change main.css variables for it to work properly. Need to make sure this doesn't ruin other people's code.
- still needs to be further refactored to align with existing ui variables
…mproved UI consistency

- modified vite.config.ts to integrate app configuration into UI setup
- updated app.config.ts to include new button, tabs, and slideover variants for better theming
- cleaned up main.css by removing unused styles and ensuring proper imports
- refactored notification components to streamline structure and improve readability
> [!Note] This stubs the unraid-ui/src/components/common/toast. Initially created a shim to convert vue-sonnner toasts to nuxtui. However, since there weren't that many, I just did a clean replacement.

# Other Changes
- replace router link with window.location.assign

The `UButton` component attempts to inject the Vue Router instance when the `:to` prop is used. In the standalone component environment (where the router is not installed), this caused a "TypeError: inject(...) is undefined" crash when rendering notifications with links.

This change replaces the `:to` prop with a standard `@click` handler that uses `window.location.assign`, ensuring navigation works correctly without requiring the router context.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/nuxtui-notifications

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.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

🚀 Storybook has been deployed to staging: https://unraid-ui-storybook-staging.unraid-workers.workers.dev

…ng logic

Problem this solution addresses:
Basically, when users filtered by alert, warning, or info, results were being paginated first, then filtered by the requested importance, so filtered notifications were not working properly in some (a lot) of cases.

- added a new async generator method to load notifications in batches, enhancing performance and error handling.
- refactored the notification loading logic to utilize the generator, improving readability and maintainability.
- updated filtering logic to streamline the process of matching notifications based on importance and type.
@github-actions
Copy link
Contributor

github-actions bot commented Dec 3, 2025

🚀 Storybook has been deployed to staging: https://unraid-ui-storybook-staging.unraid-workers.workers.dev

- updated file watching logic to ignore initial files, improving performance.
- added duplicate check for archive notifications to prevent double counting.
- implemented retry mechanism for loading notifications, enhancing reliability.
- introduced handling for risky notifications to ensure proper file creation and avoid legacy script failures.
This change ensures that Nuxt UI notifications respect the display position configured in the legacy webGUI settings.

Backend:
- Added `NotificationSettings` to the GraphQL model.
- Exposed `settings` field on the `Notifications` resolver.
- Implemented `getSettings` in `NotificationsService` to read `notify.position` from the Dynamix store.

Frontend:
- Added `getNotificationSettings` GraphQL query.
- Updated `mount-engine.ts` to fetch settings before mounting.
- Mapped legacy position values (e.g., 'center') to Nuxt UI compatible values (e.g., 'top-center').
@Ajit-Mehrotra Ajit-Mehrotra marked this pull request as ready for review December 5, 2025 21:42
@Ajit-Mehrotra Ajit-Mehrotra requested a review from pujitm December 5, 2025 21:42
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines 6 to 9
export function useClipboardWithToast() {
const { copy, copied, isSupported } = useClipboard();
const toast = useToast();

Choose a reason for hiding this comment

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

P1 Badge Import useToast in clipboard helper

The clipboard composable now calls useToast() to show success/error messages, but the module only imports useClipboard. With no useToast import in this file, the build will fail at compile time with an undefined identifier when copyWithNotification executes.

Useful? React with 👍 / 👎.

Copy link
Contributor

Choose a reason for hiding this comment

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

good callout.

Copy link
Contributor

@zackspear zackspear left a comment

Choose a reason for hiding this comment

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

Mostly focused on front-end related changes in this review. It would be helpful to have @pujitm review the API related changes.

@Ajit-Mehrotra and I also discussed how to manage unrelated bugs that arise during scoped work. And to do his best to not let unrelated bugs introduce scope creep.

// Also, for toasts, BUT this is imported in the Root UApp in mount-engine.ts
// https://ui.nuxt.com/docs/components/toast#examples
toaster: {
position: 'top-center' as const,
Copy link
Contributor

Choose a reason for hiding this comment

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

Make sure this is set to the matching default Unraid webgui value

<template>
<div class="relative flex items-center justify-center">
<BellIcon class="text-header-text-primary h-6 w-6" />
<UIcon name="i-heroicons-bell-20-solid" class="h-6 w-6" />
Copy link
Contributor

Choose a reason for hiding this comment

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

could use size-6 to replace h-6 w-6

}, '');
const icon = computed<{ component: Component; color: string } | null>(() => {
const icon = computed<{ name: string; color: string } | null>(() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Create an interface for this type so it can be shared across files. Since this is also used in Notifications/Indicator.vue.

Comment on lines +55 to +68
function dbgApolloError(prefix: string, err: ApolloError | null | undefined) {
if (!err) return;
console.group(`[Notifications] ${prefix}`);
console.log('top message:', err.message);
console.log('graphQLErrors:', err.graphQLErrors);
console.log('networkError:', err.networkError);
try {
console.log('json:', JSON.parse(JSON.stringify(err)));
} catch {
console.log('json:', 'failed to parse');
console.log('json:', err);
}
console.groupEnd();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

debug code to potentially clean up.

if you're wanting to keep this for later, abstract this into a helper file

Comment on lines +157 to +175
const displayErrorMessage = computed(() => {
if (offlineError.value) return offlineError.value.message;
const apolloErr = error.value as ApolloError | null | undefined;
const firstGqlErr = apolloErr?.graphQLErrors?.[0] as
| (GraphQLError & {
extensions?: { error?: { message?: string } };
error?: { message?: string };
})
| undefined;
const gqlEmbedded = firstGqlErr?.extensions?.error?.message;
const gqlTop = firstGqlErr?.error?.message;
const gqlMessage = firstGqlErr?.message;
const netMessage = (apolloErr?.networkError as { message?: string } | undefined)?.message;
const topMessage = apolloErr?.message;
return gqlEmbedded || gqlTop || gqlMessage || netMessage || topMessage || 'An unknown error occurred.';
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Could also potentially be used elsewhere in other components (especially in the future). Might be worth it to abstract into a display apollo error component.

<div v-if="loading" class="w-full max-w-md space-y-4">
<div v-for="n in 3" :key="n" class="py-1.5">
<div class="flex items-center gap-2">
<USkeleton class="h-5 w-5 rounded-full" />
Copy link
Contributor

Choose a reason for hiding this comment

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

size-5 instead of h-5 w-5


<!-- Default (empty state) -->
<div v-else class="contents">
<UIcon name="i-heroicons-check-20-solid" class="text-unraid-green h-10 w-10 translate-y-3" />
Copy link
Contributor

Choose a reason for hiding this comment

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

size-10 instead of h-10 w-10

});
const openSettings = () => {
window.location.assign('/Settings/Notifications');
Copy link
Contributor

Choose a reason for hiding this comment

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

I know this was called out in the description of the PR due to lack of vue-router not being used.

The more instances I see of this the more I'm wondering if we need to create a helper / composable to ensure that the usage of this is consistent across components.

'top-right': 'top-right',
'bottom-left': 'bottom-left',
'bottom-right': 'bottom-right',
center: 'top-center',
Copy link
Contributor

Choose a reason for hiding this comment

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

we discussed creating an issue for updating Nuxt UI to the latest version so we can support top-center & bottom-center post update of the dep in a follow up PR.

Comment on lines 6 to 9
export function useClipboardWithToast() {
const { copy, copied, isSupported } = useClipboard();
const toast = useToast();

Copy link
Contributor

Choose a reason for hiding this comment

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

good callout.

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.

3 participants