Skip to content

Commit eeb75ce

Browse files
authored
feat(vitals): migrate contextual analytics from monolith [MA-1788] (#133)
1 parent ed03669 commit eeb75ce

32 files changed

+1576
-22
lines changed

cypress/e2e/specs/application_registration.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ describe('Application Registration', () => {
121121
cy.mockAppearance()
122122
cy.mockStylesheetCss()
123123
cy.mockStylesheetFont()
124+
cy.mockContextualAnalytics()
124125
})
125126

126127
it('displays empty dashboard for my apps', () => {
@@ -229,8 +230,8 @@ describe('Application Registration', () => {
229230
mockApplicationWithCredAndReg(apps[0])
230231
// go to application details
231232
cy.get('[data-testid="applications-table"] tbody tr')
232-
.contains(apps[0].name)
233-
.click()
233+
.contains(apps[0].name)
234+
.click()
234235

235236
// use breadcrumb to navigate back to My Apps
236237
cy.get('.k-breadcrumbs .k-breadcrumbs-item a').contains('My Apps').click()

cypress/e2e/support/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ declare global {
2525
mockProductApiDocument(productId?: string, options?: Partial<TypeOptions> & {body: any}): Chainable<JQuery<HTMLElement>>
2626
mockProduct(productId?: string, mockProduct?: Product, mockVersions?: ProductVersion[]): Chainable<JQuery<HTMLElement>>
2727
mockApplications(searchResults?: Array<GetApplicationResponse>, totalCount?: number, pageSize?: number, pageNumber?: number): Chainable<JQuery<HTMLElement>>
28+
mockContextualAnalytics(): Chainable<JQuery<HTMLElement>>
2829
mockRegistrations(applicationId?: string, registrations?: Array<GetRegistrationResponse>, totalCount?: number): Chainable<JQuery<HTMLElement>>
2930
mockProductVersionApplicationRegistration(value:any): Chainable<JQuery<HTMLElement>>
3031
mockProductsCatalog(count?: number, overrides?: Partial<ProductCatalogIndexSource>[], pageNum?:number, pageSize?:number): Chainable<JQuery<HTMLElement>>

cypress/e2e/support/mock-commands.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,15 @@ Cypress.Commands.add('mockRegistrations', (applicationId = '*', registrations =
331331
}).as('getRegistrations')
332332
})
333333

334+
Cypress.Commands.add('mockContextualAnalytics', () => {
335+
return cy.intercept(
336+
'POST', '**/api/v2/stats', {
337+
statusCode: 200,
338+
body: { records: [] },
339+
delay: 0
340+
}).as('getContextualAnalytics')
341+
})
342+
334343
Cypress.Commands.add('mockProductVersionApplicationRegistration', (version, config = {}) => {
335344
return cy.intercept(
336345
'GET',

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
"launchdarkly-js-client-sdk": "3.1.3"
2626
},
2727
"dependencies": {
28+
"@kong-ui-public/analytics-chart": "0.8.25",
29+
"@kong-ui-public/analytics-metric-provider": "1.1.17",
30+
"@kong-ui-public/analytics-utilities": "0.5.3",
2831
"@kong-ui-public/copy-uuid": "1.1.5",
2932
"@kong-ui-public/document-viewer": "0.10.5",
3033
"@kong-ui-public/spec-renderer": "0.11.6",
@@ -60,6 +63,7 @@
6063
"cypress-split": "1.3.8",
6164
"cypress-terminal-report": "5.3.2",
6265
"cz-conventional-changelog": "3.3.0",
66+
"druid.d.ts": "0.12.2",
6367
"eslint": "8.46.0",
6468
"eslint-plugin-cypress": "2.13.3",
6569
"eslint-plugin-import": "2.28.0",

src/assets/mixins.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Mixins
2+
3+
@mixin grid-columns($columns) {
4+
display: grid;
5+
grid-template-columns: repeat($columns, 1fr);
6+
grid-column-gap: 16px;
7+
grid-row-gap: 16px;
8+
}

src/assets/variables.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Breakpoints
2+
$viewport-sm: 640px;
3+
$viewport-md: 768px;
4+
$viewport-lg: 1024px; // Mobile layout breakpoint
5+
$viewport-xl: 1280px;
6+
$viewport-2xl: 1536px;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { App } from 'vue'
22
import Content from './Content.vue'
33
import EmptyState from './EmptyState.vue'
4+
import AnalyticsEmptyState from './vitals/AnalyticsEmptyState.vue'
45

56
export const registerComponents = (app: App<Element>) => {
67
app.component('Content', Content)
78
app.component('EmptyState', EmptyState)
9+
app.component('AnalyticsEmptyState', AnalyticsEmptyState)
810
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<template>
2+
<KEmptyState
3+
data-testid="analytics-empty-state"
4+
cta-is-hidden
5+
icon="stateNoData"
6+
icon-size="96"
7+
>
8+
<template #title>
9+
<h5>{{ title }}</h5>
10+
</template>
11+
<template #message>
12+
<slot name="message">
13+
{{ message }}
14+
</slot>
15+
</template>
16+
</KEmptyState>
17+
</template>
18+
19+
<script setup lang="ts">
20+
withDefaults(defineProps<{
21+
title?: string,
22+
message?: string
23+
}>(), {
24+
title: '',
25+
message: ''
26+
})
27+
</script>
28+
29+
<style lang="scss">
30+
// !important required because kemptystate has no theming options
31+
.empty-state-wrapper {
32+
color: var(--text_colors-primary) !important;
33+
border-color: var(--section_colors-stroke, #E7E7EC) !important;
34+
border-width: 1px;
35+
background-color: var(--section_colors-body, #fff) !important;
36+
37+
.k-empty-state-message {
38+
color: var(--text_colors-primary) !important;
39+
}
40+
41+
.k-empty-state-title-header {
42+
color: var(--text_colors-headings) !important;
43+
}
44+
45+
.k-button {
46+
background-color: var(--button_colors-primary-fill, #000) !important;
47+
color: var(--text_colors-primary, #fff) !important;
48+
font-weight: 600 !important;
49+
border-radius: 100px;
50+
}
51+
52+
svg {
53+
display: inline-block;
54+
margin: 0 auto;
55+
}
56+
}
57+
</style>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<template>
2+
<KCard
3+
class="mb-3 analytics-overview"
4+
data-testid="analytics-metrics-overview"
5+
>
6+
<template #body>
7+
<MetricsProvider
8+
v-bind="metricProviderProps"
9+
>
10+
<MetricsConsumer />
11+
</MetricsProvider>
12+
</template>
13+
</KCard>
14+
</template>
15+
16+
<script setup lang="ts">
17+
import '@kong-ui-public/metric-cards/dist/style.css'
18+
19+
// Enums and Interfaces
20+
import { Timeframe } from '@kong-ui-public/analytics-utilities'
21+
22+
// Components
23+
import MetricsProvider from './MetricsProvider.vue'
24+
import { EXPLORE_V2_DIMENSIONS, EXPLORE_V2_FILTER_TYPES, MetricsConsumer } from '@kong-ui-public/analytics-metric-provider'
25+
import { computed } from 'vue'
26+
27+
const props = defineProps<{
28+
applicationId: string,
29+
productVersionIds?: string[],
30+
timeframe: Timeframe,
31+
}>()
32+
33+
const metricProviderProps = computed(() => ({
34+
overrideTimeframe: props.timeframe,
35+
additionalFilter: [
36+
{
37+
dimension: EXPLORE_V2_DIMENSIONS.APPLICATION,
38+
type: EXPLORE_V2_FILTER_TYPES.IN,
39+
values: [props.applicationId]
40+
},
41+
...(props.productVersionIds?.length > 0
42+
? [{
43+
dimension: EXPLORE_V2_DIMENSIONS.API_PRODUCT_VERSION,
44+
type: EXPLORE_V2_FILTER_TYPES.IN,
45+
values: props.productVersionIds
46+
}]
47+
: [])
48+
]
49+
}))
50+
51+
</script>
52+
53+
<style lang="scss">
54+
@import '../../assets/variables.scss';
55+
56+
.analytics-overview {
57+
background-color: var(--white, #fff) !important;
58+
59+
.kong-ui-public-metric-card-container {
60+
.metricscard {
61+
@media (min-width: $viewport-md) {
62+
max-width: 220px;
63+
justify-content: space-around;
64+
}
65+
}
66+
}
67+
}
68+
</style>

0 commit comments

Comments
 (0)