1 (function( $, app, i18n ) {
4 var data = app.ns("data");
7 ui.FilterBrowser = ui.AbstractWidget.extend({
9 cluster: null, // (required) instanceof app.services.Cluster
10 index: "" // (required) name of the index to query
13 init: function(parent) {
15 this._cluster = this.config.cluster;
16 this.el = $(this._main_template());
17 this.filtersEl = this.el.find(".uiFilterBrowser-filters");
18 this.attach( parent );
19 new data.MetaDataFactory({ cluster: this._cluster, onReady: function(metadata, eventData) {
20 this.metadata = metadata;
21 this._createFilters_handler(eventData.originalData.metadata.indices);
25 _createFilters_handler: function(data) {
27 function scan_properties(path, obj) {
29 for (var prop in obj.properties) {
30 scan_properties(path.concat(prop), obj.properties[prop]);
35 for (var subField in obj.fields) {
36 filters.push({ path: (path[path.length - 1] !== subField) ? path.concat(subField) : path, type: obj.fields[subField].type, meta: obj.fields[subField] });
39 filters.push({ path: path, type: obj.type, meta: obj });
43 for(var type in data[this.config.index].mappings) {
44 scan_properties([type], data[this.config.index].mappings[type]);
47 filters.sort( function(a, b) {
48 var x = a.path.join(".");
49 var y = b.path.join(".");
50 return (x < y) ? -1 : (x > y) ? 1 : 0;
54 { path: ["match_all"], type: "match_all", meta: {} },
55 { path: ["_all"], type: "_all", meta: {}}
58 this._addFilterRow_handler();
61 _addFilterRow_handler: function() {
62 this.filtersEl.append(this._filter_template());
65 _removeFilterRow_handler: function(jEv) {
66 $(jEv.target).closest("DIV.uiFilterBrowser-row").remove();
67 if(this.filtersEl.children().length === 0) {
68 this._addFilterRow_handler();
72 _search_handler: function() {
73 var search = new data.BoolQuery();
74 search.setSize( this.el.find(".uiFilterBrowser-outputSize").val() )
75 this.fire("startingSearch");
76 this.filtersEl.find(".uiFilterBrowser-row").each(function(i, row) {
78 var bool = row.find(".bool").val();
79 var field = row.find(".field").val();
80 var op = row.find(".op").val();
82 if(field === "match_all") {
84 } else if(op === "range") {
85 var lowqual = row.find(".lowqual").val(),
86 highqual = row.find(".highqual").val();
88 value[row.find(".lowop").val()] = lowqual;
91 value[row.find(".highop").val()] = highqual;
93 } else if(op === "fuzzy") {
94 var qual = row.find(".qual").val(),
95 fuzzyqual = row.find(".fuzzyqual").val();
97 value["value"] = qual;
99 if(fuzzyqual.length) {
100 value[row.find(".fuzzyop").val()] = fuzzyqual;
103 value = row.find(".qual").val();
105 search.addClause(value, field, op, bool);
107 if(this.el.find(".uiFilterBrowser-showSrc").attr("checked")) {
108 this.fire("searchSource", search.search);
110 this._cluster.post( this.config.index + "/_search", search.getData(), this._results_handler );
113 _results_handler: function( data ) {
114 var type = this.el.find(".uiFilterBrowser-outputFormat").val();
115 this.fire("results", this, { type: type, data: data, metadata: this.metadata });
118 _changeQueryField_handler: function(jEv) {
119 var select = $(jEv.target);
120 var spec = select.children(":selected").data("spec");
121 select.siblings().remove(".op,.qual,.range,.fuzzy");
123 if(spec.type === 'match_all') {
124 } else if(spec.type === '_all') {
125 ops = ["query_string"];
126 } else if(spec.type === 'string' || spec.type === 'text' || spec.type === 'keyword') {
127 ops = ["term", "wildcard", "prefix", "fuzzy", "range", "query_string", "text", "missing"];
128 } else if(spec.type === 'long' || spec.type === 'integer' || spec.type === 'float' ||
129 spec.type === 'byte' || spec.type === 'short' || spec.type === 'double') {
130 ops = ["term", "range", "fuzzy", "query_string", "missing"];
131 } else if(spec.type === 'date') {
132 ops = ["term", "range", "fuzzy", "query_string", "missing"];
133 } else if(spec.type === 'geo_point') {
135 } else if(spec.type === 'ip') {
136 ops = ["term", "range", "fuzzy", "query_string", "missing"];
137 } else if(spec.type === 'boolean') {
140 select.after({ tag: "SELECT", cls: "op", onchange: this._changeQueryOp_handler, children: ops.map(ut.option_template) });
141 select.next().change();
144 _changeQueryOp_handler: function(jEv) {
145 var op = $(jEv.target), opv = op.val();
146 op.siblings().remove(".qual,.range,.fuzzy");
147 if(opv === 'term' || opv === 'wildcard' || opv === 'prefix' || opv === "query_string" || opv === 'text') {
148 op.after({ tag: "INPUT", cls: "qual", type: "text" });
149 } else if(opv === 'range') {
150 op.after(this._range_template());
151 } else if(opv === 'fuzzy') {
152 op.after(this._fuzzy_template());
156 _main_template: function() {
157 return { tag: "DIV", children: [
158 { tag: "DIV", cls: "uiFilterBrowser-filters" },
159 { tag: "BUTTON", type: "button", text: i18n.text("General.Search"), onclick: this._search_handler },
160 { tag: "LABEL", children:
161 i18n.complex("FilterBrowser.OutputType", { tag: "SELECT", cls: "uiFilterBrowser-outputFormat", children: [
162 { text: i18n.text("Output.Table"), value: "table" },
163 { text: i18n.text("Output.JSON"), value: "json" },
164 { text: i18n.text("Output.CSV"), value: "csv" }
165 ].map(function( o ) { return $.extend({ tag: "OPTION" }, o ); } ) } )
167 { tag: "LABEL", children:
168 i18n.complex("FilterBrowser.OutputSize", { tag: "SELECT", cls: "uiFilterBrowser-outputSize",
169 children: [ "10", "50", "250", "1000", "5000", "25000" ].map( ut.option_template )
172 { tag: "LABEL", children: [ { tag: "INPUT", type: "checkbox", cls: "uiFilterBrowser-showSrc" }, i18n.text("Output.ShowSource") ] }
176 _filter_template: function() {
177 return { tag: "DIV", cls: "uiFilterBrowser-row", children: [
178 { tag: "SELECT", cls: "bool", children: ["must", "must_not", "should"].map(ut.option_template) },
179 { tag: "SELECT", cls: "field", onchange: this._changeQueryField_handler, children: this.filters.map(function(f) {
180 return { tag: "OPTION", data: { spec: f }, value: f.path.join("."), text: f.path.join(".") };
182 { tag: "BUTTON", type: "button", text: "+", onclick: this._addFilterRow_handler },
183 { tag: "BUTTON", type: "button", text: "-", onclick: this._removeFilterRow_handler }
187 _range_template: function() {
188 return { tag: "SPAN", cls: "range", children: [
189 { tag: "SELECT", cls: "lowop", children: ["gt", "gte"].map(ut.option_template) },
190 { tag: "INPUT", type: "text", cls: "lowqual" },
191 { tag: "SELECT", cls: "highop", children: ["lt", "lte"].map(ut.option_template) },
192 { tag: "INPUT", type: "text", cls: "highqual" }
196 _fuzzy_template: function() {
197 return { tag: "SPAN", cls: "fuzzy", children: [
198 { tag: "INPUT", cls: "qual", type: "text" },
199 { tag: "SELECT", cls: "fuzzyop", children: ["max_expansions", "min_similarity"].map(ut.option_template) },
200 { tag: "INPUT", cls: "fuzzyqual", type: "text" }
205 })( this.jQuery, this.app, this.i18n );