Skip to content

Commit

Permalink
add column management to the custom list filter
Browse files Browse the repository at this point in the history
  • Loading branch information
upalatucci committed Oct 11, 2023
1 parent 8d1dc2d commit 79b3f1a
Show file tree
Hide file tree
Showing 14 changed files with 449 additions and 62 deletions.
5 changes: 3 additions & 2 deletions cypress/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
],
"plugins": ["cypress", "chai-friendly"],
"rules": {
"cypress/no-force": "error",
"cypress/assertion-before-screenshot": "error"
"chai-friendly/no-unused-expressions": "off",
"cypress/assertion-before-screenshot": "error",
"cypress/no-force": "error"
}
}
24 changes: 12 additions & 12 deletions cypress/cypress.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
{
"viewportWidth": 1920,
"viewportHeight": 1080,
"defaultCommandTimeout": 40000,
"fixturesFolder": false,
"integrationFolder": "tests",
"screenshotsFolder": "./gui-test-screenshots/screenshots/",
"videosFolder": "./gui-test-screenshots/videos/",
"video": true,
"pluginsFile": "plugin.js",
"reporter": "../node_modules/cypress-multi-reporters",
"reporterOptions": {
"configFile": "reporter-config.json"
},
"retries": {
"openMode": 0,
"runMode": 1
},
"screenshotOnRunFailure": true,
"screenshotsFolder": "./gui-test-screenshots/screenshots/",
"supportFile": "support.ts",
"pluginsFile": "plugin.js",
"fixturesFolder": false,
"defaultCommandTimeout": 30000,
"retries": {
"runMode": 1,
"openMode": 0
}
"video": true,
"videosFolder": "./gui-test-screenshots/videos/",
"viewportHeight": 1080,
"viewportWidth": 1920
}
10 changes: 10 additions & 0 deletions locales/en/plugin__kubevirt-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@
"Add tolerations to allow a VirtualMachine to schedule onto Nodes with matching taints.": "Add tolerations to allow a VirtualMachine to schedule onto Nodes with matching taints.",
"Add volume": "Add volume",
"Adding a bridged network interface to a running VirtualMachine is a Technology Preview feature that allows you to choose between live-migrating the VirtualMachine or restarting it to apply the changes. Enabling this feature requires cluster admin permissions.": "Adding a bridged network interface to a running VirtualMachine is a Technology Preview feature that allows you to choose between live-migrating the VirtualMachine or restarting it to apply the changes. Enabling this feature requires cluster admin permissions.",
"Additional column list": "Additional column list",
"Additional columns": "Additional columns",
"Additional disks types and interfaces are available when the VirtualMachine is stopped.": "Additional disks types and interfaces are available when the VirtualMachine is stopped.",
"Additional resources": "Additional resources",
"Additional statuses": "Additional statuses",
Expand Down Expand Up @@ -248,6 +250,7 @@
"Cluster administrator permissions are required to enable this feature.": "Cluster administrator permissions are required to enable this feature.",
"Cluster scope migrations": "Cluster scope migrations",
"Collapse": "Collapse",
"Column management": "Column management",
"Completion timeout": "Completion timeout",
"CompletionTimeoutPerGiB is the maximum number of seconds per GiB a migration is allowed to take. If a live-migration takes longer to migrate than this value multiplied by the size of the VMI, the migration will be cancelled, unless AllowPostCopy is true. Defaults to 800. ": "CompletionTimeoutPerGiB is the maximum number of seconds per GiB a migration is allowed to take. If a live-migration takes longer to migrate than this value multiplied by the size of the VMI, the migration will be cancelled, unless AllowPostCopy is true. Defaults to 800. ",
"Compute-intensive applications": "Compute-intensive applications",
Expand Down Expand Up @@ -337,6 +340,8 @@
"Decrement": "Decrement",
"Dedicated resources": "Dedicated resources",
"Default": "Default",
"Default {{resourceKind}} columns": "Default {{resourceKind}} columns",
"Default column list": "Default column list",
"Default InstanceType": "Default InstanceType",
"Default templates": "Default templates",
"Default value for this parameter": "Default value for this parameter",
Expand Down Expand Up @@ -605,6 +610,7 @@
"Make persistent disk": "Make persistent disk",
"Make persistent?": "Make persistent?",
"Make sure to have clone permissions in the destination namespace. <2>Learn more <1></1></2>": "Make sure to have clone permissions in the destination namespace. <2>Learn more <1></1></2>",
"Manage columns": "Manage columns",
"Manage source": "Manage source",
"Manage source for {{dataSource}}": "Manage source for {{dataSource}}",
"Manage SSH keys": "Manage SSH keys",
Expand Down Expand Up @@ -879,6 +885,7 @@
"Restart": "Restart",
"Restart the VirtualMachine to apply changes.": "Restart the VirtualMachine to apply changes.",
"Restore": "Restore",
"Restore default columns": "Restore default columns",
"Restore is enabled only for offline VirtualMachine.": "Restore is enabled only for offline VirtualMachine.",
"Restore snapshot": "Restore snapshot",
"Restore template settings": "Restore template settings",
Expand Down Expand Up @@ -934,6 +941,7 @@
"Select StorageClass": "Select StorageClass",
"Select volume to boot from": "Select volume to boot from",
"Select workloads that must have all the following expressions.": "Select workloads that must have all the following expressions.",
"Selected columns will appear in the table.": "Selected columns will appear in the table.",
"Selected StorageClass is different from StorageClass of the source": "Selected StorageClass is different from StorageClass of the source",
"Selected sysprep": "Selected sysprep",
"Selector": "Selector",
Expand Down Expand Up @@ -1060,6 +1068,7 @@
"The following information regarding how the disks are partitioned is provided by the guest agent.": "The following information regarding how the disks are partitioned is provided by the guest agent.",
"The following resources will be deleted along with this VirtualMachine. Unchecked items will not be deleted.": "The following resources will be deleted along with this VirtualMachine. Unchecked items will not be deleted.",
"The machine type defines the virtual hardware configuration while the operating system name and version refer to the hypervisor.": "The machine type defines the virtual hardware configuration while the operating system name and version refer to the hypervisor.",
"The namespace column is only shown when in \"All projects\"": "The namespace column is only shown when in \"All projects\"",
"The preferred VirtualMachine attribute values required to run a given workload.": "The preferred VirtualMachine attribute values required to run a given workload.",
"The template has": "The template has",
"The virtctl client is a supplemental command-line utility for managing virtualization resources from the command line.": "The virtctl client is a supplemental command-line utility for managing virtualization resources from the command line.",
Expand Down Expand Up @@ -1258,6 +1267,7 @@
"You can edit the boot order in the <1>{t('Disks tab')}</1>": "You can edit the boot order in the <1>{t('Disks tab')}</1>",
"You can host and manage virtualized workloads on the same platform as container-based workloads.": "You can host and manage virtualized workloads on the same platform as container-based workloads.",
"You can select the boot source in the <2>Disks</2> tab.": "You can select the boot source in the <2>Disks</2> tab.",
"You can select up to {{MAX_VIEW_COLS}} columns": "You can select up to {{MAX_VIEW_COLS}} columns",
"You can use cloud-init to initialize the operating system with a specific configuration when the VirtualMachine is started.": "You can use cloud-init to initialize the operating system with a specific configuration when the VirtualMachine is started.",
"You must ensure that the configuration is correct before starting the VirtualMachine.": "You must ensure that the configuration is correct before starting the VirtualMachine.",
"You're in view-only mode": "You're in view-only mode"
Expand Down
47 changes: 47 additions & 0 deletions src/utils/components/ColumnManagementModal/ColumnManagement.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { FC } from 'react';

import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { isEmpty } from '@kubevirt-utils/utils/utils';
import { ColumnLayout } from '@openshift-console/dynamic-plugin-sdk';
import { Button, ToolbarGroup, ToolbarItem, Tooltip } from '@patternfly/react-core';
import { ColumnsIcon } from '@patternfly/react-icons';

import { ColumnManagementModal } from '../ColumnManagementModal/ColumnManagementModal';
import { useModal } from '../ModalProvider/ModalProvider';

type ColumnManagementProps = {
columnLayout: ColumnLayout;
hideColumnManagement?: boolean;
};

const ColumnManagement: FC<ColumnManagementProps> = ({ columnLayout, hideColumnManagement }) => {
const { t } = useKubevirtTranslation();
const { createModal } = useModal();

if (isEmpty(columnLayout) || !columnLayout?.id || hideColumnManagement) {
return null;
}

return (
<ToolbarGroup>
<ToolbarItem>
<Tooltip content={t('Manage columns')} trigger="mouseenter">
<Button
onClick={() =>
createModal((props) => (
<ColumnManagementModal {...props} columnLayout={columnLayout} />
))
}
aria-label={t('Column management')}
data-test="manage-columns"
variant="plain"
>
<ColumnsIcon />
</Button>
</Tooltip>
</ToolbarItem>
</ToolbarGroup>
);
};

export default ColumnManagement;
193 changes: 193 additions & 0 deletions src/utils/components/ColumnManagementModal/ColumnManagementModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import React, { FC, MouseEventHandler, SyntheticEvent, useState } from 'react';

import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import useKubevirtUserSettingsTableColumns from '@kubevirt-utils/hooks/useKubevirtUserSettings/useKubevirtUserSettingsTableColumns';
import { ColumnLayout } from '@openshift-console/dynamic-plugin-sdk';
import {
ActionList,
ActionListItem,
Alert,
AlertVariant,
Button,
ButtonVariant,
DataList,
Form,
Modal,
ModalVariant,
Stack,
StackItem,
} from '@patternfly/react-core';

import { MAX_VIEW_COLS } from './constants';
import DataListRow from './DataListRow';
import { createInputId, getColumnId } from './utils';

import './column-management-modal.scss';

type ColumnManagementModalProps = {
columnLayout: ColumnLayout;
isOpen: boolean;
onClose: () => void;
};

export const ColumnManagementModal: FC<ColumnManagementModalProps> = ({
columnLayout,
isOpen,
onClose,
}) => {
const { t } = useKubevirtTranslation();
const { columns, id, selectedColumns, showNamespaceOverride, type } = columnLayout;

const defaultColumns = columns.filter((column) => column.id && !column.additional);
const additionalColumns = columns.filter((column) => column.additional);

const [_, setActiveColumns, loaded, error] = useKubevirtUserSettingsTableColumns({
columnManagementID: id,
columns,
});

const [checkedColumns, setCheckedColumns] = useState<Set<string>>(
selectedColumns && selectedColumns.size !== 0
? new Set(selectedColumns)
: new Set(defaultColumns.map((col) => col.id)),
);

const onColumnChange = (checked: boolean, event: SyntheticEvent): void => {
const updatedCheckedColumns = new Set<string>(checkedColumns);
const selectedId = getColumnId(event?.currentTarget?.id);
updatedCheckedColumns.has(selectedId)
? updatedCheckedColumns.delete(selectedId)
: updatedCheckedColumns.add(selectedId);
setCheckedColumns(updatedCheckedColumns);
};

const submit: MouseEventHandler<HTMLButtonElement> = async (event) => {
event.preventDefault();
const orderedCheckedColumns = new Set<string>();
checkedColumns.forEach((ids) => orderedCheckedColumns.add(ids));

await setActiveColumns([...orderedCheckedColumns]);
onClose();
};

const areMaxColumnsDisplayed = checkedColumns.size >= MAX_VIEW_COLS;

const resetColumns = (event: SyntheticEvent): void => {
event.preventDefault();
const updatedCheckedColumns = new Set(checkedColumns);
defaultColumns.forEach((col) => col.id && updatedCheckedColumns.add(col.id));
additionalColumns.forEach((col) => updatedCheckedColumns.delete(col.id));
setCheckedColumns(updatedCheckedColumns);
};

return (
<Modal
footer={
<Stack className="kv-tabmodal-footer" hasGutter>
{error && (
<StackItem>
<Alert isInline title={t('An error occurred')} variant={AlertVariant.danger}>
<Stack hasGutter>
<StackItem>{error.message}</StackItem>
</Stack>
</Alert>
</StackItem>
)}
<StackItem>
<ActionList className="column-management-modal__action-list">
<ActionListItem>
<Button key="reset" onClick={resetColumns} variant={ButtonVariant.link}>
{t('Restore default columns')}
</Button>
</ActionListItem>

<ActionListItem>
<Button onClick={onClose} variant={ButtonVariant.secondary}>
{t('Cancel')}
</Button>
</ActionListItem>
<ActionListItem>
<Button
form="modal-with-form-form"
isDisabled={!loaded}
isLoading={!loaded}
key="create"
onClick={submit}
variant={ButtonVariant.primary}
>
{t('Save')}
</Button>
</ActionListItem>
</ActionList>
</StackItem>
</Stack>
}
isOpen={isOpen}
onClose={onClose}
position="top"
title={t('Manage columns')}
variant={ModalVariant.medium}
>
<Form className="modal-content" name="form">
<div>
<p>{t('Selected columns will appear in the table.')}</p>
</div>
<div>
<Alert
className="co-alert"
isInline
title={t('You can select up to {{MAX_VIEW_COLS}} columns', { MAX_VIEW_COLS })}
variant={AlertVariant.info}
>
{!showNamespaceOverride &&
t('The namespace column is only shown when in "All projects"')}
</Alert>
</div>
<div className="row co-m-form-row">
<div className="col-sm-12">
<span className="col-sm-6">
<label className="control-label">
{t('Default {{resourceKind}} columns', { resourceKind: type })}
</label>
<DataList
aria-label={t('Default column list')}
id="defalt-column-management"
isCompact
>
{defaultColumns.map((defaultColumn) => (
<DataListRow
checkedColumns={checkedColumns}
column={defaultColumn}
disableUncheckedRow={areMaxColumnsDisplayed}
inputId={createInputId(defaultColumn.id)}
key={defaultColumn.id}
onChange={onColumnChange}
/>
))}
</DataList>
</span>
<span className="col-sm-6">
<label className="control-label">{t('Additional columns')}</label>
<DataList
aria-label={t('Additional column list')}
id="additional-column-management"
isCompact
>
{additionalColumns.map((additionalColumn) => (
<DataListRow
checkedColumns={checkedColumns}
column={additionalColumn}
disableUncheckedRow={areMaxColumnsDisplayed}
inputId={createInputId(additionalColumn.id)}
key={additionalColumn.id}
onChange={onColumnChange}
/>
))}
</DataList>
</span>
</div>
</div>
</Form>
</Modal>
);
};
Loading

0 comments on commit 79b3f1a

Please sign in to comment.