New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds Local Volume Set Creation Form and enables LSO Plugin #5014
Adds Local Volume Set Creation Form and enables LSO Plugin #5014
Conversation
@afreen23 Can you please attach the screenshots too |
019839b
to
50115c9
Compare
const volumeTypeOptions = Object.freeze({ | ||
'SSD/NVMe': 'SSD/NVMe', | ||
HDD: 'HDD', | ||
}); | ||
const volumeModeOptions = Object.freeze({ | ||
Block: 'Block', | ||
Filesystem: 'Filesystem', | ||
}); | ||
const volumeSizeUnitOptions = Object.freeze({ | ||
TiB: 'TiB', | ||
GiB: 'GiB', | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer enums.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to keep the plain objects for future fields
GiB: 'GiB', | ||
}); | ||
|
||
const CreateLocalVolumeSet: React.FC = withHandlePromise((props: CreateLocalVolumeSetProps) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const CreateLocalVolumeSet: React.FC = withHandlePromise((props: CreateLocalVolumeSetProps) => { | |
const CreateLocalVolumeSet: React.FC = withHandlePromise<CreateLocalVolumeSetProps>((props) => { |
.catch((e) => { | ||
// eslint-disable-next-line no-console | ||
console.error(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pointless if you're already showing the error in the ActionBar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I think just catch(() -> null) here would be suffice for linter
]} | ||
/> | ||
</div> | ||
<h1 className="co-create-operand__header-text">{`Create ${modelName}`}</h1> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isRequired | ||
/> | ||
</FormGroup> | ||
<FormGroup label="Storage Class Name" fieldId="create-lvs--storage-class-name"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this not a required field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as per uxd
<Radio | ||
label="All nodes" | ||
name="nodes-selection" | ||
id="create-lvs--radio-all-nodes" | ||
className="lso-create-lvs__all-nodes-radio--padding" | ||
value="allNodes" | ||
onChange={toggleShowNodesList} | ||
description="Selecting all nodes will search for available volume storage on all nodes." | ||
defaultChecked | ||
/> | ||
<Radio | ||
label="Select nodes" | ||
name="nodes-selection" | ||
id="create-lvs--radio-select-nodes" | ||
value="selectedNodes" | ||
onChange={toggleShowNodesList} | ||
description="Selecting nodes allow you to limit the search for available volumes to specific nodes." | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are radio groups. Only one of them will be selected at a time.
The value is not significant here.
showNodesList
state takes care of toggling
const nodeLocation = node.metadata.labels?.['failure-domain.beta.kubernetes.io/zone'] ?? '-'; | ||
const nodeCpuCapacity = getNodeCPUCapacity(node); | ||
const nodeAllocatableMemory = getNodeAllocatableMemory(node); | ||
const nodeTaints = node?.spec?.taints?.length ?? 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const nodeTaints = node?.spec?.taints?.length ?? 0; | |
const nodeTaints = node.spec?.taints?.length ?? 0; |
}; | ||
|
||
type SetTableRows = (props: { | ||
componentProps: { data: NodeKind[]; filters: { name: string } }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
componentProps: { data: NodeKind[]; filters: { name: string } }; | |
componentProps: { data: NodeKind[]; filters: { name: string, labels: { all: string[] } } }; |
apiVersion: string; | ||
kind: string; | ||
metadata: { name: string }; | ||
spec: { | ||
nodeSelector?: { | ||
nodeSelectorTerms: [ | ||
{ | ||
matchExpressions: [{ key: string; operator: string; values: string[] }]; | ||
}, | ||
]; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
K8sResourceCommon might handle a few of these fields.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure 👍
title: 'CPU', | ||
props: { className: tableColumnClasses[1] }, | ||
}, | ||
{ | ||
title: 'Memory', | ||
props: { className: tableColumnClasses[2] }, | ||
}, | ||
{ | ||
title: 'Location', | ||
props: { className: tableColumnClasses[3] }, | ||
}, | ||
{ | ||
title: 'Taints', | ||
props: { className: tableColumnClasses[3] }, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add sorts for all these fields as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It as per UXD
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yuvalgalanti why are we only allowing users to sort on the basis of Name? IMO we should sort on CPU and Memory too.
]; | ||
rowUIDMap[uid] = { | ||
cells, | ||
selected: !!rows?.[uid]?.selected, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
selected: !!rows?.[uid]?.selected, | |
selected: rows?.[uid]?.selected, |
<Radio | ||
label="All nodes" | ||
name="nodes-selection" | ||
id="create-lvs--radio-all-nodes" | ||
className="lso-create-lvs__all-nodes-radio--padding" | ||
value="allNodes" | ||
onChange={toggleShowNodesList} | ||
description="Selecting all nodes will search for available volume storage on all nodes." | ||
defaultChecked | ||
/> | ||
<Radio | ||
label="Select nodes" | ||
name="nodes-selection" | ||
id="create-lvs--radio-select-nodes" | ||
value="selectedNodes" | ||
onChange={toggleShowNodesList} | ||
description="Selecting nodes allow you to limit the search for available volumes to specific nodes." | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are radio groups. Only one of them will be selected at a time.
The value is not significant here.
showNodesList
state takes care of toggling
39c2e2f
to
f8bd0d2
Compare
.then((resource) => { | ||
history.push(resourceObjPath(resource, referenceFor(resource))); | ||
}) | ||
.catch(() => null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.catch(() => null); |
No need for the catch statement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is enforced by linter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not. handlePromise
handles the catch part for you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surely handlePromise
sets state and error message on catching error but it also returns a promise. Linters are dumb they dont know that, hence I need to put a dummy catch.
This will not break anything in our case because we have error handled in state.
handlePromise: <T>(promise: Promise<T>) => Promise<T>; |
<ListPage | ||
customData={{ rows, setRows, allSelected, setAllSelected }} | ||
showTitle={false} | ||
kind="Node" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kind="Node" | |
kind={NodeKind.kind} |
<Button data-test-id="create-lvs-form-create-button" type="submit" variant="primary"> | ||
Create | ||
</Button> | ||
<Button | ||
data-test-id="create-lvs-form-cancel-button" | ||
type="button" | ||
variant="secondary" | ||
onClick={onCancel} | ||
> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Button's really don't need data-test-id since we have a common class for Primary
used throughout the console.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added as per your suggestion on chat, will remove again.
setAllSelected: React.Dispatch<React.SetStateAction<boolean>>; | ||
setRows: React.Dispatch<React.SetStateAction<RowUIDMap>>; | ||
}; | ||
filters: { name: string }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filters: { name: string }; |
You are not using it here. The type is incomplete.
storageClassName: string; | ||
volumeMode: string; | ||
deviceInclusionSpec: { | ||
deviceTypes: ('RawDisk' | 'Partition')[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deviceTypes: ('RawDisk' | 'Partition')[]; | |
deviceTypes: ('RawDisk' | 'Partition')[]; |
Please use enum instead of String Literals it's easier to use and understand.
volumeMode: string; | ||
deviceInclusionSpec: { | ||
deviceTypes: ('RawDisk' | 'Partition')[]; | ||
deviceMechanicalProperty: ('Rotational' | 'Non Rotational')[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
volumeMode, | ||
deviceInclusionSpec: { | ||
// Only Raw disk supported for 4.5 | ||
deviceTypes: ['RawDisk'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this magic string RawDisk
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is hard coded intentionally. The support is for RawDisk
only.
Hence, the request data just needs that. No other values are applicable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer it if it came via an enum.
const [volumeType, setVolumeType] = React.useState('SSD'); | ||
const [volumeMode, setVolumeMode] = React.useState('Block'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using enums for these values.
SSD: { | ||
title: 'SSD / NVMe', | ||
property: 'Non Rotational', | ||
}, | ||
HDD: { | ||
title: 'HDD', | ||
property: 'Rotational', | ||
}, | ||
}; | ||
|
||
const VOLUME_MODE = { | ||
Block: { | ||
title: 'Block', | ||
}, | ||
Filesystem: { | ||
title: 'Filesystem', | ||
}, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SSD: { | |
title: 'SSD / NVMe', | |
property: 'Non Rotational', | |
}, | |
HDD: { | |
title: 'HDD', | |
property: 'Rotational', | |
}, | |
}; | |
const VOLUME_MODE = { | |
Block: { | |
title: 'Block', | |
}, | |
Filesystem: { | |
title: 'Filesystem', | |
}, | |
}; | |
enum VolumeType { | |
SSD = 'SSD', | |
HDD = 'HDD' | |
} | |
[VolumeType.SSD]: { | |
title: 'SSD / NVMe', | |
property: 'Non Rotational', | |
}, | |
[VolumeType.HDD]: { | |
title: 'HDD', | |
property: 'Rotational', | |
}, | |
}; | |
enum VolumeMode { | |
BLOCK = 'Block', | |
FS = 'FileSystem' | |
}; | |
const VOLUME_MODE = { | |
[VolumeMode.Block]: { | |
title: 'Block', | |
}, | |
[VolumeMode.FS]: { | |
title: 'Filesystem', | |
}, | |
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surely, I can consider but a bit different .
Thanks!
f8bd0d2
to
da9f1ae
Compare
handlePromise(k8sCreate(LocalVolumeSetModel, requestData)) | ||
.then((resource) => history.push(resourceObjPath(resource, referenceFor(resource)))) | ||
.catch(() => null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handlePromise(k8sCreate(LocalVolumeSetModel, requestData)) | |
.then((resource) => history.push(resourceObjPath(resource, referenceFor(resource)))) | |
.catch(() => null); | |
return handlePromise(k8sCreate(LocalVolumeSetModel, requestData)) | |
.then((resource) => history.push(resourceObjPath(resource, referenceFor(resource)))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or just disable the rule that enforces you to do so.
const [volumeMode, setVolumeMode] = React.useState(volumeModeDropdownItems.Block); | ||
const [maxVolumeLimit, setMaxVolumeLimit] = React.useState(''); | ||
const [rows, setRows] = React.useState<RowUIDMap>({}); | ||
const [allSelected, setAllSelected] = React.useState(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const [allSelected, setAllSelected] = React.useState(null); | |
const [allSelected, setAllSelected] = React.useState<boolean>(null); |
@@ -366,6 +366,13 @@ export type TableProps = { | |||
Row?: RowFunction; | |||
Rows?: (...args) => any[]; | |||
'aria-label': string; | |||
onSelect?: ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use OnSelect
already defined in @patternfly/react-table
onSelect?: ( | |
onSelect?: OnSelect |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure , I forgot to replace it here.
Thanks!
/approve |
onChange={setVolumeType} | ||
/> | ||
</FormGroup> | ||
<Expandable toggleText="Advanced"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put a data-test-id on the toggler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
type={TextInputTypes.text} | ||
id="create-lvs--storage-class-name" | ||
value={storageClassName} | ||
onChange={setStorageClassName} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would show some errors in the console. onChange
send two params whereas setStorageClass
only accepts one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure 👍
- Local Volume Set is the new CR to be introduced in Local Stoarge Operator. - Local Volume Set will allow to filter a set of storage volumes, group them and create a dedicated storage class to consume storage for them.
da9f1ae
to
0c2991b
Compare
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: afreen23, bipuladh, rawagner The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Designs: https://marvelapp.com/8752a03/screen/67632184