From a2b4f7bfd35ba060b6e38381793dfd23c69cf7fb Mon Sep 17 00:00:00 2001 From: Nkeiruka Date: Thu, 30 Jan 2025 02:47:08 +0000 Subject: [PATCH] feat: [WD-18674] CMS Fields - ZFS.Poolname Signed-off-by: Nkeiruka --- src/api/storage-pools.tsx | 5 +++ src/components/forms/ClusterSpecificInput.tsx | 19 ++++++--- src/pages/storage/CreateStoragePool.tsx | 1 + .../forms/ClusteredZfsNameSelector.tsx | 42 +++++++++++++++++++ src/pages/storage/forms/StoragePoolForm.tsx | 1 + .../storage/forms/StoragePoolFormMain.tsx | 9 ++-- .../storage/forms/StoragePoolFormZFS.tsx | 23 +++++++++- src/sass/_cluster_specific_input.scss | 8 +++- src/util/storagePoolForm.tsx | 12 ++++-- 9 files changed, 104 insertions(+), 16 deletions(-) create mode 100644 src/pages/storage/forms/ClusteredZfsNameSelector.tsx diff --git a/src/api/storage-pools.tsx b/src/api/storage-pools.tsx index 17a962811f..21c45998d0 100644 --- a/src/api/storage-pools.tsx +++ b/src/api/storage-pools.tsx @@ -101,6 +101,7 @@ export const createClusteredPool = ( pool: LxdStoragePool, clusterMembers: LxdClusterMember[], sourcePerClusterMember?: ClusterSpecificValues, + zfsPoolNamePerClusterMember?: ClusterSpecificValues, ): Promise => { const { memberPoolPayload, clusterPoolPayload } = getClusterAndMemberPoolPayload(pool); @@ -112,6 +113,10 @@ export const createClusteredPool = ( config: { ...memberPoolPayload.config, source: sourcePerClusterMember?.[item.server_name], + + ...(zfsPoolNamePerClusterMember?.[item.server_name] && { + "zfs.pool_name": zfsPoolNamePerClusterMember[item.server_name], + }), }, }; return createPool(clusteredMemberPool, item.server_name); diff --git a/src/components/forms/ClusterSpecificInput.tsx b/src/components/forms/ClusterSpecificInput.tsx index e2201ba4bb..adbe715ee5 100644 --- a/src/components/forms/ClusterSpecificInput.tsx +++ b/src/components/forms/ClusterSpecificInput.tsx @@ -8,7 +8,7 @@ interface Props { id: string; isReadOnly: boolean; onChange: (value: ClusterSpecificValues) => void; - toggleReadOnly: () => void; + toggleReadOnly?: () => void; memberNames: string[]; values?: ClusterSpecificValues; canToggleSpecific?: boolean; @@ -16,6 +16,8 @@ interface Props { clusterMemberLinkTarget?: (member: string) => string; disabled?: boolean; helpText?: string; + placeholder?: string; + classname?: string; } const ClusterSpecificInput: FC = ({ @@ -24,12 +26,14 @@ const ClusterSpecificInput: FC = ({ isReadOnly, memberNames, onChange, - toggleReadOnly, + toggleReadOnly = () => {}, canToggleSpecific = true, isDefaultSpecific = null, clusterMemberLinkTarget = () => "/ui/cluster", disabled = false, helpText, + placeholder, + classname = "u-sv3", }) => { const [isSpecific, setIsSpecific] = useState( isDefaultSpecific, @@ -61,12 +65,13 @@ const ClusterSpecificInput: FC = ({ }; return ( -
+
{canToggleSpecific && !isReadOnly && ( { setIsSpecific((val) => !val); }} @@ -90,7 +95,9 @@ const ClusterSpecificInput: FC = ({ {isReadOnly ? ( <> {activeValue} - + {!disabled && ( + + )} ) : ( = ({ value={activeValue} onChange={(e) => setValueForMember(e.target.value, item)} disabled={disabled} + placeholder={placeholder} /> )}
@@ -120,7 +128,7 @@ const ClusterSpecificInput: FC = ({ {isReadOnly ? ( <> {firstValue} - + {!disabled && } ) : ( = ({ onChange={(e) => setValueForAllMembers(e.target.value)} disabled={disabled} help={helpText} + placeholder={placeholder} /> )}
diff --git a/src/pages/storage/CreateStoragePool.tsx b/src/pages/storage/CreateStoragePool.tsx index 4fe3e6ea4b..64aa3056ac 100644 --- a/src/pages/storage/CreateStoragePool.tsx +++ b/src/pages/storage/CreateStoragePool.tsx @@ -71,6 +71,7 @@ const CreateStoragePool: FC = () => { storagePool, clusterMembers, values.sourcePerClusterMember, + values.zfsPoolNamePerClusterMember, ) : () => createPool(storagePool); diff --git a/src/pages/storage/forms/ClusteredZfsNameSelector.tsx b/src/pages/storage/forms/ClusteredZfsNameSelector.tsx new file mode 100644 index 0000000000..82fd82cc75 --- /dev/null +++ b/src/pages/storage/forms/ClusteredZfsNameSelector.tsx @@ -0,0 +1,42 @@ +import ClusterSpecificInput from "components/forms/ClusterSpecificInput"; +import { FormikProps } from "formik"; +import { FC } from "react"; +import { StoragePoolFormValues } from "./StoragePoolForm"; +import { useClusterMembers } from "context/useClusterMembers"; +import { ensureEditMode } from "util/instanceEdit"; + +interface Props { + formik: FormikProps; + helpText?: string; + disabled?: boolean; + placeholder?: string; +} + +const ClusteredZfsNameSelector: FC = ({ + formik, + helpText, + disabled = !formik.values.isCreating, + placeholder, +}) => { + const { data: clusterMembers = [] } = useClusterMembers(); + const memberNames = clusterMembers.map((member) => member.server_name); + + return ( + { + void formik.setFieldValue("zfsPoolNamePerClusterMember", value); + }} + canToggleSpecific={formik.values.isCreating} + memberNames={memberNames} + disabled={disabled} + helpText={helpText} + placeholder={placeholder} + classname="" + /> + ); +}; + +export default ClusteredZfsNameSelector; diff --git a/src/pages/storage/forms/StoragePoolForm.tsx b/src/pages/storage/forms/StoragePoolForm.tsx index e02ba37fea..a98bf58c56 100644 --- a/src/pages/storage/forms/StoragePoolForm.tsx +++ b/src/pages/storage/forms/StoragePoolForm.tsx @@ -82,6 +82,7 @@ export interface StoragePoolFormValues { zfs_clone_copy?: string; zfs_export?: string; zfs_pool_name?: string; + zfsPoolNamePerClusterMember?: ClusterSpecificValues; } interface Props { diff --git a/src/pages/storage/forms/StoragePoolFormMain.tsx b/src/pages/storage/forms/StoragePoolFormMain.tsx index 87a8014b5f..d11d9c2af8 100644 --- a/src/pages/storage/forms/StoragePoolFormMain.tsx +++ b/src/pages/storage/forms/StoragePoolFormMain.tsx @@ -54,6 +54,9 @@ const StoragePoolFormMain: FC = ({ formik }) => { const sourceHelpText = formik.values.isCreating ? getSourceHelpForDriver(formik.values.driver) : "Source can't be changed"; + const nameHelpText = !formik.values.isCreating + ? "Cannot rename storage pools" + : undefined; return ( @@ -65,11 +68,7 @@ const StoragePoolFormMain: FC = ({ formik }) => { label="Name" required disabled={!formik.values.isCreating} - help={ - !formik.values.isCreating - ? "Cannot rename storage pools" - : undefined - } + help={nameHelpText} /> ; } const StoragePoolFormZFS: FC = ({ formik }) => { + const { data: settings } = useSettings(); + return ( = ({ formik }) => { label: "ZFS pool name", name: "zfs_pool_name", defaultValue: "", - children: , + children: isClusteredServer(settings) ? ( + + ) : ( + + ), + readOnlyRenderer: (value) => + isClusteredServer(settings) && value !== "-" ? ( + + ) : ( + <>{value} + ), disabled: !formik.values.isCreating || formik.values.readOnly, disabledReason: "ZFS pool name cannot be modified", }), diff --git a/src/sass/_cluster_specific_input.scss b/src/sass/_cluster_specific_input.scss index e7cd9d2c78..db6a8a7be5 100644 --- a/src/sass/_cluster_specific_input.scss +++ b/src/sass/_cluster_specific_input.scss @@ -2,7 +2,7 @@ align-items: center; display: grid; gap: $sp-medium; - grid-template-columns: fit-content(20%) 1fr; + grid-template-columns: fit-content(50%) 1fr; padding-bottom: $spv--large; .cluster-specific-member { @@ -13,3 +13,9 @@ grid-column-start: 2; } } + +.configuration-table { + .cluster-specific-toggle-label { + margin-bottom: $spv--small !important; + } +} diff --git a/src/util/storagePoolForm.tsx b/src/util/storagePoolForm.tsx index 72e9a6ed5d..67343f9833 100644 --- a/src/util/storagePoolForm.tsx +++ b/src/util/storagePoolForm.tsx @@ -10,10 +10,13 @@ export const toStoragePoolFormValues = ( poolOnMembers?: LXDStoragePoolOnClusterMember[], ): StoragePoolFormValues => { const sourcePerClusterMember: ClusterSpecificValues = {}; - poolOnMembers?.forEach( - (item) => - (sourcePerClusterMember[item.memberName] = item.config?.source ?? ""), - ); + const zfsPoolNamePerClusterMember: ClusterSpecificValues = {}; + + poolOnMembers?.forEach((item) => { + sourcePerClusterMember[item.memberName] = item.config?.source ?? ""; + zfsPoolNamePerClusterMember[item.memberName] = + item.config?.["zfs.pool_name"] ?? ""; + }); return { readOnly: true, @@ -53,6 +56,7 @@ export const toStoragePoolFormValues = ( zfs_pool_name: pool.config?.["zfs.pool_name"], sourcePerClusterMember, barePool: pool, + zfsPoolNamePerClusterMember, }; };