aboutsummaryrefslogtreecommitdiff
path: root/kamon-status/src/components
diff options
context:
space:
mode:
authorIvan Topolnjak <ivantopo@gmail.com>2019-02-06 15:45:09 +0100
committerIvan Topolnjak <ivantopo@gmail.com>2019-02-06 15:45:09 +0100
commit77d0fa78a8dba17e710a0caedbd91272218bfcee (patch)
treefc1cc3343402b60b416dc2c6a551162357979770 /kamon-status/src/components
parent7e9cb172cb7ead8e5579ffb1f0b0ba3ffef90605 (diff)
downloadKamon-77d0fa78a8dba17e710a0caedbd91272218bfcee.tar.gz
Kamon-77d0fa78a8dba17e710a0caedbd91272218bfcee.tar.bz2
Kamon-77d0fa78a8dba17e710a0caedbd91272218bfcee.zip
better component structure, included a Kamon APM suggestion
Diffstat (limited to 'kamon-status/src/components')
-rw-r--r--kamon-status/src/components/Card.vue4
-rw-r--r--kamon-status/src/components/EnvironmentCard.vue66
-rw-r--r--kamon-status/src/components/MetricList.vue2
-rw-r--r--kamon-status/src/components/ModuleCard.vue91
-rw-r--r--kamon-status/src/components/ModuleList.vue90
-rw-r--r--kamon-status/src/components/ModuleStatus.vue76
-rw-r--r--kamon-status/src/components/StatusCard.vue71
7 files changed, 321 insertions, 79 deletions
diff --git a/kamon-status/src/components/Card.vue b/kamon-status/src/components/Card.vue
index 745a1caf..d77596da 100644
--- a/kamon-status/src/components/Card.vue
+++ b/kamon-status/src/components/Card.vue
@@ -1,5 +1,5 @@
<template>
- <div class="outer py-1">
+ <div class="outer">
<slot/>
</div>
</template>
@@ -13,7 +13,7 @@
}
hr {
- margin: 1px;
+ margin: 0px;
border-color: #f3f3f3;
}
</style>
diff --git a/kamon-status/src/components/EnvironmentCard.vue b/kamon-status/src/components/EnvironmentCard.vue
new file mode 100644
index 00000000..97e79d28
--- /dev/null
+++ b/kamon-status/src/components/EnvironmentCard.vue
@@ -0,0 +1,66 @@
+<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>
+ </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>
+ </div>
+ </card>
+ </div>
+ </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import {Environment} from '../api/StatusApi'
+import Card from './Card.vue'
+import {Option, none} from 'ts-option'
+
+
+@Component({
+ components: {
+ card: Card
+ }
+})
+export default class EnvironmentCard extends Vue {
+ @Prop() private environment: Option<Environment> = none
+
+ get instance(): string {
+ return this.environment.map(e => e.instance).getOrElse('Unknown')
+ }
+
+ get host(): string {
+ return this.environment.map(e => e.host).getOrElse('Unknown')
+ }
+
+ get service(): string {
+ return this.environment.map(e => e.service).getOrElse('Unknown')
+ }
+
+ get environmentTags(): { [key: string]: string } {
+ return this.environment.map(e => e.tags).getOrElse({})
+ }
+}
+</script> \ No newline at end of file
diff --git a/kamon-status/src/components/MetricList.vue b/kamon-status/src/components/MetricList.vue
index b9b6a92a..60f7499a 100644
--- a/kamon-status/src/components/MetricList.vue
+++ b/kamon-status/src/components/MetricList.vue
@@ -10,7 +10,7 @@
<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-1 pb-3">
+ <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">
diff --git a/kamon-status/src/components/ModuleCard.vue b/kamon-status/src/components/ModuleCard.vue
new file mode 100644
index 00000000..ea3a0c68
--- /dev/null
+++ b/kamon-status/src/components/ModuleCard.vue
@@ -0,0 +1,91 @@
+<template>
+ <card>
+ <div class="row module-card">
+ <div class="col-auto">
+ <div class="status-indicator h-100 text-center pt-3" :class="runStatus.class">
+ <i class="fas fa-fw" :class="runStatus.icon"></i>
+ <div>
+ {{ runStatus.message }}
+ </div>
+ </div>
+ </div>
+ <div class="col">
+ <div class="py-3">
+ <h5 class="mb-0">{{ moduleStatus.name }} </h5>
+ <div class="text-label">
+ {{ moduleStatus.description }}
+ </div>
+ </div>
+ </div>
+ </div>
+ </card>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import {Module} from '../api/StatusApi'
+import Card from './Card.vue'
+
+
+@Component({
+ components: {
+ card: Card
+ }
+})
+export default class ModuleCard extends Vue {
+ @Prop({ default: true }) private showStatusIndicators!: boolean
+ @Prop({ default: false }) private isSuggestion!: boolean
+ @Prop() private moduleStatus!: Module
+
+ get discoveryStatus(): { message: string, class: string } {
+ return this.moduleStatus.isProgrammaticallyRegistered ?
+ { message: 'manual', class: '' } :
+ { message: 'automatic', class: '' }
+ }
+
+ get runStatus(): { message: string, class: string, icon: string } {
+ if (this.isSuggestion) {
+ return { message: 'suggested', class: 'suggested', icon: 'fa-plug' }
+ } else {
+ return this.moduleStatus.isStarted ?
+ { message: 'started', class: 'healthy', icon: 'fa-check' } :
+ { message: 'disabled', class: 'critical', icon: 'fa-power-off' }
+ }
+ }
+}
+</script>
+
+<style lang="scss">
+
+$indicator-size: 6rem;
+.module-card {
+ min-height: $indicator-size;
+
+ .status-indicator {
+ text-transform: uppercase;
+ min-width: $indicator-size;
+ min-height: $indicator-size;
+ line-height: 2rem;
+ font-size: 0.9rem;
+ font-weight: 600;
+ color: white;
+ background-color: #cccccc;
+
+ i {
+ font-size: 2.5rem;
+ }
+ }
+
+ .critical {
+ background-color: #dadada;
+ }
+
+ .healthy {
+ background-color: #7ade94;
+ }
+
+ .suggested {
+ background-color: #5fd7cc;
+ }
+}
+</style>
diff --git a/kamon-status/src/components/ModuleList.vue b/kamon-status/src/components/ModuleList.vue
new file mode 100644
index 00000000..746ccf16
--- /dev/null
+++ b/kamon-status/src/components/ModuleList.vue
@@ -0,0 +1,90 @@
+<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-card :moduleStatus="reporter" />
+ </div>
+ <div v-if="!hasApmModule" class="col-12 py-1 apm-suggestion">
+ <a href="https://kamon.io/" target="_blank">
+ <module-card :is-suggestion="true" :show-status-indicators="false" :moduleStatus="apmModuleSuggestion" />
+ </a>
+ </div>
+
+
+ <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-card :moduleStatus="module"/>
+ </div>
+ </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator'
+import {Module, ModuleKind} from '../api/StatusApi'
+import ModuleCard from './ModuleCard.vue'
+
+
+@Component({
+ components: {
+ 'module-card': ModuleCard
+ }
+})
+export default class ModuleList extends Vue {
+ @Prop() private modules!: Module[]
+ private apmModuleSuggestion: Module = {
+ name: 'Kamon APM',
+ description: 'See your metrics and trace data for free with a Starter account.',
+ kind: ModuleKind.Combined,
+ isProgrammaticallyRegistered: false,
+ isStarted: false,
+ clazz: ''
+ }
+
+ get sortedModules(): Module[] {
+ return this.modules.sort((left, right) => {
+ if (left.isStarted === right.isStarted) {
+ return left.name.localeCompare(right.name)
+ } else {
+ return left.isStarted ? -1 : 1
+ }
+ })
+ }
+
+
+ get reporterModules(): Module[] {
+ return this.sortedModules.filter(this.isReporter)
+ }
+
+ get plainModules(): Module[] {
+ return this.sortedModules.filter(m => !this.isReporter(m))
+ }
+
+ get hasApmModule(): boolean {
+ const knownApmClasses = [
+ 'kamon.kamino.KaminoReporter'
+ ]
+
+ return this.modules.find(m => knownApmClasses.indexOf(m.clazz) > 0) !== undefined
+ }
+
+ private isReporter(module: Module): boolean {
+ return [ModuleKind.Combined, ModuleKind.Span, ModuleKind.Metric].indexOf(module.kind) > 0
+ }
+
+ private isStarted(module: Module): boolean {
+ return module.isStarted
+ }
+}
+</script>
+
+<style lang="scss">
+.apm-suggestion {
+ .kind-label {
+ background-color: #d0f3f0;
+ }
+}
+</style>
diff --git a/kamon-status/src/components/ModuleStatus.vue b/kamon-status/src/components/ModuleStatus.vue
deleted file mode 100644
index fff3373e..00000000
--- a/kamon-status/src/components/ModuleStatus.vue
+++ /dev/null
@@ -1,76 +0,0 @@
-<template>
- <card>
- <div class="row">
- <div class="col-12">
- <div class="py-2 px-3 text-uppercase text-label">
- {{ moduleStatus.kind }}
- </div>
- <hr>
- </div>
- <div class="col">
- <div class="px-3 py-3">
- <h5 class="mb-0">{{ moduleStatus.name }}</h5>
- <div class="text-label">
- {{ moduleStatus.description }}
- </div>
- </div>
- </div>
- <div class="col-auto">
- <div class="status-indicator text-center" :class="runStatus.class">{{ runStatus.message }}</div>
- <div class="status-indicator text-center">{{ discoveryStatus.message }}</div>
- </div>
- </div>
- </card>
-</template>
-
-<script lang="ts">
-import { Component, Prop, Vue } from 'vue-property-decorator'
-import {Module} from '../api/StatusApi'
-import Card from './Card.vue'
-
-
-@Component({
- components: {
- card: Card
- }
-})
-export default class ModuleStatus extends Vue {
- @Prop() private moduleStatus!: Module
-
- get discoveryStatus(): { message: string, class: string } {
- return this.moduleStatus.isProgrammaticallyRegistered ?
- { message: 'manual', class: '' } :
- { message: 'automatic', class: '' }
- }
-
- get runStatus(): { message: string, class: string } {
- return this.moduleStatus.isStarted ?
- { message: 'started', class: 'healthy' } :
- { message: 'disabled', class: 'critical' }
- }
-}
-</script>
-
-<style scoped lang="scss">
-.status-indicator {
- font-size: 0.9rem;
- border-radius: 0.3rem;
- color: white;
- margin: 0.5rem 1rem;
- padding: 0.1rem 1rem;
- background-color: #cccccc;
-}
-
-.critical {
- background-color: #ff6e6b;
-}
-
-.healthy {
- background-color: #6ada87;
-}
-
-hr {
- margin: 1px;
- border-color: #f3f3f3;
-}
-</style>
diff --git a/kamon-status/src/components/StatusCard.vue b/kamon-status/src/components/StatusCard.vue
new file mode 100644
index 00000000..193744df
--- /dev/null
+++ b/kamon-status/src/components/StatusCard.vue
@@ -0,0 +1,71 @@
+<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>
+ </div>
+ </card>
+ </div>
+ </div>
+</template>
+
+
+<script lang="ts">
+import { Component, Vue, Prop } from 'vue-property-decorator'
+import {Option, none, some} from 'ts-option'
+import Card from '../components/Card.vue'
+import {StatusApi, ModuleRegistry, ModuleKind, MetricRegistry, Module, Metric, Instrumentation} from '../api/StatusApi'
+
+@Component({
+ components: {
+ card: Card
+ },
+})
+export default class Overview extends Vue {
+ @Prop() private moduleRegistry: Option<ModuleRegistry> = none
+ @Prop() private metricRegistry: Option<MetricRegistry> = none
+ @Prop() private instrumentation: Option<Instrumentation> = none
+
+ get reporterModules(): Module[] {
+ return this.moduleRegistry
+ .map(moduleRegistry => moduleRegistry.modules.filter(this.isReporter))
+ .getOrElse([])
+ }
+
+ get activeReporters(): Module[] {
+ return this.reporterModules.filter(this.isStarted)
+ }
+
+ get trackedMetrics(): Option<number> {
+ return this.metricRegistry.map(metricRegistry => metricRegistry.metrics.length)
+ }
+
+ get instrumentationStatusMessage(): string {
+ return this.instrumentation.map(i => (i.isActive ? 'Active' : 'Disabled') as string).getOrElse('Unknown')
+ }
+
+ get metricsStatusMessage(): string {
+ return this.trackedMetrics.map(mc => mc + ' Tracked').getOrElse('Unknown')
+ }
+
+ private isReporter(module: Module): boolean {
+ return [ModuleKind.Combined, ModuleKind.Span, ModuleKind.Metric].indexOf(module.kind) > 0
+ }
+
+ private isStarted(module: Module): boolean {
+ return module.isStarted
+ }
+}
+</script>