Skip to content
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

Provider details page #69

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 86 additions & 5 deletions console-extensions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import type { EncodedExtension } from '@openshift/dynamic-plugin-sdk';
import type {
ActionProvider,
HorizontalNavTab,
HrefNavItem,
NavSection,
ResourceActionProvider,
ResourceDetailsPage,
ResourceListPage,
ResourceNSNavItem,
RoutePage,
Separator,
} from '@openshift-console/dynamic-plugin-sdk';
Expand Down Expand Up @@ -38,16 +44,91 @@ const extensions: EncodedExtension[] = [
} as EncodedExtension<Separator>,

{
type: 'console.navigation/href',
type: 'console.navigation/resource-ns',
properties: {
id: 'providers',
insertAfter: 'importSeparator',
perspective: 'admin',
section: 'virtualization',
name: '%plugin__forklift-console-plugin~Providers for VM Import%',
href: '/mtv/providers',
model: {
group: 'forklift.konveyor.io',
kind: 'Provider',
version: 'v1beta1',
},
dataAttributes: {
'data-quickstart-id': 'qs-nav-providers',
'data-test-id': 'providers-nav-item',
},
},
} as EncodedExtension<HrefNavItem>,
} as EncodedExtension<ResourceNSNavItem>,

{
type: 'console.page/resource/list',
properties: {
component: {
$codeRef: 'ProvidersPage',
},
model: {
group: 'forklift.konveyor.io',
kind: 'Provider',
version: 'v1beta1',
},
},
} as EncodedExtension<ResourceListPage>,

{
type: 'console.page/resource/details',
properties: {
model: {
group: 'forklift.konveyor.io',
kind: 'Provider',
version: 'v1beta1',
},
component: {
$codeRef: 'EmptyDetailPage',
},
},
} as EncodedExtension<ResourceDetailsPage>,

{
type: 'console.tab/horizontalNav',
properties: {
model: {
group: 'forklift.konveyor.io',
kind: 'Provider',
version: 'v1beta1',
},
page: {
name: 'Inventory',
href: 'inventory',
},
component: {
$codeRef: 'ProviderInventoryTab',
},
},
} as EncodedExtension<HorizontalNavTab>,

{
type: 'console.action/provider',
properties: {
contextId: 'mergedProvider',
provider: {
$codeRef: 'useMergedProviders',
},
},
} as EncodedExtension<ActionProvider>,
{
type: 'console.action/resource-provider',
properties: {
model: {
group: 'forklift.konveyor.io',
kind: 'Provider',
version: 'v1beta1',
},
provider: {
$codeRef: 'useProviders',
},
},
} as EncodedExtension<ResourceActionProvider>,

{
type: 'console.navigation/href',
Expand Down
29 changes: 28 additions & 1 deletion locales/en/plugin__forklift-console-plugin.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,50 @@
{
"{{type}} provider {{name}} will no longer be selectable as a migration source.": "{{type}} provider {{name}} will no longer be selectable as a migration source.",
"{{type}} provider {{name}} will no longer be selectable as a migration target.": "{{type}} provider {{name}} will no longer be selectable as a migration target.",
"Actions": "Actions",
"Add Provider": "Add Provider",
"Cancel": "Cancel",
"Cannot remove provider": "Cannot remove provider",
"Clear all filters": "Clear all filters",
"Clusters": "Clusters",
"Delete": "Delete",
"Delete Provider": "Delete Provider",
"Edit Provider": "Edit Provider",
"Endpoint": "Endpoint",
"False": "False",
"Filter by endpoint": "Filter by endpoint",
"Filter by name": "Filter by name",
"Filter by namespace": "Filter by namespace",
"Hosts": "Hosts",
"KubeVirt": "KubeVirt",
"Loading": "Loading",
"Manage Columns": "Manage Columns",
"Mappings for VM Import": "Mappings for VM Import",
"Name": "Name",
"Namespace": "Namespace",
"Networks": "Networks",
"No information": "No information",
"No results found": "No results found",
"No results match the filter criteria. Clear all filters and try again.": "No results match the filter criteria. Clear all filters and try again.",
"oVirt": "oVirt",
"Permanently delete provider?": "Permanently delete provider?",
"Plans for VM Import": "Plans for VM Import",
"Providers": "Providers",
"Providers for VM Import": "Providers for VM Import",
"Ready": "Ready",
"Reorder": "Reorder",
"Restore default colums": "Restore default colums",
"Save": "Save",
"Select Filter": "Select Filter",
"Select migration network": "Select migration network",
"Selected columns will be displayed in the table.": "Selected columns will be displayed in the table.",
"Storage": "Storage",
"Table column management": "Table column management",
"True": "True",
"Type": "Type",
"Unable to retrieve data": "Unable to retrieve data",
"Virtualization": "Virtualization"
"Unknown": "Unknown",
"Virtualization": "Virtualization",
"VMs": "VMs",
"VMware": "VMware"
}
8 changes: 6 additions & 2 deletions plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@
"MappingsPage": "./extensions/MappingsWrapper",
"HostsPage": "./extensions/HostsPageWrapper",
"PlanWizard": "./extensions/PlanWizardWrapper",
"VMMigrationDetails": "./extensions/VMMigrationDetailsWrapper"
"VMMigrationDetails": "./extensions/VMMigrationDetailsWrapper",
"ProviderInventoryTab": "./extensions/ProviderInventoryTabWrapper",
"EmptyDetailPage": "./extensions/EmptyDetailPageWrapper",
"useMergedProviders": "./extensions/UseMergedProviders",
"useProviders": "./extensions/UseProviders"
},
"dependencies": {
"@console/pluginAPI": "*"
}
}
}
76 changes: 76 additions & 0 deletions src/Providers/ProviderInventoryTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as React from 'react';
import { ErrorState, Loading } from 'src/components/StandardPage';
import { useTranslation } from 'src/internal/i18n';
import { ProviderResource } from 'src/internal/k8s';

import {
DescriptionList,
DescriptionListDescription,
DescriptionListGroup,
DescriptionListTerm,
PageSection,
} from '@patternfly/react-core';

import { useProvidersWithInventory } from './data';

interface ProviderDetailPageProps {
obj: ProviderResource;
}

const ProviderInventoryTab = ({ obj }: ProviderDetailPageProps) => {
const [[provider], loaded, error] = useProvidersWithInventory({
kind: obj?.kind ?? '',
namespace: obj?.metadata?.namespace ?? '',
name: obj?.metadata?.name ?? '',
});
const { t } = useTranslation();
return (
<PageSection>
{!loaded && <Loading />}
{loaded && error && <ErrorState />}
{loaded && !error && provider && (
<DescriptionList
columnModifier={{
default: '1Col',
md: '2Col',
}}
>
<DescriptionListGroup>
<DescriptionListTerm>{t('Ready')}</DescriptionListTerm>
<DescriptionListDescription>{provider.ready}</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{t('Endpoint')}</DescriptionListTerm>
<DescriptionListDescription>{provider.url}</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{t('Type')}</DescriptionListTerm>
<DescriptionListDescription>{provider.type}</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{t('VMs')}</DescriptionListTerm>
<DescriptionListDescription>{provider.vmCount}</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{t('Networks')}</DescriptionListTerm>
<DescriptionListDescription>{provider.networkCount}</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{t('Clusters')}</DescriptionListTerm>
<DescriptionListDescription>{provider.clusterCount}</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{t('Hosts')}</DescriptionListTerm>
<DescriptionListDescription>{provider.hostCount}</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{t('Storage')}</DescriptionListTerm>
<DescriptionListDescription>{provider.storageCount}</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
)}
</PageSection>
);
};

export default ProviderInventoryTab;
94 changes: 94 additions & 0 deletions src/Providers/ProviderRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from 'react';
import { RowProps } from 'src/components/TableView';
import { useTranslation } from 'src/internal/i18n';
import { NAME, NAMESPACE, READY, TYPE, URL } from 'src/utils/constants';

import { StatusIcon } from '@migtools/lib-ui';
import { ResourceLink } from '@openshift-console/dynamic-plugin-sdk';
import { Button, Popover } from '@patternfly/react-core';
import { Td, Tr } from '@patternfly/react-table';

import { MergedProvider } from './data';
import { ProviderActions } from './providerActions';

interface CellProps {
value: string;
entity: MergedProvider;
}
const StatusCell = ({ value, entity: { conditions } }: CellProps) => {
const { t } = useTranslation();
const existingConditions = Object.values(conditions).filter(Boolean);
const toState = (value) => {
switch (value) {
case 'True':
return 'Ok';
case 'False':
return 'Error';
default:
return 'Unknown';
}
};
const label = ((value) => {
switch (value) {
case 'True':
return t('True');
case 'False':
return t('False');
default:
return t('Unknown');
}
})(value);
return (
<Popover
hasAutoWidth
bodyContent={
<div>
{existingConditions.length > 0
? existingConditions.map(({ message, status }) => {
return <StatusIcon key={message} status={toState(status)} label={message} />;
})
: t('No information')}
</div>
}
>
<Button variant="link" isInline aria-label={label}>
<StatusIcon status={toState(value)} label={label} />
</Button>
</Popover>
);
};

const TextCell = ({ value }: { value: string }) => <>{value}</>;

const ProviderLink = ({ value, entity }: CellProps) => (
<ResourceLink kind={entity.kind} name={value} namespace={entity?.namespace} />
);

const cellCreator = {
[NAME]: ProviderLink,
[READY]: StatusCell,
[URL]: TextCell,
[TYPE]: TextCell,
[NAMESPACE]: ({ value }: CellProps) => <ResourceLink kind="Namespace" name={value} />,
};

const ProviderRow = ({ columns, entity }: RowProps<MergedProvider>) => {
const { t } = useTranslation();
return (
<Tr>
{columns.map(({ id, toLabel }) => (
<Td key={id} dataLabel={toLabel(t)}>
{cellCreator?.[id]?.({
value: entity[id],
entity,
}) ?? <TextCell value={String(entity[id] ?? '')} />}
</Td>
))}
<Td modifier="fitContent">
<ProviderActions entity={entity} />
</Td>
</Tr>
);
};

export default ProviderRow;
Loading