cob-cli 2.12.1 → 2.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.publish.md +10 -0
- package/lib/task_lists/rsyncFilter.txt +3 -2
- package/package.json +1 -1
- package/templates/dashboards/dash/dist/css/app.97b1c4b4.css +8 -0
- package/templates/dashboards/dash/dist/dashboard.html +5 -5
- package/templates/dashboards/dash/dist/js/{app.f9c19b80.js → app.a1c26814.js} +9 -9
- package/templates/dashboards/dash/dist/js/app.a1c26814.js.map +1 -0
- package/templates/dashboards/dash/package-lock.json +3918 -5165
- package/templates/dashboards/dash/package.json +1 -1
- package/templates/dashboards/dash/src/App.vue +108 -64
- package/templates/dashboards/dash/src/collector.js +107 -35
- package/templates/dashboards/dash/src/components/Attention.vue +30 -0
- package/templates/dashboards/dash/src/components/Board.vue +22 -53
- package/templates/dashboards/dash/src/components/Dashboard.vue +24 -0
- package/templates/dashboards/dash/src/components/Filter.vue +58 -0
- package/templates/dashboards/dash/src/components/Kibana.vue +107 -0
- package/templates/dashboards/dash/src/components/Label.vue +15 -0
- package/templates/dashboards/dash/src/components/Menu.vue +33 -22
- package/templates/dashboards/dash/src/components/Totals.vue +35 -53
- package/templates/dashboards/dash/src/components/TotalsValue.vue +48 -59
- package/templates/dashboards/dash/src/dashboard.html +1 -1
- package/templates/dashboards/dash/src/definition_dashboard.json +741 -0
- package/templates/dashboards/dash/src/output.css +20103 -76122
- package/templates/dashboards/dash/tailwind.config.js +6 -10
- package/templates/frontend/common/js/cob/_show_hidden.js +1 -1
- package/templates/dashboards/dash/definition_dashboard_v59.json +0 -1
- package/templates/dashboards/dash/dist/css/app.2ca409ad.css +0 -8
- package/templates/dashboards/dash/dist/js/app.8423eff3.js +0 -188
- package/templates/dashboards/dash/dist/js/app.8423eff3.js.map +0 -1
- package/templates/dashboards/dash/dist/js/app.f9c19b80.js.map +0 -1
- package/templates/dashboards/dash/src/Dashboard.vue +0 -66
- package/templates/dashboards/dash/src/components/BoardsNav.vue +0 -23
- package/templates/dashboards/dash/src/components/BoardsPage.vue +0 -36
- package/templates/dashboards/dash/src/components/Title.vue +0 -21
- package/templates/dashboards/dash/src/definition_dashboard_v59.json +0 -394
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<iframe id="kibana" :src="shareLink" width="100%" :onload="updateIFrameStyle()" :class="classes"></iframe>
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script>
|
|
6
|
+
export default {
|
|
7
|
+
props: { component: Object },
|
|
8
|
+
data: () => ({
|
|
9
|
+
iFrame: null,
|
|
10
|
+
outputFilter: ""
|
|
11
|
+
}),
|
|
12
|
+
mounted() {
|
|
13
|
+
this.iFrame = this.$el
|
|
14
|
+
|
|
15
|
+
this.inputs.forEach(inputVar => {
|
|
16
|
+
this.$watch("component.vars."+inputVar, this.updateKibanaQuery)
|
|
17
|
+
});
|
|
18
|
+
this.updateKibanaQuery()
|
|
19
|
+
|
|
20
|
+
window.addEventListener("resize", this.updateIFrameStyle);
|
|
21
|
+
this.updateIFrameStyle();
|
|
22
|
+
|
|
23
|
+
window.addEventListener("message", this.processKibanaEvent);
|
|
24
|
+
this.processKibanaEvent();
|
|
25
|
+
},
|
|
26
|
+
computed: {
|
|
27
|
+
options() { return this.component['KibanaCustomize'][0] },
|
|
28
|
+
shareLink() { return this.component['ShareLink'] || "" },
|
|
29
|
+
classes() { return this.options['KibanaClasses'] || "" },
|
|
30
|
+
inputs() { return this.options['InputVarKibana'].map(v => v['InputVarKibana']) },
|
|
31
|
+
inputFilter() { return this.inputs.filter(v => this.component.vars[v]).map(v => this.component.vars[v]).join(" ")},
|
|
32
|
+
outputVar() { return this.options['OutputVarKibana'] || "" },
|
|
33
|
+
},
|
|
34
|
+
methods: {
|
|
35
|
+
updateIFrameStyle() {
|
|
36
|
+
if(!this.iFrame || !this.iFrame.contentWindow || !this.iFrame.contentWindow.document.head) {
|
|
37
|
+
//iFrame do Kibana ainda não está pronta. Voltar a tentar em 100ms
|
|
38
|
+
setTimeout( () => this.updateIFrameStyle(), 100)
|
|
39
|
+
} else {
|
|
40
|
+
// Ajusta tamanho do iFrame, de acordo com a dimensão do conteúdo, quando a aplicação estiver pronta
|
|
41
|
+
if (!this.iFrame.contentWindow.document.getElementsByClassName("application").length && !this.iFrame.contentWindow.document.getElementsByClassName("dashboardViewport").length) {
|
|
42
|
+
//Ainda está a carregar, espera mais um pouco
|
|
43
|
+
setTimeout( () => this.updateIFrameStyle(), 100)
|
|
44
|
+
} else {
|
|
45
|
+
// Visualizações ainda vai estar a carregar e o tamanho vai variando
|
|
46
|
+
// Ir actualizando de 100ms em 100ms até 3s (SlowestLoading estimado),
|
|
47
|
+
// para ter um comportamento optimizado tão instantânio qt possível
|
|
48
|
+
const SlowestLoading = 3000
|
|
49
|
+
for(let t = 100; t < SlowestLoading; t += 100) setTimeout(() => {
|
|
50
|
+
this.iFrame.style.minHeight = this.iFrame.contentWindow.document.body.scrollHeight + "px"
|
|
51
|
+
}, t)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Ajuste ao estilo interno do Kibana, alguns condicionais às classes passadas na iFrame (se ainda não tiver sido feito)
|
|
55
|
+
if(!this.iFrame.contentWindow.document.getElementById("cobKibanaStyle")) {
|
|
56
|
+
var s = document.createElement("style");
|
|
57
|
+
s.id = "cobKibanaStyle";
|
|
58
|
+
s.appendChild(document.createTextNode([
|
|
59
|
+
"html, .kbnWelcomeView { background-color: #ffffff00 !important }"
|
|
60
|
+
, (this.classes.indexOf("kibanaEmbPanelTransparent") != -1 ? ".euiPanel { background-color: #ffffff00 !important; border:none; box-shadow: none }" : "")
|
|
61
|
+
, (this.classes.indexOf("kibanaNoNavMenu") != -1 ? ".kbnTopNavMenu__wrapper { display: none }" : "")
|
|
62
|
+
,".visLegend__toggle { display: none!important; }"
|
|
63
|
+
|
|
64
|
+
].join("\n")));
|
|
65
|
+
// Aplica dentro de um try catch, porque a iframe Kibana no arranque tem e deixa de ter document.head e dá um erro. Não é um problema pois voltaremos a passar aqui fruto do resize ainda por fazer.
|
|
66
|
+
try { this.iFrame.contentWindow.document.head.appendChild(s); } catch {}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
processKibanaEvent(event) {
|
|
71
|
+
// Só vale a pena reagir aos eventos de mudança de filtro no Kibana
|
|
72
|
+
if(event && event.data && event.data.filters) {
|
|
73
|
+
var filters = []
|
|
74
|
+
for(let filter of event.data.filters) {
|
|
75
|
+
var queryStr;
|
|
76
|
+
var negateStr = filter.meta.negate ? "-" : "";
|
|
77
|
+
var enabled = !filter.meta.disabled;
|
|
78
|
+
|
|
79
|
+
if(filter.query.query_string) {
|
|
80
|
+
queryStr = filter.query.query_string.query;
|
|
81
|
+
} else if (filter.query.match_phrase) {
|
|
82
|
+
var key = Object.keys(filter.query.match_phrase)[0];
|
|
83
|
+
queryStr = key + ':"' + filter.query.match_phrase[key] + '"';
|
|
84
|
+
}
|
|
85
|
+
if (enabled) filters.push(negateStr + "(" +queryStr + ")");
|
|
86
|
+
};
|
|
87
|
+
this.outputFilter = filters.length > 0 ? filters.join(" AND ") : ""
|
|
88
|
+
this.$set(this.component.vars, this.outputVar, this.outputFilter)
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
updateKibanaQuery() {
|
|
92
|
+
if(!this.iFrame || !this.iFrame.contentWindow || !this.iFrame.contentWindow.document.head || !this.iFrame.contentWindow.document.getElementsByClassName("kbnTopNavMenu__wrapper").length) {
|
|
93
|
+
//O Kibana ainda não está pronto. Voltar a tentar em 100ms
|
|
94
|
+
setTimeout(this.updateKibanaQuery, 100)
|
|
95
|
+
} else if(this.inputFilter) {
|
|
96
|
+
|
|
97
|
+
if(this.iFrame.contentWindow.document.getElementsByClassName("euiLoadingChart").length > 0) {
|
|
98
|
+
//O Kibana já está pronto mas ainda está a carregar dados. Voltar a tentar em 100ms
|
|
99
|
+
setTimeout(this.updateKibanaQuery, 100)
|
|
100
|
+
} else {
|
|
101
|
+
this.iFrame.contentWindow.postMessage({"query":{ "query_string":{ "query": this.inputFilter || "*" } }}, '*');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="classes" :style="image" v-html="label"></div>
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script>
|
|
6
|
+
export default {
|
|
7
|
+
props: { component: Object },
|
|
8
|
+
computed: {
|
|
9
|
+
options() { return this.component['LabelCustomize'][0] },
|
|
10
|
+
label() { return this.component['Label'] || "" },
|
|
11
|
+
classes() { return this.options['LabelClasses'] || "text-center" },
|
|
12
|
+
image() { return this.options['Image'] ? "background-image: url(" + this.options['Image'] + ");" : "" }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
</script>
|
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
:key="
|
|
5
|
-
:class="
|
|
6
|
-
|
|
2
|
+
<div :class="classes">
|
|
3
|
+
<a v-for="(line, i) in lines"
|
|
4
|
+
:key="i"
|
|
5
|
+
:class="line.classes"
|
|
6
|
+
:href="line.link"
|
|
7
7
|
>
|
|
8
|
-
<
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
<span style="margin-right: 20px;">
|
|
9
|
+
<i v-if="line.icon" :class="line.icon" style="margin-right:4px"></i>
|
|
10
|
+
<span v-html="line.text"></span>
|
|
11
|
+
</span>
|
|
12
|
+
<Attention class="absolute right-1" :attentionInfo="line.attention"/>
|
|
13
|
+
</a>
|
|
14
|
+
</div>
|
|
13
15
|
</template>
|
|
14
16
|
|
|
15
17
|
<script>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return this.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
import Attention from './Attention.vue'
|
|
19
|
+
|
|
20
|
+
export default {
|
|
21
|
+
components: { Attention },
|
|
22
|
+
props: { component: Object },
|
|
23
|
+
computed: {
|
|
24
|
+
options() { return this.component['MenuCustomize'][0] },
|
|
25
|
+
classes() { return this.options['MenuClasses'] || "flex flex-col gap-y-2" },
|
|
26
|
+
lines() {
|
|
27
|
+
let lines = this.component['Text'].map( line => ({
|
|
28
|
+
classes: line["TextCustomize"][0]['TextClasses'] || "transition ease-in-out duration-300 rounded-md border border-gray-300 border-l-2 border-l-sky-600 shadow-sm transform hover:translate-x-0.5 p-2",
|
|
29
|
+
icon: line["TextCustomize"][0]['Icon'] || "",
|
|
30
|
+
text: line['Text'] || "",
|
|
31
|
+
link: line['Link'] || "",
|
|
32
|
+
groups: line["TextCustomize"][0]['GroupVisibility'].map(g => g["GroupVisibility"] && g["GroupVisibility"] ).filter(g => g) || [],
|
|
33
|
+
attention: line["TextCustomize"][0]['AttentionInfo'],
|
|
34
|
+
}))
|
|
35
|
+
// Filter out lines that have groupVisibility AND the user does not have any of the groups
|
|
36
|
+
let userGroups = this.component.userInfo.groups.map(g => g.name)
|
|
37
|
+
return lines.filter(l => l.groups.length == 0 || l.groups.filter(g => userGroups.includes(g)).length != 0 )
|
|
38
|
+
}
|
|
27
39
|
}
|
|
28
40
|
}
|
|
29
|
-
}
|
|
30
41
|
</script>
|
|
@@ -1,63 +1,45 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<table class="
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<tr v-for="(line, i) in lines" :key="'line'+i"
|
|
12
|
-
class="text-slate-700">
|
|
13
|
-
<td :class="'py-2 ' + line.style">{{ line.name }}</td>
|
|
14
|
-
<td v-for="(value, j) in line.values" :key="'value'+j"
|
|
15
|
-
class="py-2 text-right">
|
|
16
|
-
<TotalsValue :value-data="value" />
|
|
17
|
-
</td>
|
|
18
|
-
</tr>
|
|
19
|
-
</tbody>
|
|
2
|
+
<table :class="classes">
|
|
3
|
+
<tr v-for="(line, i) in lines" :key="'line'+i" :class="line.lineClasses">
|
|
4
|
+
<td :class="line.titleClasses">
|
|
5
|
+
{{ line.title }}
|
|
6
|
+
</td>
|
|
7
|
+
<td v-for="(value, j) in line.values" :key="'value'+i+'-'+j">
|
|
8
|
+
<TotalsValue :value-data="value"/>
|
|
9
|
+
</td>
|
|
10
|
+
</tr>
|
|
20
11
|
</table>
|
|
21
12
|
</template>
|
|
22
13
|
|
|
23
14
|
<script>
|
|
24
|
-
import TotalsValue from './TotalsValue.vue'
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return this.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}))
|
|
15
|
+
import TotalsValue from './TotalsValue.vue'
|
|
16
|
+
|
|
17
|
+
export default {
|
|
18
|
+
components: { TotalsValue },
|
|
19
|
+
props: { component: Object },
|
|
20
|
+
computed: {
|
|
21
|
+
options() { return this.component['TotalsCustomize'][0] },
|
|
22
|
+
classes() { return this.options['TotalsClasses'] || "w-full table-auto" },
|
|
23
|
+
inputs() { return this.options['InputVarTotals'].map(v => v['InputVarTotals']) },
|
|
24
|
+
inputFilter() { return this.inputs.filter(v => this.component.vars[v]).map(v => this.component.vars[v]).join(" ")},
|
|
25
|
+
lines() {
|
|
26
|
+
return this.component['Line'].map( l => ({
|
|
27
|
+
title : l['Line'] || "",
|
|
28
|
+
lineClasses: l["LineCustomize"][0]["LineClasses"] || "text-right transition ease-in-out ring-sky-600 ring-offset-1 hover:ring-2 rounded-md",
|
|
29
|
+
titleClasses: l["LineCustomize"][0]["TitleClasses"] || "text-left p-2",
|
|
30
|
+
values: l['Value']
|
|
31
|
+
}))}
|
|
41
32
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
8: "grid-cols-8",
|
|
52
|
-
9: "grid-cols-9",
|
|
53
|
-
10: "grid-cols-10",
|
|
54
|
-
11: "grid-cols-11",
|
|
55
|
-
12: "grid-cols-12",
|
|
56
|
-
none: "grid-cols-none"
|
|
33
|
+
watch: {
|
|
34
|
+
inputFilter(newValue) {
|
|
35
|
+
if(newValue == "") return //PRESSUPOSTO IMPORTANTE: se newValue é vazio é porque estamos em transições (porque usamos sempre um valor, nem que seja *) e o melhor é usar o valor antigo para o valor não mudar momentaneamente (e ainda desperdicar uma pesquisa). Se o pressuposto for quebrado vamos impedir a actualização do inputFilter quando o valor é ""
|
|
36
|
+
this.lines.forEach(l => {
|
|
37
|
+
l.values.forEach(v => {
|
|
38
|
+
let newFilter = ((v.Arg[1] || "") + newValue.trim()) || "*"
|
|
39
|
+
if(v.dash_info) v.dash_info.changeArgs({query: newFilter })
|
|
40
|
+
});
|
|
41
|
+
});
|
|
57
42
|
}
|
|
58
|
-
// Grid with cols == amount of values
|
|
59
|
-
return "grid " + dynamicClasses[this.lines[0].values.length]
|
|
60
43
|
}
|
|
61
44
|
}
|
|
62
|
-
}
|
|
63
45
|
</script>
|
|
@@ -1,69 +1,58 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<a :href="valueData.dash_info.href" :class="valueClass" class="relative inline-flex">
|
|
4
|
-
<span v-html="value"/>
|
|
2
|
+
<a v-if="state" :href="link" :class="expandedClasses">
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
8
|
-
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
9
|
-
</svg>
|
|
10
|
-
</a>
|
|
11
|
-
</div>
|
|
12
|
-
</template>
|
|
4
|
+
<Attention :attentionInfo="attention" :classes="attentionClasses" />
|
|
13
5
|
|
|
14
|
-
<
|
|
6
|
+
<span v-html="value"/><span class="" >{{unit}}</span>
|
|
15
7
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
signalChange: false
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
watch: {
|
|
26
|
-
state(newState) {
|
|
27
|
-
if(newState == "ready") {
|
|
28
|
-
this.signalChange = true;
|
|
29
|
-
setTimeout( () => this.signalChange = false,8000)
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
computed: {
|
|
34
|
-
updating() {
|
|
35
|
-
return this.valueData.dash_info.state == "updating" || this.valueData.dash_info.state == "loading"
|
|
36
|
-
},
|
|
37
|
-
value() {
|
|
38
|
-
if(this.valueData.dash_info.state == "loading") return "L"
|
|
39
|
-
if(this.valueData.dash_info.state == "error") return "E"
|
|
40
|
-
if(isNaN(this.valueData.dash_info.value)) {
|
|
41
|
-
return this.valueData.dash_info.value
|
|
42
|
-
} else {
|
|
43
|
-
return new Intl.NumberFormat('en-US', {}).format(this.valueData.dash_info.value)
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
state() {
|
|
47
|
-
return this.valueData.dash_info.state
|
|
48
|
-
},
|
|
49
|
-
valueClass() {
|
|
50
|
-
let c = "relative transition ease-in-out px-2 py-1 rounded-md text-center font-mono font-semibold transition border ring-offset-1 hover:ring-2"
|
|
8
|
+
<svg v-if="updating" class="absolute animate-spin -top-1 -right-1 h-2 w-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
9
|
+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
10
|
+
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
11
|
+
</svg>
|
|
12
|
+
</a>
|
|
13
|
+
</template>
|
|
51
14
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
15
|
+
<script>
|
|
16
|
+
import Attention from './Attention.vue'
|
|
17
|
+
const specialClasses = {
|
|
18
|
+
"Info": "border border-sky-600 bg-sky-200/10 ring-sky-600 ",
|
|
19
|
+
"Success": "border border-lime-500 bg-lime-200/10 ring-lime-500 ",
|
|
20
|
+
"Warning": "border border-amber-500 bg-amber-200/10 ring-amber-500 ",
|
|
21
|
+
"Important": "border border-rose-600 bg-rose-200/10 ring-rose-600 ",
|
|
22
|
+
"Gray": "text-gray-400 border-gray-200 bg-gray-200/10 ring-gray-200 ",
|
|
23
|
+
"Default": "inline-block " // para poder conter internamente o Attention sem ser noutra linha
|
|
24
|
+
+"whitespace-nowrap " // Para não partir o texto + attention
|
|
25
|
+
+"font-mono font-semibold " // Estilo default para o texto
|
|
26
|
+
+"px-2 py-1 " // Espaçamento horizontal e vertical
|
|
27
|
+
+"rounded-md " // Border arrendondada
|
|
28
|
+
+"transition ease-in-out ring-sky-600 ring-offset-1 hover:ring-2 ", // Estilo para hover (só funciona em localhost, não sei porquê)
|
|
29
|
+
"S_loading": "border border-amber-500 bg-amber-200/10 ring-amber-500 ", // Igual a Warning
|
|
30
|
+
"S_error": "border border-rose-600 bg-rose-200/10 ring-rose-600 ", // Igual a Important
|
|
31
|
+
}
|
|
57
32
|
|
|
58
|
-
|
|
59
|
-
|
|
33
|
+
export default {
|
|
34
|
+
components: { Attention },
|
|
35
|
+
props: { valueData: Object },
|
|
36
|
+
computed: {
|
|
37
|
+
options() { return this.valueData['ValueCustomize'][0] },
|
|
38
|
+
view() { return this.options['View'] },
|
|
39
|
+
attention() { return this.options['AttentionInfo'] },
|
|
40
|
+
attentionClasses() { return this.options['AttentionClasses'] },
|
|
41
|
+
unit() { return this.options['Unit'] },
|
|
42
|
+
state() { return this.valueData.dash_info && this.valueData.dash_info.state || "" },
|
|
43
|
+
updating() { return this.state == "updating" || this.state == "loading" },
|
|
44
|
+
classes() { return (this.options['ValueClasses'] || "Default Info") + " S_"+this.valueData.dash_info.state },
|
|
45
|
+
link() { return this.valueData.dash_info.href + (this.view ? "?&av=" + this.view : "") },
|
|
46
|
+
expandedClasses() { return this.classes.split(/\s/).map(c => specialClasses[c] || c ).join(" ") },
|
|
47
|
+
value() {
|
|
48
|
+
if(this.valueData.dash_info.state == "loading") return "L"
|
|
49
|
+
if(this.valueData.dash_info.state == "error") return "E"
|
|
50
|
+
if(isNaN(this.valueData.dash_info.value)) {
|
|
51
|
+
return this.valueData.dash_info.value
|
|
52
|
+
} else {
|
|
53
|
+
return new Intl.NumberFormat('en-US', {maximumFractionDigits: 0}).format(this.valueData.dash_info.value)
|
|
54
|
+
}
|
|
60
55
|
}
|
|
61
|
-
|
|
62
|
-
if(this.valueData.dash_info.state == "loading") return c + " " + lookup["Warning"]
|
|
63
|
-
if(this.valueData.dash_info.state == "error") return c + " " + lookup["Important"]
|
|
64
|
-
|
|
65
|
-
return c + " " + (this.valueData.dash_info.value == 0 ? lookup["Gray"] : lookup[this.valueData.style] ? lookup[this.valueData.style] : lookup["Fallback"])
|
|
66
56
|
}
|
|
67
57
|
}
|
|
68
|
-
}
|
|
69
58
|
</script>
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
</head>
|
|
19
19
|
<body>
|
|
20
20
|
<% } %>
|
|
21
|
-
<style>section.custom-resource{visibility: hidden;opacity:0;}</style>
|
|
21
|
+
<style>section.custom-resource{visibility: hidden;opacity:0;left:0px;right:0px;bottom:0px;padding:0px;}</style>
|
|
22
22
|
<div id="app"></div>
|
|
23
23
|
<script>
|
|
24
24
|
// mimes: .cob-app tem estilos globais que se aplicam a elementos vuetify que mudam o aspecto previsto
|