<< ..

superset filterbox 预填充

发布时间:

我们在superset中创建了一个Dashboard里放了一个过滤器,希望每次加载页面的时候,过滤器能默认填充几项。做到在superset Dashboard页面首次加载预填充的效果。

Edit Sqla Table页面其实有一个选项叫Fetch Values Predicate似乎能满足这种页面加载后预填充的需求,但实在不知道怎么填,也找不到一个例子,gitter问了也没人回。好在老子够hack,找到个办法。

观众朋友们,在$SUPERSET_HOME/superset/assets/visualizations有一个文件叫filter_box.jsx,该文件就是负责过滤器部分的js源码,react写的,选择框部分用的控件叫react-select。这些都不重要,重要的是负责过滤render的部分是从83行开始:

<Select.Creatable
  placeholder={`Select [${filter}]`}
  key={filter}
  multi
  value={this.state.selectedValues[filter]}
  ....
/>

里面的value={this.state.selectedValues[filter]} 部分负责了表单内的过滤值,于是我想着增改这部分。

关键源码001部分就是对将要筛选的字段多加一层判断,如果是需要筛选的字段,就将filter_values填充成想预选的值,然后filter_values传给002部分。当页面初次打开this.state.selectedValues[filter]undefined状态,于是filter_values神走位补上。在示例中,如果判断是event_key这个字段,就给filter_values填充一个["d "],从而筛选event_key=[“d”]的字段预填充好,你需要留意到["d "]后面一堆空格居然是有意义的,如果没有这堆空格filter_values不生效了。

关键源码:

// 001.
var filter_values = undefined;
if (filter == "event_key") {
    filter_values = ["d                                                                       "]
}
// 002.
value={this.state.selectedValues[filter] || filter_values}

全部代码:

const filters = Object.keys(this.props.filtersChoices).map((filter) => {
  const data = this.props.filtersChoices[filter];
  const maxes = {};
  maxes[filter] = d3.max(data, function (d) {
    return d.metric;
  });

  // 001
  var filter_values = undefined;
  if (filter == "event_key") {
      filter_values = ["d                                                                       "]
  }

  return (
    <div key={filter} className="m-b-5">
      {this.props.datasource.verbose_map[filter] || filter}
      <Select.Creatable
        placeholder={`Select [${filter}]`}
        key={filter}
        multi
        // 002
        value={this.state.selectedValues[filter] || filter_values}
        options={data.map((opt) => {
          const perc = Math.round((opt.metric / maxes[opt.filter]) * 100);
          const backgroundImage = (
            'linear-gradient(to right, lightgrey, ' +
            `lightgrey ${perc}%, rgba(0,0,0,0) ${perc}%`
          );
          const style = {
            backgroundImage,
            padding: '2px 5px',
          };
          return { value: opt.id, label: opt.id, style };
        })}
        onChange={this.changeFilter.bind(this, filter)}
      />
    </div>
  );