Skip to content

Commit

Permalink
Merge pull request #8757 from richard-cox/forced-project-filtering
Browse files Browse the repository at this point in the history
Expand enforced namespace filtering to multiple namespaces and projects
  • Loading branch information
richard-cox authored May 18, 2023
2 parents 59aef1f + 5feb263 commit 762987d
Show file tree
Hide file tree
Showing 21 changed files with 414 additions and 216 deletions.
6 changes: 3 additions & 3 deletions pkg/epinio/store/epinio-store/getters.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EPINIO_TYPES } from '../../types';
import {
NAMESPACE_FILTER_SPECIAL as SPECIAL,
NAMESPACE_FILTER_ALL as ALL
NAMESPACE_FILTER_ALL as ALL,
NAMESPACE_FILTER_KINDS
} from '@shell/utils/namespace-filter';

export default {
Expand Down Expand Up @@ -51,7 +51,7 @@ export default {
}: any) => {
const out = [{
id: ALL,
kind: SPECIAL,
kind: NAMESPACE_FILTER_KINDS.SPECIAL,
label: rootGetters['i18n/t']('nav.ns.all'),
}];

Expand Down
16 changes: 8 additions & 8 deletions shell/assets/translations/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4591,8 +4591,8 @@ resourceList:
create: Create
createFromYaml: Create from YAML
createResource: "Create {resourceName}"
nsFiltering: "There are too many {resource}.<br>Please filter them by selecting a Namespace above."
nsFilterToolTip: "There are too many resources, filtering is restricted to a single {mode}."
nsFiltering: "Please select one or more namespaces or projects using the filter above."
nsFilterToolTip: "Filtering is restricted to projects and namespaces"
resourceLoadingIndicator:
loading: Loading

Expand Down Expand Up @@ -6994,6 +6994,7 @@ performance:
When enabled, resources will appear more quickly, but it may take slightly longer to load the entire set of resources. This setting only applies to resources that come from the Kubernetes API
checkboxLabel: Enable incremental loading
inputLabel: Resource Threshold
incompatibleDescription: "Incremental Loading is incomaptible with Namespace/Project filtering. Enabling this will disable it."
manualRefresh:
label: Manual Refresh
setting: You can configure a threshold above which manual refresh will be enabled.
Expand All @@ -7002,6 +7003,7 @@ performance:
When enabled, list data will not auto-update but instead the user must manually trigger a list-view refresh. This setting only applies to resources that come from the Kubernetes API
checkboxLabel: Enable manual refresh of data for lists
inputLabel: Resource Threshold
incompatibleDescription: "Manual Refresh is incomaptible with Namespace/Project filtering. Enabling this will disable it."
websocketNotification:
label: Websocket Notifications
description: |-
Expand Down Expand Up @@ -7029,12 +7031,10 @@ performance:
description: Resource types must exceed this amount to be considered for garbage collection.
inputLabel: Resource Count
nsFiltering:
label: Require Namespace Filtering
description: When there are too many resources to show in a list, require the user to select a single namespace and only fetch resources from within it.
checkboxLabel: Enable Required Namespace Filtering
count:
inputLabel: Resource Threshold
description: The threshold above which filtering by a namespace is required
label: Require Namespace / Project Filtering
description: Require the user to select namespaces and/or projects. This restricts the number of resources fetched when viewing lists and should help the responsiveness of the UI in systems with a lot of resources.
checkboxLabel: Enable Required Namespace / Project Filtering
incompatibleDescription: "Required Namespace / Project Filtering is incomaptible with Manual Refresh and Incremental Loading. Enabling this will disable them."
advancedWorker:
label: Websocket Web Worker
description: Updates to resources pushed to the UI come via WebSocket and are handled in the UI thread. Enable this option to handle cluster WebSocket updates in a Web Worker in a separate thread. This should help the responsiveness of the UI in systems where resources change often.
Expand Down
6 changes: 0 additions & 6 deletions shell/components/ResourceList/Masthead.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,6 @@ export default {
default: false
},
loadNamespace: {
type: String,
default: null
},
showIncrementalLoadingIndicator: {
type: Boolean,
default: false
Expand Down Expand Up @@ -183,7 +178,6 @@ export default {
v-if="showIncrementalLoadingIndicator"
:resources="loadResources"
:indeterminate="loadIndeterminate"
:namespace="loadNamespace"
/>
</div>
<div class="actions-container">
Expand Down
10 changes: 1 addition & 9 deletions shell/components/ResourceList/ResourceLoadingIndicator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ export default {
type: Boolean,
default: false,
},
namespace: {
type: String,
default: undefined
},
},
data() {
Expand All @@ -44,10 +40,6 @@ export default {
// Have we loaded all resources for the types that are needed
haveAll() {
return this.resources.reduce((acc, r) => {
if (this.namespace) {
return acc && this.$store.getters[`${ this.inStore }/haveAllNamespace`](r, this.namespace);
}
return acc && this.$store.getters[`${ this.inStore }/haveAll`](r);
}, true);
},
Expand All @@ -58,7 +50,7 @@ export default {
return this.resources.reduce((acc, r) => {
const resourceCounts = clusterCounts?.[0]?.counts?.[r];
const resourceCount = this.namespace ? resourceCounts?.namespaces?.[this.namespace]?.count : resourceCounts?.summary?.count;
const resourceCount = resourceCounts?.summary?.count;
const count = resourceCount || 0;
return acc + count;
Expand Down
13 changes: 7 additions & 6 deletions shell/components/ResourceList/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import IconMessage from '@shell/components/IconMessage.vue';
import { ResourceListComponentName } from './resource-list.config';
import { PanelLocation, ExtensionPoint } from '@shell/core/types';
import ExtensionPanel from '@shell/components/ExtensionPanel';
import { sameContents } from 'utils/array';
export default {
name: ResourceListComponentName,
Expand Down Expand Up @@ -146,7 +147,11 @@ export default {
*
* This covers case 1
*/
namespaceFilter(neu) {
namespaceFilter(neu, old) {
if (sameContents(neu, old)) {
return;
}
if (neu && !this.hasFetch) {
this.$fetchType(this.resource);
}
Expand Down Expand Up @@ -176,10 +181,7 @@ export default {
icon="icon-filter_alt"
>
<template #message>
<span
v-clean-html="t('resourceList.nsFiltering', { resource: $store.getters['type-map/labelFor'](schema, 2) || customTypeDisplay }, true)"
class="filter"
/>
{{ t('resourceList.nsFiltering') }}
</template>
</IconMessage>
<div v-else>
Expand All @@ -191,7 +193,6 @@ export default {
:show-incremental-loading-indicator="showIncrementalLoadingIndicator"
:load-resources="loadResources"
:load-indeterminate="loadIndeterminate"
:load-namespace="namespaceFilter"
>
<template slot="extraActions">
<slot name="extraActions" />
Expand Down
16 changes: 13 additions & 3 deletions shell/components/ResourceTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,12 @@ export default {
return acc;
}, {});
return { listGroups, listGroupMapped };
// Confirm which store we're in, if schema isn't available we're probably showing a list with different types
const inStore = this.schema?.id ? this.$store.getters['currentStore'](this.schema.id) : undefined;
return {
listGroups, listGroupMapped, inStore
};
},
computed: {
Expand Down Expand Up @@ -244,8 +249,13 @@ export default {
filteredRows() {
const isAll = this.$store.getters['isAllNamespaces'];
// If the resources isn't namespaced or we want ALL of them, there's nothing to do.
if ( !this.isNamespaced || (isAll && !this.currentProduct?.hideSystemResources) || this.ignoreFilter) {
// Do we need to filter by namespace like things?
if (
!this.isNamespaced || // Resource type isn't namespaced
this.ignoreFilter || // Component owner strictly states no filtering
(isAll && !this.currentProduct?.hideSystemResources) || // Need all
(this.inStore ? this.$store.getters[`${ this.inStore }/haveNamespace`](this.schema.id)?.length : false)// Store reports type has namespace filter, so rows already contain the correctly filtered resources
) {
return this.rows || [];
}
Expand Down
33 changes: 26 additions & 7 deletions shell/components/__tests__/NamespaceFilter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ describe('component: NamespaceFilter', () => {
options: () => [],
value: () => [],
},
mocks: { $fetchState: { pending: false } },
directives: { shortkey: () => jest.fn() }
});
const filter = wrapper.find(`[data-testid="namespaces-filter"]`);
Expand All @@ -25,7 +26,10 @@ describe('component: NamespaceFilter', () => {
options: () => [],
value: () => [],
},
mocks: { $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } } },
mocks: {
$store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } },
$fetchState: { pending: false }
},
directives: { shortkey: () => jest.fn() }
});
const element = wrapper.find(`[data-testid="namespaces-values-none"]`).element.textContent;
Expand All @@ -44,6 +48,7 @@ describe('component: NamespaceFilter', () => {
kind: 'special',
}]),
},
mocks: { $fetchState: { pending: false } },
directives: { shortkey: () => jest.fn() }
});

Expand All @@ -61,7 +66,10 @@ describe('component: NamespaceFilter', () => {
value: () => [{ label: text }],
},
directives: { shortkey: () => jest.fn() },
mocks: { $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } } },
mocks: {
$store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } },
$fetchState: { pending: false }
},
});

const element = wrapper.find(`[data-testid="namespaces-value-0"]`).element.textContent;
Expand Down Expand Up @@ -97,7 +105,8 @@ describe('component: NamespaceFilter', () => {
'prefs/get': () => preferences,
namespaceFilterMode: () => undefined,
},
}
},
$fetchState: { pending: false }
},
directives: { shortkey: () => jest.fn() }
});
Expand All @@ -116,7 +125,10 @@ describe('component: NamespaceFilter', () => {
options: () => [],
value: () => [],
},
mocks: { $store: { getters: { 'i18n/t': () => '', namespaceFilterMode: () => undefined } } },
mocks: {
$store: { getters: { 'i18n/t': () => '', namespaceFilterMode: () => undefined } },
$fetchState: { pending: false }
},
directives: { shortkey: () => jest.fn() }
});
const dropdown = wrapper.find(`[data-testid="namespaces-dropdown"]`);
Expand All @@ -135,7 +147,10 @@ describe('component: NamespaceFilter', () => {
options: () => [],
value: () => [],
},
mocks: { $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } } },
mocks: {
$store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } },
$fetchState: { pending: false }
},
directives: { shortkey: () => jest.fn() }
});
const dropdown = wrapper.find(`[data-testid="namespaces-dropdown"]`);
Expand All @@ -153,7 +168,10 @@ describe('component: NamespaceFilter', () => {
options: () => [],
value: () => [],
},
mocks: { $store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } } },
mocks: {
$store: { getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined } },
$fetchState: { pending: false }
},
directives: { shortkey: () => jest.fn() }
});

Expand Down Expand Up @@ -194,7 +212,8 @@ describe('component: NamespaceFilter', () => {
$store: {
getters: { 'i18n/t': () => text, namespaceFilterMode: () => undefined },
dispatch: action
}
},
$fetchState: { pending: false }
},
directives: { shortkey: () => jest.fn() }
});
Expand Down
Loading

0 comments on commit 762987d

Please sign in to comment.