Skip to content
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

feat: changes policy type dropdown to in-page list #1356

Merged
merged 14 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from 13 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
2 changes: 1 addition & 1 deletion features/application/Titles.feature
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ Feature: The HTML title is correct on each page
| /mesh/default/data-planes | Data Plane Proxies |
| /mesh/default/data-plane/data-plane-name | Data Plane Proxy |

| /mesh/default/policies/circuit-breakers | CircuitBreaker |
| /mesh/default/policies/circuit-breakers | Policies |
| /mesh/default/policy/circuit-breakers/program-0 | program-0 CircuitBreaker |
32 changes: 26 additions & 6 deletions features/mesh/policies/Index.feature
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Feature: mesh / policies / index
Background:
Given the CSS selectors
| Alias | Selector |
| policy-type-list | [data-testid='policy-type-list'] |
| items | [data-testid='policy-collection'] |
| items-header | $items th |
| item | $items tbody tr |
Expand All @@ -23,7 +24,7 @@ Feature: mesh / policies / index
- total: 2
FaultInjection: ~
HealthChecks: ~
MeshGatewayRoute',
MeshGatewayRoute: ~
MeshGateway: ~
ProxyTemplate: ~
RateLimit: ~
Expand All @@ -48,18 +49,17 @@ Feature: mesh / policies / index
Then the "$button-docs" element exists

Scenario: The items have the correct columns
Then the "$items-header" element exists 3 times
Then the "$items-header" element exists 2 times
Then the "$items-header" elements contain
| Value |
| Name |
| Type |

Scenario: The items have the expected content and UI elements
Then the "$button-tab-selected" element exists
Then the "$item" element exists 2 times
Then the "$item:nth-child(1)" element contains
| Value |
| fake-cb-1 |
| CircuitBreaker |
| Value |
| fake-cb-1 |

Scenario: Clicking the link goes to the detail page and back again
Then the "$item:nth-child(1) td:nth-child(1)" element contains "fake-cb-1"
Expand All @@ -68,3 +68,23 @@ Feature: mesh / policies / index

When I click the "$breadcrumbs > .k-breadcrumbs-item:nth-child(3) > a" element
Then the "$item" element exists 2 times

Scenario: Clicking policy types in the sidebar switches listing
Given the URL "/meshes/default/meshfaultinjections" responds with
"""
body:
items:
- name: mfi-1
spec:
targetRef:
kind: MeshService
name: service-1
- name: mfi-2
"""

When I visit the "/mesh/default/policies/circuit-breakers" URL
Then the "$item:nth-child(1)" element contains "fake-cb-1"

When I click the "[data-testid='policy-type-link-MeshFaultInjection']" element
Then the "$item:nth-child(1)" element contains "mfi-1"
And the "$item:nth-child(1)" element contains "MeshService service-1"
12 changes: 8 additions & 4 deletions src/app/common/DocumentationLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@
icon="book"
color="currentColor"
size="16"
hide-title
:title="t('common.documentation')"
/>

<span class="visually-hidden">Documentation</span>
<span class="visually-hidden">{{ t('common.documentation') }}</span>
</a>
</template>

<script lang="ts" setup>
import { useI18n } from '@/utilities'

const { t } = useI18n()

const props = defineProps({
href: {
type: String,
Expand All @@ -28,7 +32,7 @@ const props = defineProps({
.docs-link {
display: inline-flex;
align-items: center;
padding-right: var(--spacing-sm);
padding-left: var(--spacing-sm);
padding-right: $kui-space-40;
padding-left: $kui-space-40;
}
</style>
279 changes: 279 additions & 0 deletions src/app/policies/components/PolicyList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
<template>
kleinfreund marked this conversation as resolved.
Show resolved Hide resolved
<div class="policy-list-content">
<KCard
class="policy-type-list"
data-testid="policy-type-list"
>
<template #body>
<div
v-for="(policyType, index) in props.policyTypes"
:key="index"
class="policy-type-link-wrapper"
:class="{
'policy-type-link-wrapper--is-active': policyType.path === props.currentPolicyType.path,
}"
>
<RouterLink
class="policy-type-link"
:to="{
name: 'policies-list-view',
params: {
mesh: route.params.mesh,
policyPath: policyType.path,
},
}"
:data-testid="`policy-type-link-${policyType.name}`"
>
{{ policyType.name }}
</RouterLink>

<div class="policy-count">
{{ props.meshInsight?.policies?.[policyType.name]?.total ?? 0 }}
</div>
</div>
</template>
</KCard>

<div class="policy-list">
<div class="stack">
<KCard>
<template #body>
<div class="description">
<div class="description-content">
<h3>
<PolicyTypeTag :policy-type="props.currentPolicyType.name">
{{ t('policies.collection.title', { name: props.currentPolicyType.name }) }}
</PolicyTypeTag>
</h3>

<p>{{ t('policies.collection.description') }}</p>
</div>

<div class="description-actions">
<KBadge
v-if="props.currentPolicyType.isExperimental"
appearance="warning"
>
{{ t('policies.collection.beta') }}
</KBadge>

<KBadge
v-if="props.currentPolicyType.isInbound"
appearance="neutral"
>
{{ t('policies.collection.inbound') }}
</KBadge>

<KBadge
v-if="props.currentPolicyType.isOutbound"
appearance="neutral"
>
{{ t('policies.collection.outbound') }}
</KBadge>

<DocumentationLink
:href="t('policies.href.docs', { name: props.currentPolicyType.name })"
data-testid="policy-documentation-link"
/>
</div>
</div>
</template>
</KCard>

<KCard>
<template #body>
<AppCollection
class="policy-collection"
data-testid="policy-collection"
:empty-state-title="t('common.emptyState.title')"
:empty-state-message="t('common.emptyState.message', { type: `${props.currentPolicyType.name} policies` })"
:headers="[
{ label: 'Name', key: 'name' },
props.currentPolicyType.isTargetRefBased ? { label: 'Target ref', key: 'targetRef' } : undefined,
{ label: 'Actions', key: 'actions', hideLabel: true },
].filter(notEmpty)"
:page-number="props.pageNumber"
:page-size="props.pageSize"
:total="props.policyCollection?.total"
:items="props.policyCollection?.items"
:error="props.policyError"
@change="emit('change', $event)"
>
<template #name="{ rowValue }">
<RouterLink
:to="{
name: 'policy-detail-view',
params: {
mesh: route.params.mesh,
policyPath: props.currentPolicyType.path,
policy: rowValue,
},
}"
>
{{ rowValue }}
</RouterLink>
</template>

<template #targetRef="{ row }">
<template v-if="props.currentPolicyType.isTargetRefBased">
<KBadge appearance="neutral">
{{ row.spec.targetRef.kind }}<span v-if="row.spec.targetRef.name">:<b>{{ row.spec.targetRef.name }}</b>
</span>
</KBadge>
</template>

<template v-else>
{{ t('common.detail.none') }}
</template>
</template>

<template #actions="{ row }">
<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"
>
<template #icon>
<KIcon
color="var(--black-400)"
icon="more"
size="16"
/>
</template>
</KButton>
</template>

<template #items>
<KDropdownItem
:item="{
to: {
name: 'policy-detail-view',
params: {
mesh: route.params.mesh,
policyPath: props.currentPolicyType.path,
policy: row.name,
},
},
label: t('common.collection.actions.view'),
}"
/>
</template>
</KDropdownMenu>
</template>
</AppCollection>
</template>
</KCard>
</div>
</div>
</div>
</template>

<script lang="ts" setup>
import {
KBadge,
KButton,
KCard,
KDropdownItem,
KDropdownMenu,
KIcon,
} from '@kong/kongponents'
import { useRoute } from 'vue-router'

import { PolicyCollection } from '../sources'
import AppCollection from '@/app/application/components/app-collection/AppCollection.vue'
import DocumentationLink from '@/app/common/DocumentationLink.vue'
import PolicyTypeTag from '@/app/common/PolicyTypeTag.vue'
import type { MeshInsight, PolicyType } from '@/types/index.d'
import { useI18n } from '@/utilities'
import { notEmpty } from '@/utilities/notEmpty'

type ChangeValue = {
page: number
size: number
s: string
}

const { t } = useI18n()
const route = useRoute()

const props = defineProps<{
pageNumber: number
pageSize: number
policyTypes: PolicyType[]
currentPolicyType: PolicyType
policyCollection: PolicyCollection | undefined
policyError: Error | undefined
meshInsight: MeshInsight | undefined
}>()

const emit = defineEmits<{
(event: 'change', value: ChangeValue): void
}>()
</script>

<style lang="scss" scoped>
.policy-list-content {
display: flex;
gap: var(--AppGap);
}

.policy-type-list {
align-self: flex-start;
}

.policy-type-link-wrapper {
font-size: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
gap: $kui-space-60;
}

.policy-type-link-wrapper--is-active {
background-color: $kui-color-background-primary-weakest;
}

.policy-type-link-wrapper:not(.policy-type-link-wrapper--is-active) {
color: $kui-color-text-neutral;
}

.policy-type-link {
color: currentColor;
flex-grow: 1;
padding: $kui-space-40 $kui-space-60;
}

.policy-count {
text-align: right;
padding-right: $kui-space-60;
}

.policy-list {
flex-grow: 1;
}

.description {
display: flex;
gap: $kui-space-60;
}

.description-content {
flex-grow: 1;
}

.description-actions {
display: flex;
align-items: flex-start;
gap: $kui-space-40;
}

.actions-dropdown {
display: inline-block;
}
</style>
8 changes: 7 additions & 1 deletion src/app/policies/locales/en-us/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ policies:
title: "{name} {type}"
breadcrumbs: Policies
items:
title: "{name}"
title: "Policies"
href:
docs: '{KUMA_DOCS_URL}/policies/{name}?{KUMA_UTM_QUERY_PARAMS}'
collection:
beta: 'Beta'
title: 'About {name}'
description: 'Use policies to apply filters to incoming or outgoing traffic of Data Plane Proxies. To generate the Envoy configuration of a proxy the control-plane uses its data-plane configuration with the policies matching it.'
inbound: 'Inbound'
outbound: 'Outbound'
Loading
Loading