-
Notifications
You must be signed in to change notification settings - Fork 334
[11513] Added workload-dashboard #17728
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
c5cb980
7c1a8a4
4091873
17992fe
ecdfeef
27fff42
37bab37
42bbb23
2f82e5f
37c8f3d
100cf2d
35451b7
15e0278
9d93cec
f1f339c
1d5116e
c9b94cc
16dd1c5
0d9ee46
36431d6
201d7bd
e618784
4ba249b
e10e265
5d89ac0
c518a45
2f193b6
6a9058b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| import PagePo from '@/cypress/e2e/po/pages/page.po'; | ||
| import BurgerMenuPo from '@/cypress/e2e/po/side-bars/burger-side-menu.po'; | ||
| import ProductNavPo from '@/cypress/e2e/po/side-bars/product-side-nav.po'; | ||
| import CardPo from '@/cypress/e2e/po/components/Resource/Detail/Card/statusCard.po'; | ||
| import BannersPo from '@/cypress/e2e/po/components/banners.po'; | ||
|
|
||
| export default class WorkloadDashboardPagePo extends PagePo { | ||
| private static createPath(clusterId: string) { | ||
| return `/c/${ clusterId }/explorer/workload-dashboard`; | ||
| } | ||
|
|
||
| static goTo(clusterId: string): Cypress.Chainable<Cypress.AUTWindow> { | ||
| return super.goTo(WorkloadDashboardPagePo.createPath(clusterId)); | ||
| } | ||
|
|
||
| constructor(clusterId = 'local') { | ||
| super(WorkloadDashboardPagePo.createPath(clusterId)); | ||
| } | ||
|
|
||
| static navTo(clusterId = 'local') { | ||
| const burgerMenu = new BurgerMenuPo(); | ||
| const sideNav = new ProductNavPo(); | ||
|
|
||
| burgerMenu.goToCluster(clusterId); | ||
| sideNav.navToSideMenuGroupByLabel('Workloads'); | ||
| } | ||
|
|
||
| title() { | ||
| return cy.get('[data-testid="workload-dashboard-title"]'); | ||
| } | ||
|
|
||
| subtitle() { | ||
| return cy.get('[data-testid="workload-dashboard-subtitle"]'); | ||
| } | ||
|
|
||
| byStateSection() { | ||
| return cy.get('[data-testid="workload-dashboard-by-state"]'); | ||
| } | ||
|
|
||
| stateCards() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same for cards, if we're using generic components there'll be a PO
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated! |
||
| return cy.get('[data-testid="workload-dashboard-state-card"]'); | ||
| } | ||
|
|
||
| byTypeSection() { | ||
| return cy.get('[data-testid="workload-dashboard-by-type"]'); | ||
| } | ||
|
|
||
| byTypeCard(index = 0) { | ||
| return new CardPo(`[data-testid="resource-detail-status-card"]:eq(${ index })`); | ||
| } | ||
|
|
||
| byTypeCards() { | ||
| return cy.get('[data-testid="resource-detail-status-card"]'); | ||
| } | ||
|
|
||
| interceptSummariesAsEmpty() { | ||
| return cy.intercept('GET', '/v1/*?summary=*', { | ||
| summary: [], count: 0, data: [] | ||
| }).as('emptySummary'); | ||
| } | ||
|
|
||
| waitForEmptySummaries() { | ||
| return cy.wait('@emptySummary'); | ||
| } | ||
|
|
||
| emptyState() { | ||
| return cy.get('[data-testid="workload-dashboard-empty"]'); | ||
| } | ||
|
|
||
| errorBanner() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. banner po
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok! Done! |
||
| return new BannersPo('.banner.error'); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import WorkloadDashboardPagePo from '@/cypress/e2e/po/pages/explorer/workloads/workload-dashboard.po'; | ||
|
|
||
| const workloadDashboard = new WorkloadDashboardPagePo('local'); | ||
|
|
||
| describe('Workload Dashboard', { testIsolation: 'off', tags: ['@explorer2', '@adminUser'] }, () => { | ||
| before(() => { | ||
| cy.login(); | ||
| cy.updateNamespaceFilter('local', 'none', '{"local":[]}'); | ||
| WorkloadDashboardPagePo.navTo(); | ||
| workloadDashboard.waitForPage(); | ||
| }); | ||
|
|
||
| it('should display the title', () => { | ||
| workloadDashboard.title().should('contain.text', 'Workloads Overview'); | ||
| }); | ||
|
|
||
| it('should display a namespace subtitle with workload count', () => { | ||
| workloadDashboard.subtitle().should('be.visible'); | ||
| workloadDashboard.subtitle().invoke('text').should('match', /\(\d+\)/); | ||
| }); | ||
|
|
||
| it('should display the By State section with state cards', () => { | ||
| workloadDashboard.byStateSection().should('be.visible'); | ||
| workloadDashboard.stateCards().should('have.length.gte', 1); | ||
| }); | ||
|
|
||
| it('should display the By Type section with type cards', () => { | ||
| workloadDashboard.byTypeSection().should('be.visible'); | ||
| workloadDashboard.byTypeCards().should('have.length.gte', 1); | ||
| }); | ||
|
|
||
| it('should navigate to the resource list when clicking a By Type card', () => { | ||
| WorkloadDashboardPagePo.navTo(); | ||
| workloadDashboard.waitForPage(); | ||
|
|
||
| workloadDashboard.byTypeCards().first().click(); | ||
|
|
||
| cy.url().should('match', /\/c\/local\/explorer\/(apps\.|batch\.)?[a-z]+/); | ||
| }); | ||
|
|
||
| it('should show empty state when namespace filter matches no workloads', () => { | ||
| workloadDashboard.interceptSummariesAsEmpty(); | ||
|
|
||
| WorkloadDashboardPagePo.navTo(); | ||
| workloadDashboard.waitForPage(); | ||
| workloadDashboard.waitForEmptySummaries(); | ||
|
|
||
| workloadDashboard.emptyState().should('be.visible'); | ||
| }); | ||
|
|
||
| after(() => { | ||
| cy.login(); | ||
| cy.updateNamespaceFilter('local', 'none', '{"local":["all://user"]}'); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -7425,6 +7425,29 @@ wm: | |||||
| kubectlShell: | ||||||
| title: "Kubectl: {name}" | ||||||
|
|
||||||
| workloadDashboard: | ||||||
| title: Workloads Overview | ||||||
| subtitle: | ||||||
| allNamespaces: "For all namespaces ({count})" | ||||||
| userNamespaces: "Only for user namespaces ({count})" | ||||||
| systemNamespaces: "Only for system namespaces ({count})" | ||||||
| namespacedOnly: "Only for namespaced resources ({count})" | ||||||
| clusterOnly: "Only for cluster resources ({count})" | ||||||
| project: "For the namespaces of Project {name} ({count})" | ||||||
| namespace: "For the namespace {name} ({count})" | ||||||
| multipleSelected: "For {selected} items selected ({count})" | ||||||
| sections: | ||||||
| byState: By State | ||||||
| byType: By Type | ||||||
| errors: | ||||||
| noAccess: "No access to {type}" | ||||||
| fetchType: "Failed to fetch {type}" | ||||||
| fetchAll: Failed to fetch workload summaries | ||||||
| empty: | ||||||
| title: No workloads to show | ||||||
| message: "Tips: undo the last namespace filter you applied or <resetLink>reset the namespaces filter</resetLink>." | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this use case is different, the user may have not set any and the default
Suggested change
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one is provided by @oboc-sts from the Figma. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I totally missed the "suggested change"... Yeah, we can go with the suggestion @richard-cox made above, it makes sense, I like it ;) |
||||||
| docsMessage: "Want to learn more about Workloads? Read our <docsLink>documentation</docsLink>." | ||||||
|
|
||||||
| workload: | ||||||
| scaleWorkloads: Scale workloads | ||||||
| healthWorkloads: Jobs/Pods health status | ||||||
|
|
||||||
|
marcelofukumoto marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,25 +1,50 @@ | ||
| <script setup lang="ts"> | ||
| import { computed } from 'vue'; | ||
| import { RouterLink, RouteLocationRaw } from 'vue-router'; | ||
|
|
||
| export interface Props { | ||
| to: RouteLocationRaw; | ||
| to?: RouteLocationRaw; | ||
| href?: string; | ||
| target?: string; | ||
| openInNewTabLabel?: string; | ||
| } | ||
|
|
||
| const { to } = defineProps<Props>(); | ||
| const props = defineProps<Props>(); | ||
|
|
||
| const isExternal = computed(() => !!props.href); | ||
| </script> | ||
|
|
||
| <template> | ||
| <RouterLink | ||
| <component | ||
| :is="isExternal ? 'a' : RouterLink" | ||
| class="subtle-link" | ||
| :to="to" | ||
| v-bind="isExternal | ||
| ? { href, target, rel: target === '_blank' ? 'noopener noreferrer nofollow' : undefined } | ||
| : { to }" | ||
| > | ||
| <slot name="default" /> | ||
| </RouterLink> | ||
| <span | ||
| v-if="openInNewTabLabel" | ||
| class="sr-only" | ||
| >{{ openInNewTabLabel }}</span> | ||
| <slot name="default" /><span v-if="openInNewTabLabel"> </span><i | ||
| v-if="openInNewTabLabel" | ||
| class="link-icon icon icon-external-link" | ||
| /> | ||
| </component> | ||
| </template> | ||
|
|
||
| <style lang="scss" scoped> | ||
| .subtle-link { | ||
| text-decoration: underline; | ||
| color: var(--body-text); | ||
|
|
||
| &:hover, | ||
| &:active { | ||
| text-decoration: none; | ||
| } | ||
| } | ||
|
|
||
| .link-icon { | ||
| display: inline; | ||
| } | ||
| </style> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there'll be a Po for this, think it's something around the masthead. should also have something for subtitle
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not using the MastHead, the header has different structure.
I added some testid to make it better on this PO.