aboutsummaryrefslogtreecommitdiff
path: root/kamon-status/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'kamon-status/src/components')
-rw-r--r--kamon-status/src/components/Card.vue19
-rw-r--r--kamon-status/src/components/EnvironmentCard.vue58
-rw-r--r--kamon-status/src/components/InstrumentationModuleStatusCard.vue2
-rw-r--r--kamon-status/src/components/MetricList.vue83
-rw-r--r--kamon-status/src/components/MetricListItem.vue108
-rw-r--r--kamon-status/src/components/ModuleList.vue40
-rw-r--r--kamon-status/src/components/ModuleStatusCard.vue4
-rw-r--r--kamon-status/src/components/OverviewCard.vue42
-rw-r--r--kamon-status/src/components/StatusCard.vue9
-rw-r--r--kamon-status/src/components/StatusSection.vue19
10 files changed, 275 insertions, 109 deletions
diff --git a/kamon-status/src/components/Card.vue b/kamon-status/src/components/Card.vue
index d77596da..d3300336 100644
--- a/kamon-status/src/components/Card.vue
+++ b/kamon-status/src/components/Card.vue
@@ -1,19 +1,20 @@
<template>
- <div class="outer">
+ <div class="card-wrapper">
<slot/>
</div>
</template>
+<script lang="ts">
+import { Component, Vue } from 'vue-property-decorator'
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped lang="scss">
-.outer {
+@Component
+export default class Card extends Vue {}
+</script>
+
+
+<style lang="scss">
+.card-wrapper {
background-color: white;
box-shadow: 0 2px 9px 1px rgba(0, 0, 0, 0.1);
}
-
-hr {
- margin: 0px;
- border-color: #f3f3f3;
-}
</style>
diff --git a/kamon-status/src/components/EnvironmentCard.vue b/kamon-status/src/components/EnvironmentCard.vue
index 97e79d28..98dc3f9f 100644
--- a/kamon-status/src/components/EnvironmentCard.vue
+++ b/kamon-status/src/components/EnvironmentCard.vue
@@ -1,47 +1,47 @@
<template>
- <div class="row">
- <div class="col-12">
- <card>
- <div class="row py-2 no-gutters">
- <div class="col-auto py-2 px-3">
- <div class="text-uppercase text-label pb-1">Service</div>
- <h6>{{ service }}</h6>
- </div>
- <div class="col-auto py-2 px-3">
- <div class="text-uppercase text-label pb-1">Host</div>
- <h6>{{ host }}</h6>
- </div>
- <div class="col-auto py-2 px-3">
- <div class="text-uppercase text-label pb-1">instance</div>
- <h6>{{instance}}</h6>
+ <status-section title="Environment">
+ <card>
+ <div class="row py-2 no-gutters">
+ <div class="col-auto py-2 px-3">
+ <div class="text-uppercase text-label pb-1">Service</div>
+ <h6>{{ service }}</h6>
+ </div>
+ <div class="col-auto py-2 px-3">
+ <div class="text-uppercase text-label pb-1">Host</div>
+ <h6>{{ host }}</h6>
+ </div>
+ <div class="col-auto py-2 px-3">
+ <div class="text-uppercase text-label pb-1">instance</div>
+ <h6>{{instance}}</h6>
+ </div>
+ <div class="col-12 col-md-3 py-2 px-3">
+ <div class="text-uppercase text-label pb-1">tags</div>
+ <div class="tag-container" v-if="Object.keys(environmentTags).length > 0">
+ <span class="tag" v-for="tag in Object.keys(environmentTags)" :key="tag">
+ {{ tag }}=<span class="tag-value">{{ environmentTags[tag] }}</span>
+ </span>
</div>
- <div class="col-12 col-md-3 py-2 px-3">
- <div class="text-uppercase text-label pb-1">tags</div>
- <div class="tag-container" v-if="Object.keys(environmentTags).length > 0">
- <span class="tag" v-for="tag in Object.keys(environmentTags)" :key="tag">
- {{ tag }}=<span class="tag-value">{{ environmentTags[tag] }}</span>
- </span>
- </div>
- <div v-else>
- <h6>None</h6>
- </div>
+ <div v-else>
+ <h6>None</h6>
</div>
</div>
- </card>
- </div>
- </div>
+ </div>
+ </card>
+ </status-section>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import {Environment} from '../api/StatusApi'
import Card from './Card.vue'
+import StatusSection from '../components/StatusSection.vue'
import {Option, none} from 'ts-option'
@Component({
components: {
- card: Card
+ 'card': Card,
+ 'status-section': StatusSection
}
})
export default class EnvironmentCard extends Vue {
diff --git a/kamon-status/src/components/InstrumentationModuleStatusCard.vue b/kamon-status/src/components/InstrumentationModuleStatusCard.vue
index 6fb1206f..ed74143a 100644
--- a/kamon-status/src/components/InstrumentationModuleStatusCard.vue
+++ b/kamon-status/src/components/InstrumentationModuleStatusCard.vue
@@ -1,6 +1,6 @@
<template>
<status-card :indicator-text="runStatus.message" :indicator-icon="runStatus.icon" :indicator-background-color="runStatus.color">
- <div slot="default" class="py-3">
+ <div slot="default" class="py-3 pl-4">
<h5 class="mb-0">{{ module.name }}</h5>
<div class="text-label">
{{ module.description }}
diff --git a/kamon-status/src/components/MetricList.vue b/kamon-status/src/components/MetricList.vue
index 60f7499a..f0f4637b 100644
--- a/kamon-status/src/components/MetricList.vue
+++ b/kamon-status/src/components/MetricList.vue
@@ -2,27 +2,19 @@
<div class="row no-gutters">
<div class="col-12">
<div class="search-box mb-3">
- <input class="w-100 px-3 py-2" v-model="filterPattern" type="text" placeholder="filter">
+ <span class="search-icon"><i class="fas fa-search fa-fw fa-flip-horizontal"></i></span>
+ <input class="w-100" v-model="filterPattern" type="text">
<span class="search-stats">{{ searchStats }}</span>
</div>
</div>
- <div class="col-12">
- <card v-if="matchedMetrics.length > 0">
- <div class="row no-gutters" v-for="(metric, index) in matchedMetrics" :key="metric.search">
- <div class="col-12 px-3 pt-2 pb-3">
- <div class="text-uppercase text-label">{{ metric.type }}</div>
- <h5>{{ metric.name }}</h5>
- <div class="tag-container">
- <span class="tag" v-for="tag in Object.keys(metric.tags)" :key="tag">
- {{ tag }}=<span class="tag-value">{{ metric.tags[tag] }}</span>
- </span>
- </div>
-
- </div>
- <hr v-if="index < (matchedMetrics.length - 1)" class="w-100">
+ <div class="col-12" v-if="matchedMetrics.length > 0">
+ <div class="row no-gutters" v-for="(group, index) in groups" :key="group.name">
+ <div class="col-12">
+ <metric-list-item :group="group"/>
</div>
- </card>
+ <hr v-if="index < (groups.length - 1)" class="w-100">
+ </div>
</div>
</div>
</template>
@@ -31,30 +23,55 @@
import { Component, Prop, Vue } from 'vue-property-decorator'
import {Metric} from '../api/StatusApi'
import Card from './Card.vue'
-
+import MetricListItem, {MetricGroup} from './MetricListItem.vue'
+import StatusCard from './StatusCard.vue'
+import _ from 'underscore'
@Component({
components: {
- card: Card
+ 'card': Card,
+ 'status-card': StatusCard,
+ 'metric-list-item': MetricListItem
}
})
export default class MetricList extends Vue {
- @Prop() private metrics!: Metric[]
+ @Prop( { default: [] }) private metrics!: Metric[]
private filterPattern: string = ''
get totalMetrics(): number {
return this.metrics.length
}
+ get groups(): MetricGroup[] {
+ const gropedByName = _.groupBy(this.matchedMetrics, m => m.name)
+ const metricGroups: MetricGroup[] = []
+
+ Object.keys(gropedByName).forEach(metricName => {
+ const metrics = gropedByName[metricName]
+
+ // All metrics with the same name must have the same unit (constrained in Kamon) so
+ // we can safely assume the first unit is the same for all.
+ metricGroups.push({
+ name: metricName,
+ type: metrics[0].type,
+ unitDimension: metrics[0].unitDimension,
+ unitMagnitude: metrics[0].unitMagnitude,
+ metrics
+ })
+ })
+
+ return _.sortBy(metricGroups, mg => mg.metrics.length).reverse()
+ }
+
get filterRegex(): RegExp {
return new RegExp(this.filterPattern)
}
get searchStats(): string {
if (this.filterPattern.length > 0) {
- return this.matchedMetrics.length + ' matched'
+ return 'showing ' + this.matchedMetrics.length + ' out of ' + this.totalMetrics + ' series'
} else {
- return this.totalMetrics + ' metrics'
+ return this.totalMetrics + ' series'
}
}
@@ -68,14 +85,19 @@ export default class MetricList extends Vue {
}
</script>
-<style scoped lang="scss">
+<style lang="scss">
.search-box {
input {
color: #676767;
- height: 2.5rem;
+ caret-color: #676767;
+ height: 3rem;
border: none;
- border-radius: 0.3rem;
+ border-radius: 0.4rem;
background-color: #efefef;
+ padding-left: 3.5rem;
+ font-size: 1.1rem;
+ box-shadow: 0 2px 4px 1px rgba(0, 0, 0, 0.1);
+
&:focus {
outline: none;
@@ -86,11 +108,22 @@ export default class MetricList extends Vue {
color: #929292;
}
+ .search-icon {
+ color: #c0c0c0;
+ line-height: 3rem;
+ font-size: 1.4rem;
+ position: absolute;
+ left: 1rem;
+ }
+
.search-stats {
+ color: #a2a2a2;
+ font-size: 1.1rem;
position: absolute;
- line-height: 2.5rem;
+ line-height: 3rem;
right: 0;
padding-right: 1rem;
}
}
+
</style>
diff --git a/kamon-status/src/components/MetricListItem.vue b/kamon-status/src/components/MetricListItem.vue
new file mode 100644
index 00000000..1414bbaf
--- /dev/null
+++ b/kamon-status/src/components/MetricListItem.vue
@@ -0,0 +1,108 @@
+<template>
+ <status-card indicator-background-color="#7ade94" class="metric-list-item c-pointer my-1" :class="{ 'my-4': expanded }">
+
+ <div slot="status-indicator" @click="onCardClick">
+ <div class="metric-count">
+ {{ group.metrics.length }}
+ </div>
+ <div>SERIES</div>
+ </div>
+
+ <div slot="default" @click="onCardClick">
+ <div class="row no-gutters">
+ <div class="col">
+ <div class="py-3 pl-4">
+ <h5>{{ group.name }}</h5>
+ <div class="text-label">
+ <span>{{group.type}}</span>
+ <span v-if="group.unitDimension !== 'none'"> - {{ group.unitDimension }}</span>
+ <span v-if="group.unitMagnitude !== 'none'"> - {{ group.unitMagnitude }}</span>
+ </div>
+ </div>
+ </div>
+ <div class="col-auto expansion-icon px-5">
+ <i class="fas fa-fw" :class="expansionIcon"></i>
+ </div>
+ <div class="col-12 series-container" v-if="expanded">
+ <div v-for="(metric, index) in group.metrics" :key="index">
+ <div class="p-3">
+ <h6>Incarnation #{{ index + 1 }}</h6>
+ <div class="tag-container">
+ <span class="tag" v-for="tag in Object.keys(metric.tags)" :key="tag">
+ {{ tag }}=<span class="tag-value">{{ metric.tags[tag] }}</span>
+ </span>
+ <span v-if="Object.keys(metric.tags).length === 0" class="pl-2">Base Metric - No Tags</span>
+ </div>
+ </div>
+ <hr v-if="index < (group.metrics.length - 1)" class="w-100 incarnation-hr">
+ </div>
+ </div>
+ </div>
+ </div>
+
+
+ </status-card>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import {Metric} from '../api/StatusApi'
+import Card from './Card.vue'
+import StatusCard from './StatusCard.vue'
+import _ from 'underscore'
+
+export interface MetricGroup {
+ name: string
+ type: string
+ unitDimension: string
+ unitMagnitude: string
+ metrics: Metric[]
+}
+
+@Component({
+ components: {
+ 'status-card': StatusCard
+ }
+})
+export default class MetricListItem extends Vue {
+ @Prop( { default: [] }) private group!: MetricGroup
+ private expanded: boolean = false
+
+ get expansionIcon(): string {
+ return this.expanded ? 'fa-angle-up' : 'fa-angle-down'
+ }
+
+ private onCardClick() {
+ this.expanded = !this.expanded
+ }
+}
+</script>
+
+<style lang="scss">
+
+.metric-count {
+ font-size: 2rem;
+ font-weight: 700;
+ line-height: 4rem;
+}
+
+.expansion-icon {
+ line-height: 6rem;
+ color: #d0d0d0;
+ font-size: 2rem;
+}
+
+.series-container {
+ background-color: #f7f7f7;
+}
+
+.incarnation-hr {
+ border-color: #e2e2e2;
+}
+
+.metric-list-item {
+ .tag {
+ background-color: #e6e6e6;
+ }
+}
+</style>
diff --git a/kamon-status/src/components/ModuleList.vue b/kamon-status/src/components/ModuleList.vue
index eddc05d0..6cef9e2d 100644
--- a/kamon-status/src/components/ModuleList.vue
+++ b/kamon-status/src/components/ModuleList.vue
@@ -1,23 +1,25 @@
<template>
- <div class="row">
- <div class="col-12 pt-4 pb-2">
- <h3>Reporters</h3>
- </div>
- <div class="col-12 py-1" v-for="reporter in reporterModules" :key="reporter.name">
- <module-status-card :module="reporter" />
- </div>
- <div v-if="!hasApmModule" class="col-12 py-1 apm-suggestion">
- <a href="https://kamon.io/" target="_blank">
- <module-status-card :is-suggestion="true" :module="apmModuleSuggestion" />
- </a>
- </div>
+ <div class="w-100">
+ <status-section title="Reporters">
+ <div class="row">
+ <div class="col-12 py-1" v-for="reporter in reporterModules" :key="reporter.name">
+ <module-status-card :module="reporter" />
+ </div>
+ <div v-if="!hasApmModule" class="col-12 py-1 apm-suggestion">
+ <a href="https://kamon.io/" target="_blank">
+ <module-status-card :is-suggestion="true" :module="apmModuleSuggestion" />
+ </a>
+ </div>
+ </div>
+ </status-section>
- <div class="col-12 pt-4 pb-2" v-if="plainModules.length > 0">
- <h2>Modules</h2>
- </div>
- <div class="col-12 py-1" v-for="module in plainModules" :key="module.name">
- <module-status-card :module="module"/>
- </div>
+ <status-section title="Modules" v-if="plainModules.length > 0">
+ <div class="row">
+ <div class="col-12 py-1" v-for="module in plainModules" :key="module.name">
+ <module-status-card :module="module"/>
+ </div>
+ </div>
+ </status-section>
</div>
</template>
@@ -25,10 +27,12 @@
import { Component, Prop, Vue } from 'vue-property-decorator'
import {Module, ModuleKind} from '../api/StatusApi'
import ModuleStatusCard from './ModuleStatusCard.vue'
+import StatusSection from './StatusSection.vue'
@Component({
components: {
+ 'status-section': StatusSection,
'module-status-card': ModuleStatusCard
}
})
diff --git a/kamon-status/src/components/ModuleStatusCard.vue b/kamon-status/src/components/ModuleStatusCard.vue
index 825fce40..d095d7b3 100644
--- a/kamon-status/src/components/ModuleStatusCard.vue
+++ b/kamon-status/src/components/ModuleStatusCard.vue
@@ -1,6 +1,6 @@
<template>
<status-card :indicator-text="runStatus.message" :indicator-icon="runStatus.icon" :indicator-background-color="runStatus.color">
- <div slot="default" class="py-3">
+ <div slot="default" class="py-3 pl-4">
<h5 class="mb-0 mr-3 d-inline-block">{{ module.name }}</h5>
<div class="tag-container d-inline-block" v-if="!isSuggestion">
<span class="tag">{{ module.kind }}</span>
@@ -36,7 +36,7 @@ export default class ModuleStatusCard extends Vue {
get runStatus(): { message: string, color: string, icon: string } {
if (this.isSuggestion) {
return { message: 'suggested', color: '#5fd7cc', icon: 'fa-plug' }
- } else if(!this.module.enabled) {
+ } else if (!this.module.enabled) {
return { message: 'disabled', color: '#ff9898', icon: 'fa-stop-circle' }
} else {
return this.module.started ?
diff --git a/kamon-status/src/components/OverviewCard.vue b/kamon-status/src/components/OverviewCard.vue
index a1805596..8939d93d 100644
--- a/kamon-status/src/components/OverviewCard.vue
+++ b/kamon-status/src/components/OverviewCard.vue
@@ -1,24 +1,22 @@
<template>
- <div class="row">
- <div class="col-12">
- <card>
- <div class="row py-2 no-gutters">
- <div class="col-12 col-md-3 py-2 px-3">
- <div class="text-uppercase text-label pb-1">Instrumentation</div>
- <h5>{{instrumentationStatusMessage}}</h5>
- </div>
- <div class="col-12 col-md-3 py-2 px-3">
- <div class="text-uppercase text-label pb-1">Reporters</div>
- <h5>{{ activeReporters.length }} Started</h5>
- </div>
- <div class="col-12 col-md-3 py-2 px-3">
- <div class="text-uppercase text-label pb-1">Metrics</div>
- <h5>{{metricsStatusMessage}}</h5>
- </div>
+ <status-section title="Overview">
+ <card>
+ <div class="row py-2 no-gutters">
+ <div class="col-12 col-md-3 py-2 px-3">
+ <div class="text-uppercase text-label pb-1">Instrumentation</div>
+ <h5>{{instrumentationStatusMessage}}</h5>
</div>
- </card>
- </div>
- </div>
+ <div class="col-12 col-md-3 py-2 px-3">
+ <div class="text-uppercase text-label pb-1">Reporters</div>
+ <h5>{{ activeReporters.length }} Started</h5>
+ </div>
+ <div class="col-12 col-md-3 py-2 px-3">
+ <div class="text-uppercase text-label pb-1">Metrics</div>
+ <h5>{{metricsStatusMessage}}</h5>
+ </div>
+ </div>
+ </card>
+ </status-section>
</template>
@@ -26,11 +24,13 @@
import { Component, Vue, Prop } from 'vue-property-decorator'
import {Option, none, some} from 'ts-option'
import Card from '../components/Card.vue'
+import StatusSection from '../components/StatusSection.vue'
import {StatusApi, ModuleRegistry, ModuleKind, MetricRegistry, Module, Metric, Instrumentation} from '../api/StatusApi'
@Component({
components: {
- card: Card
+ 'card': Card,
+ 'status-section': StatusSection
},
})
export default class OverviewCard extends Vue {
@@ -57,7 +57,7 @@ export default class OverviewCard extends Vue {
}
get metricsStatusMessage(): string {
- return this.trackedMetrics.map(mc => mc + ' Tracked').getOrElse('Unknown')
+ return this.trackedMetrics.map(mc => mc + ' Series').getOrElse('Unknown')
}
private isReporter(module: Module): boolean {
diff --git a/kamon-status/src/components/StatusCard.vue b/kamon-status/src/components/StatusCard.vue
index 7293940e..c402842f 100644
--- a/kamon-status/src/components/StatusCard.vue
+++ b/kamon-status/src/components/StatusCard.vue
@@ -1,6 +1,6 @@
<template>
<card>
- <div class="row status-card">
+ <div class="row status-card no-gutters">
<div class="col-auto">
<div class="status-indicator-wrap text-center text-uppercase" :style="indicatorStyle">
<slot name="status-indicator">
@@ -56,15 +56,16 @@ $indicator-size: 6rem;
.status-indicator-wrap {
height: 100%;
min-width: $indicator-size;
+ max-width: $indicator-size;
min-height: $indicator-size;
+ font-size: 0.9rem;
+ font-weight: 600;
}
.status-indicator {
line-height: 2rem;
- font-size: 0.9rem;
- font-weight: 600;
- i {
+ i {
font-size: 2.5rem;
}
}
diff --git a/kamon-status/src/components/StatusSection.vue b/kamon-status/src/components/StatusSection.vue
new file mode 100644
index 00000000..b94b5bdf
--- /dev/null
+++ b/kamon-status/src/components/StatusSection.vue
@@ -0,0 +1,19 @@
+<template>
+ <div class="row">
+ <div class="col-12 pt-4 pb-2">
+ <h3>{{ title }}</h3>
+ </div>
+ <div class="col-12 py-1">
+ <slot name="default"/>
+ </div>
+ </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+
+@Component
+export default class StatusSection extends Vue {
+ @Prop() private title!: string
+}
+</script> \ No newline at end of file