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
Re-enable Snapshots tab #6807
Re-enable Snapshots tab #6807
Conversation
@@ -41,6 +49,8 @@ export const breadcrumbsForVMPage = (match: any) => () => [ | |||
|
|||
export const VirtualMachinesDetailsPage: React.FC<VirtualMachinesDetailsPageProps> = (props) => { | |||
const { name, ns: namespace } = props.match.params; | |||
const [snapData, snapLoaded, snapErr] = useK8sGet(VirtualMachineSnapshotModel); | |||
const isSnapshotSupported = snapData && snapLoaded && !snapErr; |
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.
can you please look at the original description of this bug https://bugzilla.redhat.com/show_bug.cgi?id=1881125 ? And fix the loading when reintroducing the snapshots again?
072377c
to
8b7e188
Compare
@suomiy we now look for snapshots only in the relevant namespace. Is this solution sufficient? |
@glekner we should check if the CRD is present |
import { VMEnvironmentFirehose } from './vm-environment/vm-environment-page'; | ||
import { VMNics } from '../vm-nics'; | ||
import { PendingChangesWarningFirehose } from './pending-changes-warning'; | ||
import { VMSnapshotsPage } from '../vm-snapshots/vm-snapshots'; | ||
import { |
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.
nitpick: This should be above the kubevirt package imports. Of course, we can catch it in a follow-up if you don't have any other changes to make.
8b7e188
to
cfa1281
Compare
cfa1281
to
393ba0b
Compare
393ba0b
to
d7c82fb
Compare
@@ -41,6 +49,7 @@ export const breadcrumbsForVMPage = (match: any) => () => [ | |||
|
|||
export const VirtualMachinesDetailsPage: React.FC<VirtualMachinesDetailsPageProps> = (props) => { | |||
const { name, ns: namespace } = props.match.params; | |||
const isSnapshotsAvailable = useModelLoaded(VirtualMachineSnapshotModel.kind); |
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.
shouldn't referenceForModel
be used here?
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.
depends on the use case, some would use referenceForModel(model)
but in our case the resource in store is called VMSnapshotModel
so we need VMSnapshotModel.kind
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 might get loaded only with the group+version to the store so we should use referenceForModel
to be safe
@@ -95,6 +102,7 @@ export const VirtualMachinesDetailsPage: React.FC<VirtualMachinesDetailsPageProp | |||
consolePage, | |||
nicsPage, | |||
disksPage, | |||
...(isSnapshotsAvailable ? [snapshotsPage] : []), |
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.
are we expecting more pages? IMO simple if would be more readable.
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 a one line and it is a convention.
check https://github.com/openshift/console/blob/master/frontend/webpack.config.ts#L192 for example
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 wouldn't cite webpack.config.ts as a convention. I know there are both use cases in the code base.
This one is less elegant.
Do as you want - I can live with both.
@@ -61,6 +61,9 @@ const useModelsLoaded = (): boolean => { | |||
return ref.current; | |||
}; | |||
|
|||
export const useModelLoaded = (model: string): boolean => | |||
!!useSelector<RootState, K8sKind>(({ k8s }) => k8s.getIn(['RESOURCES', 'models', model])); |
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.
we could check for empty model
first
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.
react hooks shouldn't be called conditionally. eslint will shout at 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.
yes, unless the condition is inside
@@ -61,6 +61,9 @@ const useModelsLoaded = (): boolean => { | |||
return ref.current; | |||
}; | |||
|
|||
export const useModelLoaded = (model: string): boolean => |
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.
+1 hook might be useful
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.
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.
yeah that sound much better
d7c82fb
to
7671197
Compare
@@ -91,7 +98,22 @@ export const VMSnapshotsPage: React.FC<VMLikeEntityTabProps> = ({ obj: vmLikeEnt | |||
[namespace], | |||
); | |||
|
|||
const [snapshots, snapshotsLoaded, snapshotsError] = useK8sWatchResource<VMSnapshot[]>(resource); | |||
const restoreResource: WatchK8sResource = React.useMemo( |
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.
useK8sWatchResource doesnt require memoized resource anymore :)
@@ -66,12 +56,14 @@ const getActions = ( | |||
return []; | |||
} | |||
|
|||
const actions = [menuActionRestore, menuActionDelete]; | |||
const actions = [menuActionDelete]; |
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 about the snapshot detail later?
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.
snapshot detail?
the restore is now a dedicated button for each row, not a kebab option
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.
are we planning to have also snapshot details?
@@ -4,6 +4,8 @@ import { Kebab } from '@console/internal/components/utils'; | |||
export const snapshotsTableColumnClasses = [ |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
4be4c72
to
94050a7
Compare
@@ -64,6 +64,13 @@ export const VMSnapshotsTable: React.FC<VMSnapshotsTableProps> = ({ | |||
sortField: 'status.readyToUse', | |||
transforms: [sortable], | |||
}, | |||
{ | |||
title: 'Last restored', |
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.
@suomiy
since the latest restore date is computed inside the row component (because one snapshot can have multiple restore objects) we can't sort the table by it. do you have any suggestions?
https://github.com/openshift/console/pull/6807/files#diff-d4bb250ed498bbf43eeee21385193b71R146
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.
@glekner you can use sortFunc prop
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.
done, hope it won't cause performance issues
https://github.com/openshift/console/pull/6807/files#diff-b2d4cf524cc534d555f71cccff72c6ecR172
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 am not a big fan of expecting that the core code should handle our CRDs. Wouldn't it be more straightforward to just resolve the time here and pass it as a data like we do in our other tables?
3c6c405
to
53faa72
Compare
Updated to match latest design can you review @suomiy @matthewcarleton @yfrimanm |
53faa72
to
c3b95a0
Compare
Thanks @glekner |
@@ -66,12 +56,14 @@ const getActions = ( | |||
return []; | |||
} | |||
|
|||
const actions = [menuActionRestore, menuActionDelete]; | |||
const actions = [menuActionDelete]; |
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.
are we planning to have also snapshot details?
const snapshotReady = isVMSnapshotReady(snapshot); | ||
|
||
if (snapshotError) { | ||
return <ErrorStatus title={'Create Failed'}>{snapshotError?.message}</ErrorStatus>; |
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.
can we also visit a snapshot detail when error occurs? like we can do with restore detail?
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.
user can access the snapshot details by clicking on its name in the table
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.
In that case, we are missing the restore action in the detail
@@ -6,4 +7,6 @@ export type VMSnapshotRowCustomData = { | |||
vmLikeEntity: VMLikeEntityKind; | |||
columnClasses: string[]; | |||
isDisabled: boolean; | |||
restores: VMRestore[]; | |||
withProgress: (promise: Promise<any>) => void; |
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.
why do we need withProgress in snapshots?
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.
why not? its a resource creation like any other modal?
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.
because this feature is used only by the wizard
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.
ah you are right, It is used by the detail pages as well
@@ -64,6 +64,13 @@ export const VMSnapshotsTable: React.FC<VMSnapshotsTableProps> = ({ | |||
sortField: 'status.readyToUse', | |||
transforms: [sortable], | |||
}, | |||
{ | |||
title: 'Last restored', |
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 am not a big fan of expecting that the core code should handle our CRDs. Wouldn't it be more straightforward to just resolve the time here and pass it as a data like we do in our other tables?
const [restores, restoresLoaded, restoresError] = useK8sWatchResource<VMRestore[]>( | ||
restoreResource, | ||
); | ||
const sortedRestores = React.useMemo( |
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 might be easier to create a map with getVmRestoreSnapshotName
key here for better consumption.
Then it wouldn't need to be even sorted as you could just save the relevant restore.
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.
which snapshotName? one vm can have multiple snapshots with different names? a row for each.
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.
yes, but relevant restore shoul be only one , right?
9d33c17
to
2e359cc
Compare
@suomiy can you review? |
|
||
const mappedRelevantRestores = React.useMemo( | ||
() => | ||
restores.reduce((restoreMap, currentRestore) => { |
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 be simpler
restores.reduce((restoreMap, currentRestore) => {
const relevantRestore = restoreMap[getVmRestoreSnapshotName(currentRestore)];
if (!relevantRestore || new Date(getVmRestoreTime(relevantRestore)).getTime() < new Date(getVmRestoreTime(currentRestore)).getTime()) {
restoreMap[getVmRestoreSnapshotName(currentRestore)] = currentRestore
}
return restoreMap
}, {}),
I was under an impression that it would make more sense to show snapshots as one logical resources (ie as an aggregation of resources like vm/vmi does). |
3cda155
to
67b9267
Compare
@suomiy @matthewcarleton @yfrimanm can you take a look |
67b9267
to
b17f80b
Compare
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.
@glekner we probably should ask for delete confirmation of snapshots when we delete the VM. The same we do with disks. To prevent stale snapshots being stored in the system.
Thoughts?
Also not sure if we want an owner reference on them.
<div className="row"> | ||
<div className="col-sm-6"> | ||
<ResourceSummary resource={obj} showAnnotations={false}> | ||
{obj?.metadata?.annotations?.description && ( |
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 the convention is to show NA when the data is not there
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.
also it might be useful to make it editable
return [ | ||
{ | ||
name: 'Virtualization', | ||
path: `/k8s/ns/${namespace || 'default'}/virtualization`, |
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.
let's make a variable vmNamespace for this
isDisabled: !isVMSnapshotReady(snapshot), | ||
callback: () => snapshotRestoreModal({ snapshot }), | ||
}), | ||
...common, |
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.
there is a discrepancy in the names Snapshot vs Virtual Machine Snapshot
snapshot, | ||
}).result, | ||
), | ||
}); | ||
|
||
const menuActionDelete = ( |
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.
could we have all the actions in the same place? eg menu-actions file? And use a subset of them in places where we need them.
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.
We don't need any of it actually, the only kebab option as of now is Delete.so now just using
const { Delete } = Kebab.factory
) : ( | ||
<Status status={readyToUse ? 'Ready' : 'Not Ready'} /> | ||
); | ||
export const VMSnapshotStatus: React.FC<VMSnapshotStatusProps> = ({ snapshot, restore }) => { |
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.
can you please move the status to standalone file?
|
||
const [restores, restoresLoaded] = useK8sWatchResource<VMRestore[]>(restoreResource); | ||
|
||
const mappedRelevantRestores = React.useMemo( |
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.
could we make a hook for this, since we are using ti twice?
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 could include useK8sWatchResource
into the new hook and it would return [mappedRestores, loaded, error]
cde5803
to
279df00
Compare
279df00
to
8be1738
Compare
[restores], | ||
); | ||
|
||
return [mappedRelevantRestores, restoresLoaded, restoresError]; |
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 return directly from React.useMemo so you wont create a new array every time
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.
fixed
}, | ||
{ | ||
name: `${vmName} Snapshots`, | ||
path: `/k8s/ns/${match.params.ns || |
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.
can use the variable here 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.
fixed
8be1738
to
3123c26
Compare
|
||
export const VMDescriptionModal = withHandlePromise((props: VMDescriptionModalProps) => { | ||
const { vmLikeEntity, inProgress, errorMessage, handlePromise, close, cancel } = props; | ||
const DescriptionModal = withHandlePromise((props: DescriptionModalProps) => { |
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 DescriptionModal = withHandlePromise((props: DescriptionModalProps) => { | |
const DescriptionModal = withHandlePromise<DescriptionModalProps>((props) => { |
@@ -0,0 +1 @@ | |||
export * from './description-modal'; |
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.
lets avoid creating new index files, they cause cyclic deps and we will be removing them in the future
<FormRow title="Description" fieldId={asId('desc')}> | ||
<TextArea | ||
value={description} | ||
onChange={(d) => setDescription(d)} |
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.
onChange={(d) => setDescription(d)} | |
onChange={setDescription} |
resources={[resource]} | ||
menuActions={menuActions} | ||
pages={pages} | ||
breadcrumbsFor={(obj) => breadcrumbsForSnapshots(obj)} |
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.
breadcrumbsFor={(obj) => breadcrumbsForSnapshots(obj)} | |
breadcrumbsFor={breadcrumbsForSnapshots} |
@@ -26,7 +25,7 @@ export const getLabelValue = (entity: K8sResourceKind, label: string): string => | |||
|
|||
// Annotations | |||
export const getAnnotations = ( | |||
vm: VMGenericLikeEntityKind, | |||
vm: K8sResourceKind, |
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.
vm: K8sResourceKind, | |
vm: K8sResourceCommon, |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: glekner, 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 |
No description provided.