From c82d110737a6c79e8b5344c6221e5c8b8a947e25 Mon Sep 17 00:00:00 2001 From: Radoslaw Szwajkowski Date: Wed, 14 Sep 2022 16:28:43 +0200 Subject: [PATCH] Improve column management 1. prevent user from hiding columns needed to identify the row: Name and Namespace(in All Namespaces mode) 2. show Namespace column in All Namespaces mode and hide otherwise 3. provide links for resources displayed in the table --- .../en/plugin__forklift-console-plugin.json | 2 + src/Providers/ProvidersPage.tsx | 38 +++++++++++++-- src/Providers/components/EnumFilter.tsx | 3 -- .../components/ManageColumnsToolbar.tsx | 3 +- src/Providers/components/ProviderRow.tsx | 47 +++++++++++++------ src/Providers/components/shared.ts | 2 + 6 files changed, 72 insertions(+), 23 deletions(-) diff --git a/locales/en/plugin__forklift-console-plugin.json b/locales/en/plugin__forklift-console-plugin.json index d9671ede5..a2b5be64d 100644 --- a/locales/en/plugin__forklift-console-plugin.json +++ b/locales/en/plugin__forklift-console-plugin.json @@ -3,12 +3,14 @@ "Any": "Any", "Cancel": "Cancel", "FilterByName": "Filter by name", + "FilterByNamespace": "Filter by namespace", "FilterByStatus": "Filter by status", "FilterByType": "Filter by type", "FilterByUrl": "Filter by endpoint", "ManageColumns": "Manage columns", "Mappings for VM Import": "Mappings for VM Import", "Name": "Name", + "Namespace": "Namespace", "No": "No", "Openshift": "Openshift", "Ovirt": "oVirt", diff --git a/src/Providers/ProvidersPage.tsx b/src/Providers/ProvidersPage.tsx index fb227884a..811c75e8b 100644 --- a/src/Providers/ProvidersPage.tsx +++ b/src/Providers/ProvidersPage.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { useTranslation } from 'src/internal/i18n'; import { ProviderResource } from 'src/internal/k8s'; @@ -23,7 +23,7 @@ import { ManageColumnsToolbar } from './components/ManageColumnsToolbar'; import PrimaryFilters from './components/PrimaryFilters'; import ProviderRow from './components/ProviderRow'; import { createMetaMatcher, Field } from './components/shared'; -import { NAME, READY, TYPE, URL } from './components/shared'; +import { NAME, NAMESPACE, READY, TYPE, URL } from './components/shared'; import TableView from './components/TableView'; const isMock = process.env.DATA_SOURCE === 'mock'; @@ -54,6 +54,7 @@ const defaultFields: Field[] = [ id: NAME, tKey: 'plugin__forklift-console-plugin~Name', isVisible: true, + isIdentity: true, filter: { type: 'freetext', placeholderKey: 'plugin__forklift-console-plugin~FilterByName', @@ -61,6 +62,18 @@ const defaultFields: Field[] = [ sortable: true, toValue: (provider) => provider?.metadata?.name ?? '', }, + { + id: NAMESPACE, + tKey: 'plugin__forklift-console-plugin~Namespace', + isVisible: true, + isIdentity: true, + filter: { + type: 'freetext', + placeholderKey: 'plugin__forklift-console-plugin~FilterByNamespace', + }, + sortable: true, + toValue: (provider) => provider?.metadata?.namespace ?? '', + }, { id: READY, tKey: 'plugin__forklift-console-plugin~Ready', @@ -111,13 +124,27 @@ const defaultFields: Field[] = [ }, ]; +const useFields = (namespace, defaultFields) => { + const [fields, setFields] = useState(defaultFields); + const namespaceAwareFields = useMemo( + () => + fields.map(({ id, isVisible, ...rest }) => ({ + id, + ...rest, + isVisible: id === NAMESPACE ? !namespace : isVisible, + })), + [namespace, fields], + ); + return [namespaceAwareFields, setFields]; +}; + export const ProvidersPage = ({ namespace, kind }: ProvidersPageProps) => { const { t } = useTranslation(); const [providers, loaded, error] = useProviders({ kind, namespace }); const [selectedFilters, setSelectedFilters] = useState({}); - const [fields, setFields] = useState(defaultFields); + const [fields, setFields] = useFields(namespace, defaultFields); - console.error('Providers', defaultFields, fields); + console.error('Providers', defaultFields, fields, namespace, kind); return ( <> @@ -155,6 +182,7 @@ export const ProvidersPage = ({ namespace, kind }: ProvidersPageProps) => { fields={fields} defaultFields={defaultFields} setFields={setFields} + key={namespace ?? ''} /> @@ -170,7 +198,7 @@ export const ProvidersPage = ({ namespace, kind }: ProvidersPageProps) => { fields={fields} visibleFields={fields.filter(({ isVisible }) => isVisible)} aria-label={t('plugin__forklift-console-plugin~Providers')} - Row={ProviderRow} + Row={ProviderRow(kind)} /> )} diff --git a/src/Providers/components/EnumFilter.tsx b/src/Providers/components/EnumFilter.tsx index 762dc92a0..c2f71e30f 100644 --- a/src/Providers/components/EnumFilter.tsx +++ b/src/Providers/components/EnumFilter.tsx @@ -66,8 +66,6 @@ export const useUnique = ({ ...new Set(selectedEnumIds.map((id) => idToLabel[id]).filter(Boolean)), ] as string[]; - console.warn('non-unique', supportedEnumValues, selectedEnumIds); - console.warn('unique', filterNames, selectedFilters, idToLabel, labelToIds); return { filterNames, onFilterUpdate, selectedFilters }; }; @@ -119,7 +117,6 @@ const EnumFilter = ({ if (isPlaceholder) { return; } - console.error('select!', hasFilter(option), option); hasFilter(option) ? deleteFilter(option) : addFilter(option); }} selections={selectedFilters} diff --git a/src/Providers/components/ManageColumnsToolbar.tsx b/src/Providers/components/ManageColumnsToolbar.tsx index 789ab034c..ba95dfbf5 100644 --- a/src/Providers/components/ManageColumnsToolbar.tsx +++ b/src/Providers/components/ManageColumnsToolbar.tsx @@ -140,7 +140,7 @@ const ManageColumns = ({ id="table-column-management" isCompact > - {editedColumns.map(({ id, isVisible, tKey }) => ( + {editedColumns.map(({ id, isVisible, isIdentity, tKey }) => ( onSelect(id, value)} otherControls /> diff --git a/src/Providers/components/ProviderRow.tsx b/src/Providers/components/ProviderRow.tsx index 1af870db2..df4079cc3 100644 --- a/src/Providers/components/ProviderRow.tsx +++ b/src/Providers/components/ProviderRow.tsx @@ -5,15 +5,17 @@ import { ProviderResource } from 'src/internal/k8s'; import { getMostSeriousCondition, getStatusType } from '@app/common/helpers'; import { IStatusCondition } from '@app/queries/types'; 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 { NAME, READY, TYPE, URL } from './shared'; +import { NAME, NAMESPACE, READY, TYPE, URL } from './shared'; import { RowProps } from './TableView'; interface CellProps { value: string; resource: ProviderResource; t(key: string): string; + kind: string; } const StatusCell = ({ value, resource, t }: CellProps) => { return ( @@ -48,25 +50,42 @@ const StatusCell = ({ value, resource, t }: CellProps) => { const TextCell = ({ value }: CellProps) => <>{value}; +const ProviderLink = ({ value, resource, kind }: CellProps) => ( + +); + const cellCreator = { - [NAME]: TextCell, + [NAME]: ProviderLink, [READY]: StatusCell, [URL]: TextCell, [TYPE]: TextCell, + [NAMESPACE]: ({ value }: CellProps) => ( + + ), }; -const ProviderRow = ({ columns, resource }: RowProps) => { - const { t } = useTranslation(); +const ProviderRow = (kind: string) => + function ProviderRow({ columns, resource }: RowProps) { + const { t } = useTranslation(); - return ( - - {columns.map(({ id, tKey, toValue }) => ( - - {cellCreator?.[id]({ t, value: toValue(resource), resource }) ?? null} - - ))} - - ); -}; + return ( + + {columns.map(({ id, tKey, toValue }) => ( + + {cellCreator?.[id]?.({ + kind, + t, + value: toValue(resource), + resource, + }) ?? null} + + ))} + + ); + }; export default ProviderRow; diff --git a/src/Providers/components/shared.ts b/src/Providers/components/shared.ts index 0901703e1..6919c1bad 100644 --- a/src/Providers/components/shared.ts +++ b/src/Providers/components/shared.ts @@ -98,6 +98,7 @@ export interface Field { id: string; tKey: string; isVisible?: boolean; + isIdentity?: boolean; sortable?: boolean; filter: FilterDef; toValue: (provider: ProviderResource) => string; @@ -122,3 +123,4 @@ export const NAME = 'name'; export const READY = 'ready'; export const TYPE = 'type'; export const URL = 'url'; +export const NAMESPACE = 'namespace';