From a5cfc9d1343d6d4a5a0059ef949e368ced6f03da Mon Sep 17 00:00:00 2001 From: Jordon Leach Date: Thu, 5 Dec 2024 15:20:53 -0500 Subject: [PATCH] Simplify growl hook - add hook for prompt modal lint --- package.json | 3 +- shell/components/GrowlManager.vue | 5 +- shell/plugins/rancher-api/index.ts | 4 +- shell/plugins/rancher-api/shell-api-class.ts | 79 ++++++++++++++----- shell/types/rancher-api/cluster.d.ts | 35 +++++++++ shell/types/rancher-api/growl.d.ts | 25 ++++++ shell/types/rancher-api/modal.d.ts | 82 ++++++++++++++++++++ shell/utils/growl.ts | 53 ------------- 8 files changed, 210 insertions(+), 76 deletions(-) create mode 100644 shell/types/rancher-api/cluster.d.ts create mode 100644 shell/types/rancher-api/growl.d.ts create mode 100644 shell/types/rancher-api/modal.d.ts delete mode 100644 shell/utils/growl.ts diff --git a/package.json b/package.json index 2d74f684a1f..59ac7a5d553 100644 --- a/package.json +++ b/package.json @@ -205,5 +205,6 @@ }, "resolutions": { "html-webpack-plugin": "^5.0.0" - } + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/shell/components/GrowlManager.vue b/shell/components/GrowlManager.vue index f992716cdd1..287cff7266f 100644 --- a/shell/components/GrowlManager.vue +++ b/shell/components/GrowlManager.vue @@ -103,7 +103,10 @@ export default { class="close hand icon icon-close" @click="close(growl)" /> -
+
{{ growl.title }}

diff --git a/shell/plugins/rancher-api/index.ts b/shell/plugins/rancher-api/index.ts index d88ed659607..ae58959ee99 100644 --- a/shell/plugins/rancher-api/index.ts +++ b/shell/plugins/rancher-api/index.ts @@ -1,5 +1,3 @@ -// shell/plugins/rancher-api/index.ts - import { Store } from 'vuex'; import { ApiPrototype } from '@shell/types/rancher-api'; // import RancherApi from './rancher-api-class'; @@ -12,7 +10,7 @@ interface PluginContext { [key: string]: any; } -export default function (context: PluginContext, inject: (key: string, value: any) => void) { +export default function(context: PluginContext, inject: (key: string, value: any) => void) { const { store } = context; /** diff --git a/shell/plugins/rancher-api/shell-api-class.ts b/shell/plugins/rancher-api/shell-api-class.ts index 0ec80e3d236..28e5a6d2356 100644 --- a/shell/plugins/rancher-api/shell-api-class.ts +++ b/shell/plugins/rancher-api/shell-api-class.ts @@ -1,6 +1,7 @@ import { Store } from 'vuex'; -import { GrowlConfig, handleGrowl } from '@shell/utils/growl'; +import { GrowlConfig } from '@shell/types/rancher-api/growl'; +import { ModalConfig } from '@shell/types/rancher-api/modal'; interface ShellApiOptions { store: Store; @@ -14,27 +15,69 @@ export default class ShellApi { } /** - * Dispatches a growl notification based on the provided configuration. + * Dispatches a growl notification. * * @param config - Configuration for the growl notification. + * - If `message` is a string, it is treated as the main content of the notification. + * - If `message` is a `DetailedMessage` object, `title` and `description` are extracted. * - * The `config` parameter is an object of type `GrowlConfig`, which includes: - * - `error`: An `ErrorMessage` object containing the details of the error to be displayed. - * This object can have an optional `data` property with `_statusText` and `message`, - * or these properties can be directly on the `error` object. - * - `store`: A parameter representing the Vuex store used to dispatch actions. - * This is where the growl notification action will be dispatched. - * - `type`: An optional string representing the type of notification (e.g., 'success', 'info', 'warning', 'error'). - * If not provided, defaults to 'error'. - * - `timeout`: An optional number representing the duration in milliseconds - * for which the notification should be displayed. Defaults to 5000 milliseconds if not provided. - * - * The action payload includes: - * - `title`: The error status text. - * - `message`: The detailed error message. - * - `timeout`: The specified or default timeout duration. + * Example: + * ``` + * this.$shell.growl({ message: 'Operation successful!', type: 'success' }); + * this.$shell.growl({ message: { title: 'Warning', description: 'Check your input.' }, type: 'warning' }); + * ``` */ growl(config: GrowlConfig): void { - handleGrowl(config); + const { type = 'error', timeout = 5000 } = config; + + let title = ''; + let description = ''; + + if (typeof config.message === 'string') { + description = config.message; + } else { + title = config.message.title || ''; + description = config.message.description; + } + + this.$store.dispatch( + `growl/${ type }`, + { + title, + message: description, + timeout, + }, + { root: true } + ); + } + + /** + * Opens a modal by committing to the Vuex store. + * + * This method updates the store's `action-menu` module to show a modal with the + * specified configuration. The modal is rendered using the `PromptModal` component, + * and its content is dynamically loaded based on the `component` field in the configuration. + * + * @param config A `ModalConfig` object defining the modal’s content and behavior. + * + * Example: + * ``` + * this.$shell.modal({ + * component: 'MyCustomDialog', + * componentProps: { title: 'Hello Modal' }, + * resources: [someResource], + * modalWidth: '800px', + * closeOnClickOutside: false + * }); + * ``` + */ + modal(config: ModalConfig): void { + this.$store.commit('action-menu/togglePromptModal', { + component: config.component, + componentProps: config.componentProps || {}, + resources: config.resources || [], + modalWidth: config.modalWidth || '600px', + closeOnClickOutside: config.closeOnClickOutside ?? true, + }); } } diff --git a/shell/types/rancher-api/cluster.d.ts b/shell/types/rancher-api/cluster.d.ts new file mode 100644 index 00000000000..36a6c70a443 --- /dev/null +++ b/shell/types/rancher-api/cluster.d.ts @@ -0,0 +1,35 @@ +/** + * TODO: Update @shell/plugins/dashboard-store/resource-class to TS. + */ +export interface SteveResource { + save(): Promise, + remove(): Promise, +} + +export interface ResourceFetchOptions { + id?: string, + namespace?: string, + selector?: string, + force?: boolean +} + +export interface ResourceFetchRequest { + type: string, + options?: ResourceFetchOptions +} + +export interface ResourceManageOptions { + metadata: { + name: string, + namespace?: string, + labels?: {[key: string]: string}, + annotations?: {[key: string]: string} + }, + spec?: any +} + +export interface ResourceManageRequest { + type: string, + options: ResourceManageOptions, + resource?: SteveResource +} diff --git a/shell/types/rancher-api/growl.d.ts b/shell/types/rancher-api/growl.d.ts new file mode 100644 index 00000000000..def12827a65 --- /dev/null +++ b/shell/types/rancher-api/growl.d.ts @@ -0,0 +1,25 @@ +export interface DetailedMessage { + title?: string; + description: string; +} + +export interface GrowlConfig { + /** + * The content of the notification message. + * Either a simple string or an object with `title` and `description` for detailed notifications. + */ + message: string | DetailedMessage; + + /** + * Optional type of the growl notification. + * Determines the visual style of the notification. + * Defaults to `'error'` if not provided. + */ + type?: 'success' | 'info' | 'warning' | 'error'; + + /** + * Optional duration (in milliseconds) for which the notification should be displayed. + * Defaults to `5000` milliseconds. A value of `0` keeps the notification indefinitely. + */ + timeout?: number; +} diff --git a/shell/types/rancher-api/modal.d.ts b/shell/types/rancher-api/modal.d.ts new file mode 100644 index 00000000000..87b481b1581 --- /dev/null +++ b/shell/types/rancher-api/modal.d.ts @@ -0,0 +1,82 @@ +/** + * Configuration object for opening a modal. + */ +export interface ModalConfig { + /** + * TODO: Understand how this works with extensions + * + * The name of the component to be displayed inside the modal. + * + * The component must reside in the `dialog` directory, depending on the environment: + * + * 1. **When Using the Shell as Part of the Core Project**: + * - Components must live in the `@shell/dialog` directory. + * - Example: + * ``` + * shell/dialog/MyCustomDialog.vue + * ``` + * + * 2. **When Using the Shell as a Library (Extensions)**: + * - Components must live in the `pkg//dialog` directory within the extension. + * - Example, in an extension named `my-extension`: + * ``` + * /pkg/my-extension/dialog/MyCustomDialog.vue + * ``` + * + * - The `component` value should still match the file name without the `.vue` extension. + * - Example: + * ```typescript + * component: 'MyCustomDialog' // Dynamically imports MyCustomDialog.vue + * ``` + * + */ + component: string; + + /** + * Optional props to pass directly to the component rendered inside the modal. + * This can be a record of key-value pairs where keys are the prop names, and + * values are the corresponding prop values for the component. + * + * Example: + * ``` + * componentProps: { title: 'Hello Modal', isVisible: true } + * ``` + */ + componentProps?: Record; + + /** + * Optional array of resources that the modal component might need. + * These resources are passed directly to the modal's `resources` prop. + * + * Example: + * ``` + * resources: [myResource, anotherResource] + * ``` + */ + resources?: any[]; + + /** + * Custom width for the modal. Defaults to `600px`. + * The width can be specified as a number (pixels) or as a string + * with a valid unit, such as `px` or `%`. + * + * Example: + * ``` + * modalWidth: '800px' // Width in pixels + * modalWidth: '75%' // Width as a percentage + * ``` + */ + modalWidth?: string; + + /** + * If true, clicking outside the modal will close it. Defaults to `true`. + * Set this to `false` if you want the modal to remain open until the user + * explicitly closes it. + * + * Example: + * ``` + * closeOnClickOutside: false + * ``` + */ + closeOnClickOutside?: boolean; +} diff --git a/shell/utils/growl.ts b/shell/utils/growl.ts deleted file mode 100644 index 1898760cff1..00000000000 --- a/shell/utils/growl.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Store } from 'vuex'; - -export interface Message { - data?: { - _statusText: string, - message: string - } - _statusText?: string, - message?: string -} - -export interface GrowlConfig { - message: Message, - store: Store, - type?: string, - timeout?: number -} - -/** - * Dispatches a growl notification based on the provided configuration. - * - * @param config - Configuration for the growl notification. - * - * The `config` parameter is an object of type `GrowlConfig`, which includes: - * - `message`: An `Message` object containing the details of the error to be displayed. - * This object can have an optional `data` property with `_statusText` and `message`, - * or these properties can be directly on the `error` object. - * - `store`: A parameter representing the Vuex store used to dispatch actions. - * This is where the growl notification action will be dispatched. - * - `type`: An optional string representing the type of notification (e.g., 'success', 'info', 'warning', 'error'). - * If not provided, defaults to 'error'. - * - `timeout`: An optional number representing the duration in milliseconds - * for which the notification should be displayed. Defaults to 5000 milliseconds if not provided. - * - * The function extracts error details either from `config.error.data` or `config.error` - * (if `data` is not present), and dispatches a growl notification action to the store. - * The action dispatched is of the form `growl/[type]` where `[type]` is either - * the provided type in the config or 'error' by default. - * - * The action payload includes: - * - `title`: The error status text. - * - `message`: The detailed error message. - * - `timeout`: The specified or default timeout duration. - */ -export function handleGrowl(config: GrowlConfig): void { - const message = config.message?.data || config.message; - - config.store.dispatch(`growl/${ config.type || 'error' }`, { - title: message._statusText, - message: message.message, - timeout: config.timeout || 5000, - }, { root: true }); -}