Skip to content

Commit

Permalink
Create a Wrapper StandardPageWithSelection
Browse files Browse the repository at this point in the history
Signed-off-by: yzamir <[email protected]>
  • Loading branch information
yaacov committed Feb 6, 2024
1 parent 0fa192a commit 6083b78
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@
"This resource is managed by <2></2> and any modifications may be overwritten. Edit the managing resource to preserve changes.": "This resource is managed by <2></2> and any modifications may be overwritten. Edit the managing resource to preserve changes.",
"To": "To",
"To make changes to the plan, select Duplicate and edit the duplicate plan.": "To make changes to the plan, select Duplicate and edit the duplicate plan.",
"To migrate virtual machines from <1>{obj?.provider.metadata.name}</1> provider, select the virtual machines to migrate from the list of available virtual machines and click the <4>Migrate</4> button.": "To migrate virtual machines from <1>{obj?.provider.metadata.name}</1> provider, select the virtual machines to migrate from the list of available virtual machines and click the <4>Migrate</4> button.",
"To migrate virtual machines from <1>{name}</1> provider, select the virtual machines to migrate from the list of available virtual machines and click the <4>Migrate</4> button.": "To migrate virtual machines from <1>{name}</1> provider, select the virtual machines to migrate from the list of available virtual machines and click the <4>Migrate</4> button.",
"To migrate virtual machines from <1>{provider.metadata.name}</1> provider, select the virtual machines to migrate from the list of available virtual machines located in the virtual machines tab. <4>Go to <1>Virtual Machines</1> tab</4>": "To migrate virtual machines from <1>{provider.metadata.name}</1> provider, select the virtual machines to migrate from the list of available virtual machines located in the virtual machines tab. <4>Go to <1>Virtual Machines</1> tab</4>",
"To troubleshoot, check the Forklift controller pod events and logs.": "To troubleshoot, check the Forklift controller pod events and logs.",
"To troubleshoot, check the Forklift controller pod logs.": "To troubleshoot, check the Forklift controller pod logs.",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC, useState } from 'react';
import React, { FC } from 'react';

import {
DefaultHeader,
Expand Down Expand Up @@ -59,6 +59,16 @@ export interface IdBasedSelectionProps<T> {
* @returns true if items can be selected, false otherwise
*/
canSelect: (item: T) => boolean;

/**
* onSelect is called when selection changes
*/
onSelect: (selectedIds: string[]) => void;

/**
* Selected ids
*/
selectedIds: string[];
}

export type GlobalActionWithSelection<T> = GlobalActionToolbarProps<T> & {
Expand All @@ -71,18 +81,26 @@ export type GlobalActionWithSelection<T> = GlobalActionToolbarProps<T> & {
* 1. IDs provided with toId() function are unique and constant in time
* 2. check box status at row level does not depend from other rows and can be calculated from the item via canSelect() function
*/
export function withIdBasedSelection<T>({ toId, canSelect }: IdBasedSelectionProps<T>) {
export function withIdBasedSelection<T>({
toId,
canSelect,
onSelect,
selectedIds,
}: IdBasedSelectionProps<T>) {
const Enhanced = (props: StandardPageProps<T>) => {
const [selectedIds, setSelectedIds]: [string[], (selected: string[]) => void] = useState([]);
const isSelected = (item: T) => selectedIds.includes(toId(item));

const toggleSelectFor = (items: T[]) => {
const ids = items.map(toId);
const allSelected = ids.every((id) => selectedIds.includes(id));
setSelectedIds([
const newSelectedIds = [
...selectedIds.filter((it) => !ids.includes(it)),
...(allSelected ? [] : ids),
]);
];

onSelect(newSelectedIds);
};

return (
<StandardPage
{...props}
Expand Down Expand Up @@ -111,3 +129,27 @@ export function withIdBasedSelection<T>({ toId, canSelect }: IdBasedSelectionPro
Enhanced.displayName = 'StandardPageWithSelection';
return Enhanced;
}

export interface StandardPageWithSelectionProps<T> extends StandardPageProps<T> {
toId?: (item: T) => string;
canSelect?: (item: T) => boolean;
onSelect?: (selectedIds: string[]) => void;
selectedIds?: string[];
}

export function StandardPageWithSelection<T>(props: StandardPageWithSelectionProps<T>) {
const { toId, canSelect = () => true, onSelect, selectedIds, ...rest } = props;

if (onSelect && (!toId || !selectedIds)) {
throw new Error('Missing required properties: toId, selectedIds');
}

const EnhancedStandardPage = withIdBasedSelection<T>({
toId,
canSelect,
onSelect,
selectedIds,
});

return onSelect ? <EnhancedStandardPage {...rest} /> : <StandardPage {...rest} />;
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import React, { FC, useState } from 'react';
import StandardPage from 'src/components/page/StandardPage';
import { GlobalActionWithSelection, withIdBasedSelection } from 'src/components/page/withSelection';
import {
GlobalActionWithSelection,
StandardPageWithSelection,
StandardPageWithSelectionProps,
} from 'src/components/page/StandardPageWithSelection';
import { useProviderInventory } from 'src/modules/Providers/hooks';
import { useModal } from 'src/modules/Providers/modals';
import { useForkliftTranslation } from 'src/utils/i18n';

import { loadUserSettings, ResourceFieldFactory } from '@kubev2v/common';
import {
HostModelGroupVersionKind,
V1beta1Host,
V1beta1Provider,
VSphereHost,
} from '@kubev2v/types';
import { HostModelGroupVersionKind, V1beta1Host, VSphereHost } from '@kubev2v/types';
import { useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk';
import { Button, ToolbarItem } from '@patternfly/react-core';

import { VSphereNetworkModal } from './modals/VSphereNetworkModal';
import { InventoryHostPair, matchHostsToInventory } from './utils/helpers';
import { SelectNetworkButton } from './components';
import { ProviderHostsProps } from './ProviderHosts';
import { VSphereHostsCells } from './VSphereHostsRow';

Expand Down Expand Up @@ -60,19 +56,19 @@ export const hostsFieldsMetadataFactory: ResourceFieldFactory = (t) => [
},
];

const PageWithSelection = withIdBasedSelection<InventoryHostPair>({
toId: (item: InventoryHostPair) => item.inventory.id,
canSelect: (item: InventoryHostPair) => item?.inventory?.networkAdapters?.length > 0,
});
const PageWithSelection = StandardPageWithSelection<InventoryHostPair>;
type PageWithSelectionProps = StandardPageWithSelectionProps<InventoryHostPair>;
type PageGlobalActions = FC<GlobalActionWithSelection<InventoryHostPair>>[];

export const VSphereHostsList: FC<ProviderHostsProps> = ({ obj }) => {
const { t } = useForkliftTranslation();

const [userSettings] = useState(() => loadUserSettings({ pageId: 'ProviderHosts' }));

const { provider, permissions } = obj;
const { namespace } = provider?.metadata || {};

const [selectedIds, setSelectedIds] = useState([]);
const [userSettings] = useState(() => loadUserSettings({ pageId: 'ProviderHosts' }));

const {
inventory: hostsInventory,
loading,
Expand All @@ -91,45 +87,29 @@ export const VSphereHostsList: FC<ProviderHostsProps> = ({ obj }) => {

const hostsData = matchHostsToInventory(hostsInventory, hosts, provider);

const Page = permissions?.canPatch ? PageWithSelection : StandardPage<InventoryHostPair>;
const actions: FC<GlobalActionWithSelection<InventoryHostPair>>[] = permissions?.canPatch
? [({ selectedIds }) => <SelectNetworkBtn {...{ hostsData, provider, selectedIds }} />]
: [];
const actions: PageGlobalActions = [
({ selectedIds }) => <SelectNetworkButton {...{ hostsData, provider, selectedIds }} />,
];

return (
<Page
data-testid="hosts-list"
dataSource={[hostsData || [], !loading, error]}
CellMapper={VSphereHostsCells}
fieldsMetadata={hostsFieldsMetadataFactory(t)}
namespace={namespace}
title={t('Hosts')}
userSettings={userSettings}
GlobalActionToolbarItems={actions}
/>
);
};
const props: PageWithSelectionProps = {
dataSource: [hostsData || [], !loading, error],
CellMapper: VSphereHostsCells,
fieldsMetadata: hostsFieldsMetadataFactory(t),
namespace: namespace,
title: t('Hosts'),
userSettings: userSettings,
};

const SelectNetworkBtn: FC<{
selectedIds: string[];
provider: V1beta1Provider;
hostsData: InventoryHostPair[];
}> = ({ selectedIds, provider, hostsData }) => {
const { t } = useForkliftTranslation();
const { showModal } = useModal();
return (
<ToolbarItem>
<Button
variant="secondary"
onClick={() =>
showModal(
<VSphereNetworkModal provider={provider} data={hostsData} selected={selectedIds} />,
)
}
isDisabled={!selectedIds?.length}
>
{t('Select migration network')}
</Button>
</ToolbarItem>
);
const extendedProps: PageWithSelectionProps = permissions?.canPatch
? {
...props,
toId: (item: InventoryHostPair) => item.inventory.id,
canSelect: (item: InventoryHostPair) => item?.inventory?.networkAdapters?.length > 0,
onSelect: setSelectedIds,
selectedIds: selectedIds,
GlobalActionToolbarItems: actions,
}
: props;

return <PageWithSelection {...extendedProps} />;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { FC } from 'react';
import { useModal } from 'src/modules/Providers/modals';
import { useForkliftTranslation } from 'src/utils/i18n';

import { V1beta1Provider } from '@kubev2v/types';
import { Button, ToolbarItem } from '@patternfly/react-core';

import { VSphereNetworkModal } from '../modals';
import { InventoryHostPair } from '../utils';

/**
* `SelectNetworkButton` is a functional component that renders a button for selecting a migration network.
* When clicked, it opens a modal dialog for choosing the network.
*
* @component
* @example
* // Usage within a parent component
* <SelectNetworkButton
* selectedIds={['host1', 'host2']}
* provider={myProvider}
* hostsData={myInventoryHostPairs}
* />
*
* @param {Object} props - The properties passed to the component.
* @param {string[]} props.selectedIds - An array of host IDs that are selected for migration.
* @param {V1beta1Provider} props.provider - The provider object containing details about the provider.
* @param {InventoryHostPair[]} props.hostsData - An array of inventory host pairs for displaying in the modal.
*/
export const SelectNetworkButton: FC<{
selectedIds: string[];
provider: V1beta1Provider;
hostsData: InventoryHostPair[];
}> = ({ selectedIds, provider, hostsData }) => {
const { t } = useForkliftTranslation();
const { showModal } = useModal();

return (
<ToolbarItem>
<Button
variant="secondary"
onClick={() =>
showModal(
<VSphereNetworkModal provider={provider} data={hostsData} selected={selectedIds} />,
)
}
isDisabled={!selectedIds?.length}
>
{t('Select migration network')}
</Button>
</ToolbarItem>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export * from './LinkSpeedCellRenderer';
export * from './MTUCellRenderer';
export * from './NameCellRenderer';
export * from './NetworkCellRenderer';
export * from './SelectNetworkButton';
// @endindex
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ export const OVirtVirtualMachinesList: React.FC<ProviderVirtualMachinesProps> =
obj,
loaded,
loadError,
onSelect,
initialSelectedIds,
}) => (
<ProviderVirtualMachinesList
title={title}
Expand All @@ -102,5 +104,7 @@ export const OVirtVirtualMachinesList: React.FC<ProviderVirtualMachinesProps> =
cellMapper={OVirtVirtualMachinesCells}
fieldsMetadataFactory={oVirtVmFieldsMetadataFactory}
pageId="OVirtVirtualMachinesList"
onSelect={onSelect}
initialSelectedIds={initialSelectedIds}
/>
);
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ export const OpenShiftVirtualMachinesList: React.FC<ProviderVirtualMachinesProps
obj,
loaded,
loadError,
onSelect,
initialSelectedIds,
}) => (
<ProviderVirtualMachinesList
title={title}
Expand All @@ -87,5 +89,7 @@ export const OpenShiftVirtualMachinesList: React.FC<ProviderVirtualMachinesProps
cellMapper={OpenShiftVirtualMachinesCells}
fieldsMetadataFactory={openShiftVmFieldsMetadataFactory}
pageId="OpenShiftVirtualMachinesList"
onSelect={onSelect}
initialSelectedIds={initialSelectedIds}
/>
);
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ export const OpenStackVirtualMachinesList: React.FC<ProviderVirtualMachinesProps
obj,
loaded,
loadError,
onSelect,
initialSelectedIds,
}) => (
<ProviderVirtualMachinesList
title={title}
Expand All @@ -118,5 +120,7 @@ export const OpenStackVirtualMachinesList: React.FC<ProviderVirtualMachinesProps
cellMapper={OpenStackVirtualMachinesCells}
fieldsMetadataFactory={openStackVmFieldsMetadataFactory}
pageId="OpenStackVirtualMachinesList"
onSelect={onSelect}
initialSelectedIds={initialSelectedIds}
/>
);
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export const OvaVirtualMachinesList: React.FC<ProviderVirtualMachinesProps> = ({
obj,
loaded,
loadError,
onSelect,
initialSelectedIds,
}) => (
<ProviderVirtualMachinesList
title={title}
Expand All @@ -56,5 +58,7 @@ export const OvaVirtualMachinesList: React.FC<ProviderVirtualMachinesProps> = ({
cellMapper={OvaVirtualMachinesCells}
fieldsMetadataFactory={ovaVmFieldsMetadataFactory}
pageId="OvaVirtualMachinesList"
onSelect={onSelect}
initialSelectedIds={initialSelectedIds}
/>
);
Loading

0 comments on commit 6083b78

Please sign in to comment.