Skip to content
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
12 changes: 10 additions & 2 deletions frontend/packages/console-plugin-sdk/src/typings/pages.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { RouteProps, RouteComponentProps } from 'react-router';
import { K8sKind, K8sResourceKindReference } from '@console/internal/module/k8s';
import { K8sKind, K8sResourceKindReference, K8sResourceKind } from '@console/internal/module/k8s';
import { Extension } from './extension';

type LazyLoader<T> = () => Promise<React.ComponentType<T>>;
Expand All @@ -13,6 +13,11 @@ namespace ExtensionProperties {
loader: LazyLoader<T>;
}

interface ResourceListFilterGroups {
selected: any;
all: string[];
}

export type ResourceListPage = ResourcePage<{
/** See https://reacttraining.com/react-router/web/api/match */
match?: RouteComponentProps['match'];
Expand All @@ -24,7 +29,10 @@ namespace ExtensionProperties {
mock?: boolean;
/** The namespace scope. */
namespace?: string;
}>;
}> & {
/** Function. If "true" is returned then particular item is included in the list. */
filter?: (filterGroups: ResourceListFilterGroups, obj: K8sResourceKind) => boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mareklibra If I understand correctly, this PR is effectively about extending the listFilters object declared in public/components/factory/list.tsx, which is used to filter List component's rendered data.

The ResourceListPage extension makes Console aware of additional list pages, mapping model to page component to handle listing for that model. The implementation of the entire list page component is provided by the plugin.

Therefore, I think a better approach is to make the List component itself extensible in terms of list filters used.

ListInnerProps already includes filters, this value is used to lookup the corresponding filter impl. within the listFilters object. So I'd suggest doing the following:

Step 1, improve typing of list filters. In the List component:

  • add ListFilterGroups type (the Resource prefix is not needed)
  • add type: type ListFilter = (groups: ListFilterGroups, obj: K8sResourceKind) => boolean;
  • update listFilters object to use ListFilter type consistently, for example:
    • 'name': (filter, obj): ListFilter => fuzzyCaseInsensitive(filter, obj.metadata.name),
  • adapt ListFilterGroups type if necessary (add properties like values etc.)

Step 2, allow extension of built-in list filters. In the List component:

  • in ListInnerProps, add customFilterFuncs?: {[name: string]: ListFilter};
  • in stateToProps
    • add customFilterFuncs = {} to props object destructuring assignment
    • change getFilteredRows(allFilters, data); to getFilteredRows(allFilters, data, customFilterFuncs);
  • in getFilteredRows
    • const filter = listFilters[name] || customFilterFuncs[name];
  • in filterPropType
    • if (key in listFilters || key in customFilterFuncs || key === 'loadTest') { continue; }

Step 3, use the newly introduced customFilterFuncs prop of List component in VirtualMachinesPage.

This way, we have a List component that supports using custom filters in addition to ones that are built-in.

cc @christianvogt @spadgett

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the List component is deprecated and soon to be removed! We should be making these changes to table.tsx.

Copy link
Contributor

@vojtechszocs vojtechszocs Jun 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I'll look into this.

What we actually need here is adding new prop to Table component (successor of List) that allows us to extend the built-in tableFilters.

(This is unrelated to resource list page mapping extension point.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the filter be named and allow more than one?

    filters?:  { [key: string]: (filterGroups: ResourceListFilterGroups, obj: K8sResourceKind) => boolean };

};

export type ResourceDetailsPage = ResourcePage<{
/** See https://reacttraining.com/react-router/web/api/match */
Expand Down
27 changes: 27 additions & 0 deletions frontend/public/components/factory/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
getTemplateInstanceStatus,
getNodeRoles,
} from '../../module/k8s';
import * as plugins from '../../plugins';

const fuzzyCaseInsensitive = (a, b) => fuzzy(_.toLower(a), _.toLower(b));

Expand Down Expand Up @@ -194,6 +195,32 @@ const listFilters = {
},
};

/* Append filters from plugins

TODO(mlibra):
Some objects (like VirtualMachines) require to query additional objects
to fully asses state (like pods and CRs in the case of a VirtualMachine).
Recent filtering logic can handle just a single "listed" object.
We will need to find a way how to pass additional resources there.
*/
(function () {
const baseListCount = Object.keys(listFilters).length;

plugins.registry.getResourceListPages()
.filter(rlp => !!rlp.properties.filter)
.forEach(rlp => {
if (listFilters[rlp.properties.model.kind]) {
// eslint-disable-next-line no-console
console.warn(`List filter for ${rlp.properties.model.kind} already defined, skipping.`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this check to a unit test.
fyi @vojtechszocs

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is exactly the purpose of #1708 - run extension checks as part of yarn test while keeping the runtime browser console log cleaner.

} else {
listFilters[rlp.properties.model.kind] = rlp.properties.filter;
}
});

// eslint-disable-next-line no-console
console.info(`${Object.keys(listFilters).length - baseListCount} new list filters added by plugins.`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really necessary?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in-line with a former convention to inform users about extensions being applied & any potential conflicts.

With #1708 we no longer need this because

  • conflicts are detected via extension checks (test phase)
  • reporting on various extensions is meant to be done via plugin-stats (printed as part of the Console webpack build)

})();

const getFilteredRows = (_filters, objects) => {
if (_.isEmpty(_filters)) {
return objects;
Expand Down