Skip to content

Commit f3c6481

Browse files
authored
Merge pull request #41 from rdytech/NEP-18619_adjust_dashboard_dataset_endpoint_to_include_filter_dataset
[NEP-18619]: Adjust the endpoint for Dashboard::Datasets::List to optionally include filter datasets
2 parents 98064fc + 4126d06 commit f3c6481

File tree

14 files changed

+186
-42
lines changed

14 files changed

+186
-42
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
## Change Log
22

3+
## 0.2.3 - 2024-11-15
4+
5+
* modifies the `Superset::Dashboard::Datasets::List.new(id).dataset_details` and `Superset::Dashboard::Datasets::List.new(id).list` to optionally include filter datasets as well to duplicate those during the dashboard duplication process. It also add a new column "Filter only" in the result which shows if a dataset is used only on filters
6+
* This also adds an additional check in source dataset duplication that if any dataset already exists with the new name in the target schema we can use the existing dataset itself for the new dashboard also.
7+
* Exporting a Dashboard will also include the Zip file in the repo backup (destination_path) folder.
8+
* Exporting a Dashboard and copying the files to the backup folder will also clear out any previous backup files that no longer exist in the current zip export.
9+
* Adds a put endpoint for chart and datasets which is needed for the bulk update of set of charts/datasets
10+
311
## 0.2.2 - 2024-10-10
412

513
* add ImportDashboardAcrossEnvironments class for transfering between superset environments

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ GIT
1414
PATH
1515
remote: .
1616
specs:
17-
superset (0.2.2)
17+
superset (0.2.3)
1818
dotenv (~> 2.7)
1919
enumerate_it (~> 1.7.0)
2020
faraday (~> 1.0)

doc/usage.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ Superset::Database::GetSchemas.new(1).list # get schemas for database 1
1010

1111
Superset::Dashboard::List.call
1212
Superset::Dashboard::List.new(title_contains: 'Sales').list
13-
Superset::Dashboard::Datasets::List.new(10).list # get all datasets for dashboard 10
13+
Superset::Dashboard::Datasets::List.new(dashboard_id: 10).list # get all datasets for dashboard 10
14+
15+
Superset::Dashboard::Datasets::List.new(dashboard_id: 10, include_filter_datasets: true).list # get all datasets for dashboard 10 including the ones used only in dashboard filters
1416
Superset::Dashboard::WarmUpCache.new(dashboard_id: 10).perform
1517

1618
Superset::Dataset::List.call

lib/superset/dashboard/bulk_delete_cascade.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def perform
3131
private
3232

3333
def delete_datasets(dashboard_id)
34-
datasets_to_delete = Superset::Dashboard::Datasets::List.new(dashboard_id).datasets_details.map{|d| d[:id] }
34+
datasets_to_delete = Superset::Dashboard::Datasets::List.new(dashboard_id: dashboard_id).datasets_details.map{|d| d[:id] }
3535
Superset::Dataset::BulkDelete.new(dataset_ids: datasets_to_delete).perform if datasets_to_delete.any?
3636
end
3737

lib/superset/dashboard/compare.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ def second_dashboard
3737

3838
def list_datasets
3939
puts "\n ====== DASHBOARD DATASETS ====== "
40-
Superset::Dashboard::Datasets::List.new(first_dashboard_id).list
41-
Superset::Dashboard::Datasets::List.new(second_dashboard_id).list
40+
Superset::Dashboard::Datasets::List.new(dashboard_id: first_dashboard_id).list
41+
Superset::Dashboard::Datasets::List.new(dashboard_id: second_dashboard_id).list
4242
end
4343

4444
def list_charts

lib/superset/dashboard/datasets/list.rb

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ module Superset
77
module Dashboard
88
module Datasets
99
class List < Superset::Request
10-
attr_reader :id # dashboard id
10+
attr_reader :id, :include_filter_datasets # id - dashboard id
1111

1212
def self.call(id)
1313
self.new(id).list
1414
end
1515

16-
def initialize(id)
17-
@id = id
16+
def initialize(dashboard_id:, include_filter_datasets: false)
17+
@id = dashboard_id
18+
@include_filter_datasets = include_filter_datasets
1819
end
1920

2021
def perform
@@ -36,37 +37,64 @@ def schemas
3637
end
3738

3839
def datasets_details
39-
result.map do |details|
40+
chart_datasets = result.map do |details|
4041
details.slice('id', 'datasource_name', 'schema', 'sql').merge('database' => details['database'].slice('id', 'name', 'backend')).with_indifferent_access
4142
end
43+
return chart_datasets unless include_filter_datasets
44+
chart_dataset_ids = chart_datasets.map{|d| d['id'] }
45+
filter_dataset_ids_not_used_in_charts = filter_dataset_ids - chart_dataset_ids
46+
return chart_datasets if filter_dataset_ids_not_used_in_charts.empty?
47+
# returning chart and filter datasets
48+
chart_datasets + filter_datasets(filter_dataset_ids_not_used_in_charts)
4249
end
4350

4451
private
4552

53+
def filter_dataset_ids
54+
@filter_dataset_ids ||= dashboard.filter_configuration.map { |c| c['targets'] }.flatten.compact.map { |c| c['datasetId'] }.flatten.compact.uniq
55+
end
56+
57+
def filter_datasets(filter_dataset_ids_not_used_in_charts)
58+
filter_dataset_ids_not_used_in_charts.map do |filter_dataset_id|
59+
filter_dataset = Superset::Dataset::Get.new(filter_dataset_id).result
60+
database_info = {
61+
'id' => filter_dataset['database']['id'],
62+
'name' => filter_dataset['database']['database_name'],
63+
'backend' => filter_dataset['database']['backend']
64+
}
65+
filter_dataset.slice('id', 'datasource_name', 'schema', 'sql').merge('database' => database_info, 'filter_only': true).with_indifferent_access
66+
end
67+
end
68+
4669
def route
4770
"dashboard/#{id}/datasets"
4871
end
4972

5073
def list_attributes
51-
['id', 'datasource_name', 'database_id', 'database_name', 'database_backend', 'schema'].map(&:to_sym)
74+
['id', 'datasource_name', 'database_id', 'database_name', 'database_backend', 'schema', 'filter_only'].map(&:to_sym)
5275
end
5376

5477
def rows
55-
result.map do |d|
78+
datasets_details.map do |d|
5679
[
5780
d[:id],
5881
d[:datasource_name],
5982
d[:database][:id],
6083
d[:database][:name],
6184
d[:database][:backend],
62-
d[:schema]
85+
d[:schema],
86+
d[:filter_only]
6387
]
6488
end
6589
end
6690

6791
# when displaying a list of datasets, show dashboard title as well
6892
def title
69-
@title ||= [id, Superset::Dashboard::Get.new(id).title].join(' ')
93+
@title ||= [id, dashboard.title].join(' ')
94+
end
95+
96+
def dashboard
97+
@dashboard ||= Superset::Dashboard::Get.new(id)
7098
end
7199
end
72100
end

lib/superset/dashboard/get.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ def title
2525
def json_metadata
2626
JSON.parse(result['json_metadata'])
2727
end
28+
29+
def filter_configuration
30+
json_metadata['native_filter_configuration'] || []
31+
end
2832

2933
def positions
3034
JSON.parse(result['position_json'])

lib/superset/dashboard/warm_up_cache.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def validate_dashboard_id
3535
end
3636

3737
def fetch_dataset_details(dashboard_id)
38-
Superset::Dashboard::Datasets::List.new(dashboard_id).datasets_details.map { |dataset| dataset['database'].slice('name').merge(dataset.slice('datasource_name'))}
38+
Superset::Dashboard::Datasets::List.new(dashboard_id: dashboard_id).datasets_details.map { |dataset| dataset['database'].slice('name').merge(dataset.slice('datasource_name'))}
3939
end
4040
end
4141
end

lib/superset/services/duplicate_dashboard.rb

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,18 @@ def duplicate_source_dashboard_datasets
9393
# duplicate the dataset, renaming to use of suffix as the target_schema
9494
# reason: there is a bug(or feature) in the SS API where a dataset name must be uniq when duplicating.
9595
# (note however renaming in the GUI to a dup name works fine)
96-
new_dataset_id = Superset::Dataset::Duplicate.new(source_dataset_id: dataset[:id], new_dataset_name: "#{dataset[:datasource_name]}-#{target_schema}").perform
97-
96+
new_dataset_name = "#{dataset[:datasource_name]}-#{target_schema}"
97+
existing_datasets = Superset::Dataset::List.new(title_equals: new_dataset_name, schema_equals: target_schema).result
98+
if existing_datasets.any?
99+
logger.info "Dataset #{existing_datasets[0]["table_name"]} already exists. Reusing it"
100+
new_dataset_id = existing_datasets[0]["id"] # assuming that we do not name multiple datasets with same name in a single schema
101+
else
102+
new_dataset_id = Superset::Dataset::Duplicate.new(source_dataset_id: dataset[:id], new_dataset_name: new_dataset_name).perform
103+
# update the new dataset with the target schema and target database
104+
Superset::Dataset::UpdateSchema.new(source_dataset_id: new_dataset_id, target_database_id: target_database_id, target_schema: target_schema).perform
105+
end
98106
# keep track of the previous dataset and the matching new dataset_id
99107
dataset_duplication_tracker << { source_dataset_id: dataset[:id], new_dataset_id: new_dataset_id }
100-
101-
# update the new dataset with the target schema and target database
102-
Superset::Dataset::UpdateSchema.new(source_dataset_id: new_dataset_id, target_database_id: target_database_id, target_schema: target_schema).perform
103108
end
104109
end
105110

@@ -179,7 +184,7 @@ def new_dashboard
179184

180185
# retrieve the datasets that will be duplicated
181186
def source_dashboard_datasets
182-
@source_dashboard_datasets ||= Superset::Dashboard::Datasets::List.new(source_dashboard_id).datasets_details
187+
@source_dashboard_datasets ||= Superset::Dashboard::Datasets::List.new(dashboard_id: source_dashboard_id, include_filter_datasets: true).datasets_details
183188
rescue => e
184189
raise "Unable to retrieve datasets for source dashboard #{source_dashboard_id}: #{e.message}"
185190
end
@@ -199,7 +204,7 @@ def validate_params
199204
raise ValidationError, "The source dashboard datasets are required to point to one schema only. Actual schema list is #{source_dashboard_schemas.join(',')}" if source_dashboard_has_more_than_one_schema?
200205
raise ValidationError, "One or more source dashboard filters point to a different schema than the dashboard charts. Identified Unpermittied Filter Dataset Ids are #{unpermitted_filter_dataset_ids.to_s}" if unpermitted_filter_dataset_ids.any?
201206

202-
# new dataset validations
207+
# new dataset validations - Need to be commented for EU dashboard duplication as we are using the existing datasets for the new dashboard
203208
raise ValidationError, "DATASET NAME CONFLICT: The Target Schema #{target_schema} already has existing datasets named: #{target_schema_matching_dataset_names.join(',')}" unless target_schema_matching_dataset_names.empty?
204209
validate_source_dashboard_datasets_sql_does_not_hard_code_schema
205210

@@ -241,7 +246,7 @@ def source_dashboard_dataset_names
241246
# here we will need to decide if we want to use the existing dataset or not see NEP-????
242247
# for now we will exit with an error if we find any existing datasets of the same name
243248
def target_schema_matching_dataset_names
244-
source_dashboard_dataset_names.map do |source_dataset_name|
249+
@target_schema_matching_dataset_names ||= source_dashboard_dataset_names.map do |source_dataset_name|
245250
existing_names = Superset::Dataset::List.new(title_contains: source_dataset_name, schema_equals: target_schema).result.map{|t|t['table_name']}.uniq # contains match to cover with suffix as well
246251
unless existing_names.flatten.empty?
247252
logger.error " HALTING PROCESS: Schema #{target_schema} already has Dataset called #{existing_names}"
@@ -255,11 +260,7 @@ def source_dashboard_dataset_ids
255260
end
256261

257262
def source_dashboard_filter_dataset_ids
258-
filters_configuration = JSON.parse(source_dashboard.result['json_metadata'])['native_filter_configuration'] || []
259-
return Array.new unless filters_configuration && filters_configuration.any?
260-
261-
# pull only the filters dataset ids from the dashboard
262-
filters_configuration.map { |c| c['targets'] }.flatten.compact.map { |c| c['datasetId'] }.flatten.compact
263+
@filter_dataset_ids ||= source_dashboard.filter_configuration.map { |c| c['targets'] }.flatten.compact.map { |c| c['datasetId'] }.flatten.compact.uniq
263264
end
264265

265266
# Primary Assumption is that all charts datasets on the source dashboard are pointing to the same database schema

lib/superset/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module Superset
4-
VERSION = "0.2.2"
4+
VERSION = "0.2.3"
55
end

0 commit comments

Comments
 (0)