diff --git a/frontend/packages/console-app/src/components/data-view/ResourceDataView.tsx b/frontend/packages/console-app/src/components/data-view/ResourceDataView.tsx index e17c872dc51..552e47a20ce 100644 --- a/frontend/packages/console-app/src/components/data-view/ResourceDataView.tsx +++ b/frontend/packages/console-app/src/components/data-view/ResourceDataView.tsx @@ -134,10 +134,17 @@ export const ResourceDataView = < const basicFilters: React.ReactNode[] = []; if (!hideNameLabelFilters) { - basicFilters.push(); + basicFilters.push( + , + ); } - if (!hideNameLabelFilters && !hideLabelFilter) { + if (!hideNameLabelFilters && !hideLabelFilter && loaded) { basicFilters.push( , ); @@ -149,7 +156,7 @@ export const ResourceDataView = < // Can't use data in the deps array as it will recompute the filters and will cause the selected category to reset // eslint-disable-next-line react-hooks/exhaustive-deps - }, [additionalFilterNodes, t]); + }, [additionalFilterNodes, t, loaded]); return mock ? ( diff --git a/frontend/packages/console-app/src/components/data-view/useResourceDataViewData.tsx b/frontend/packages/console-app/src/components/data-view/useResourceDataViewData.tsx index 2906f38023e..1f47b2d0551 100644 --- a/frontend/packages/console-app/src/components/data-view/useResourceDataViewData.tsx +++ b/frontend/packages/console-app/src/components/data-view/useResourceDataViewData.tsx @@ -76,42 +76,35 @@ export const useResourceDataViewData = < const dataViewColumns = React.useMemo[]>( () => - activeColumns.map( - ( - { id, title, sort, props: { classes, isStickyColumn, stickyMinWidth, modifier } }, - index, - ) => { - const headerProps: ThProps = { - className: classes, - isStickyColumn, - stickyMinWidth, - modifier, + activeColumns.map(({ id, title, sort, props }, index) => { + const headerProps: ThProps = { + ...props, + dataLabel: title, + }; + + if (sort) { + headerProps.sort = { + columnIndex: index, + sortBy: { + index: 0, + direction: SortByDirection.asc, + defaultDirection: SortByDirection.asc, + }, }; - - if (sort) { - headerProps.sort = { - columnIndex: index, - sortBy: { - index: 0, - direction: SortByDirection.asc, - defaultDirection: SortByDirection.asc, - }, - }; - } - - return { - id, - title, - sortFunction: sort, - props: headerProps, - cell: title ? ( - {title} - ) : ( - {t('public~Actions')} - ), - }; - }, - ), + } + + return { + id, + title, + sortFunction: sort, + props: headerProps, + cell: title ? ( + {title} + ) : ( + {t('public~Actions')} + ), + }; + }), [activeColumns, t], ); diff --git a/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/alertmanager.cy.ts b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/alertmanager.cy.ts index b464bcea103..fece21d1f38 100644 --- a/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/alertmanager.cy.ts +++ b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/alertmanager.cy.ts @@ -75,10 +75,10 @@ describe('Alertmanager', () => { cy.byTestID('label-0').type(label); alertmanager.save(); alertmanager.validateCreation(receiverName, receiverType, label); - listPage.rows.clickKebabAction(receiverName, 'Delete Receiver'); + listPage.dvRows.clickKebabAction(receiverName, 'Delete Receiver'); warningModal.confirm('AlertmanagerDeleteReceiverConfirmation'); warningModal.shouldBeClosed('AlertmanagerDeleteReceiverConfirmation'); - listPage.rows.shouldNotExist(receiverName); + listPage.dvRows.shouldNotExist(receiverName); }); it('prevents deletion and form edit of a receiver with sub-route', () => { @@ -100,7 +100,7 @@ receivers: yamlEditor.clickSaveCreateButton(); cy.byTestID('alert-success').should('exist'); detailsPage.selectTab('Details'); - cy.get('[data-test-rows="resource-row"]') + cy.get('[data-test="data-view-table"]') .contains('team-X-pager') .parents('tr') .within(() => { @@ -180,7 +180,7 @@ route: yamlEditor.clickSaveCreateButton(); cy.get('.yaml-editor__buttons .pf-m-success').should('exist'); detailsPage.selectTab('Details'); - listPage.rows.shouldExist(receiverName); + listPage.dvRows.shouldExist(receiverName); alertmanager.visitEditPage(receiverName); cy.byTestID('label-0').should('have.value', matcher1); cy.byTestID('label-1').should('have.value', matcher2); diff --git a/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/pagerduty.cy.ts b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/pagerduty.cy.ts index fa6b9b0171e..bf556d8eb9a 100644 --- a/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/pagerduty.cy.ts +++ b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/pagerduty.cy.ts @@ -53,7 +53,7 @@ describe('Alertmanager: PagerDuty Receiver Form', () => { alertmanager.validateCreation(receiverName, receiverType, label); cy.log('update pagerduty_url'); - listPage.rows.clickKebabAction(receiverName, 'Edit Receiver'); + listPage.dvRows.clickKebabAction(receiverName, 'Edit Receiver'); // Save as default checkbox disabled when url equals global url cy.byTestID('save-as-default').should('be.disabled'); // changing url enables Save as default checkbox, should save pagerduty_url with Receiver diff --git a/frontend/packages/integration-tests-cypress/tests/crud/other-routes.cy.ts b/frontend/packages/integration-tests-cypress/tests/crud/other-routes.cy.ts index cf3bd8d043b..1ead06d2c58 100644 --- a/frontend/packages/integration-tests-cypress/tests/crud/other-routes.cy.ts +++ b/frontend/packages/integration-tests-cypress/tests/crud/other-routes.cy.ts @@ -41,7 +41,7 @@ describe('Visiting other routes', () => { }, { path: '/api-explorer', - waitFor: () => cy.get('[data-ouia-component-type$="TableRow"]').should('be.visible'), + waitFor: () => cy.get('[data-test="data-view-table"]').should('be.visible'), }, { path: '/api-resource/ns/default/core~v1~Pod', @@ -59,7 +59,7 @@ describe('Visiting other routes', () => { ? [ { path: '/api-resource/ns/default/core~v1~Pod/access', - waitFor: () => cy.get('[data-ouia-component-type$="TableRow"]').should('be.visible'), + waitFor: () => cy.get('[data-test="data-view-table"]').should('be.visible'), }, { path: '/k8s/cluster/user.openshift.io~v1~User', diff --git a/frontend/packages/integration-tests-cypress/views/alertmanager.ts b/frontend/packages/integration-tests-cypress/views/alertmanager.ts index 39baa287e2f..c7c7f5e9337 100644 --- a/frontend/packages/integration-tests-cypress/views/alertmanager.ts +++ b/frontend/packages/integration-tests-cypress/views/alertmanager.ts @@ -73,9 +73,9 @@ export const alertmanager = { validateCreation: (receiverName: string, type: string, label: string) => { cy.byLegacyTestID('item-filter').clear(); cy.byLegacyTestID('item-filter').type(receiverName); - listPage.rows.shouldExist(receiverName); - listPage.rows.shouldExist(type); - listPage.rows.shouldExist(label); + listPage.dvRows.shouldExist(receiverName); + listPage.dvRows.shouldExist(type); + listPage.dvRows.shouldExist(label); }, visitAlertmanagerPage: () => { cy.visit('/settings/cluster/alertmanagerconfig'); diff --git a/frontend/packages/integration-tests-cypress/views/list-page.ts b/frontend/packages/integration-tests-cypress/views/list-page.ts index 663d1cc2a4a..5da6a57a164 100644 --- a/frontend/packages/integration-tests-cypress/views/list-page.ts +++ b/frontend/packages/integration-tests-cypress/views/list-page.ts @@ -104,6 +104,12 @@ export const listPage = { shouldBeLoaded: () => { cy.get(`[data-test="data-view-table"]`).should('be.visible'); }, + shouldExist: (resourceName: string) => + cy.get(`[data-test="data-view-cell-${resourceName}-name"]`).contains(resourceName), + shouldNotExist: (resourceName: string) => + cy + .get(`[data-test="data-view-cell-${resourceName}-name"]`, { timeout: 90000 }) + .should('not.exist'), clickKebabAction: (resourceName: string, actionName: string) => { cy.get(`[data-test="data-view-cell-${resourceName}-name"]`) .contains(resourceName) diff --git a/frontend/public/components/alert-manager.tsx b/frontend/public/components/alert-manager.tsx index 5c0bb591347..ae0cb04aa52 100644 --- a/frontend/public/components/alert-manager.tsx +++ b/frontend/public/components/alert-manager.tsx @@ -1,7 +1,6 @@ +import * as React from 'react'; import { useCallback } from 'react'; -import i18next from 'i18next'; import { useTranslation } from 'react-i18next'; -import { sortable } from '@patternfly/react-table'; import { Button, DescriptionList, @@ -14,11 +13,21 @@ import { import { PencilAltIcon } from '@patternfly/react-icons/dist/esm/icons/pencil-alt-icon'; import PaneBody from '@console/shared/src/components/layout/PaneBody'; -import { referenceForModel, K8sResourceKind } from '../module/k8s'; -import { ListPage, DetailsPage, Table, TableData, RowFunctionArgs } from './factory'; +import { referenceForModel, K8sResourceKind, TableColumn } from '../module/k8s'; +import { ListPage, DetailsPage } from './factory'; +import { + actionsCellProps, + cellIsStickyProps, + getNameCellProps, + initialFiltersDefault, + ResourceDataView, +} from '@console/app/src/components/data-view/ResourceDataView'; +import { GetDataViewRows } from '@console/app/src/components/data-view/types'; import { SectionHeading, LabelList, navFactory, ResourceLink, Selector, pluralize } from './utils'; import { useConfigureCountModal } from './modals/configure-count-modal'; import { AlertmanagerModel } from '../models'; +import { LoadingBox } from './utils/status-box'; +import { LazyActionMenu } from '@console/shared'; const Details: React.FCC = (props) => { const alertManager = props.obj; @@ -97,93 +106,151 @@ const Details: React.FCC = (props) => { }; const { details, editYaml } = navFactory; +const kind = referenceForModel(AlertmanagerModel); export const AlertManagersDetailsPage = (props) => ( ); -const tableColumnClasses = [ - '', - '', - 'pf-m-hidden pf-m-visible-on-md pf-v6-u-w-25-on-md', - 'pf-m-hidden pf-m-visible-on-lg', - 'pf-m-hidden pf-m-visible-on-lg pf-v6-u-w-25-on-lg', +const tableColumnInfo = [ + { id: 'name' }, + { id: 'namespace' }, + { id: 'labels' }, + { id: 'version' }, + { id: 'nodeSelector' }, + { id: 'actions' }, ]; -const AlertManagerTableRow: React.FC> = ({ - obj: alertManager, -}) => { - const { metadata, spec } = alertManager; - return ( - <> - - - - - - - - - - {spec.version} - - - - - ); -}; +const getDataViewRows: GetDataViewRows = (data, columns) => { + return data.map(({ obj: alertManager }) => { + const { metadata, spec } = alertManager; + const resourceKind = referenceForModel(AlertmanagerModel); + const context = { [resourceKind]: alertManager }; -const AlertManagerTableHeader = () => { - return [ - { - title: i18next.t('public~Name'), - sortField: 'metadata.name', - transforms: [sortable], - props: { className: tableColumnClasses[0] }, - }, - { - title: i18next.t('public~Namespace'), - sortField: 'metadata.namespace', - transforms: [sortable], - props: { className: tableColumnClasses[1] }, - }, - { - title: i18next.t('public~Labels'), - sortField: 'metadata.labels', - transforms: [sortable], - props: { className: tableColumnClasses[2] }, - }, - { - title: i18next.t('public~Version'), - sortField: 'spec.version', - transforms: [sortable], - props: { className: tableColumnClasses[3] }, - }, - { - title: i18next.t('public~Node selector'), - sortField: 'spec.nodeSelector', - transforms: [sortable], - props: { className: tableColumnClasses[4] }, - }, - ]; + const rowCells = { + [tableColumnInfo[0].id]: { + cell: ( + + ), + props: getNameCellProps(metadata.name), + }, + [tableColumnInfo[1].id]: { + cell: ( + + ), + }, + [tableColumnInfo[2].id]: { + cell: , + props: { + modifier: 'nowrap', + width: 20, + }, + }, + [tableColumnInfo[3].id]: { + cell: spec.version || '-', + }, + [tableColumnInfo[4].id]: { + cell: , + props: { + modifier: 'nowrap', + width: 20, + }, + }, + [tableColumnInfo[5].id]: { + cell: , + props: actionsCellProps, + }, + }; + + return columns.map(({ id }) => { + const cell = rowCells[id]?.cell || '-'; + return { + id, + props: rowCells[id]?.props, + cell, + }; + }); + }); }; -AlertManagerTableHeader.displayName = 'AlertManagerTableHeader'; -const AlertManagersList = (props) => { +const useAlertManagerColumns = (): TableColumn[] => { const { t } = useTranslation(); + const columns = React.useMemo(() => { + return [ + { + title: t('public~Name'), + id: tableColumnInfo[0].id, + sort: 'metadata.name', + props: { + ...cellIsStickyProps, + modifier: 'nowrap', + }, + }, + { + title: t('public~Namespace'), + id: tableColumnInfo[1].id, + sort: 'metadata.namespace', + props: { + modifier: 'nowrap', + }, + }, + { + title: t('public~Labels'), + id: tableColumnInfo[2].id, + sort: 'metadata.labels', + props: { + modifier: 'nowrap', + }, + }, + { + title: t('public~Version'), + id: tableColumnInfo[3].id, + sort: 'spec.version', + props: { + modifier: 'nowrap', + }, + }, + { + title: t('public~Node selector'), + id: tableColumnInfo[4].id, + sort: 'spec.nodeSelector', + props: { + modifier: 'nowrap', + }, + }, + { + title: '', + id: tableColumnInfo[5].id, + props: { + ...cellIsStickyProps, + }, + }, + ]; + }, [t]); + return columns; +}; + +const AlertManagersList: React.FCC = ({ data, loaded, ...props }) => { + const columns = useAlertManagerColumns(); + return ( - + }> + + ); }; @@ -192,10 +259,17 @@ export const AlertManagersPage = (props) => ( {...props} ListComponent={AlertManagersList} canCreate={false} - kind={referenceForModel(AlertmanagerModel)} + kind={kind} + omitFilterToolbar={true} /> ); type DetailsProps = { obj: K8sResourceKind; }; + +type AlertManagersListProps = { + data: K8sResourceKind[]; + loaded: boolean; + [key: string]: any; +}; diff --git a/frontend/public/components/api-explorer.tsx b/frontend/public/components/api-explorer.tsx index b742daec46e..c24bb2ee996 100644 --- a/frontend/public/components/api-explorer.tsx +++ b/frontend/public/components/api-explorer.tsx @@ -8,10 +8,6 @@ import { DocumentTitle } from '@console/shared/src/components/document-title/Doc import { Map as ImmutableMap } from 'immutable'; import * as fuzzy from 'fuzzysearch'; import { - Toolbar, - ToolbarContent, - ToolbarItem, - ToolbarToggleGroup, Switch, FlexItem, Flex, @@ -20,12 +16,11 @@ import { DescriptionListTerm, DescriptionListDescription, } from '@patternfly/react-core'; -import { FilterIcon } from '@patternfly/react-icons/dist/esm/icons/filter-icon'; import { sortable } from '@patternfly/react-table'; import { useTranslation } from 'react-i18next'; import i18next from 'i18next'; -import { ALL_NAMESPACES_KEY, FLAGS, APIError, getTitleForNodeKind } from '@console/shared'; +import { ALL_NAMESPACES_KEY, FLAGS, APIError, getTitleForNodeKind, DASH } from '@console/shared'; import { useExactSearch } from '@console/app/src/components/user-preferences/search/useExactSearch'; import { PageTitleContext } from '@console/shared/src/components/pagetitle/PageTitleContext'; import { Page, useAccessReview } from '@console/internal/components/utils'; @@ -50,6 +45,14 @@ import { RowFilter } from './row-filter'; import { DefaultPage } from './default-resource'; import { Table, TextFilter } from './factory'; import { exactMatch, fuzzyCaseInsensitive } from './factory/table-filters'; +import { + cellIsStickyProps, + getNameCellProps, + initialFiltersDefault, + ResourceDataView, +} from '@console/app/src/components/data-view/ResourceDataView'; +import { GetDataViewRows } from '@console/app/src/components/data-view/types'; + import { getResourceListPages } from './resource-pages'; import { ExploreType } from './sidebars/explore-type-sidebar'; import { ConsoleSelect } from '@console/internal/components/utils/console-select'; @@ -60,10 +63,8 @@ import { LinkifyExternal, LoadError, LoadingBox, - removeQueryArgument, ResourceIcon, ScrollToTopOnMount, - setQueryArgument, } from './utils'; import { isResourceListPage, useExtensions, ResourceListPage } from '@console/plugin-sdk'; import { @@ -114,11 +115,6 @@ const APIResourceLink = connect = () => { - const { t } = useTranslation(); - return ; -}; - const Group: React.FC<{ value: string }> = ({ value }) => { if (!value) { return <>-; @@ -134,42 +130,116 @@ const Group: React.FC<{ value: string }> = ({ value }) => { ); }; - -const tableClasses = [ - 'pf-v6-u-w-25-on-2xl', - 'pf-v6-u-w-16-on-2xl', - 'pf-v6-u-w-16-on-lg pf-v6-u-w-10-on-2xl', - 'pf-m-hidden pf-m-visible-on-xl pf-v6-u-w-16-on-lg', - 'pf-m-hidden pf-m-visible-on-lg', +const TableColumnInfo = [ + { id: 'kind' }, + { id: 'group' }, + { id: 'version' }, + { id: 'namespaced' }, + { id: 'description' }, ]; -const APIResourceRows = ({ componentProps: { data } }) => - _.map(data, (model: K8sKind) => [ - { - title: , - props: { className: tableClasses[0] }, - }, - { - title: ( - - - - ), - props: { className: tableClasses[1] }, - }, - { - title: model.apiVersion, - props: { className: tableClasses[2] }, - }, - { - title: model.namespaced ? i18next.t('public~true') : i18next.t('public~false'), - props: { className: tableClasses[3] }, - }, - { - title:
{getResourceDescription(model)}
, - props: { className: tableClasses[4] }, - }, - ]); +const getAPIExplorerDataViewRows: GetDataViewRows = (data, columns) => { + return data.map(({ obj: model }) => { + const rowCells = { + [TableColumnInfo[0].id]: { + cell: , + props: getNameCellProps(model.kind), + }, + [TableColumnInfo[1].id]: { + cell: ( + + + + ), + props: { + modifier: 'nowrap', + }, + }, + [TableColumnInfo[2].id]: { + cell: model.apiVersion, + }, + [TableColumnInfo[3].id]: { + cell: model.namespaced ? i18next.t('public~true') : i18next.t('public~false'), + props: { + modifier: 'nowrap', + props: { + width: 20, + }, + }, + }, + [TableColumnInfo[4].id]: { + cell:
{getResourceDescription(model)}
, + props: { + modifier: 'wrap', + width: 40, + }, + }, + }; + + return columns.map(({ id }) => { + const cell = rowCells[id]?.cell || DASH; + return { + id, + props: rowCells[id]?.props, + cell, + }; + }); + }); +}; + +const useAPIExplorerColumns = () => { + const { t } = useTranslation(); + const columns = React.useMemo(() => { + return [ + { + title: t('public~Kind'), + id: TableColumnInfo[0].id, + sort: 'kind', + props: { + ...cellIsStickyProps, + modifier: 'nowrap', + 'data-test-id': 'api-kind-header', + }, + }, + { + title: t('public~Group'), + id: TableColumnInfo[1].id, + sort: 'apiGroup', + props: { + modifier: 'nowrap', + 'data-test-id': 'api-group-header', + }, + }, + { + title: t('public~Version'), + id: TableColumnInfo[2].id, + sort: 'apiVersion', + props: { + modifier: 'nowrap', + 'data-test-id': 'api-version-header', + }, + }, + { + title: t('public~Namespaced'), + id: TableColumnInfo[3].id, + sort: 'namespaced', + props: { + modifier: 'nowrap', + 'data-test-id': 'api-namespaced-header', + }, + }, + { + title: t('public~Description'), + id: TableColumnInfo[4].id, + props: { + modifier: 'nowrap', + 'data-test-id': 'api-description-header', + }, + }, + ]; + }, [t]); + return columns; +}; const stateToProps = ({ k8s }) => ({ models: k8s.getIn(['RESOURCES', 'models']), @@ -185,24 +255,14 @@ const APIResourcesList = compose( const TEXT_FILTER_PARAM = 'q'; const SCOPE_PARAM = 's'; const search = new URLSearchParams(location.search); - // Differentiate between an empty group and an unspecified param. const groupFilter = search.has(GROUP_PARAM) ? search.get(GROUP_PARAM) : ALL; const versionFilter = search.get(VERSION_PARAM) || ALL; const textFilter = search.get(TEXT_FILTER_PARAM) || ''; const scopeFilter = search.get(SCOPE_PARAM) || ALL; - const { t } = useTranslation(); - // group options const groups: Set = models.reduce((result: Set, { apiGroup }) => { return apiGroup ? result.add(apiGroup) : result; }, new Set()); const sortedGroups: string[] = [...groups].sort(); - const groupOptions = sortedGroups.reduce( - (result, group: string) => { - result[group] = ; - return result; - }, - { [ALL]: t('public~All groups'), '': t('public~No group') }, - ); const [isExactSearch] = useExactSearch(); const matchFn: Function = isExactSearch ? exactMatch : fuzzyCaseInsensitive; @@ -211,35 +271,17 @@ const APIResourcesList = compose( groupSpacer.add(sortedGroups[0]); } - const autocompleteGroups = (text: string, _item: string, key: string): boolean => { - return key !== ALL && fuzzy(text, key); - }; - // version options const versions: Set = models.reduce((result: Set, { apiVersion }) => { return result.add(apiVersion); }, new Set()); const sortedVersions: string[] = [...versions].sort(); - const versionOptions = sortedVersions.reduce( - (result, version: string) => { - result[version] = version; - return result; - }, - { [ALL]: t('public~All versions') }, - ); const versionSpacer = new Set(); if (sortedVersions.length) { versionSpacer.add(sortedVersions[0]); } - const scopeOptions = { - [ALL]: t('public~All scopes'), - cluster: t('public~Cluster'), - namespace: t('public~Namespace'), - }; - const scopeSpacer = new Set(['cluster']); - // filter by group, version, or text const filteredResources = models.filter(({ kind, apiGroup, apiVersion, namespaced }) => { if (groupFilter !== ALL && (apiGroup || '') !== groupFilter) { @@ -272,113 +314,25 @@ const APIResourcesList = compose( 'kind', ]); - const updateURL = (k: string, v: string) => { - if (v === ALL) { - removeQueryArgument(k); - } else { - setQueryArgument(k, v); - } - }; - const onGroupSelected = (group: string) => updateURL(GROUP_PARAM, group); - const onVersionSelected = (version: string) => updateURL(VERSION_PARAM, version); - const onScopeSelected = (scope: string) => updateURL(SCOPE_PARAM, scope); - const setTextFilter = (text: string) => { - if (!text) { - removeQueryArgument(TEXT_FILTER_PARAM); - } else { - setQueryArgument(TEXT_FILTER_PARAM, text); - } - }; - - const APIResourceHeader = () => [ - { - title: t('public~Kind'), - sortField: 'kind', - transforms: [sortable], - props: { className: tableClasses[0] }, - }, - { - title: t('public~Group'), - sortField: 'apiGroup', - transforms: [sortable], - props: { className: tableClasses[1] }, - }, - { - title: t('public~Version'), - sortField: 'apiVersion', - transforms: [sortable], - props: { className: tableClasses[2] }, - }, - { - title: t('public~Namespaced'), - sortField: 'namespaced', - transforms: [sortable], - props: { className: tableClasses[3] }, - }, - { - title: t('public~Description'), - props: { className: tableClasses[4] }, - }, - ]; - return ( - - - } breakpoint="md"> - - - - - - - - - - - - setTextFilter(value)} - /> - - - -
+ }> + + data={sortedResources.map((model) => ({ + ...model, + metadata: { + name: model.kind, + uid: model.kind, + }, + }))} + loaded={!!models.size} + columns={useAPIExplorerColumns()} + initialFilters={initialFiltersDefault} + getDataViewRows={getAPIExplorerDataViewRows} + hideColumnManagement={true} + label="API resources" + /> + ); }); diff --git a/frontend/public/components/factory/list-page.tsx b/frontend/public/components/factory/list-page.tsx index 9a41d7547ab..92788b33a6c 100644 --- a/frontend/public/components/factory/list-page.tsx +++ b/frontend/public/components/factory/list-page.tsx @@ -147,6 +147,7 @@ export const ListPageWrapper: React.FC = (props) => { hideLabelFilter={hideLabelFilter} columnLayout={columnLayout} uniqueFilterName={name} + omitFilterToolbar={omitFilterToolbar} {...props} /> ); diff --git a/frontend/public/components/factory/table.tsx b/frontend/public/components/factory/table.tsx index 99a5c68bf5b..cb183885056 100644 --- a/frontend/public/components/factory/table.tsx +++ b/frontend/public/components/factory/table.tsx @@ -55,7 +55,7 @@ import { podPhase, podReadiness, podRestarts } from '../../module/k8s/pods'; import { useTableData } from './table-data-hook'; import TableHeader from './Table/TableHeader'; -const sorts = { +export const sorts = { alertingRuleStateOrder, alertSeverityOrder, crdLatestVersion: (crd: CustomResourceDefinitionKind): string => getLatestVersionForCRD(crd), diff --git a/frontend/public/components/monitoring/alertmanager/alertmanager-config.tsx b/frontend/public/components/monitoring/alertmanager/alertmanager-config.tsx index e76b327c4b7..a6c77f0334b 100644 --- a/frontend/public/components/monitoring/alertmanager/alertmanager-config.tsx +++ b/frontend/public/components/monitoring/alertmanager/alertmanager-config.tsx @@ -323,7 +323,13 @@ const ReceiverTableRow: React.FC - {receiver.name} + + {receiver.name} + {(receiver.name === InitialReceivers.Critical || receiver.name === InitialReceivers.Default) && diff --git a/frontend/public/locales/en/public.json b/frontend/public/locales/en/public.json index 088b06321df..d8dbf29f812 100644 --- a/frontend/public/locales/en/public.json +++ b/frontend/public/locales/en/public.json @@ -16,7 +16,6 @@ "Labels": "Labels", "Version": "Version", "Node selector": "Node selector", - "Alertmanagers": "Alertmanagers", "API resources": "API resources", "true": "true", "false": "false", @@ -1556,6 +1555,7 @@ "ServiceMonitors": "ServiceMonitors", "PodMonitor": "PodMonitor", "PodMonitors": "PodMonitors", + "Alertmanagers": "Alertmanagers", "Service": "Service", "Services": "Services", "DaemonSet": "DaemonSet",