diff --git a/.eslintrc.cjs b/.eslintrc.cjs index adc52e737d..f75b8b9535 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -2,7 +2,7 @@ const path = require("path"); module.exports = { root: true, - plugins: ["unused-imports", "prettier"], + plugins: ["unused-imports", "complexity", "prettier"], extends: [ "react-app", "plugin:prettier/recommended", @@ -50,6 +50,7 @@ module.exports = { }, rules: { "prettier/prettier": "error", + complexity: ["error", { max: 25 }], "@typescript-eslint/no-unused-vars": "off", "unused-imports/no-unused-imports": "error", "unused-imports/no-unused-vars": [ diff --git a/package.json b/package.json index 7d774ebd1d..4c8c98a50b 100644 --- a/package.json +++ b/package.json @@ -129,6 +129,7 @@ "eslint-config-prettier": "9.1.0", "eslint-config-react-app": "7.0.1", "eslint-import-resolver-typescript": "3.6.1", + "eslint-plugin-complexity": "1.0.2", "eslint-plugin-cypress": "2.15.2", "eslint-plugin-no-only-tests": "3.1.0", "eslint-plugin-playwright": "1.6.1", diff --git a/src/app/base/components/ActionForm/ActionForm.tsx b/src/app/base/components/ActionForm/ActionForm.tsx index 1dfa123c26..ab78546735 100644 --- a/src/app/base/components/ActionForm/ActionForm.tsx +++ b/src/app/base/components/ActionForm/ActionForm.tsx @@ -6,6 +6,7 @@ import type { FormikFormProps } from "@/app/base/components/FormikForm"; import FormikForm from "@/app/base/components/FormikForm"; import { useProcessing } from "@/app/base/hooks"; import type { ActionState } from "@/app/base/types"; +import type { NodeActions } from "@/app/store/types/node"; import { getNodeActionLabel } from "@/app/store/utils"; const getLabel = ( @@ -28,7 +29,7 @@ const getLabel = ( // e.g. "2 machines" modelString = `${selectedCount} ${modelName}s`; } - return getNodeActionLabel(modelString, actionName, processing); + return getNodeActionLabel(modelString, actionName as NodeActions, processing); }; export type ActionFormProps = Omit< diff --git a/src/app/base/components/node/networking/NetworkTable/NetworkTable.tsx b/src/app/base/components/node/networking/NetworkTable/NetworkTable.tsx index 87b060f48e..184b377604 100644 --- a/src/app/base/components/node/networking/NetworkTable/NetworkTable.tsx +++ b/src/app/base/components/node/networking/NetworkTable/NetworkTable.tsx @@ -1,3 +1,4 @@ +import type { ValueOf } from "@canonical/react-components"; import { MainTable } from "@canonical/react-components"; import type { MainTableRow } from "@canonical/react-components/dist/components/MainTable/MainTable"; import classNames from "classnames"; @@ -105,6 +106,93 @@ const getSortValue = (sortKey: SortKey, row: NetworkRow) => { return isComparable(value) ? value : null; }; +const generateColumnData = ( + checkboxHandler: CheckboxHandlers | null, + hasActions: boolean, + isABondOrBridgeParent: boolean, + link: NetworkLink | null, + nic: NetworkInterface, + node: MachineDetails | ControllerDetails, + selected: Props["selected"], + setExpanded?: SetExpanded, + setSelected?: Props["setSelected"] +) => [ + { + "aria-label": Label.Name, + content: ( + + ), + }, + { + "aria-label": Label.PXE, + content: !isABondOrBridgeParent && ( + + ), + className: "u-align--center", + }, + { + "aria-label": Label.Speed, + content: , + }, + { + "aria-label": Label.Type, + content: , + }, + { + "aria-label": Label.Fabric, + content: !isABondOrBridgeParent && ( + + ), + }, + { + "aria-label": Label.Subnet, + content: !isABondOrBridgeParent && ( + + ), + }, + { + "aria-label": Label.IP, + content: !isABondOrBridgeParent && ( + + ), + }, + { + "aria-label": Label.DHCP, + content: !isABondOrBridgeParent && , + }, + ...(hasActions + ? [ + { + "aria-label": Label.Actions, + className: "u-align--right", + content: + !isABondOrBridgeParent && nodeIsMachine(node) && setExpanded ? ( + + ) : null, + }, + ] + : []), +]; + const generateRow = ( checkboxHandler: CheckboxHandlers | null, fabrics: Fabric[], @@ -147,96 +235,29 @@ const generateRow = ( nic, link ); - const showCheckbox = !isABondOrBridgeParent && hasActions; - const select = showCheckbox - ? { - linkId: link?.id, - nicId: nic?.id, - } - : null; + const columns = generateColumnData( + checkboxHandler, + hasActions, + isABondOrBridgeParent, + link, + nic, + node, + selected, + setExpanded, + setSelected + ); + return { className: classNames("p-table__row", { "truncated-border": isABondOrBridgeParent, }), - columns: [ - { - "aria-label": Label.Name, - content: ( - - ), - }, - { - "aria-label": Label.PXE, - content: !isABondOrBridgeParent && ( - - ), - className: "u-align--center", - }, - { - "aria-label": Label.Speed, - content: , - }, - { - "aria-label": Label.Type, - content: , - }, - { - "aria-label": Label.Fabric, - content: !isABondOrBridgeParent && ( - - ), - }, - { - "aria-label": Label.Subnet, - content: !isABondOrBridgeParent && ( - - ), - }, - { - "aria-label": Label.IP, - content: !isABondOrBridgeParent && ( - - ), - }, - { - "aria-label": Label.DHCP, - content: !isABondOrBridgeParent && , - }, - ...(hasActions - ? [ - { - "aria-label": Label.Actions, - className: "u-align--right", - content: - !isABondOrBridgeParent && nodeIsMachine(node) && setExpanded ? ( - - ) : null, - }, - ] - : []), - ], + columns, "data-testid": name, key: name, - select, + select: + !isABondOrBridgeParent && hasActions + ? { linkId: link?.id, nicId: nic?.id } + : null, sortData: { bondOrBridge: (isABondOrBridgeParent && nic.children[0]) || @@ -323,6 +344,33 @@ const getChild = (row: NetworkRow, rows: NetworkRow[]): NetworkRow | null => { ); }; +const compareValues = ( + rowAValue: string | number | null, + rowBValue: string | number | null, + direction: ValueOf +) => { + if (!rowAValue && !rowBValue) { + return 0; + } + if ( + (rowBValue && !rowAValue) || + (isComparable(rowAValue) && + isComparable(rowBValue) && + rowAValue < rowBValue) + ) { + return direction === SortDirection.DESCENDING ? -1 : 1; + } + if ( + (rowAValue && !rowBValue) || + (isComparable(rowAValue) && + isComparable(rowBValue) && + rowAValue > rowBValue) + ) { + return direction === SortDirection.DESCENDING ? 1 : -1; + } + return 0; +}; + const rowSort = ( rowA: NetworkRow, rowB: NetworkRow, @@ -336,21 +384,20 @@ const rowSort = ( key = "bondOrBridge"; direction = SortDirection.ASCENDING; } + // Get the bond or bridge child rows. const childA = getChild(rowA, rows); const childB = getChild(rowB, rows); const inSameBondOrBridge = rowA.sortData.bondOrBridge === rowB.sortData.bondOrBridge; - // Get the values to sort by. When comparing bond or bridge parents (the - // "siblings" of the bond or bridge) then use the row values, otherwise use - // the value from the child (the main row that preceeds the parents) so that all - // the rows for a bond or bridge end up together. + let rowAValue = key ? getSortValue(key, childA && !inSameBondOrBridge ? childA : rowA) : null; let rowBValue = key ? getSortValue(key, childB && !inSameBondOrBridge ? childB : rowB) : null; + // If the rows are in the same bond or bridge then put the child first. if (inSameBondOrBridge) { if ( @@ -363,33 +410,15 @@ const rowSort = ( return 0; } } + if (rowAValue === rowBValue) { // Rows that have the same value need to be sorted by the bond or bridge id // so that they don't lose their grouping. rowAValue = getSortValue("bondOrBridge", rowA); rowBValue = getSortValue("bondOrBridge", rowB); } - // From this point on compare the values as normal. - if (!rowAValue && !rowBValue) { - return 0; - } - if ( - (rowBValue && !rowAValue) || - (isComparable(rowAValue) && - isComparable(rowBValue) && - rowAValue < rowBValue) - ) { - return direction === SortDirection.DESCENDING ? -1 : 1; - } - if ( - (rowAValue && !rowBValue) || - (isComparable(rowAValue) && - isComparable(rowBValue) && - rowAValue > rowBValue) - ) { - return direction === SortDirection.DESCENDING ? 1 : -1; - } - return 0; + + return compareValues(rowAValue, rowBValue, direction); }; export const generateUniqueId = ({ linkId, nicId }: Selected): string => diff --git a/src/app/kvm/utils.ts b/src/app/kvm/utils.ts index 6e9265c9f8..58928fc815 100644 --- a/src/app/kvm/utils.ts +++ b/src/app/kvm/utils.ts @@ -18,31 +18,33 @@ export const memoryWithUnit = (memory: number): string => { return `${formatted.value}${formatted.unit}`; }; +const kvmSidePanelTitleMap = { + [KVMSidePanelViews.ADD_LXD_HOST[1]]: "Add LXD host", + [KVMSidePanelViews.ADD_VIRSH_HOST[1]]: "Add Virsh host", + [KVMSidePanelViews.COMPOSE_VM[1]]: "Compose", + [KVMSidePanelViews.DELETE_KVM[1]]: "Delete", + [KVMSidePanelViews.REFRESH_KVM[1]]: "Refresh", +} as const; + /** * Get header title depending on header content. * @param sidePanelContent - The currently selected header content. * @returns Header title. */ export const getFormTitle = (sidePanelContent: SidePanelContent): string => { - switch (sidePanelContent && sidePanelContent.view) { - case KVMSidePanelViews.ADD_LXD_HOST: - return "Add LXD host"; - case KVMSidePanelViews.ADD_VIRSH_HOST: - return "Add Virsh host"; - case KVMSidePanelViews.COMPOSE_VM: - return "Compose"; - case KVMSidePanelViews.DELETE_KVM: - return "Delete"; - case KVMSidePanelViews.REFRESH_KVM: - return "Refresh"; - default: - // We need to explicitly cast sidePanelContent here - TypeScript doesn't - // seem to be able to infer remaining object tuple values as with string - // values. - // https://github.com/canonical/maas-ui/issues/3040 - const machineSidePanelContent = sidePanelContent; - return getSidePanelTitle("", machineSidePanelContent); + if (sidePanelContent && sidePanelContent.view) { + const [, title] = sidePanelContent.view; + if (title && title in kvmSidePanelTitleMap) { + return kvmSidePanelTitleMap[title as keyof typeof kvmSidePanelTitleMap]; + } } + + // We need to explicitly cast sidePanelContent here - TypeScript doesn't + // seem to be able to infer remaining object tuple values as with string + // values. + // https://github.com/canonical/maas-ui/issues/3040 + const machineSidePanelContent = sidePanelContent; + return getSidePanelTitle("", machineSidePanelContent); }; /** diff --git a/src/app/machines/components/MachineForms/MachineForms.tsx b/src/app/machines/components/MachineForms/MachineForms.tsx index 8a95e64a35..1bbf86253f 100644 --- a/src/app/machines/components/MachineForms/MachineForms.tsx +++ b/src/app/machines/components/MachineForms/MachineForms.tsx @@ -49,6 +49,7 @@ type Props = SidePanelContentTypes & { viewingDetails?: boolean; } & MachineActionVariableProps; +/* eslint-disable complexity */ export const MachineForms = ({ sidePanelContent, machines, diff --git a/src/app/store/pod/types/base.ts b/src/app/store/pod/types/base.ts index da257162b4..d19feaef49 100644 --- a/src/app/store/pod/types/base.ts +++ b/src/app/store/pod/types/base.ts @@ -12,6 +12,8 @@ import type { Node } from "@/app/store/types/node"; import type { GenericState } from "@/app/store/types/state"; import type { VMCluster, VMClusterMeta } from "@/app/store/vmcluster/types"; +export type PodActions = "compose" | "remove" | "refresh"; + export type PodStoragePool = { available: number; id: string; diff --git a/src/app/store/utils/node/base.ts b/src/app/store/utils/node/base.ts index 95022553c8..7bd156c276 100644 --- a/src/app/store/utils/node/base.ts +++ b/src/app/store/utils/node/base.ts @@ -9,6 +9,7 @@ import { isDeviceDetails } from "@/app/store/device/utils"; import type { Machine } from "@/app/store/machine/types"; // Import from the common utils to prevent an import loop in machine/utils/index.ts. import { isMachineDetails } from "@/app/store/machine/utils/common"; +import type { PodActions } from "@/app/store/pod/types/base"; import type { Node, NodeDetails } from "@/app/store/types/node"; import { NodeActions, @@ -47,134 +48,181 @@ export const getNodeTypeDisplay = (nodeType: NodeType): string => { * @returns Formatted node action title. */ export const getNodeActionTitle = (actionName: NodeActions): string => { - switch (actionName) { - case NodeActions.ABORT: - return "Abort"; - case NodeActions.ACQUIRE: - return "Allocate"; - case NodeActions.CHECK_POWER: - return "Check power"; - case NodeActions.CLONE: - return "Clone from"; - case NodeActions.COMMISSION: - return "Commission"; - case NodeActions.DELETE: - return "Delete"; - case NodeActions.DEPLOY: - return "Deploy"; - case NodeActions.EXIT_RESCUE_MODE: - return "Exit rescue mode"; - case NodeActions.IMPORT_IMAGES: - return "Import images"; - case NodeActions.LOCK: - return "Lock"; - case NodeActions.MARK_BROKEN: - return "Mark broken"; - case NodeActions.MARK_FIXED: - return "Mark fixed"; - case NodeActions.OFF: - return "Power off"; - case NodeActions.ON: - return "Power on"; - case NodeActions.SOFT_OFF: - return "Soft power off"; - case NodeActions.OVERRIDE_FAILED_TESTING: - return "Override failed testing"; - case NodeActions.RELEASE: - return "Release"; - case NodeActions.RESCUE_MODE: - return "Enter rescue mode"; - case NodeActions.SET_POOL: - return "Set pool"; - case NodeActions.SET_ZONE: - return "Set zone"; - case NodeActions.TAG: - return "Tag"; - case NodeActions.TEST: - return "Test"; - case NodeActions.UNLOCK: - return "Unlock"; - default: - return "Action"; - } -}; + const actionTitles: Record = { + [NodeActions.ABORT]: "Abort", + [NodeActions.ACQUIRE]: "Allocate", + [NodeActions.CHECK_POWER]: "Check power", + [NodeActions.CLONE]: "Clone from", + [NodeActions.COMMISSION]: "Commission", + [NodeActions.DELETE]: "Delete", + [NodeActions.DEPLOY]: "Deploy", + [NodeActions.EXIT_RESCUE_MODE]: "Exit rescue mode", + [NodeActions.IMPORT_IMAGES]: "Import images", + [NodeActions.LOCK]: "Lock", + [NodeActions.MARK_BROKEN]: "Mark broken", + [NodeActions.MARK_FIXED]: "Mark fixed", + [NodeActions.OFF]: "Power off", + [NodeActions.ON]: "Power on", + [NodeActions.SOFT_OFF]: "Soft power off", + [NodeActions.OVERRIDE_FAILED_TESTING]: "Override failed testing", + [NodeActions.RELEASE]: "Release", + [NodeActions.RESCUE_MODE]: "Enter rescue mode", + [NodeActions.SET_POOL]: "Set pool", + [NodeActions.SET_ZONE]: "Set zone", + [NodeActions.TAG]: "Tag", + [NodeActions.UNTAG]: "Untag", + [NodeActions.TEST]: "Test", + [NodeActions.UNLOCK]: "Unlock", + }; + return actionTitles[actionName] || "Action"; +}; export const getNodeActionLabel = ( modelString: string, - actionName: string, + actionName: NodeActions | PodActions, isProcessing: boolean ): string => { - switch (actionName) { - case NodeActions.ABORT: - return `${ - isProcessing ? "Aborting" : "Abort" - } actions for ${modelString}`; - case NodeActions.ACQUIRE: - return `${isProcessing ? "Allocating" : "Allocate"} ${modelString}`; - case NodeActions.CHECK_POWER: - return `${ - isProcessing ? "Checking power" : "Check power" - } for ${modelString}`; - case NodeActions.CLONE: - return isProcessing ? "Cloning in progress" : `Clone to ${modelString}`; - case NodeActions.COMMISSION: - return `${ - isProcessing ? "Starting" : "Start" - } commissioning for ${modelString}`; - case "compose": - return `${isProcessing ? "Composing" : "Compose"} ${modelString}`; - case NodeActions.DELETE: - return `${isProcessing ? "Deleting" : "Delete"} ${modelString}`; - case NodeActions.DEPLOY: - return `${isProcessing ? "Deploying" : "Deploy"} ${modelString}`; - case NodeActions.EXIT_RESCUE_MODE: - return `${ - isProcessing ? "Exiting" : "Exit" - } rescue mode for ${modelString}`; - case NodeActions.IMPORT_IMAGES: - return `${ - isProcessing ? "Importing images" : "Import images" - } for ${modelString}`; - case NodeActions.LOCK: - return `${isProcessing ? "Locking" : "Lock"} ${modelString}`; - case NodeActions.ON: - return `${isProcessing ? "Powering" : "Power"} on ${modelString}`; - case NodeActions.OFF: - return `${isProcessing ? "Powering" : "Power"} off ${modelString}`; - case NodeActions.MARK_BROKEN: - return `${isProcessing ? "Marking" : "Mark"} ${modelString} broken`; - case NodeActions.MARK_FIXED: - return `${isProcessing ? "Marking" : "Mark"} ${modelString} fixed`; - case NodeActions.OVERRIDE_FAILED_TESTING: - return `${ - isProcessing ? "Overriding" : "Override" - } failed tests for ${modelString}`; - case NodeActions.RELEASE: - return `${isProcessing ? "Releasing" : "Release"} ${modelString}`; - case "refresh": - return `${isProcessing ? "Refreshing" : "Refresh"} ${modelString}`; - case "remove": - return `${isProcessing ? "Removing" : "Remove"} ${modelString}`; - case NodeActions.RESCUE_MODE: - return `${ - isProcessing ? "Entering" : "Enter" - } rescue mode for ${modelString}`; - case NodeActions.SET_POOL: - return `${isProcessing ? "Setting" : "Set"} pool for ${modelString}`; - case NodeActions.SET_ZONE: - return `${isProcessing ? "Setting" : "Set"} zone for ${modelString}`; - case NodeActions.SOFT_OFF: - return `${isProcessing ? "Powering" : "Soft power"} off ${modelString}`; - case NodeActions.TAG: - case NodeActions.UNTAG: - return `${isProcessing ? "Updating" : "Update"} tags for ${modelString}`; - case NodeActions.TEST: - return `${isProcessing ? "Starting" : "Start"} tests for ${modelString}`; - case NodeActions.UNLOCK: - return `${isProcessing ? "Unlocking" : "Unlock"} ${modelString}`; - default: - return `${isProcessing ? "Processing" : "Process"} ${modelString}`; + const actionLabels: Record = { + [NodeActions.ABORT]: [ + `Abort actions for ${modelString}`, + `Aborting actions for ${modelString}`, + ], + [NodeActions.ACQUIRE]: [ + `Allocate ${modelString}`, + `Allocating ${modelString}`, + ], + [NodeActions.CHECK_POWER]: [ + `Check power for ${modelString}`, + `Checking power for ${modelString}`, + ], + [NodeActions.CLONE]: [`Clone to ${modelString}`, `Cloning in progress`], + [NodeActions.COMMISSION]: [ + `Start commissioning for ${modelString}`, + `Starting commissioning for ${modelString}`, + ], + [NodeActions.DELETE]: [`Delete ${modelString}`, `Deleting ${modelString}`], + [NodeActions.DEPLOY]: [`Deploy ${modelString}`, `Deploying ${modelString}`], + [NodeActions.EXIT_RESCUE_MODE]: [ + `Exit rescue mode for ${modelString}`, + `Exiting rescue mode for ${modelString}`, + ], + [NodeActions.IMPORT_IMAGES]: [ + `Import images for ${modelString}`, + `Importing images for ${modelString}`, + ], + [NodeActions.LOCK]: [`Lock ${modelString}`, `Locking ${modelString}`], + [NodeActions.ON]: [`Power on ${modelString}`, `Powering on ${modelString}`], + [NodeActions.OFF]: [ + `Power off ${modelString}`, + `Powering off ${modelString}`, + ], + [NodeActions.MARK_BROKEN]: [ + `Mark ${modelString} broken`, + `Marking ${modelString} broken`, + ], + [NodeActions.MARK_FIXED]: [ + `Mark ${modelString} fixed`, + `Marking ${modelString} fixed`, + ], + [NodeActions.OVERRIDE_FAILED_TESTING]: [ + `Override failed tests for ${modelString}`, + `Overriding failed tests for ${modelString}`, + ], + [NodeActions.RELEASE]: [ + `Release ${modelString}`, + `Releasing ${modelString}`, + ], + [NodeActions.RESCUE_MODE]: [ + `Enter rescue mode for ${modelString}`, + `Entering rescue mode for ${modelString}`, + ], + [NodeActions.SET_POOL]: [ + `Set pool for ${modelString}`, + `Setting pool for ${modelString}`, + ], + [NodeActions.SET_ZONE]: [ + `Set zone for ${modelString}`, + `Setting zone for ${modelString}`, + ], + [NodeActions.SOFT_OFF]: [ + `Soft power off ${modelString}`, + `Powering off ${modelString}`, + ], + [NodeActions.TAG]: [ + `Update tags for ${modelString}`, + `Updating tags for ${modelString}`, + ], + [NodeActions.UNTAG]: [ + `Update tags for ${modelString}`, + `Updating tags for ${modelString}`, + ], + [NodeActions.TEST]: [ + `Start tests for ${modelString}`, + `Starting tests for ${modelString}`, + ], + [NodeActions.UNLOCK]: [`Unlock ${modelString}`, `Unlocking ${modelString}`], + compose: [`Compose ${modelString}`, `Composing ${modelString}`], + refresh: [`Refresh ${modelString}`, `Refreshing ${modelString}`], + remove: [`Remove ${modelString}`, `Removing ${modelString}`], + }; + + const label = actionLabels[actionName]; + if (Array.isArray(label)) { + const [actionLabel, actionProcessingLabel] = label; + return isProcessing ? actionProcessingLabel : actionLabel; } + + return `${isProcessing ? "Processing" : "Process"} ${modelString}`; +}; + +const sidePanelTitleMap: Record = { + [SidePanelViews.ADD_ALIAS[1]]: "Add alias", + [SidePanelViews.ADD_BOND[1]]: "Create bond", + [SidePanelViews.ADD_BRIDGE[1]]: "Create bridge", + [SidePanelViews.ADD_CONTROLLER[1]]: "Add controller", + [SidePanelViews.ADD_CHASSIS[1]]: "Add chassis", + [SidePanelViews.ADD_DISCOVERY[1]]: "Add discovery", + [SidePanelViews.ADD_DOMAIN[1]]: "Add domains", + [SidePanelViews.ADD_INTERFACE[1]]: "Add interface", + [SidePanelViews.ADD_MACHINE[1]]: "Add machine", + [SidePanelViews.ADD_DEVICE[1]]: "Add device", + [SidePanelViews.ADD_SPECIAL_FILESYSTEM[1]]: "Add special filesystem", + [SidePanelViews.AddTag[1]]: "Create new tag", + [SidePanelViews.ADD_VLAN[1]]: "Add VLAN", + [SidePanelViews.CHANGE_SOURCE[1]]: "Change source", + [SidePanelViews.APPLY_STORAGE_LAYOUT[1]]: "Change storage layout", + [SidePanelViews.CLEAR_ALL_DISCOVERIES[1]]: "Clear all discoveries", + [SidePanelViews.CREATE_BCACHE[1]]: "Create bcache", + [SidePanelViews.CREATE_CACHE_SET[1]]: "Create cache set", + [SidePanelViews.CREATE_DATASTORE[1]]: "Create datastore", + [SidePanelViews.CREATE_LOGICAL_VOLUME[1]]: "Create logical volume", + [SidePanelViews.CREATE_PARTITION[1]]: "Create partition", + [SidePanelViews.CREATE_RAID[1]]: "Create raid", + [SidePanelViews.CREATE_VOLUME_GROUP[1]]: "Create volume group", + [SidePanelViews.DELETE_DISCOVERY[1]]: "Delete discovery", + [SidePanelViews.DELETE_DISK[1]]: "Delete disk", + [SidePanelViews.DELETE_FILESYSTEM[1]]: "Delete filesystem", + [SidePanelViews.DELETE_SPECIAL_FILESYSTEM[1]]: "Delete special filesystem", + [SidePanelViews.DeleteTag[1]]: "Delete tag", + [SidePanelViews.DELETE_VOLUME_GROUP[1]]: "Delete volume group", + [SidePanelViews.EDIT_INTERFACE[1]]: "Edit interface", + [SidePanelViews.CREATE_ZONE[1]]: "Add AZ", + [SidePanelViews.EDIT_DISK[1]]: "Edit disk", + [SidePanelViews.EDIT_PARTITION[1]]: "Edit partition", + [SidePanelViews.EDIT_PHYSICAL[1]]: "Edit physical", + [SidePanelViews.DELETE_IMAGE[1]]: "Delete image", + [SidePanelViews.DELETE_SPACE[1]]: "Delete space", + [SidePanelViews.DELETE_FABRIC[1]]: "Delete fabric", + [SidePanelViews.MARK_CONNECTED[1]]: "Mark as connected", + [SidePanelViews.MARK_DISCONNECTED[1]]: "Mark as disconnected", + [SidePanelViews.REMOVE_INTERFACE[1]]: "Remove interface", + [SidePanelViews.REMOVE_PARTITION[1]]: "Remove partition", + [SidePanelViews.REMOVE_PHYSICAL[1]]: "Remove physical", + [SidePanelViews.SET_BOOT_DISK[1]]: "Set boot disk", + [SidePanelViews.SET_DEFAULT[1]]: "Set default", + [SidePanelViews.UNMOUNT_FILESYSTEM[1]]: "Unmount filesystem", + [SidePanelViews.UPDATE_DATASTORE[1]]: "Update datastore", + [SidePanelViews.UpdateTag[1]]: "Update Tag", }; /** @@ -189,104 +237,11 @@ export const getSidePanelTitle = ( ): string => { if (sidePanelContent) { const [, name] = sidePanelContent.view; - switch (name) { - case SidePanelViews.ADD_ALIAS[1]: - return "Add alias"; - case SidePanelViews.ADD_BOND[1]: - return "Create bond"; - case SidePanelViews.ADD_BRIDGE[1]: - return "Create bridge"; - case SidePanelViews.ADD_CONTROLLER[1]: - return "Add controller"; - case SidePanelViews.ADD_CHASSIS[1]: - return "Add chassis"; - case SidePanelViews.ADD_DISCOVERY[1]: - return "Add discovery"; - case SidePanelViews.ADD_DOMAIN[1]: - return "Add domains"; - case SidePanelViews.ADD_INTERFACE[1]: - return "Add interface"; - case SidePanelViews.ADD_MACHINE[1]: - return "Add machine"; - case SidePanelViews.ADD_DEVICE[1]: - return "Add device"; - case SidePanelViews.ADD_SPECIAL_FILESYSTEM[1]: - return "Add special filesystem"; - case SidePanelViews.AddTag[1]: - return "Create new tag"; - case SidePanelViews.ADD_VLAN[1]: - return "Add VLAN"; - case SidePanelViews.CHANGE_SOURCE[1]: - return "Change source"; - case SidePanelViews.APPLY_STORAGE_LAYOUT[1]: - return "Change storage layout"; - case SidePanelViews.CLEAR_ALL_DISCOVERIES[1]: - return "Clear all discoveries"; - case SidePanelViews.CREATE_BCACHE[1]: - return "Create bcache"; - case SidePanelViews.CREATE_CACHE_SET[1]: - return "Create cache set"; - case SidePanelViews.CREATE_DATASTORE[1]: - return "Create datastore"; - case SidePanelViews.CREATE_LOGICAL_VOLUME[1]: - return "Create logical volume"; - case SidePanelViews.CREATE_PARTITION[1]: - return "Create partition"; - case SidePanelViews.CREATE_RAID[1]: - return "Create raid"; - case SidePanelViews.CREATE_VOLUME_GROUP[1]: - return "Create volume group"; - case SidePanelViews.DELETE_DISCOVERY[1]: - return "Delete discovery"; - case SidePanelViews.DELETE_DISK[1]: - return "Delete disk"; - case SidePanelViews.DELETE_FILESYSTEM[1]: - return "Delete filesystem"; - case SidePanelViews.DELETE_SPECIAL_FILESYSTEM[1]: - return "Delete special filesystem"; - case SidePanelViews.DeleteTag[1]: - return "Delete tag"; - case SidePanelViews.DELETE_VOLUME_GROUP[1]: - return "Delete volume group"; - case SidePanelViews.EDIT_INTERFACE[1]: - return "Edit interface"; - case SidePanelViews.CREATE_ZONE[1]: - return "Add AZ"; - case SidePanelViews.EDIT_DISK[1]: - return "Edit disk"; - case SidePanelViews.EDIT_PARTITION[1]: - return "Edit partition"; - case SidePanelViews.EDIT_PHYSICAL[1]: - return "Edit physical"; - case SidePanelViews.DELETE_IMAGE[1]: - return "Delete image"; - case SidePanelViews.DELETE_SPACE[1]: - return "Delete space"; - case SidePanelViews.DELETE_FABRIC[1]: - return "Delete fabric"; - case SidePanelViews.MARK_CONNECTED[1]: - return "Mark as connected"; - case SidePanelViews.MARK_DISCONNECTED[1]: - return "Mark as disconnected"; - case SidePanelViews.REMOVE_INTERFACE[1]: - return "Remove interface"; - case SidePanelViews.REMOVE_PARTITION[1]: - return "Remove partition"; - case SidePanelViews.REMOVE_PHYSICAL[1]: - return "Remove physical"; - case SidePanelViews.SET_BOOT_DISK[1]: - return "Set boot disk"; - case SidePanelViews.SET_DEFAULT[1]: - return "Set default"; - case SidePanelViews.UNMOUNT_FILESYSTEM[1]: - return "Unmount filesystem"; - case SidePanelViews.UPDATE_DATASTORE[1]: - return "Update datastore"; - case SidePanelViews.UpdateTag[1]: - return "Update Tag"; - default: - return name ? getNodeActionTitle(name as NodeActions) : defaultTitle; - } + return ( + sidePanelTitleMap[name] || + getNodeActionTitle(name as NodeActions) || + defaultTitle + ); } return defaultTitle; }; diff --git a/yarn.lock b/yarn.lock index 6f60c06091..09fd06988b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2347,9 +2347,9 @@ integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== "@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@isaacs/cliui@^8.0.2": version "8.0.2" @@ -7437,6 +7437,13 @@ eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: dependencies: debug "^3.2.7" +eslint-plugin-complexity@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-complexity/-/eslint-plugin-complexity-1.0.2.tgz#32772ed363989a9032f8336b3c856c57989f5dd8" + integrity sha512-6SwGZ2Kz3pNBfKDpT38bh6XTsrPCkPVgYYsXhtWVa88IrlQ8HnHbvfKqjL826jYEU0AQiiljNRJ5BQNJe45qNw== + dependencies: + eslint-utils "^3.0.0" + eslint-plugin-cypress@2.15.2: version "2.15.2" resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.2.tgz#f22e12fad4c434edad7b298ef92bac8fa087ffa0" @@ -7596,7 +7603,14 @@ eslint-scope@^7.2.2: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^2.1.0: +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== @@ -8449,14 +8463,7 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.19.0: - version "13.23.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02" - integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA== - dependencies: - type-fest "^0.20.2" - -globals@^13.20.0, globals@^13.23.0: +globals@^13.19.0, globals@^13.20.0, globals@^13.23.0: version "13.24.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== @@ -12233,7 +12240,8 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.2.3: + name string-width-cjs version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -12251,15 +12259,6 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -12325,7 +12324,8 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.1: + name strip-ansi-cjs version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -12339,13 +12339,6 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" -strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" @@ -13531,7 +13524,8 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + name wrap-ansi-cjs version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -13549,15 +13543,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"