From 5162c41292b03748e2da85c3c6c5fc9fb44ed64b Mon Sep 17 00:00:00 2001 From: Jordon Leach Date: Thu, 7 Nov 2024 10:08:44 -0500 Subject: [PATCH 1/6] Fix UX issues of policy reports in dashboard page --- pkg/kubewarden/components/Dashboard/Card.vue | 55 ++- .../components/Dashboard/DashboardView.vue | 464 +++++++----------- .../components/Dashboard/Masthead.vue | 297 +++++++++++ pkg/kubewarden/components/Dashboard/Modes.vue | 25 + .../components/Dashboard/Reports.vue | 51 ++ .../components/Dashboard/ReportsGauge.vue | 81 +++ pkg/kubewarden/config/table-headers.ts | 24 +- pkg/kubewarden/l10n/en-us.yaml | 23 +- .../Dashboard/DashboardView.spec.ts | 209 +------- .../components/Dashboard/Masthead.spec.ts | 229 +++++++++ 10 files changed, 923 insertions(+), 535 deletions(-) create mode 100644 pkg/kubewarden/components/Dashboard/Masthead.vue create mode 100644 pkg/kubewarden/components/Dashboard/Modes.vue create mode 100644 pkg/kubewarden/components/Dashboard/Reports.vue create mode 100644 pkg/kubewarden/components/Dashboard/ReportsGauge.vue create mode 100644 tests/unit/components/Dashboard/Masthead.spec.ts diff --git a/pkg/kubewarden/components/Dashboard/Card.vue b/pkg/kubewarden/components/Dashboard/Card.vue index 0235e452..1d5e2f7d 100644 --- a/pkg/kubewarden/components/Dashboard/Card.vue +++ b/pkg/kubewarden/components/Dashboard/Card.vue @@ -27,24 +27,23 @@ export default { :class="setLoading" >
- -

- {{ t(card.title) }} -

-
+ +
+ +

+ {{ t(card.title) }} +

+
+

+

-

- - - {{ t(card.linkText) }} - - -


-
-

{{ t(card.slotTitle) }}

- + +
+ +
+
@@ -54,7 +53,9 @@ export default { display: flex; flex-direction: column; align-items: flex-start; + justify-content: space-between; height: 100%; + width: 100%; padding: $space-m; grid-auto-rows: 1fr; gap: $space-m; @@ -66,14 +67,25 @@ export default { display: flex; align-items: center; + .title { + display: flex; + flex-direction: column; + justify-content: center; + } + h1 { margin: 0; - font-size: 18px; + color: var(--link); + } + + h1:hover { + color: var(--body-text); } - } - p { - min-height: 48px; + p { + font-size: 10.5px; + font-weight: 700; + } } .d-slot { @@ -115,7 +127,12 @@ export default { } } } + + .d-action { + width: 100%; + } } + .loading { min-height: 325px; overflow: hidden; diff --git a/pkg/kubewarden/components/Dashboard/DashboardView.vue b/pkg/kubewarden/components/Dashboard/DashboardView.vue index 2003eeb0..68c82a18 100644 --- a/pkg/kubewarden/components/Dashboard/DashboardView.vue +++ b/pkg/kubewarden/components/Dashboard/DashboardView.vue @@ -1,55 +1,57 @@ + + + + \ No newline at end of file diff --git a/pkg/kubewarden/components/Dashboard/Modes.vue b/pkg/kubewarden/components/Dashboard/Modes.vue new file mode 100644 index 00000000..19d02b2f --- /dev/null +++ b/pkg/kubewarden/components/Dashboard/Modes.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/pkg/kubewarden/components/Dashboard/Reports.vue b/pkg/kubewarden/components/Dashboard/Reports.vue new file mode 100644 index 00000000..ed0a82c2 --- /dev/null +++ b/pkg/kubewarden/components/Dashboard/Reports.vue @@ -0,0 +1,51 @@ + + + + + \ No newline at end of file diff --git a/pkg/kubewarden/components/Dashboard/ReportsGauge.vue b/pkg/kubewarden/components/Dashboard/ReportsGauge.vue new file mode 100644 index 00000000..8acbb6d4 --- /dev/null +++ b/pkg/kubewarden/components/Dashboard/ReportsGauge.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/pkg/kubewarden/config/table-headers.ts b/pkg/kubewarden/config/table-headers.ts index b8439a06..b5215fcc 100644 --- a/pkg/kubewarden/config/table-headers.ts +++ b/pkg/kubewarden/config/table-headers.ts @@ -151,17 +151,6 @@ export const POLICY_HEADERS = [ ]; export const DASHBOARD_HEADERS = [ - { - isEnabled: true, - isLoaded: true, - icon: 'icon-question-mark', - cta: createKubewardenRoute({ name: 'c-cluster-product-resource-create', params: { resource: KUBEWARDEN.POLICY_SERVER } }), - link: createKubewardenRoute({ name: 'c-cluster-product-resource', params: { resource: KUBEWARDEN.POLICY_SERVER } }), - linkText: 'kubewarden.dashboard.headers.policyServer.linkText', - description: 'kubewarden.dashboard.headers.policyServer.description', - slotTitle: 'kubewarden.dashboard.headers.policyServer.slotTitle', - title: 'kubewarden.dashboard.headers.policyServer.title' - }, { isEnabled: true, isLoaded: true, @@ -183,7 +172,18 @@ export const DASHBOARD_HEADERS = [ description: 'kubewarden.dashboard.headers.clusterAdmissionPolicy.description', slotTitle: 'kubewarden.dashboard.headers.clusterAdmissionPolicy.slotTitle', title: 'kubewarden.dashboard.headers.clusterAdmissionPolicy.title' - } + }, + { + isEnabled: true, + isLoaded: true, + icon: 'icon-question-mark', + cta: createKubewardenRoute({ name: 'c-cluster-product-resource-create', params: { resource: KUBEWARDEN.POLICY_SERVER } }), + link: createKubewardenRoute({ name: 'c-cluster-product-resource', params: { resource: KUBEWARDEN.POLICY_SERVER } }), + linkText: 'kubewarden.dashboard.headers.policyServer.linkText', + description: 'kubewarden.dashboard.headers.policyServer.description', + slotTitle: 'kubewarden.dashboard.headers.policyServer.slotTitle', + title: 'kubewarden.dashboard.headers.policyServer.title' + }, ]; export const TRACE_HEADERS = [ diff --git a/pkg/kubewarden/l10n/en-us.yaml b/pkg/kubewarden/l10n/en-us.yaml index 164544b4..cbd02543 100644 --- a/pkg/kubewarden/l10n/en-us.yaml +++ b/pkg/kubewarden/l10n/en-us.yaml @@ -30,23 +30,24 @@ kubewarden: headers: policyServer: title: Policy Servers - description: Kubewarden uses Policy Servers to receive requests to be validated. It does that by executing Kubewarden's policies. + description: Policy Servers validate requests linkText: Create Policy Server - slotTitle: Policy Server Pods admissionPolicy: - title: Admission Policies - description: An Admission Policy is a namespace-wide resource. The policy will process only the requests that are targeting the Namespace where the Admission Policy is defined. - linkText: Create Admission Policy - slotTitle: Policies + title: Namespaced Policies + description: Namespace-wide policy validation + linkText: Create Namespaced Policy clusterAdmissionPolicy: - title: Cluster Admission Policies - description: The Cluster Admission Policy resource is the core of the Kubewarden stack. This resource defines how policies evaluate requests. - linkText: Create Cluster Admission Policy - slotTitle: Policies + title: Cluster Policies + description: Cluster-wide policy validation + linkText: Create Cluster Policy modes: - title: Policy Modes + title: Modes monitor: Monitor protect: Protect + reports: + title: Reports + success: Success + fail: Fail appInstall: title: Kubewarden App Install description: This will take you to the app installation page for Kubewarden. diff --git a/tests/unit/components/Dashboard/DashboardView.spec.ts b/tests/unit/components/Dashboard/DashboardView.spec.ts index a12adf04..90d6084e 100644 --- a/tests/unit/components/Dashboard/DashboardView.spec.ts +++ b/tests/unit/components/Dashboard/DashboardView.spec.ts @@ -1,22 +1,15 @@ import { shallowMount } from '@vue/test-utils'; import { describe, expect, it } from '@jest/globals'; -import { SHOW_PRE_RELEASE } from '@shell/store/prefs'; - import DashboardView from '@kubewarden/components/Dashboard/DashboardView.vue'; -import DefaultsBanner from '@kubewarden/components/DefaultsBanner'; import ConsumptionGauge from '@shell/components/ConsumptionGauge'; -import DEFAULTS_APP from '@tests/unit/_templates_/defaultsApp'; -import { controllerCharts } from '@tests/unit/_templates_/controllerCharts'; - describe('component: DashboardView', () => { const commonMocks = { $fetchState: { pending: false }, $store: { getters: { currentCluster: () => 'current_cluster', - 'kubewarden/hideBannerDefaults': jest.fn(), 'i18n/t': jest.fn(), 'catalog/chart': jest.fn(), 'catalog/charts': jest.fn(), @@ -28,14 +21,8 @@ describe('component: DashboardView', () => { }; const commonComputed = { - controllerApp: () => null, - controllerChart: () => null, - defaultsApp: () => DEFAULTS_APP, - hideBannerDefaults: () => false, globalPolicies: () => [], - namespacedPolicies: () => [], - version: () => '1.25', - upgradeAvailable: () => null, + namespacedPolicies: () => [] }; const createWrapper = (overrides) => { @@ -46,19 +33,6 @@ describe('component: DashboardView', () => { }); }; - it('renders defaults banner when default app is not found', () => { - const wrapper = createWrapper({ - stubs: { - Card: { template: '' }, - ConsumptionGauge: { template: '' }, - }, - }); - - const banner = wrapper.findComponent(DefaultsBanner); - - expect(banner.exists()).toBe(true); - }); - it('renders correct gauge info of policy servers', () => { const pods = [ { @@ -83,13 +57,13 @@ describe('component: DashboardView', () => { const wrapper = createWrapper({ computed: { policyServerPods: () => pods }, - stubs: { DefaultsBanner: { template: '' } }, + stubs: { Masthead: { template: '' } }, }); const gauges = wrapper.findAllComponents(ConsumptionGauge); - expect(gauges.at(0).props().capacity).toStrictEqual(pods.length as Number); - expect(gauges.at(0).props().used).toStrictEqual(1 as Number); + expect(gauges.at(2).props().capacity).toStrictEqual(pods.length as Number); + expect(gauges.at(2).props().used).toStrictEqual(1 as Number); }); it('renders correct gauge info of admission policies', () => { @@ -119,183 +93,14 @@ describe('component: DashboardView', () => { const wrapper = createWrapper({ computed: { namespacedPolicies: () => policies }, - stubs: { DefaultsBanner: { template: '' } }, + stubs: { Masthead: { template: '' } } }); const gauges = wrapper.findAllComponents(ConsumptionGauge); - expect(gauges.at(1).props().capacity).toStrictEqual( + expect(gauges.at(0).props().capacity).toStrictEqual( policies.length as Number ); - expect(gauges.at(1).props().used).toStrictEqual(1 as Number); - }); - - it('renders the Upgradable button when an upgrade is available', () => { - const oldControllerApp = { spec: { chart: { metadata: { version: '2.0.4', appVersion: 'v1.9.0' } } } }; - - const wrapper = createWrapper({ - computed: { - controllerApp: () => oldControllerApp, - controllerChart: () => controllerCharts, - version: () => 'v1.9.0', - }, - }); - - const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); - - expect(upgradeButton.exists()).toBe(true); - expect(upgradeButton.text()).toContain( - '%kubewarden.dashboard.upgrade.appUpgrade%: v1.9.0 - %kubewarden.dashboard.upgrade.controllerChart%: 2.0.5' - ); - }); - - it('calculates the correct chart for a supported MAJOR version upgrade', () => { - const oldControllerApp = { spec: { chart: { metadata: { version: '0.4.6', appVersion: 'v0.5.5' } } } }; - - const wrapper = createWrapper({ - computed: { - controllerApp: () => oldControllerApp, - controllerChart: () => controllerCharts, - version: () => 'v0.5.5', - }, - }); - - const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); - - expect(upgradeButton.exists()).toBe(true); - expect(upgradeButton.text()).toContain( - '%kubewarden.dashboard.upgrade.appUpgrade%: v1.0.0 - %kubewarden.dashboard.upgrade.controllerChart%: 1.0.0' - - ); - }); - - it('calculates the correct chart for a supported MINOR version upgrade', () => { - const oldControllerApp = { spec: { chart: { metadata: { version: '1.1.1', appVersion: 'v1.1.0' } } } }; - - const wrapper = createWrapper({ - computed: { - controllerApp: () => oldControllerApp, - controllerChart: () => controllerCharts, - version: () => 'v1.1.0', - }, - }); - - const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); - - expect(upgradeButton.exists()).toBe(true); - expect(upgradeButton.text()).toContain( - '%kubewarden.dashboard.upgrade.appUpgrade%: v1.1.1 - %kubewarden.dashboard.upgrade.controllerChart%: 1.2.3' - ); - }); - - it('calculates the correct chart for a supported PATCH version upgrade', () => { - const oldControllerApp = { spec: { chart: { metadata: { version: '2.0.0', appVersion: 'v1.8.0' } } } }; - - const wrapper = createWrapper({ - computed: { - controllerApp: () => oldControllerApp, - controllerChart: () => controllerCharts, - version: () => 'v1.8.0', - }, - }); - - const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); - - expect(upgradeButton.exists()).toBe(true); - expect(upgradeButton.text()).toContain( - '%kubewarden.dashboard.upgrade.appUpgrade%: v1.9.0 - %kubewarden.dashboard.upgrade.controllerChart%: 2.0.5' - ); - expect(wrapper.vm.controllerUpgradeAvailable).toBe(controllerCharts.versions[1]); - }); - - it('calculates the correct chart for multiple appVersions with chart PATCH available', () => { - const oldControllerApp = { spec: { chart: { metadata: { version: '1.6.0', appVersion: 'v1.7.0' } } } }; - - const wrapper = createWrapper({ - computed: { - controllerApp: () => oldControllerApp, - controllerChart: () => controllerCharts, - version: () => 'v1.7.0', - }, - }); - - const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); - - expect(upgradeButton.exists()).toBe(true); - expect(upgradeButton.text()).toContain( - '%kubewarden.dashboard.upgrade.appUpgrade%: v1.8.0 - %kubewarden.dashboard.upgrade.controllerChart%: 2.0.2' - ); - }); - - it('calculates the correct chart for inconsistent appVersion semantics', () => { - const oldControllerApp = { spec: { chart: { metadata: { version: '1.4.0', appVersion: '1.5.0' } } } }; - - const wrapper = createWrapper({ - computed: { - controllerApp: () => oldControllerApp, - controllerChart: () => controllerCharts, - version: () => '1.5.0', - }, - }); - - const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); - - expect(upgradeButton.exists()).toBe(true); - expect(upgradeButton.text()).toContain( - '%kubewarden.dashboard.upgrade.appUpgrade%: v1.6.0 - %kubewarden.dashboard.upgrade.controllerChart%: 1.5.3' - ); - }); - - it('calculates the correct chart for pre-release versions', () => { - const oldControllerApp = { spec: { chart: { metadata: { version: '2.0.5', appVersion: 'v1.9.0' } } } }; - - commonMocks.$store.getters['prefs/get'].mockImplementation((key) => { - if ( key === SHOW_PRE_RELEASE ) { - return true; - } - - return undefined; - }); - - const wrapper = createWrapper({ - computed: { - controllerApp: () => oldControllerApp, - controllerChart: () => controllerCharts, - version: () => 'v1.9.0', - showPreRelease: () => true, - }, - }); - - const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); - - expect(upgradeButton.exists()).toBe(true); - expect(upgradeButton.text()).toContain( - '%kubewarden.dashboard.upgrade.appUpgrade%: v1.10.0-rc1 - %kubewarden.dashboard.upgrade.controllerChart%: 2.0.6-rc1' - ); - }); - - it('does not show pre-release upgrades when preference is false', () => { - const oldControllerApp = { spec: { chart: { metadata: { version: '2.0.5', appVersion: 'v1.9.0' } } } }; - - commonMocks.$store.getters['prefs/get'].mockImplementation((key) => { - if ( key === SHOW_PRE_RELEASE ) { - return false; - } - - return undefined; - }); - - const wrapper = createWrapper({ - computed: { - controllerApp: () => oldControllerApp, - controllerChart: () => controllerCharts, - version: () => 'v1.9.0', - showPreRelease: () => false, - }, - }); - - const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); - - expect(upgradeButton.exists()).toBe(false); + expect(gauges.at(0).props().used).toStrictEqual(1 as Number); }); }); diff --git a/tests/unit/components/Dashboard/Masthead.spec.ts b/tests/unit/components/Dashboard/Masthead.spec.ts new file mode 100644 index 00000000..993ffbf9 --- /dev/null +++ b/tests/unit/components/Dashboard/Masthead.spec.ts @@ -0,0 +1,229 @@ +import { shallowMount } from '@vue/test-utils'; +import { describe, expect, it } from '@jest/globals'; + +import { SHOW_PRE_RELEASE } from '@shell/store/prefs'; + +import Masthead from '@kubewarden/components/Dashboard/Masthead.vue'; +import DefaultsBanner from '@kubewarden/components/DefaultsBanner'; + +import DEFAULTS_APP from '@tests/unit/_templates_/defaultsApp'; +import { controllerCharts } from '@tests/unit/_templates_/controllerCharts'; + +describe('component: Masthead', () => { + const commonMocks = { + $fetchState: { pending: false }, + $store: { + getters: { + currentCluster: () => 'current_cluster', + 'kubewarden/hideBannerDefaults': jest.fn(), + 'i18n/t': jest.fn(), + 'catalog/chart': jest.fn(), + 'catalog/charts': jest.fn(), + 'cluster/all': jest.fn(), + 'cluster/canList': () => true, + 'prefs/get': jest.fn(), + }, + }, + }; + + const commonComputed = { + controllerApp: () => null, + controllerChart: () => null, + defaultsApp: () => DEFAULTS_APP, + hideBannerDefaults: () => false, + globalPolicies: () => [], + namespacedPolicies: () => [], + version: () => '1.25', + upgradeAvailable: () => null, + }; + + const createWrapper = (overrides) => { + return shallowMount(Masthead, { + mocks: commonMocks, + computed: commonComputed, + ...overrides, + }); + }; + + it('renders defaults banner when default app is not found', () => { + const wrapper = createWrapper({ + stubs: { + Card: { template: '' }, + ConsumptionGauge: { template: '' }, + }, + }); + + const banner = wrapper.findComponent(DefaultsBanner); + + expect(banner.exists()).toBe(true); + }); + + it('renders the Upgradable button when an upgrade is available', () => { + const oldControllerApp = { spec: { chart: { metadata: { version: '2.0.4', appVersion: 'v1.9.0' } } } }; + + const wrapper = createWrapper({ + computed: { + controllerApp: () => oldControllerApp, + controllerChart: () => controllerCharts, + version: () => 'v1.9.0', + }, + }); + + const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); + + expect(upgradeButton.exists()).toBe(true); + expect(upgradeButton.text()).toContain( + '%kubewarden.dashboard.upgrade.appUpgrade%: v1.9.0 - %kubewarden.dashboard.upgrade.controllerChart%: 2.0.5' + ); + }); + + it('calculates the correct chart for a supported MAJOR version upgrade', () => { + const oldControllerApp = { spec: { chart: { metadata: { version: '0.4.6', appVersion: 'v0.5.5' } } } }; + + const wrapper = createWrapper({ + computed: { + controllerApp: () => oldControllerApp, + controllerChart: () => controllerCharts, + version: () => 'v0.5.5', + }, + }); + + const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); + + expect(upgradeButton.exists()).toBe(true); + expect(upgradeButton.text()).toContain( + '%kubewarden.dashboard.upgrade.appUpgrade%: v1.0.0 - %kubewarden.dashboard.upgrade.controllerChart%: 1.0.0' + + ); + }); + + it('calculates the correct chart for a supported MINOR version upgrade', () => { + const oldControllerApp = { spec: { chart: { metadata: { version: '1.1.1', appVersion: 'v1.1.0' } } } }; + + const wrapper = createWrapper({ + computed: { + controllerApp: () => oldControllerApp, + controllerChart: () => controllerCharts, + version: () => 'v1.1.0', + }, + }); + + const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); + + expect(upgradeButton.exists()).toBe(true); + expect(upgradeButton.text()).toContain( + '%kubewarden.dashboard.upgrade.appUpgrade%: v1.1.1 - %kubewarden.dashboard.upgrade.controllerChart%: 1.2.3' + ); + }); + + it('calculates the correct chart for a supported PATCH version upgrade', () => { + const oldControllerApp = { spec: { chart: { metadata: { version: '2.0.0', appVersion: 'v1.8.0' } } } }; + + const wrapper = createWrapper({ + computed: { + controllerApp: () => oldControllerApp, + controllerChart: () => controllerCharts, + version: () => 'v1.8.0', + }, + }); + + const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); + + expect(upgradeButton.exists()).toBe(true); + expect(upgradeButton.text()).toContain( + '%kubewarden.dashboard.upgrade.appUpgrade%: v1.9.0 - %kubewarden.dashboard.upgrade.controllerChart%: 2.0.5' + ); + expect(wrapper.vm.controllerUpgradeAvailable).toBe(controllerCharts.versions[1]); + }); + + it('calculates the correct chart for multiple appVersions with chart PATCH available', () => { + const oldControllerApp = { spec: { chart: { metadata: { version: '1.6.0', appVersion: 'v1.7.0' } } } }; + + const wrapper = createWrapper({ + computed: { + controllerApp: () => oldControllerApp, + controllerChart: () => controllerCharts, + version: () => 'v1.7.0', + }, + }); + + const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); + + expect(upgradeButton.exists()).toBe(true); + expect(upgradeButton.text()).toContain( + '%kubewarden.dashboard.upgrade.appUpgrade%: v1.8.0 - %kubewarden.dashboard.upgrade.controllerChart%: 2.0.2' + ); + }); + + it('calculates the correct chart for inconsistent appVersion semantics', () => { + const oldControllerApp = { spec: { chart: { metadata: { version: '1.4.0', appVersion: '1.5.0' } } } }; + + const wrapper = createWrapper({ + computed: { + controllerApp: () => oldControllerApp, + controllerChart: () => controllerCharts, + version: () => '1.5.0', + }, + }); + + const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); + + expect(upgradeButton.exists()).toBe(true); + expect(upgradeButton.text()).toContain( + '%kubewarden.dashboard.upgrade.appUpgrade%: v1.6.0 - %kubewarden.dashboard.upgrade.controllerChart%: 1.5.3' + ); + }); + + it('calculates the correct chart for pre-release versions', () => { + const oldControllerApp = { spec: { chart: { metadata: { version: '2.0.5', appVersion: 'v1.9.0' } } } }; + + commonMocks.$store.getters['prefs/get'].mockImplementation((key) => { + if ( key === SHOW_PRE_RELEASE ) { + return true; + } + + return undefined; + }); + + const wrapper = createWrapper({ + computed: { + controllerApp: () => oldControllerApp, + controllerChart: () => controllerCharts, + version: () => 'v1.9.0', + showPreRelease: () => true, + }, + }); + + const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); + + expect(upgradeButton.exists()).toBe(true); + expect(upgradeButton.text()).toContain( + '%kubewarden.dashboard.upgrade.appUpgrade%: v1.10.0-rc1 - %kubewarden.dashboard.upgrade.controllerChart%: 2.0.6-rc1' + ); + }); + + it('does not show pre-release upgrades when preference is false', () => { + const oldControllerApp = { spec: { chart: { metadata: { version: '2.0.5', appVersion: 'v1.9.0' } } } }; + + commonMocks.$store.getters['prefs/get'].mockImplementation((key) => { + if ( key === SHOW_PRE_RELEASE ) { + return false; + } + + return undefined; + }); + + const wrapper = createWrapper({ + computed: { + controllerApp: () => oldControllerApp, + controllerChart: () => controllerCharts, + version: () => 'v1.9.0', + showPreRelease: () => false, + }, + }); + + const upgradeButton = wrapper.find('[data-testid="kw-app-controller-upgrade-button"]'); + + expect(upgradeButton.exists()).toBe(false); + }); +}); From e2ea76a7f5d2c10e6ffe574a18e5e4f7854f0dd6 Mon Sep 17 00:00:00 2001 From: Jordon Leach Date: Thu, 15 Aug 2024 13:58:27 -0400 Subject: [PATCH 2/6] Add custom bar graph - error status - fix unit tests --- pkg/kubewarden/components/Dashboard/Card.vue | 38 ++-- .../components/Dashboard/DashboardView.vue | 38 ++-- pkg/kubewarden/components/Graph/Bar.vue | 75 ++++++++ pkg/kubewarden/l10n/en-us.yaml | 1 + .../Dashboard/DashboardView.spec.ts | 178 ++++++++++++++---- 5 files changed, 273 insertions(+), 57 deletions(-) create mode 100644 pkg/kubewarden/components/Graph/Bar.vue diff --git a/pkg/kubewarden/components/Dashboard/Card.vue b/pkg/kubewarden/components/Dashboard/Card.vue index 1d5e2f7d..154ad8f4 100644 --- a/pkg/kubewarden/components/Dashboard/Card.vue +++ b/pkg/kubewarden/components/Dashboard/Card.vue @@ -27,24 +27,24 @@ export default { :class="setLoading" >
- -
- -

- {{ t(card.title) }} -

-
-

+

+ +
+ +

+ {{ t(card.title) }} +

+
+

+

+ +
- -
- -
@@ -66,6 +66,14 @@ export default { .d-header { display: flex; align-items: center; + justify-content: space-between; + width: 100%; + + .title-container { + display: flex; + align-items: center; + width: 55%; + } .title { display: flex; @@ -86,6 +94,10 @@ export default { font-size: 10.5px; font-weight: 700; } + + .action { + width: 45%; + } } .d-slot { @@ -129,7 +141,7 @@ export default { } .d-action { - width: 100%; + width: auto; } } diff --git a/pkg/kubewarden/components/Dashboard/DashboardView.vue b/pkg/kubewarden/components/Dashboard/DashboardView.vue index 68c82a18..d6df02a8 100644 --- a/pkg/kubewarden/components/Dashboard/DashboardView.vue +++ b/pkg/kubewarden/components/Dashboard/DashboardView.vue @@ -288,18 +288,23 @@ export default { status: { success: res?.status?.success + ( neu?.result === 'pass' ? 1 : 0 ), fail: res?.status?.fail + ( neu?.result === 'fail' ? 1 : 0 ), + error: res?.status?.error + ( neu?.result === 'error' ? 1 : 0 ) }, total: res?.total + 1 }; }, { - status: { success: 0, fail: 0 }, - total: 0 + status: { + success: 0, fail: 0, error: 0 + }, + total: 0 }); } return { - status: { success: 0, fail: 0 }, - total: 0 + status: { + success: 0, fail: 0, error: 0 + }, + total: 0 }; } } @@ -324,6 +329,23 @@ export default { {{ allPolicyServers.length || 0 }} + + - - @@ -383,7 +399,7 @@ export default { .get-started { display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); grid-gap: 20px; .card-container { diff --git a/pkg/kubewarden/components/Graph/Bar.vue b/pkg/kubewarden/components/Graph/Bar.vue new file mode 100644 index 00000000..fcae3aad --- /dev/null +++ b/pkg/kubewarden/components/Graph/Bar.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/pkg/kubewarden/l10n/en-us.yaml b/pkg/kubewarden/l10n/en-us.yaml index cbd02543..01239529 100644 --- a/pkg/kubewarden/l10n/en-us.yaml +++ b/pkg/kubewarden/l10n/en-us.yaml @@ -48,6 +48,7 @@ kubewarden: title: Reports success: Success fail: Fail + error: Error appInstall: title: Kubewarden App Install description: This will take you to the app installation page for Kubewarden. diff --git a/tests/unit/components/Dashboard/DashboardView.spec.ts b/tests/unit/components/Dashboard/DashboardView.spec.ts index 90d6084e..03d47eb9 100644 --- a/tests/unit/components/Dashboard/DashboardView.spec.ts +++ b/tests/unit/components/Dashboard/DashboardView.spec.ts @@ -1,8 +1,16 @@ -import { shallowMount } from '@vue/test-utils'; +import { mount } from '@vue/test-utils'; import { describe, expect, it } from '@jest/globals'; -import DashboardView from '@kubewarden/components/Dashboard/DashboardView.vue'; import ConsumptionGauge from '@shell/components/ConsumptionGauge'; +import Loading from '@shell/components/Loading'; + +import DashboardView from '@kubewarden/components/Dashboard/DashboardView.vue'; +import Card from '@kubewarden/components/Dashboard/Card.vue'; +import Masthead from '@kubewarden/components/Dashboard/Masthead.vue'; +import Modes from '@kubewarden/components/Dashboard/Modes.vue'; +import Events from '@kubewarden/components/Dashboard/Events.vue'; +import EventsGauge from '@kubewarden/components/Dashboard/EventsGauge.vue'; +import { DASHBOARD_HEADERS } from '@kubewarden/config/table-headers'; describe('component: DashboardView', () => { const commonMocks = { @@ -14,7 +22,7 @@ describe('component: DashboardView', () => { 'catalog/chart': jest.fn(), 'catalog/charts': jest.fn(), 'cluster/all': jest.fn(), - 'cluster/canList': () => true, + 'cluster/canList': jest.fn(() => true), 'prefs/get': jest.fn(), }, }, @@ -22,17 +30,117 @@ describe('component: DashboardView', () => { const commonComputed = { globalPolicies: () => [], - namespacedPolicies: () => [] + namespacedPolicies: () => [], + allPolicyServers: () => [], + policyServerCounts: () => ({ + status: { + running: 0, stopped: 0, pending: 0 + }, + total: 0 + }), }; + const commonStubs = { 'router-link': { template: '' } }; + const createWrapper = (overrides) => { - return shallowMount(DashboardView, { + return mount(DashboardView, { mocks: commonMocks, computed: commonComputed, + stubs: commonStubs, ...overrides, }); }; + it('renders the Masthead component', () => { + const wrapper = createWrapper({}); + + expect(wrapper.findComponent(Masthead).exists()).toBe(true); + }); + + it('renders the Loading component when fetch state is pending', () => { + const wrapper = createWrapper({ + mocks: { + ...commonMocks, + $fetchState: { pending: true }, + }, + }); + + expect(wrapper.findComponent(Loading).exists()).toBe(true); + }); + + it('renders the correct number of Card components based on DASHBOARD_HEADERS', () => { + const wrapper = createWrapper({}); + const cardComponents = wrapper.findAllComponents(Card); + + expect(cardComponents.length).toBe(DASHBOARD_HEADERS.length); + }); + + it('renders ConsumptionGauge component with correct props', () => { + const wrapper = createWrapper({ + computed: { + globalPolicies: () => [], + namespacedPolicies: () => [], + allPolicyServers: () => [], + policyServerCounts: () => ({ + status: { + running: 1, stopped: 0, pending: 0 + }, + total: 2 + }) + } + }); + + const gauge = wrapper.findComponent(ConsumptionGauge); + + expect(gauge.exists()).toBe(true); + expect(gauge.props('capacity')).toBe(2); + expect(gauge.props('used')).toBe(1); + expect(gauge.props('colorStops')).toEqual({ + 25: '--error', 50: '--warning', 70: '--info' + }); + }); + + it('correctly applies class names based on policy server counts', () => { + const wrapper = createWrapper({ + computed: { + globalPolicies: () => [], + namespacedPolicies: () => [], + allPolicyServers: () => [{}, {}] + } + }); + + const btn = wrapper.find('.role-secondary'); + + expect(btn.exists()).toBe(true); + }); + + it('renders EventsGauge component when namespacedPolicies are present', () => { + const wrapper = createWrapper({ + computed: { + globalPolicies: () => [], + namespacedPolicies: () => [{}, {}], + allPolicyServers: () => [] + } + }); + + const eventsGauge = wrapper.findComponent(EventsGauge); + + expect(eventsGauge.exists()).toBe(true); + }); + + it('renders Events and Modes components for namespaced policies', () => { + const wrapper = createWrapper({ + computed: { + globalPolicies: () => [], + namespacedPolicies: () => [{}, {}], + allPolicyServers: () => [] + } + }); + + expect(wrapper.findComponent(Events).exists()).toBe(true); + expect(wrapper.findComponent(Modes).exists()).toBe(true); + }); + it('renders correct gauge info of policy servers', () => { const pods = [ { @@ -56,51 +164,55 @@ describe('component: DashboardView', () => { ]; const wrapper = createWrapper({ - computed: { policyServerPods: () => pods }, - stubs: { Masthead: { template: '' } }, + computed: { + globalPolicies: () => [], + namespacedPolicies: () => [], + allPolicyServers: () => [{}], + policyServerPods: () => pods + }, + stubs: { Masthead: { template: '' } }, }); - const gauges = wrapper.findAllComponents(ConsumptionGauge); + const gauges = wrapper.findComponent(ConsumptionGauge); - expect(gauges.at(2).props().capacity).toStrictEqual(pods.length as Number); - expect(gauges.at(2).props().used).toStrictEqual(1 as Number); + expect(gauges.props().capacity).toStrictEqual(pods.length as Number); + expect(gauges.props().used).toStrictEqual(1 as Number); }); - it('renders correct gauge info of admission policies', () => { + it('renders correct gauge info for admission policy events', () => { const policies = [ { - status: { - policyStatus: 'active', - error: false, - }, - spec: { mode: 'protect' }, + result: 'pass', + policy: 'namespaced-policy-1', }, { - status: { - policyStatus: 'pending', - error: false, - }, - spec: { mode: 'protect' }, + result: 'fail', + policy: 'namespaced-policy-2', }, { - status: { - policyStatus: 'unschedulable', - error: true, - }, - spec: { mode: 'monitor' }, + result: 'error', + policy: 'namespaced-policy-3', }, ]; + const summary = { + status: { + error: 1, fail: 1, success: 1 + }, + total: 3 + }; const wrapper = createWrapper({ - computed: { namespacedPolicies: () => policies }, - stubs: { Masthead: { template: '' } } + computed: { + admissionPolicyResults: () => policies, + namespacedPolicies: () => [], + globalPolicies: () => [], + allPolicyServers: () => [], + } }); - const gauges = wrapper.findAllComponents(ConsumptionGauge); + const gauges = wrapper.findAllComponents(EventsGauge); - expect(gauges.at(0).props().capacity).toStrictEqual( - policies.length as Number - ); - expect(gauges.at(0).props().used).toStrictEqual(1 as Number); + expect(gauges.at(0).exists()).toBe(true); + expect(gauges.at(0).props().events).toStrictEqual(summary); }); }); From 571b1e4e1fe07148551ad31d4e1fb764fb286242 Mon Sep 17 00:00:00 2001 From: Jordon Leach Date: Thu, 15 Aug 2024 14:06:24 -0400 Subject: [PATCH 3/6] Update appVersionSatisfies --- pkg/kubewarden/components/Dashboard/Masthead.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kubewarden/components/Dashboard/Masthead.vue b/pkg/kubewarden/components/Dashboard/Masthead.vue index 9a264eaa..b072db2e 100644 --- a/pkg/kubewarden/components/Dashboard/Masthead.vue +++ b/pkg/kubewarden/components/Dashboard/Masthead.vue @@ -31,7 +31,7 @@ export default { ...mapGetters({ charts: 'catalog/charts' }), appVersionSatisfies() { - const satisfies = appVersionSatisfiesConstraint(this.$store, this.controllerAppVersion, this.defaultsAppVersion, '='); + const satisfies = appVersionSatisfiesConstraint(this.$store, this.controllerAppVersion, this.defaultsAppVersion, '<='); return satisfies || false; }, From fd761c52261485f85f3354353b2c9b24a9c27971 Mon Sep 17 00:00:00 2001 From: Jordon Leach Date: Fri, 8 Nov 2024 08:16:29 -0500 Subject: [PATCH 4/6] unify policy server active color with reports colors --- pkg/kubewarden/components/Dashboard/DashboardView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kubewarden/components/Dashboard/DashboardView.vue b/pkg/kubewarden/components/Dashboard/DashboardView.vue index d6df02a8..2623e443 100644 --- a/pkg/kubewarden/components/Dashboard/DashboardView.vue +++ b/pkg/kubewarden/components/Dashboard/DashboardView.vue @@ -56,7 +56,7 @@ export default { data() { const colorStops = { - 25: '--error', 50: '--warning', 70: '--info' + 25: '--error', 50: '--warning', 70: '--success' }; return { From cc6ef125ac0bb09a59c567029a58b8e8971655bd Mon Sep 17 00:00:00 2001 From: Jordon Leach Date: Fri, 8 Nov 2024 09:36:35 -0500 Subject: [PATCH 5/6] Add empty reports bar --- pkg/kubewarden/components/Dashboard/DashboardView.vue | 2 -- pkg/kubewarden/components/Dashboard/ReportsGauge.vue | 8 ++++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/kubewarden/components/Dashboard/DashboardView.vue b/pkg/kubewarden/components/Dashboard/DashboardView.vue index 2623e443..0d2fdc5a 100644 --- a/pkg/kubewarden/components/Dashboard/DashboardView.vue +++ b/pkg/kubewarden/components/Dashboard/DashboardView.vue @@ -352,7 +352,6 @@ export default {