Skip to content

Commit 3247a47

Browse files
authored
Merge pull request #20 from rdytech/NEP-17500-update-tag-filter
NEP-17500 Filter dashboards by array of tags
2 parents 054f657 + af1f2a8 commit 3247a47

24 files changed

+568
-28
lines changed

Gemfile.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ GIT
1414
PATH
1515
remote: .
1616
specs:
17-
superset (0.1.3)
17+
superset (0.1.4)
1818
dotenv (~> 2.7)
19-
enumerate_it (~> 3.2)
19+
enumerate_it (~> 1.7.0)
2020
faraday (~> 1.0)
2121
faraday-multipart (~> 1.0)
2222
json (~> 2.6)
@@ -51,8 +51,8 @@ GEM
5151
dotenv (2.8.1)
5252
drb (2.2.0)
5353
ruby2_keywords
54-
enumerate_it (3.2.4)
55-
activesupport (>= 5.0.7.2)
54+
enumerate_it (1.7.0)
55+
activesupport (>= 3.0.0)
5656
faraday (1.10.3)
5757
faraday-em_http (~> 1.0)
5858
faraday-em_synchrony (~> 1.0)

lib/superset/chart/bulk_delete.rb

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# frozen_string_literal: true
2+
# TODO: the gui delete has a confirmation step, this API call does not.
3+
# Potentially we could add a confirm_delete parameter to the constructor that would ensure that all charts either
4+
# 1 belong to only an expected dashboard before deleting
5+
# 2 or do not belong to any dashboards
6+
# ( not sure if this needed at this point )
7+
8+
module Superset
9+
module Chart
10+
class BulkDelete < Superset::Request
11+
attr_reader :chart_ids
12+
13+
def initialize(chart_ids: [])
14+
@chart_ids = chart_ids
15+
end
16+
17+
def perform
18+
raise InvalidParameterError, "chart_ids array of integers expected" unless chart_ids.is_a?(Array)
19+
raise InvalidParameterError, "chart_ids array must contain Integer only values" unless chart_ids.all? { |item| item.is_a?(Integer) }
20+
21+
logger.info("Attempting to delete charts with id: #{chart_ids.join(', ')}")
22+
response
23+
end
24+
25+
def response
26+
@response ||= client.delete(route, params)
27+
end
28+
29+
private
30+
31+
def params
32+
{ q: "!(#{chart_ids.join(',')})" }
33+
end
34+
35+
def route
36+
"chart/"
37+
end
38+
end
39+
end
40+
end

lib/superset/chart/delete.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# frozen_string_literal: true
2+
3+
module Superset
4+
module Chart
5+
class Delete < Superset::Request
6+
attr_reader :chart_id
7+
8+
def initialize(chart_id: )
9+
@chart_id = chart_id
10+
end
11+
12+
def perform
13+
raise InvalidParameterError, "chart_id integer is required" unless chart_id.present? && chart_id.is_a?(Integer)
14+
15+
logger.info("Attempting to delete chart with id: #{chart_id}")
16+
response
17+
end
18+
19+
def response
20+
@response ||= client.delete(route)
21+
end
22+
23+
private
24+
25+
def route
26+
"chart/#{chart_id}"
27+
end
28+
end
29+
end
30+
end
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# frozen_string_literal: true
2+
3+
# TODO: the gui delete has a confirmation step, this API call does not.
4+
# Potentially we could add a confirm_delete parameter to the constructor that would ensure that all dashboards either
5+
# 1 have an expected set of charts or filters before deleting
6+
# 2 or do not have any charts or filters linked to them
7+
# ( not sure if this needed at this point )
8+
9+
module Superset
10+
module Dashboard
11+
class BulkDelete < Superset::Request
12+
attr_reader :dashboard_ids
13+
14+
def initialize(dashboard_ids: [])
15+
@dashboard_ids = dashboard_ids
16+
end
17+
18+
def perform
19+
raise InvalidParameterError, "dashboard_ids array of integers expected" unless dashboard_ids.is_a?(Array)
20+
raise InvalidParameterError, "dashboard_ids array must contain Integer only values" unless dashboard_ids.all? { |item| item.is_a?(Integer) }
21+
22+
logger.info("Attempting to delete dashboards with id: #{dashboard_ids.join(', ')}")
23+
response
24+
end
25+
26+
def response
27+
@response ||= client.delete(route, params)
28+
end
29+
30+
private
31+
32+
def params
33+
{ q: "!(#{dashboard_ids.join(',')})" }
34+
end
35+
36+
def route
37+
"dashboard/"
38+
end
39+
end
40+
end
41+
end

lib/superset/dashboard/charts/list.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def rows
2222
c[:id],
2323
c[:slice_name],
2424
c[:form_data][:datasource],
25-
c[:form_data][:dashboards]
25+
# c[:form_data][:dashboards] # NOTE: form_data dashboards is not accurate .. looks to be bugs related to copying charts
2626
]
2727
end
2828
end
@@ -34,7 +34,7 @@ def route
3434
end
3535

3636
def list_attributes
37-
['id', 'slice_name', 'datasource', 'dashboards'].map(&:to_sym)
37+
['id', 'slice_name', 'datasource'].map(&:to_sym)
3838
end
3939

4040
# when displaying a list of datasets, show dashboard id and title as well

lib/superset/dashboard/delete.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# frozen_string_literal: true
2+
3+
module Superset
4+
module Dashboard
5+
class Delete < Superset::Request
6+
7+
attr_reader :dashboard_id, :confirm_zero_charts
8+
9+
def initialize(dashboard_id: , confirm_zero_charts: true)
10+
@dashboard_id = dashboard_id
11+
@confirm_zero_charts = confirm_zero_charts
12+
end
13+
14+
def perform
15+
raise InvalidParameterError, "dashboard_id integer is required" unless dashboard_id.present? && dashboard_id.is_a?(Integer)
16+
17+
confirm_zero_charts_on_dashboard if confirm_zero_charts
18+
19+
logger.info("Attempting to delete dashboard with id: #{dashboard_id}")
20+
response
21+
end
22+
23+
def response
24+
@response ||= client.delete(route)
25+
end
26+
27+
private
28+
29+
def confirm_zero_charts_on_dashboard
30+
raise "Error: Dashboard includes #{dashboard_charts.count} charts. Please delete all charts before deleting the dashboard or override and set confirm_zero_charts: false" if dashboard_charts.count.positive?
31+
end
32+
33+
def dashboard_charts
34+
@dashboard_charts ||= Superset::Dashboard::Charts::List.new(dashboard_id).rows
35+
end
36+
37+
def route
38+
"dashboard/#{dashboard_id}"
39+
end
40+
end
41+
end
42+
end

lib/superset/dashboard/embedded/get.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def initialize(id)
1515
def response
1616
@response ||= client.get(route)
1717
rescue Happi::Error::NotFound => e
18-
puts "Dashboard #{id} has no Embedded settings. (skipping)" # some dashboards don't have embedded settings, fine to ignore.
18+
logger.info("Dashboard #{id} has no Embedded settings. (skipping)") # some dashboards don't have embedded settings, fine to ignore.
1919
@response = { result: [] }.with_indifferent_access
2020
@response
2121
end

lib/superset/dashboard/info.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Superset
22
module Dashboard
33
class Info < Superset::Request
4+
alias result response
45

56
def filters
67
result['filters']

lib/superset/dashboard/list.rb

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
1+
# Usage: Superset::Dashboard::List.new.list
2+
# Usage: Superset::Dashboard::List.new(page_num: 1, title_contains: 'Test').list
3+
# Usage: Superset::Dashboard::List.new(tags_equal: ['embedded', 'product:acme']).list
4+
15
module Superset
26
module Dashboard
37
class List < Superset::Request
4-
attr_reader :title_contains, :tag_equals
8+
attr_reader :title_contains, :tags_equal, :ids_not_in
59

6-
def initialize(page_num: 0, title_contains: '', tag_equals: '')
10+
def initialize(page_num: 0, title_contains: '', tags_equal: [], ids_not_in: [])
711
@title_contains = title_contains
8-
@tag_equals = tag_equals
12+
@tags_equal = tags_equal
13+
@ids_not_in = ids_not_in
914
super(page_num: page_num)
1015
end
1116

1217
def self.call
1318
self.new.list
1419
end
1520

21+
def response
22+
validate_constructor_args
23+
super
24+
end
25+
1626
def all
1727
result.map do |d|
1828
OpenStruct.new(
@@ -45,6 +55,10 @@ def rows
4555
end
4656
end
4757

58+
def ids
59+
result.map { |d| d[:id] }
60+
end
61+
4862
private
4963

5064
def route
@@ -55,15 +69,31 @@ def filters
5569
# TODO filtering across all list classes can be refactored to support multiple options in a more flexible way
5670
filter_set = []
5771
filter_set << "(col:dashboard_title,opr:ct,value:'#{title_contains}')" if title_contains.present?
58-
filter_set << "(col:tags,opr:dashboard_tags,value:#{tag_equals})" if tag_equals.present?
72+
filter_set << tag_filters if tags_equal.present?
73+
filter_set << ids_not_in_filters if ids_not_in.present?
5974
unless filter_set.empty?
6075
"filters:!(" + filter_set.join(',') + "),"
6176
end
6277
end
6378

79+
def tag_filters
80+
tags_equal.map {|tag| "(col:tags,opr:dashboard_tags,value:'#{tag}')"}.join(',')
81+
end
82+
83+
def ids_not_in_filters
84+
ids_not_in.map {|id| "(col:id,opr:neq,value:'#{id}')"}.join(',')
85+
end
86+
6487
def list_attributes
6588
[:id, :dashboard_title, :status, :url]
6689
end
90+
91+
def validate_constructor_args
92+
raise InvalidParameterError, "title_contains must be a String type" unless title_contains.is_a?(String)
93+
raise InvalidParameterError, "tags_equal must be an Array type" unless tags_equal.is_a?(Array)
94+
raise InvalidParameterError, "tags_equal array must contain string only values" unless tags_equal.all? { |item| item.is_a?(String) }
95+
raise InvalidParameterError, "ids_not_in must be an Array type" unless ids_not_in.is_a?(Array)
96+
end
6797
end
6898
end
69-
end
99+
end
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# frozen_string_literal: true
2+
3+
# TODO: the gui delete has a confirmation step, this API call does not.
4+
# Potentially we could add a confirm_delete parameter to the constructor that would ensure that all datasets either
5+
# 1 belong to only an expected charts or filters before deleting
6+
# 2 or do not belong to any charts or filters
7+
# ( not sure if this needed at this point )
8+
9+
module Superset
10+
module Dataset
11+
class BulkDelete < Superset::Request
12+
attr_reader :dataset_ids
13+
14+
def initialize(dataset_ids: [])
15+
@dataset_ids = dataset_ids
16+
end
17+
18+
def perform
19+
raise InvalidParameterError, "dataset_ids array of integers expected" unless dataset_ids.is_a?(Array)
20+
raise InvalidParameterError, "dataset_ids array must contain Integer only values" unless dataset_ids.all? { |item| item.is_a?(Integer) }
21+
22+
logger.info("Attempting to delete datasets with id: #{dataset_ids.join(', ')}")
23+
response
24+
end
25+
26+
def response
27+
@response ||= client.delete(route, params)
28+
end
29+
30+
private
31+
32+
def params
33+
{ q: "!(#{dataset_ids.join(',')})" }
34+
end
35+
36+
def route
37+
"dataset/"
38+
end
39+
end
40+
end
41+
end

0 commit comments

Comments
 (0)