Files
api/web/store/errors.ts
Eli Bosley 345e83bfb0 feat: upgrade nuxt-custom-elements (#1461)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added new modal dialogs and UI components, including activation steps,
OS update feedback, and expanded notification management.
* Introduced a plugin to configure internationalization, state
management, and Apollo client support in web components.
* Added a new Log Viewer page with a streamlined interface for viewing
logs.

* **Improvements**
* Centralized Pinia state management by consolidating all stores to use
a shared global Pinia instance.
* Simplified component templates by removing redundant
internationalization host wrappers.
* Enhanced ESLint configuration with stricter rules and global variable
declarations.
* Refined custom element build process to prevent jQuery conflicts and
optimize minification.
* Updated component imports and templates for consistent structure and
maintainability.
* Streamlined log viewer dropdowns using simplified select components
with improved formatting.
* Improved notification sidebar with filtering by importance and modular
components.
* Replaced legacy notification popups with new UI components and added
automatic root session creation for localhost requests.
* Updated OS version display and user profile UI with refined styling
and component usage.

* **Bug Fixes**
* Fixed component tag capitalization and improved type annotations
across components.

* **Chores**
* Updated development dependencies including ESLint plugins and build
tools.
* Removed deprecated log viewer patch class and cleaned up related test
fixtures.
  * Removed unused imports and simplified Apollo client setup.
* Cleaned up test mocks and removed obsolete i18n host component tests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210730229632804

---------

Co-authored-by: Pujit Mehrotra <pujit@lime-technology.com>
Co-authored-by: Zack Spear <zackspear@users.noreply.github.com>
2025-07-08 10:05:39 -04:00

150 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ref } from 'vue';
import { defineStore } from 'pinia';
import { OBJ_TO_STR } from '~/helpers/functions';
import type { BrandButtonProps } from '@unraid/ui';
import type { Server } from '~/types/server';
/**
* Uses the shared global Pinia instance from ~/store/globalPinia.ts
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
* @see https://github.com/vuejs/pinia/discussions/1085
*/
import '~/store/globalPinia';
export type ErrorType =
| 'account'
| 'callback'
| 'installKey'
| 'request'
| 'server'
| 'serverState'
| 'unraidApiGQL'
| 'unraidApiState';
export interface Error {
actions?: BrandButtonProps[];
debugServer?: Server;
forumLink?: boolean;
heading: string; // if adding new errors be sure to add translations key value pairs
level: 'error' | 'info' | 'warning';
message: string;
ref?: string;
supportLink?: boolean;
type: ErrorType;
}
export const useErrorsStore = defineStore('errors', () => {
const errors = ref<Error[]>([]);
// const displayedErrors = computed(() => errors.value.filter(error => error.type === 'server' || error.type === 'serverState'));
const removeErrorByIndex = (index: number) => {
errors.value = errors.value.filter((_error, i) => i !== index);
};
const removeErrorByRef = (ref: string) => {
errors.value = errors.value.filter((error) => error?.ref !== ref);
};
const resetErrors = () => {
errors.value = [];
};
const setError = (error: Error) => {
console.error('[setError]', error);
errors.value.push(error);
};
interface TroubleshootPayload {
email: string;
includeUnraidApiLogs: boolean;
}
const openTroubleshoot = async (payload: TroubleshootPayload) => {
try {
// @ts-expect-error `FeedbackButton` will be included in 6.10.4+ DefaultPageLayout
await FeedbackButton();
// once the modal is visible we need to select the radio to correctly show the bug report form
let $modal = document.querySelector('.sweet-alert.visible');
while (!$modal) {
await new Promise((resolve) => setTimeout(resolve, 100));
$modal = document.querySelector('.sweet-alert.visible');
}
// autofill errors into the bug report form
if (errors.value.length) {
let $textarea: HTMLInputElement | null = $modal.querySelector('#troubleshootDetails');
while (!$textarea) {
await new Promise((resolve) => setTimeout(resolve, 100));
$textarea = $modal.querySelector('#troubleshootDetails');
}
const errorMessages = errors.value
.map((error, index) => {
const index1 = index + 1;
let message = `• Error ${index1}: ${error.heading}\n`;
message += `• Error ${index1} Message: ${error.message}\n`;
message += `• Error ${index1} Level: ${error.level}\n`;
message += `• Error ${index1} Type: ${error.type}\n`;
if (error.ref) {
message += `• Error ${index1} Ref: ${error.ref}\n`;
}
if (error.debugServer) {
message += `• Error ${index1} Debug Server:\n${OBJ_TO_STR(error.debugServer)}\n`;
}
return message;
})
.join('\n***************\n');
$textarea.value += '\n##########################\n';
$textarea.value += `# Debug Details Component Errors ${errors.value.length} #\n`;
$textarea.value += '##########################\n';
$textarea.value += errorMessages;
}
// autofill emails
let $emailInput: HTMLInputElement | null = $modal.querySelector('#troubleshootEmail');
while (!$emailInput) {
await new Promise((resolve) => setTimeout(resolve, 100));
$emailInput = $modal.querySelector('#troubleshootEmail');
}
if (payload.email) {
$emailInput.value = payload.email;
} else {
$emailInput.focus();
}
// select the radio to correctly show the bug report form
let $myRadio: HTMLInputElement | null = $modal.querySelector('#optTroubleshoot');
while (!$myRadio) {
await new Promise((resolve) => setTimeout(resolve, 100));
$myRadio = $modal.querySelector('#optTroubleshoot');
}
$myRadio.checked = true;
// show the correct form in the modal
let $panels = $modal.querySelectorAll('.allpanels');
while (!$panels) {
await new Promise((resolve) => setTimeout(resolve, 100));
$panels = $modal.querySelectorAll('.allpanels');
}
$panels.forEach(($panel: Element) => {
if ($panel.id === 'troubleshoot_panel') {
// @ts-expect-error - the webgui feedback modal has different "panel" elements, so we'll automatically select the troubleshooting option for the user
$panel.style.display = 'block';
} else {
// @ts-expect-error - the webgui feedback modal has different "panel" elements, so we'll automatically select the troubleshooting option for the user
$panel.style.display = 'none';
}
});
} catch (error) {
console.error('[openTroubleshoot]', error);
}
};
return {
errors,
removeErrorByIndex,
removeErrorByRef,
resetErrors,
setError,
openTroubleshoot,
};
});