Skip to content

Commit

Permalink
feat(zones): adds an available services listing tab for zone ingresses (
Browse files Browse the repository at this point in the history
#1607)

Adds a listing tab for ZoneIngress AvailableServices.

---------

Signed-off-by: John Cowen <[email protected]>
  • Loading branch information
johncowen authored Oct 17, 2023
1 parent 82fe2a4 commit cf19850
Show file tree
Hide file tree
Showing 17 changed files with 217 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
Feature: zones / ingresses / item
Background:
Given the CSS selectors
| Alias | Selector |
| detail-view | [data-testid='zone-ingress-detail-view'] |
| config-view | [data-testid='zone-ingress-config-view'] |
| detail-tabs-view | [data-testid='zone-ingress-detail-tabs-view'] |
| config-tab | #zone-ingress-config-view-tab a |
| Alias | Selector |
| detail-view | [data-testid='zone-ingress-detail-view'] |
| config-view | [data-testid='zone-ingress-config-view'] |
| detail-tabs-view | [data-testid='zone-ingress-detail-tabs-view'] |
| config-tab | #zone-ingress-config-view-tab a |
| navigation | [data-testid='zone-ingress-detail-tabs-view'] [data-testid='nav-tabs'] > ul |

And the environment
"""
KUMA_MODE: global
"""

Scenario: Clicking through the secondary navigation
When I visit the "/zones/zone-cp-1/ingresses/item-1/overview" URL
Then I click the "$navigation li:nth-child(2) a" element
Then I click the "$navigation li:nth-child(3) a" element
Then I click the "$navigation li:nth-child(4) a" element
Then I click the "$navigation li:nth-child(5) a" element
Then I click the "$navigation li:nth-child(6) a" element
Then I click the "$navigation li:nth-child(1) a" element

Scenario: Detail view has expected content
And the URL "/zoneingresses+insights/item-1" responds with
"""
Expand Down
28 changes: 28 additions & 0 deletions features/zones/zone-cps/ingresses/item/Services.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Feature: zones / ingresses / item / services
Background:
Given the CSS selectors
| Alias | Selector |
| items | [data-testid='available-services-collection'] |
| item | $items tbody tr |

And the environment
"""
KUMA_MODE: global
KUMA_SERVICE_COUNT: 2
"""

Scenario: An ingress with 2 available services
Given the URL "/zoneingresses+insights/item-1" responds with
"""
body:
zoneIngress:
zone: zone-cp-1
availableServices:
- tags:
kuma.io/service: service-1
- tags:
kuma.io/service: service-2
"""
When I visit the "/zones/zone-cp-1/ingresses/item-1/services" URL
Then the "$item" element exists 2 times

2 changes: 1 addition & 1 deletion src/app/meshes/views/MeshConfigView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</h2>
</template>

<KCard class="mt-4">
<KCard>
<template #body>
<DataSource
v-slot="{ data, error }: MeshSource"
Expand Down
3 changes: 3 additions & 0 deletions src/app/zone-egresses/sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ export const sources = (api: KumaApi) => {

const res = await api.getAllZoneEgressOverviews({ size, offset })
if (name !== '*') {
// temporary frontend filtering until we have support for filtering
// 'gresses by zone in the backend. Until we have backend support its fine
// to assume we won't need to recreate paging for 'gresses
res.items = res.items.filter((item) => {
return item.zoneEgress.zone === name
})
Expand Down
2 changes: 1 addition & 1 deletion src/app/zone-egresses/views/item/ConfigView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</h2>
</template>

<KCard class="mt-4">
<KCard>
<template #body>
<DataSource
v-slot="{ data, error }: ZoneEgressSource"
Expand Down
24 changes: 24 additions & 0 deletions src/app/zone-ingresses/data/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { ZoneIngressOverview as PartialZoneIngressOverview } from '@/types/index.d'
export type { AvailableService } from '@/types/index.d'
type PartialZoneIngress = PartialZoneIngressOverview['zoneIngress']

type RequiredZoneIngress =
Required<Pick<PartialZoneIngress,
'availableServices'
>>
& PartialZoneIngressOverview['zoneIngress']

export type ZoneIngressOverview = PartialZoneIngressOverview & {
zoneIngress: RequiredZoneIngress
}
export const ZoneIngressOverview = {
fromObject: (item: PartialZoneIngressOverview): ZoneIngressOverview => {
return {
...item,
zoneIngress: {
...item.zoneIngress,
availableServices: !Array.isArray(item.zoneIngress.availableServices) ? [] : item.zoneIngress.availableServices,
},
}
},
}
1 change: 1 addition & 0 deletions src/app/zone-ingresses/locales/en-us/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ zone-ingresses:
breadcrumbs: Ingresses
navigation:
zone-ingress-detail-view: 'Overview'
zone-ingress-services-view: 'Services'
zone-ingress-xds-config-view: 'XDS Configuration'
zone-ingress-stats-view: 'Stats'
zone-ingress-clusters-view: 'Clusters'
Expand Down
5 changes: 5 additions & 0 deletions src/app/zone-ingresses/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export const routes = (prefix = 'ingresses') => {
name: 'zone-ingress-detail-view',
component: () => import('@/app/zone-ingresses/views/item/DetailView.vue'),
},
{
path: 'services',
name: 'zone-ingress-services-view',
component: () => import('@/app/zone-ingresses/views/item/ServicesView.vue'),
},
{
path: 'xds-config',
name: 'zone-ingress-xds-config-view',
Expand Down
15 changes: 11 additions & 4 deletions src/app/zone-ingresses/sources.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ZoneIngressOverview } from './data'
import { DataSourceResponse } from '@/app/application/services/data-source/DataSourcePool'
import type KumaApi from '@/services/kuma-api/KumaApi'
import type { PaginatedApiListResponse as CollectionResponse } from '@/types/api.d'
import type { ZoneIngressOverview, ZoneIngress } from '@/types/index.d'
import type { ZoneIngress } from '@/types/index.d'

type PaginationParams = {
size: number
Expand All @@ -28,18 +29,24 @@ export type EnvoyDataSource = DataSourceResponse<object | string>
export const sources = (api: KumaApi) => {
return {

'/zone-cps/:name/ingresses': async (params: DetailParams & PaginationParams, source: Closeable) => {
'/zone-cps/:name/ingresses': async (params: DetailParams & PaginationParams, source: Closeable): Promise<ZoneIngressOverviewCollection> => {
source.close()

const { name, size, page } = params
const offset = size * (page - 1)

const res = await api.getAllZoneIngressOverviews({ size, offset })
// temporary frontend filtering until we have support for filtering
// 'gresses by zone in the backend. Until we have backend support its fine
// to assume we won't need to recreate paging for 'gresses
res.items = res.items.filter((item) => {
return item.zoneIngress.zone === name
})
res.total = res.items.length
return res
return {
...res,
total: res.items.length,
items: res.items.map(ZoneIngressOverview.fromObject),
}
},

'/zone-ingresses/:name': async (params: DetailParams, source: Closeable) => {
Expand Down
2 changes: 1 addition & 1 deletion src/app/zone-ingresses/views/item/ConfigView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</h2>
</template>

<KCard class="mt-4">
<KCard>
<template #body>
<DataSource
v-slot="{ data, error }: ZoneIngressSource"
Expand Down
2 changes: 1 addition & 1 deletion src/app/zone-ingresses/views/item/IndexView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
<script lang="ts" setup>
import { RouteRecordRaw, useRouter } from 'vue-router'
import { ZoneIngressOverviewSource } from '../../sources'
import type { ZoneIngressOverviewSource } from '../../sources'
import ErrorBlock from '@/app/common/ErrorBlock.vue'
import LoadingBlock from '@/app/common/LoadingBlock.vue'
import NavTabs, { NavTab } from '@/app/common/NavTabs.vue'
Expand Down
111 changes: 111 additions & 0 deletions src/app/zone-ingresses/views/item/ServicesView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<template>
<RouteView
v-slot="{ t }"
name="zone-ingress-services-view"
>
<AppView>
<template #title>
<h2>
<RouteTitle
:title="t('zone-ingresses.routes.item.navigation.zone-ingress-services-view')"
:render="true"
/>
</h2>
</template>

<KCard>
<template #body>
<AppCollection
data-testid="available-services-collection"
:empty-state-message="t('common.emptyState.message', { type: 'Services' })"
:headers="[
{ label: 'Name', key: 'name' },
{ label: 'Mesh', key: 'mesh' },
{ label: 'Protocol', key: 'protocol' },
{ label: 'No. Instances', key: 'instances' },
{ label: 'Actions', key: 'actions', hideLabel: true },
]"
:items="props.data.zoneIngress.availableServices"
>
<template #name="{ row: item }: {row: AvailableService}">
<RouterLink
:to="{
name: 'service-detail-view',
params: {
mesh: item.mesh,
service: item.tags['kuma.io/service'],
},
}"
>
{{ item.tags['kuma.io/service'] }}
</RouterLink>
</template>

<template #mesh="{ row: item }: {row: AvailableService}">
<RouterLink
:to="{
name: 'mesh-detail-view',
params: {
mesh: item.mesh,
},
}"
>
{{ item.mesh }}
</RouterLink>
</template>

<template #protocol="{ row: item }: {row: AvailableService}">
{{ item.tags['kuma.io/protocol'] ?? t('common.collection.none') }}
</template>

<template #instances="{ row: item }">
{{ item.instances }}
</template>

<template #actions="{ row: item }: {row: AvailableService}">
<KDropdownMenu
class="actions-dropdown"
:kpop-attributes="{ placement: 'bottomEnd', popoverClasses: 'mt-5 more-actions-popover' }"
width="150"
>
<template #default>
<KButton
class="non-visual-button"
appearance="secondary"
size="small"
>
<MoreIcon :size="KUI_ICON_SIZE_30" />
</KButton>
</template>
<template #items>
<KDropdownItem
:item="{
to: {
name: 'service-detail-view',
params: {
mesh: item.mesh,
service: item.tags['kuma.io/service'],
},
},
label: t('common.collection.actions.view'),
}"
/>
</template>
</KDropdownMenu>
</template>
</AppCollection>
</template>
</KCard>
</AppView>
</RouteView>
</template>

<script lang="ts" setup>
import { KUI_ICON_SIZE_30 } from '@kong/design-tokens'
import type { AvailableService, ZoneIngressOverview } from '../../data'
import AppCollection from '@/app/application/components/app-collection/AppCollection.vue'
const props = defineProps<{
data: ZoneIngressOverview
}>()
</script>
2 changes: 1 addition & 1 deletion src/app/zones/views/item/ConfigView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</h2>
</template>

<KCard class="mt-4">
<KCard>
<template #body>
<template
v-for="(conf, i) in [getConfig(props.data)]"
Expand Down
2 changes: 1 addition & 1 deletion src/locales/en-us/common/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ common:
message: 'There are no {type} present'
icon: 'stateNoData'
collection:
none: ' '
none: ''
actions:
delete: 'Delete'
edit: 'Edit'
Expand Down
1 change: 1 addition & 0 deletions src/test-support/fake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export type MockEnvKeys = keyof {
KUMA_DATAPLANE_COUNT: string
KUMA_CIRCUITBREAKER_COUNT: string
KUMA_FAULTINJECTION_COUNT: string
KUMA_SERVICE_COUNT: string
KUMA_SERVICEINSIGHT_COUNT: string
KUMA_EXTERNALSERVICE_COUNT: string
KUMA_ZONEEGRESS_COUNT: string
Expand Down
31 changes: 11 additions & 20 deletions src/test-support/mocks/src/zoneingresses+insights/_.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default ({ fake, env }: EndpointDependencies): MockResponder => (req) =>
const zoneName = fake.hacker.noun()

const subscriptionCount = parseInt(env('KUMA_SUBSCRIPTION_COUNT', `${fake.number.int({ min: 1, max: 10 })}`))
const serviceCount = parseInt(env('KUMA_SERVICE_COUNT', `${fake.number.int({ min: 1, max: 10 })}`))
return {
headers: {},
body: {
Expand All @@ -19,30 +20,20 @@ export default ({ fake, env }: EndpointDependencies): MockResponder => (req) =>
port: fake.internet.port(),
advertisedPort: fake.internet.port(),
},
availableServices: [
{
tags: {
app: 'demo-app',
'kuma.io/protocol': fake.kuma.protocol(),
'kuma.io/service': 'demo-app_kuma-demo_svc_5000',
'kuma.io/zone': zoneName,
'pod-template-hash': '5845d6447b',
},
instances: 1,
mesh: 'default',
},
{
availableServices: Array.from({ length: serviceCount }).map(_ => {
const mesh = `${fake.hacker.noun()}-app`
return {
tags: {
app: 'redis',
app: mesh,
'kuma.io/protocol': fake.kuma.protocol(),
'kuma.io/service': 'redis_kuma-demo_svc_6379',
'kuma.io/service': `${mesh}_${fake.hacker.noun()}_svc_${fake.number.int({ min: 0, max: 65535 })}`,
'kuma.io/zone': zoneName,
'pod-template-hash': '59c9d56fc',
'pod-template-hash': fake.string.alphanumeric({ casing: 'lower', length: 10 }),
},
instances: 1,
mesh: 'default',
},
],
instances: fake.number.int({ min: 1, max: 100 }),
mesh,
}
}),
},
zoneIngressInsight: {
subscriptions: Array.from({ length: subscriptionCount }).map((item, i, arr) => {
Expand Down
2 changes: 1 addition & 1 deletion src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ export interface ZoneIngressNetworking {
}

export interface AvailableService {
tags?: Record<string, string>
tags: Record<'kuma.io/service', string> & Record<string, string | undefined>
instances?: number
mesh?: string
externalService?: boolean
Expand Down

0 comments on commit cf19850

Please sign in to comment.