-
Notifications
You must be signed in to change notification settings - Fork 45
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
[UI] Volume Batch Creation #2981
Conversation
Hello chengyanjin,My role is to assist you with the merge of this Status report is not available. |
Waiting for approvalThe following approvals are needed before I can proceed with the merge:
Peer approvals must include at least 1 approval from the following list: |
45a0312
to
ec378cf
Compare
ui/src/services/utils.js
Outdated
export const linuxDrivesNamingIncrement = (string, increment) => { | ||
if (string.match(/^\/dev\/vd[a-z]/)) { | ||
while (increment--) { | ||
var lastChar = string.slice(-1); |
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'm not yet sure about your styleguide conventions but I would always prefer usage of let or const for variable definitions, using const here will reflect clearly that this variable doesn't change elsewhere and will slightly simplify reading this code
ui/src/services/utils.js
Outdated
* | ||
* const nextDevicePath = linuxDrivesNamingIncrement(string) | ||
*/ | ||
export const linuxDrivesNamingIncrement = (string, increment) => { |
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 rename string
to something more explicit such as drivePath
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.
Additionally for utils function like this one it seems important for me to add a unit test that covers the edge cases you want to support, but not sure if it is your traditional way of working so we can discuss about it.
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.
Indeed, it's a very bad name. I will rename it to devicePath
.
ui/src/services/utils.js
Outdated
* @example | ||
* const string = '/dev/vda' | ||
* | ||
* const nextDevicePath = linuxDrivesNamingIncrement(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.
This example lack increment parameter
ui/src/services/utils.js
Outdated
@@ -419,3 +419,45 @@ export const useDynamicChartSize = (container_id) => { | |||
|
|||
return [graphWidth, window.innerHeight / 6 - 30]; | |||
}; | |||
|
|||
/** | |||
* This function increments the string by 1 |
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 description doesn't seems to be accurate
ui/src/containers/CreateVolume.js
Outdated
const RecommendNameField = (props) => { | ||
const { | ||
values: { name }, | ||
touched, | ||
setFieldValue, | ||
} = useFormikContext(); | ||
const [field, meta] = useField(props); | ||
React.useEffect(() => { | ||
if (name.trim() !== '' && touched.name) { | ||
setFieldValue(props.name, `${name}${props.index + 1}`); | ||
} | ||
}, [name, touched.name, setFieldValue, props.name, props.index]); | ||
|
||
return ( | ||
<> | ||
<Input {...props} {...field} /> | ||
{!!meta.touched && !!meta.error && <div>{meta.error}</div>} | ||
</> | ||
); | ||
}; | ||
|
||
const RecommendDevicePathField = (props) => { | ||
const { | ||
values: { path }, | ||
touched, | ||
setFieldValue, | ||
} = useFormikContext(); | ||
const [field, meta] = useField(props); | ||
React.useEffect(() => { | ||
if (path.trim() !== '' && touched.path) { | ||
setFieldValue( | ||
props.name, | ||
linuxDrivesNamingIncrement(path, props.index + 1), | ||
); | ||
} | ||
}, [path, touched.path, setFieldValue, props.name, props.index]); | ||
|
||
return ( | ||
<> | ||
<Input {...props} {...field} /> | ||
{!!meta.touched && !!meta.error && <div>{meta.error}</div>} | ||
</> | ||
); | ||
}; |
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 those two components only differs in the way they setFieldValue, they might be factorized.
message: intl.translate('volume_creation_failed', { | ||
name: newVolume.name, | ||
}), | ||
title: 'Volume Form Error', |
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.
Translation seems to be missing here
ui/src/containers/CreateVolume.js
Outdated
@@ -54,6 +55,8 @@ const ActionContainer = styled.div` | |||
const CreateVolumeLayout = styled.div` | |||
display: inline-block; | |||
margin-top: ${padding.base}; | |||
overflow-y: scroll; |
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 it intended to display scrollbars by default even for non scrollable content ? You might prefer to use auto
instead
ui/src/containers/CreateVolume.js
Outdated
placement="right" | ||
overlay={ | ||
<div style={{ minWidth: '200px' }}> | ||
A devicePath or a partition mount point. |
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 think there is a missing translation here
ui/src/containers/CreateVolume.js
Outdated
createVolume(newVolume); | ||
const newVolumes = { ...values }; | ||
newVolumes.size = `${values.sizeInput}${values.selectedUnit}`; | ||
if (newVolumes.multiVolumeCreation) { |
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 if could be transferred in formatDataForBatchVolumeCreation as it already partially exists there and just missing the else branch to return a one element array
ui/src/services/NodeVolumesUtils.js
Outdated
@@ -276,3 +276,28 @@ export const getVolumeListData = createSelector( | |||
return nodeVolumes.sort((a, b) => compareHealth(b.health, a.health)); | |||
}, | |||
); | |||
|
|||
export const formatDataForBatchVolumeCreation = (newVolumes) => { |
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 add a simple unit test for the two branches of this function, also as mentioned in the usage of this function I would handle the !multiVolumeCreation
case here and return a single entry array containing newVolumes, that would allow a simpler usage of the function as its ouput will always be of the same shape (newVolumes: VolumeCreationFormState) => Volume[]
instead of (newVolumes: VolumeCreationFormState) => Volume[] | void
ConflictThere is a conflict between your branch Please resolve the conflict on the feature branch ( $ git fetch
$ git checkout origin/feature/2964-volume-batch-creation
$ git merge origin/development/2.7
$ # <intense conflict resolution>
$ git commit
$ git push origin HEAD:feature/2964-volume-batch-creation |
e497e57
to
1bc8143
Compare
We KILL breadcrumb! Refs: #2964
"overflow-y: scroll" protentially would display the scrollbar by default even for non scrollable content, which casue the issue of we have the scrollbar everywhere. Refs: #2964
Handle the single volume creation case in the utility function instead of in the createVolume component so that the return of this function is always an array. For single volume, return an array with the origin volume. For batch volume, return an array with the formatted volumes. Refs: #2964
Correct the variable declaration too Refs: #2964
1bc8143
to
ac5c3ff
Compare
Waiting for approvalThe following approvals are needed before I can proceed with the merge:
Peer approvals must include at least 1 approval from the following list: |
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.
@ChengYanJin I like the behavior.
I would change one little thing:
When you create multiple Volumes, the Device Path for each Volume is computed from the Global Device Path field. I think the first Volume should get what you input in the Global Device Path field (i.e. not increment the Device Path of the first Volume).
Also when playing with multiple Volume check box and the number of Volumes, you will observe strange behavior. Maybe some state not properly managed
I wonder if we should disable Global Name and Device Path global fields when creating multiple Volumes because if you override Name or Device Path and then you change the Global field, you will lose all your customizations (@JBWatenbergScality what do you think?)
Also for number increments, I would do 01, 02, 03 etc ... instead of 1, 2, 3 ....
Thanks and well done
Waiting for approvalThe following approvals are needed before I can proceed with the merge:
Peer approvals must include at least 1 approval from the following list:
The following reviewers are expecting changes from the author, or must review again: |
@thomasdanan @ChengYanJin From my point of view once the name or path is touched we shouldn't change automatically their values to maintain the user intentions but should still let the ability for the user to change the first volume name and path. Also the ui might be a little bit misleading as the user is unsure if the default values will actually create a volume. To be precise mentioning The simplest interaction I could think of closed enough to the current implementation would be to remove the default name and path fields when checking |
ui/src/services/utils.js
Outdated
|
||
/** | ||
* This function formats the name base on the index | ||
* @param {string} name - The name the default volume 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.
Remove redundant name The name the default volume
ui/src/services/utils.js
Outdated
* @example | ||
* const name = 'volume-test' | ||
* | ||
* const nextDevicePath = linuxDrivesNamingIncrement(name, 1) |
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 formatedName = formatBatchName(name, 1)
{intl.translate('number_volume_create')} | ||
</span> | ||
{/* TODO: Generalize the number input component to core-ui. */} | ||
<InputNumberComponentStyle |
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 think we should handle a max number of volumes to avoid dom freeze in case of the user mistakenly ask 10000 volumes, simply add a max prop here should be enough
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.
Indeed, good point!
I am going to set the max
number to70
for the moment.
1c36230
to
4c3cbe3
Compare
Hello @thomasdanan @JBWatenbergScality , According to the feedback from you and our offline discussions. I've addressed the following issues.
Fix the bug of the Device path, the first volume should be the same as the Global field.
Fix the bug, will add interaction test of the form in the following PR.
In order to keep the user customization, edit the global value(name/path) should not affect the defaults pre-fill of the touched field.
Done.
Please let me know if you see any improvements/ bugs to be done. |
4c3cbe3
to
6622ce5
Compare
Set the max number of the input volume creation to 70, since it frozes the UI when rendering the form. We may even want to lower the max number depents on the use case. Refs: #2964
ui/src/containers/CreateVolume.js
Outdated
if ( | ||
touched && | ||
touched.volumes && | ||
touched?.volumes[i]?.name === true | ||
) { | ||
continue; | ||
} else { | ||
setFieldValue(`volumes[${i}]name`, ''); | ||
} | ||
if ( | ||
touched && | ||
touched.volumes && | ||
touched?.volumes[i]?.path === true | ||
) { | ||
continue; | ||
} else { | ||
setFieldValue(`volumes[${i}]path`, ''); | ||
} |
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 think this can be simplified to :
if (!touched?.volumes[i]?.name) {
setFieldValue(`volumes[${i}]name`, '');
}
if (!touched?.volumes[i]?.path) {
setFieldValue(`volumes[${i}]path`, '');
}
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.
Hi @JBWatenbergScality ,
Yes. Good point. But I guess we need to use optional chaining to make sure the Volumes array exists.
Please see:
if (!touched?.volumes?.[i]?.name) {
setFieldValue(`volumes[${i}]name`, '');
}
if (!touched?.volumes?.[i]?.path) {
setFieldValue(`volumes[${i}]path`, '');
}
6622ce5
to
5d584ae
Compare
In order to keep the user customization, edit the global value (name/path) should not affect the defaults pre-fill of the touched field. Unless the users uncheck the box of multi-volume creation and re-check again, we only update the untouched field with the new global value. Refs: #2964
/approve |
Waiting for approvalThe following approvals are needed before I can proceed with the merge:
Peer approvals must include at least 1 approval from the following list:
The following reviewers are expecting changes from the author, or must review again: The following options are set: approve |
Addressed the issues and improvements.
In the queueThe changeset has received all authorizations and has been added to the The changeset will be merged in:
The following branches will NOT be impacted:
There is no action required on your side. You will be notified here once IMPORTANT Please do not attempt to modify this pull request.
If you need this pull request to be removed from the queue, please contact a The following options are set: approve |
I have successfully merged the changeset of this pull request
The following branches have NOT changed:
Please check the status of the associated issue None. Goodbye chengyanjin. |
Component: ui, volumes
Context:
We want to be able to batch create volume from UI.
Summary:
Note that:
For
RawBlockDevice
, the recommended path only happens with'/dev/vda'
, we will see later ifFor
SparseLoopDevice
, the size of the batch volume are the same as the default one.Acceptance criteria:
The Default Volume Creation Form
Volume type
RawBlockDevice
batch creationVolume type
SparseLoopDevice
batch creation. (From big HD screen)Closes: #2964