cob-cli 2.13.2 → 2.15.0
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/lib/task_lists/customize_copy.js +5 -1
- package/package.json +1 -1
- package/templates/dashboards/dash/dist/dashboard.html +2 -2
- package/templates/dashboards/dash/dist/js/{app.a1c26814.js → app.abf0f315.js} +6 -6
- package/templates/dashboards/dash/dist/js/app.abf0f315.js.map +1 -0
- package/templates/dashboards/dash/src/App.vue +1 -1
- package/templates/dashboards/dash/src/collector.js +15 -7
- package/templates/dashboards/dash/src/components/Board.vue +6 -3
- package/templates/dashboards/dash/src/components/Dashboard.vue +5 -2
- package/templates/dashboards/dash/src/components/Filter.vue +5 -4
- package/templates/dashboards/dash/src/components/Kibana.vue +44 -14
- package/templates/dashboards/dash/src/components/Totals.vue +7 -3
- package/templates/dashboards/dash/src/definition_dashboard.json +766 -740
- package/templates/dashboards/dash/dist/js/app.a1c26814.js.map +0 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<div v-else-if="dashboardState=='Error'" class="text-center my-20 text-2xl text-red-500">
|
|
7
7
|
{{error}}
|
|
8
8
|
</div>
|
|
9
|
-
<Dashboard v-else :dashboard="dashboardParsed" />
|
|
9
|
+
<Dashboard v-else :dashboard="dashboardParsed" :userInfo="userInfo" />
|
|
10
10
|
</div>
|
|
11
11
|
</template>
|
|
12
12
|
|
|
@@ -11,7 +11,7 @@ function collect(bucket, source) {
|
|
|
11
11
|
//Means that found one key in current source
|
|
12
12
|
if (Array.isArray(bucket[sourceName])) {
|
|
13
13
|
// Means type of value to collect is array
|
|
14
|
-
if(
|
|
14
|
+
if(bucket[sourceName].length === 0 || bucket[sourceName][0]["Mark"] === "JUST COPY" ) {
|
|
15
15
|
//Means the bucket template only specify to get the raw elements that match (empty array in bucket template or having first element signaled that it was originally an empty array)
|
|
16
16
|
source["Mark"] = "JUST COPY" // Signal it was an empty array
|
|
17
17
|
source[sourceName] = source.value // Add extra field with original name of the source
|
|
@@ -122,12 +122,14 @@ function parseDashboard(raw_dashboard, userInfo){
|
|
|
122
122
|
"KibanaClasses": "",
|
|
123
123
|
"OutputVarKibana": "",
|
|
124
124
|
"InputVarKibana": [{}],
|
|
125
|
+
"InputQueryKibana": ""
|
|
125
126
|
}],
|
|
126
127
|
"ShareLink": "",
|
|
127
128
|
},
|
|
128
129
|
"Filter": {
|
|
129
130
|
"FilterCustomize": [{
|
|
130
|
-
"FilterClasses": ""
|
|
131
|
+
"FilterClasses": "",
|
|
132
|
+
"Placeholder": ""
|
|
131
133
|
}],
|
|
132
134
|
"OutputVarFilter": "",
|
|
133
135
|
}
|
|
@@ -158,14 +160,14 @@ function parseDashboard(raw_dashboard, userInfo){
|
|
|
158
160
|
c.userInfo = userInfo
|
|
159
161
|
c.vars = dash.vars
|
|
160
162
|
|
|
161
|
-
if (c.Component
|
|
163
|
+
if (c.Component === "Menu") {
|
|
162
164
|
c.Text.forEach(t => {
|
|
163
165
|
// If Attention is configured for this menu line then add attention status as user check
|
|
164
166
|
if(t["TextCustomize"][0]["TextAttention"]) {
|
|
165
167
|
t["TextCustomize"][0].AttentionInfo = dashFunctions.instancesList("Dashboard-Attention","name.raw:" + t["TextCustomize"][0]["TextAttention"],1,0,{validity:30})
|
|
166
168
|
}
|
|
167
169
|
})
|
|
168
|
-
} else if (c.Component
|
|
170
|
+
} else if (c.Component === "Totals") {
|
|
169
171
|
c.Line.forEach(l => {
|
|
170
172
|
l.Value = l.Value.map(v => {
|
|
171
173
|
if(v.Arg[2] && (v.Arg[2]+"").startsWith("{")) {
|
|
@@ -176,17 +178,23 @@ function parseDashboard(raw_dashboard, userInfo){
|
|
|
176
178
|
v["ValueCustomize"][0].AttentionInfo = dashFunctions.instancesList("Dashboard-Attention","name.raw:" + v["ValueCustomize"][0]["ValueAttention"],1,0,{validity:10})
|
|
177
179
|
}
|
|
178
180
|
|
|
179
|
-
if(v.Value
|
|
181
|
+
if(v.Value === 'Label') {
|
|
180
182
|
v.dash_info = {value: v.Arg[0].Arg, state:"ready"}
|
|
181
|
-
} else if(v.Value
|
|
183
|
+
} else if(v.Value === 'link') {
|
|
182
184
|
v.dash_info = { value: icon, href: url, state: undefined, isLink: true }
|
|
183
185
|
} else {
|
|
184
186
|
// add dash-info values in Totals
|
|
185
|
-
v.dash_info = dashFunctions[v.Value].apply(this, v['Arg'].map( a =>
|
|
187
|
+
v.dash_info = dashFunctions[v.Value].apply(this, v['Arg'].map( a =>
|
|
188
|
+
a['Arg'].replaceAll("__USERNAME__",c.userInfo.username)
|
|
189
|
+
)) // Return DashInfo, which is used by the component
|
|
186
190
|
}
|
|
187
191
|
return v
|
|
188
192
|
})
|
|
189
193
|
})
|
|
194
|
+
}else if (c.Component === "Kibana") {
|
|
195
|
+
if (c["KibanaCustomize"][0]["InputQueryKibana"] !== null) {
|
|
196
|
+
c["KibanaCustomize"][0]["InputQueryKibana"] = c["KibanaCustomize"][0]["InputQueryKibana"].replaceAll("__USERNAME__", c.userInfo.username)
|
|
197
|
+
}
|
|
190
198
|
}
|
|
191
199
|
}))
|
|
192
200
|
return dash
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
<template v-for="(item, i) in components">
|
|
4
4
|
<Label v-if="item['Component'] == 'Label'" :component="item" :key="i" />
|
|
5
5
|
<Menu v-if="item['Component'] == 'Menu'" :component="item" :key="i" />
|
|
6
|
-
<Totals v-if="item['Component'] == 'Totals'" :component="item" :key="i" />
|
|
7
|
-
<Kibana v-if="item['Component'] == 'Kibana'" :component="item" :key="i" />
|
|
6
|
+
<Totals v-if="item['Component'] == 'Totals'" :component="item" :key="i" :userInfo="userInfo"/>
|
|
7
|
+
<Kibana v-if="item['Component'] == 'Kibana'" :component="item" :key="i" :userInfo="userInfo"/>
|
|
8
8
|
<Filtro v-if="item['Component'] == 'Filter'" :component="item" :key="i" />
|
|
9
9
|
</template>
|
|
10
10
|
</div>
|
|
@@ -19,7 +19,10 @@
|
|
|
19
19
|
|
|
20
20
|
export default {
|
|
21
21
|
components: { Label, Menu, Totals, Kibana, Filtro },
|
|
22
|
-
props: {
|
|
22
|
+
props: {
|
|
23
|
+
board: Object,
|
|
24
|
+
userInfo: Object
|
|
25
|
+
},
|
|
23
26
|
computed: {
|
|
24
27
|
options() { return this.board['BoardCustomize'][0] },
|
|
25
28
|
components() { return this.board['Component'] },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="classes" :style="image" >
|
|
3
3
|
<div :class="width + ' ' + grid">
|
|
4
|
-
<Board v-for="(board,i) in boards" :board="board" :key="i"/>
|
|
4
|
+
<Board v-for="(board,i) in boards" :board="board" :key="i" :userInfo="userInfo"/>
|
|
5
5
|
</div>
|
|
6
6
|
</div>
|
|
7
7
|
</template>
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
|
|
12
12
|
export default {
|
|
13
13
|
components: { Board },
|
|
14
|
-
props: {
|
|
14
|
+
props: {
|
|
15
|
+
dashboard: Object,
|
|
16
|
+
userInfo: Object
|
|
17
|
+
},
|
|
15
18
|
computed: {
|
|
16
19
|
options() { return this.dashboard['DashboardCustomize'][0] },
|
|
17
20
|
boards() { return this.dashboard['Board'] },
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
@keyup.enter="applyFilter"
|
|
7
7
|
@focus="resize"
|
|
8
8
|
@keyup="resize"
|
|
9
|
-
placeholder="
|
|
9
|
+
:placeholder="placeholder"
|
|
10
10
|
></textarea>
|
|
11
11
|
<button @click="applyFilter" type="submit" class="max-h-11 p-2.5 ml-2 text-sm font-medium text-white bg-blue-700 rounded-lg border border-blue-700 hover:bg-blue-800">
|
|
12
12
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
|
|
@@ -34,9 +34,10 @@
|
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
computed: {
|
|
37
|
-
options()
|
|
38
|
-
outputVar()
|
|
39
|
-
|
|
37
|
+
options() { return this.component['FilterCustomize'][0] },
|
|
38
|
+
outputVar() { return this.component['OutputVarFilter'] || "" },
|
|
39
|
+
placeholder() { return this.options['Placeholder'] || "Pesquisar ..." },
|
|
40
|
+
classes() { return this.options['FilterClasses'] || "w-full max-w-xs resize-none min-h-min h-min border border-slate-300 rounded-md py-2 px-2 outline-slate-300 leading-5" },
|
|
40
41
|
},
|
|
41
42
|
methods: {
|
|
42
43
|
applyFilter: function() {
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
<script>
|
|
6
6
|
export default {
|
|
7
|
-
props: {
|
|
7
|
+
props: {
|
|
8
|
+
component: Object,
|
|
9
|
+
userInfo: Object
|
|
10
|
+
},
|
|
8
11
|
data: () => ({
|
|
9
12
|
iFrame: null,
|
|
10
13
|
outputFilter: ""
|
|
@@ -27,8 +30,13 @@
|
|
|
27
30
|
options() { return this.component['KibanaCustomize'][0] },
|
|
28
31
|
shareLink() { return this.component['ShareLink'] || "" },
|
|
29
32
|
classes() { return this.options['KibanaClasses'] || "" },
|
|
33
|
+
fixedQuery() { return this.options['InputQueryKibana']|| "" },
|
|
30
34
|
inputs() { return this.options['InputVarKibana'].map(v => v['InputVarKibana']) },
|
|
31
|
-
inputFilter() {
|
|
35
|
+
inputFilter() {
|
|
36
|
+
let filters = this.inputs.filter(v => this.component.vars[v]).map(v => this.component.vars[v]);
|
|
37
|
+
if (this.fixedQuery !== "") filters.push(" AND (" + this.fixedQuery + ")");
|
|
38
|
+
return filters.join(" ")
|
|
39
|
+
},
|
|
32
40
|
outputVar() { return this.options['OutputVarKibana'] || "" },
|
|
33
41
|
},
|
|
34
42
|
methods: {
|
|
@@ -71,19 +79,40 @@
|
|
|
71
79
|
// Só vale a pena reagir aos eventos de mudança de filtro no Kibana
|
|
72
80
|
if(event && event.data && event.data.filters) {
|
|
73
81
|
var filters = []
|
|
74
|
-
for(let filter of event.data.filters) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
for (let filter of event.data.filters) {
|
|
83
|
+
let queryStr = "";
|
|
84
|
+
let negateStr = filter.meta.negate ? "-" : "";
|
|
85
|
+
let enabled = !filter.meta.disabled;
|
|
86
|
+
let key;
|
|
87
|
+
|
|
88
|
+
let query = filter.query;
|
|
89
|
+
|
|
90
|
+
if (query.query_string) {
|
|
91
|
+
// condições incluídas no próprio dashboard via query DSL
|
|
92
|
+
queryStr = query.query_string.query;
|
|
93
|
+
|
|
94
|
+
} else if (query.query) {
|
|
95
|
+
queryStr = query.query;
|
|
78
96
|
|
|
79
|
-
if(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
97
|
+
} else if (query.match) {
|
|
98
|
+
key = Object.keys(query.match)[0];
|
|
99
|
+
queryStr = key + ':"' + query.match[key] + '"';
|
|
100
|
+
|
|
101
|
+
} else if (query.match_phrase) {
|
|
102
|
+
key = Object.keys(query.match_phrase)[0];
|
|
103
|
+
let _phrase = query.match_phrase[key];
|
|
104
|
+
queryStr = key + ':"' + (_phrase instanceof Object ? _phrase.query : _phrase) + '"';
|
|
105
|
+
|
|
106
|
+
} else if (query.bool && query.bool.must.length === 1 && query.bool.must[0].query_string) {
|
|
107
|
+
// filtros adicionados a partir de visualizações com splits por filtros
|
|
108
|
+
queryStr = query.bool.must[0].query_string.query;
|
|
109
|
+
|
|
110
|
+
} else {
|
|
111
|
+
window.console.error('COB', "unknown filter, can't send to RM", filter);
|
|
84
112
|
}
|
|
85
|
-
|
|
86
|
-
|
|
113
|
+
|
|
114
|
+
if (enabled) filters.push(negateStr + "(" + queryStr + ")");
|
|
115
|
+
}
|
|
87
116
|
this.outputFilter = filters.length > 0 ? filters.join(" AND ") : ""
|
|
88
117
|
this.$set(this.component.vars, this.outputVar, this.outputFilter)
|
|
89
118
|
}
|
|
@@ -98,7 +127,8 @@
|
|
|
98
127
|
//O Kibana já está pronto mas ainda está a carregar dados. Voltar a tentar em 100ms
|
|
99
128
|
setTimeout(this.updateKibanaQuery, 100)
|
|
100
129
|
} else {
|
|
101
|
-
|
|
130
|
+
console.debug("KIBANA QUERY: ", this.inputFilter.replaceAll("__USERNAME__",this.userInfo.username) );
|
|
131
|
+
this.iFrame.contentWindow.postMessage({"query":{ "query_string":{ "query": this.inputFilter.replaceAll("__USERNAME__",this.userInfo.username) || "*" } }}, '*');
|
|
102
132
|
}
|
|
103
133
|
}
|
|
104
134
|
}
|
|
@@ -16,7 +16,10 @@
|
|
|
16
16
|
|
|
17
17
|
export default {
|
|
18
18
|
components: { TotalsValue },
|
|
19
|
-
props: {
|
|
19
|
+
props: {
|
|
20
|
+
component: Object,
|
|
21
|
+
userInfo: Object
|
|
22
|
+
},
|
|
20
23
|
computed: {
|
|
21
24
|
options() { return this.component['TotalsCustomize'][0] },
|
|
22
25
|
classes() { return this.options['TotalsClasses'] || "w-full table-auto" },
|
|
@@ -35,8 +38,9 @@
|
|
|
35
38
|
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
39
|
this.lines.forEach(l => {
|
|
37
40
|
l.values.forEach(v => {
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
let arg = (v.Arg[1] instanceof Object ? v.Arg[1].Arg : v.Arg[1])
|
|
42
|
+
let newFilter = ((arg || "") + " " + newValue.trim()) || "*"
|
|
43
|
+
if (v.dash_info) v.dash_info.changeArgs({query: newFilter.replaceAll("__USERNAME__",this.userInfo.username)})
|
|
40
44
|
});
|
|
41
45
|
});
|
|
42
46
|
}
|