Skip to content

Commit

Permalink
CNV-40059: Align VMs and Templates lists empty pages with the new format
Browse files Browse the repository at this point in the history
  • Loading branch information
Hilda Stastna committed Apr 11, 2024
1 parent 24fa96a commit 13187d0
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 92 deletions.
5 changes: 4 additions & 1 deletion locales/en/plugin__kubevirt-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@
"Clear all filters": "Clear all filters",
"CLI": "CLI",
"Click <1>Create MigrationPolicy</1> to create your first policy": "Click <1>Create MigrationPolicy</1> to create your first policy",
"Click <1>Create Template</1> to create your first template": "Click <1>Create Template</1> to create your first template",
"Click <1>Create VirtualMachine</1> to create your first VirtualMachine or view the <4>catalog</4> tab to create a VirtualMachine from the available options": "Click <1>Create VirtualMachine</1> to create your first VirtualMachine or view the <4>catalog</4> tab to create a VirtualMachine from the available options",
"Click Connect to open serial console.": "Click Connect to open serial console.",
"Click Connect to open the VNC console.": "Click Connect to open the VNC console.",
"Clone": "Clone",
Expand Down Expand Up @@ -632,6 +634,7 @@
"Learn more about Red Hat support": "Learn more about Red Hat support",
"Learn more about snapshots": "Learn more about snapshots",
"Learn more about supported formats": "Learn more about supported formats",
"Learn more about templates": "Learn more about templates",
"Learn more about working with projects": "Learn more about working with projects",
"Limitations": "Limitations",
"Linux only": "Linux only",
Expand Down Expand Up @@ -799,7 +802,7 @@
"No Template found": "No Template found",
"No Template items are being shown due to the filters being applied.": "No Template items are being shown due to the filters being applied.",
"No Template was selected for review, please go to the catalog and select one.": "No Template was selected for review, please go to the catalog and select one.",
"No templates found": "No templates found",
"No Templates found": "No Templates found",
"No Upload URL found {{configError}}": "No Upload URL found {{configError}}",
"No username set, see operating system documentation for the default username.": "No username set, see operating system documentation for the default username.",
"No VirtualMachineClusterInstanceType found": "No VirtualMachineClusterInstanceType found",
Expand Down
3 changes: 3 additions & 0 deletions src/utils/constants/url-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ export const AUTOCOMPUTE_CPU_LIMITS_LINK =

export const TECH_PREVIEW_LINK = 'https://access.redhat.com/support/offerings/techpreview';
export const DEV_PREVIEW_LINK = 'https://access.redhat.com/support/offerings/devpreview';

export const CREATING_VMS_FROM_TEMPLATES_LINK =
'https://docs.openshift.com/container-platform/4.15/virt/virtual_machines/creating_vms_rh/virt-creating-vms-from-templates.html';
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { FC, memo, useEffect, useState } from 'react';

import ExternalLink from '@kubevirt-utils/components/ExternalLink/ExternalLink';
import HelpTextIcon from '@kubevirt-utils/components/HelpTextIcon/HelpTextIcon';
import { CREATING_VMS_FROM_TEMPLATES_LINK } from '@kubevirt-utils/constants/url-constants';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import {
pluralize,
Expand Down Expand Up @@ -50,12 +51,7 @@ export const TemplatesCatalogHeader: FC<{
bodyContent={
<>
{t('Red Hat recommended configuration for each OS.')}{' '}
<ExternalLink
href={
'https://docs.openshift.com/container-platform/4.15/virt/virtual_machines/creating_vms_rh/virt-creating-vms-from-templates.html'
}
text={t('Learn more')}
/>
<ExternalLink href={CREATING_VMS_FROM_TEMPLATES_LINK} text={t('Learn more')} />
</>
}
/>
Expand Down
62 changes: 31 additions & 31 deletions src/views/templates/list/VirtualMachineTemplatesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import { modelToRef, TemplateModel } from '@kubevirt-ui/kubevirt-api/console';
import { V1beta1DataSource } from '@kubevirt-ui/kubevirt-api/containerized-data-importer/models';
import ListPageFilter from '@kubevirt-utils/components/ListPageFilter/ListPageFilter';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { isEmpty } from '@kubevirt-utils/utils/utils';
import {
K8sResourceCommon,
ListPageBody,
ListPageCreate,
ListPageHeader,
useListPageFilter,
VirtualizedTable,
} from '@openshift-console/dynamic-plugin-sdk';
import { Stack, StackItem } from '@patternfly/react-core';

import VirtualMachineTemplatesCreateButton from './components/VirtualMachineTemplatesCreateButton/VirtualMachineTemplatesCreateButton';
import VirtualMachineTemplatesEmptyState from './components/VirtualMachineTemplatesEmptyState/VirtualMachineTemplatesEmptyState';
import VirtualMachineTemplatesRow from './components/VirtualMachineTemplatesRow';
import VirtualMachineTemplateSupport from './components/VirtualMachineTemplateSupport/VirtualMachineTemplateSupport';
import { useTemplatesWithAvailableSource } from './hooks/useTemplatesWithAvailableSource';
Expand Down Expand Up @@ -47,35 +49,37 @@ const VirtualMachineTemplatesList: FC<VirtualMachineTemplatesListProps> = ({ nam
return (
<>
<ListPageHeader title={t('VirtualMachine Templates')}>
<ListPageCreate
createAccessReview={{ groupVersionKind: modelToRef(TemplateModel), namespace }}
groupVersionKind={modelToRef(TemplateModel)}
>
{t('Create Template')}
</ListPageCreate>
{!isEmpty(templates) && <VirtualMachineTemplatesCreateButton namespace={namespace} />}
</ListPageHeader>
<ListPageBody>
<Stack hasGutter>
{!isEmpty(templates) && (
<StackItem>
<VirtualMachineTemplateSupport />
</StackItem>
)}
<StackItem>
<VirtualMachineTemplateSupport />
</StackItem>
<StackItem>
<ListPageFilter
columnLayout={{
columns: columns?.map(({ additional, id, title }) => ({
additional,
id,
title,
})),
id: modelToRef(TemplateModel),
selectedColumns: new Set(activeColumns?.map((col) => col?.id)),
type: t('Template'),
}}
data={data}
loaded={templatesLoaded && loadedColumns}
onFilterChange={onFilterChange}
rowFilters={filters}
/>
{!isEmpty(templates) && (
<ListPageFilter
columnLayout={{
columns: columns?.map(({ additional, id, title }) => ({
additional,
id,
title,
})),
id: modelToRef(TemplateModel),
selectedColumns: new Set(activeColumns?.map((col) => col?.id)),
type: t('Template'),
}}
data={data}
loaded={templatesLoaded && loadedColumns}
onFilterChange={onFilterChange}
rowFilters={filters}
/>
)}
{templatesLoaded && isEmpty(filteredData) && (
<VirtualMachineTemplatesEmptyState namespace={namespace} />
)}
<VirtualizedTable<
K8sResourceCommon,
{
Expand All @@ -84,13 +88,9 @@ const VirtualMachineTemplatesList: FC<VirtualMachineTemplatesListProps> = ({ nam
cloneInProgressDatasources: Record<string, V1beta1DataSource>;
}
>
EmptyMsg={() => (
<div className="pf-u-text-align-center" id="no-templates-msg">
{t('No templates found')}
</div>
)}
columns={activeColumns}
data={filteredData}
EmptyMsg={() => <></>}
loaded={templatesLoaded && loadedColumns}
loadError={error}
Row={VirtualMachineTemplatesRow}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { FC } from 'react';

import { modelToRef, TemplateModel } from '@kubevirt-ui/kubevirt-api/console';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { ListPageCreate } from '@openshift-console/dynamic-plugin-sdk';

type VirtualMachineTemplatesCreateButtonProps = {
namespace: string;
};

const VirtualMachineTemplatesCreateButton: FC<VirtualMachineTemplatesCreateButtonProps> = ({
namespace,
}) => {
const { t } = useKubevirtTranslation();

return (
<ListPageCreate
createAccessReview={{ groupVersionKind: modelToRef(TemplateModel), namespace }}
groupVersionKind={modelToRef(TemplateModel)}
>
{t('Create Template')}
</ListPageCreate>
);
};

export default VirtualMachineTemplatesCreateButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { FC } from 'react';
import { Trans } from 'react-i18next';
import { Link } from 'react-router-dom-v5-compat';

import { CREATING_VMS_FROM_TEMPLATES_LINK } from '@kubevirt-utils/constants/url-constants';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import {
EmptyState,
EmptyStateActions,
EmptyStateBody,
EmptyStateFooter,
EmptyStateHeader,
EmptyStateIcon,
EmptyStateVariant,
} from '@patternfly/react-core';
import { ExternalLinkAltIcon, PficonTemplateIcon } from '@patternfly/react-icons';

import VirtualMachineTemplatesCreateButton from '../VirtualMachineTemplatesCreateButton/VirtualMachineTemplatesCreateButton';

type VirtualMachineTemplatesEmptyStateProps = {
namespace: string;
};

const VirtualMachineTemplatesEmptyState: FC<VirtualMachineTemplatesEmptyStateProps> = ({
namespace,
}) => {
const { t } = useKubevirtTranslation();

return (
<EmptyState variant={EmptyStateVariant.lg}>
<EmptyStateHeader
headingLevel="h4"
icon={<EmptyStateIcon icon={PficonTemplateIcon} />}
titleText={<>{t('No Templates found')}</>}
/>
<EmptyStateBody>
<Trans ns="plugin__kubevirt-plugin" t={t}>
Click <b>Create Template</b> to create your first template
</Trans>
</EmptyStateBody>
<EmptyStateFooter>
<EmptyStateActions>
<VirtualMachineTemplatesCreateButton namespace={namespace} />
</EmptyStateActions>
<br />
<EmptyStateActions>
<Link to={CREATING_VMS_FROM_TEMPLATES_LINK}>
{t('Learn more about templates')} <ExternalLinkAltIcon />
</Link>
</EmptyStateActions>
</EmptyStateFooter>
</EmptyState>
);
};

export default VirtualMachineTemplatesEmptyState;
80 changes: 41 additions & 39 deletions src/views/virtualmachines/list/VirtualMachinesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,46 +153,48 @@ const VirtualMachinesList: FC<VirtualMachinesListProps> = ({ kind, namespace })
</ListPageHeader>
<ListPageBody>
<div className="list-managment-group">
<ListPageFilter
columnLayout={{
columns: columns?.map(({ additional, id, title }) => ({
additional,
id,
title,
})),
id: VirtualMachineModelRef,
selectedColumns: new Set(activeColumns?.map((col) => col?.id)),
type: t('VirtualMachine'),
}}
onFilterChange={(...args) => {
onFilterChange(...args);
setPagination((prevPagination) => ({
...prevPagination,
endIndex: prevPagination?.perPage,
page: 1,
startIndex: 0,
}));
}}
data={unfilteredData}
loaded={loaded}
rowFilters={filters}
searchFilters={searchFilters}
/>
{!isEmpty(vms) && (
<Pagination
onPerPageSelect={(_e, perPage, page, startIndex, endIndex) =>
onPageChange({ endIndex, page, perPage, startIndex })
}
onSetPage={(_e, page, perPage, startIndex, endIndex) =>
onPageChange({ endIndex, page, perPage, startIndex })
}
className="list-managment-group__pagination"
isLastFullPageShown
itemCount={data?.length}
page={pagination?.page}
perPage={pagination?.perPage}
perPageOptions={paginationDefaultValues}
/>
<>
<ListPageFilter
columnLayout={{
columns: columns?.map(({ additional, id, title }) => ({
additional,
id,
title,
})),
id: VirtualMachineModelRef,
selectedColumns: new Set(activeColumns?.map((col) => col?.id)),
type: t('VirtualMachine'),
}}
onFilterChange={(...args) => {
onFilterChange(...args);
setPagination((prevPagination) => ({
...prevPagination,
endIndex: prevPagination?.perPage,
page: 1,
startIndex: 0,
}));
}}
data={unfilteredData}
loaded={loaded}
rowFilters={filters}
searchFilters={searchFilters}
/>
<Pagination
onPerPageSelect={(_e, perPage, page, startIndex, endIndex) =>
onPageChange({ endIndex, page, perPage, startIndex })
}
onSetPage={(_e, page, perPage, startIndex, endIndex) =>
onPageChange({ endIndex, page, perPage, startIndex })
}
className="list-managment-group__pagination"
isLastFullPageShown
itemCount={data?.length}
page={pagination?.page}
perPage={pagination?.perPage}
perPageOptions={paginationDefaultValues}
/>
</>
)}
</div>
{loaded && isEmpty(data) && (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.VirtualMachineEmptyState {
.pf-v5-c-empty-state__content {
max-width: fit-content;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FC } from 'react';
import { Trans } from 'react-i18next';
import { useNavigate } from 'react-router-dom-v5-compat';
import { Link, useNavigate } from 'react-router-dom-v5-compat';

import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import {
Expand All @@ -14,10 +14,12 @@ import {
EmptyStateIcon,
EmptyStateVariant,
} from '@patternfly/react-core';
import { RocketIcon, VirtualMachineIcon } from '@patternfly/react-icons';
import { RouteIcon, VirtualMachineIcon } from '@patternfly/react-icons';

import VirtualMachinesCreateButton from '../VirtualMachinesCreateButton/VirtualMachinesCreateButton';

import './VirtualMachineEmptyState.scss';

type VirtualMachineEmptyStateProps = {
catalogURL: string;
namespace: string;
Expand All @@ -28,19 +30,19 @@ const VirtualMachineEmptyState: FC<VirtualMachineEmptyStateProps> = ({ catalogUR
const navigate = useNavigate();

return (
<EmptyState variant={EmptyStateVariant.lg}>
<EmptyState className="VirtualMachineEmptyState" variant={EmptyStateVariant.lg}>
<EmptyStateHeader
headingLevel="h4"
icon={<EmptyStateIcon icon={VirtualMachineIcon} />}
titleText={<>{t('No VirtualMachines found')}</>}
/>
<EmptyStateBody>
<Trans ns="plugin__kubevirt-plugin" t={t}>
See the{' '}
Click <b>Create VirtualMachine</b> to create your first VirtualMachine or view the{' '}
<Button isInline onClick={() => navigate(catalogURL)} variant={ButtonVariant.link}>
catalog tab
catalog
</Button>{' '}
to quickly create a VirtualMachine from the available Templates.
tab to create a VirtualMachine from the available options
</Trans>
</EmptyStateBody>
<EmptyStateFooter>
Expand All @@ -50,16 +52,11 @@ const VirtualMachineEmptyState: FC<VirtualMachineEmptyStateProps> = ({ catalogUR
namespace={namespace}
/>
</EmptyStateActions>
<br />
<EmptyStateActions>
<Button
onClick={() =>
navigate({ pathname: '/quickstart', search: '?keyword=virtual+machine' })
}
icon={<RocketIcon />}
variant={ButtonVariant.secondary}
>
{t('Learn how to use VirtualMachines')}
</Button>
<Link to={'/quickstart?keyword=virtual+machine'}>
{t('Learn how to use VirtualMachines')} <RouteIcon />
</Link>
</EmptyStateActions>
</EmptyStateFooter>
</EmptyState>
Expand Down

0 comments on commit 13187d0

Please sign in to comment.