superset 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.buildkite/pipeline.yml +16 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +13 -0
  5. data/CHANGELOG.md +48 -0
  6. data/Dockerfile +17 -0
  7. data/LICENSE +21 -0
  8. data/README.md +205 -0
  9. data/Rakefile +12 -0
  10. data/doc/duplicate_dashboards.md +214 -0
  11. data/doc/setting_up_personal_api_credentials.md +127 -0
  12. data/docker-compose.override.yml +10 -0
  13. data/docker-compose.yml +8 -0
  14. data/env.sample +9 -0
  15. data/lib/loggers/duplicate_dashboard_logger.rb +15 -0
  16. data/lib/superset/authenticator.rb +55 -0
  17. data/lib/superset/chart/bulk_delete.rb +40 -0
  18. data/lib/superset/chart/delete.rb +30 -0
  19. data/lib/superset/chart/get.rb +56 -0
  20. data/lib/superset/chart/list.rb +59 -0
  21. data/lib/superset/chart/update_dataset.rb +90 -0
  22. data/lib/superset/client.rb +53 -0
  23. data/lib/superset/credential/api_user.rb +25 -0
  24. data/lib/superset/credential/embedded_user.rb +25 -0
  25. data/lib/superset/dashboard/bulk_delete.rb +42 -0
  26. data/lib/superset/dashboard/bulk_delete_cascade.rb +52 -0
  27. data/lib/superset/dashboard/charts/list.rb +47 -0
  28. data/lib/superset/dashboard/compare.rb +94 -0
  29. data/lib/superset/dashboard/copy.rb +78 -0
  30. data/lib/superset/dashboard/datasets/list.rb +74 -0
  31. data/lib/superset/dashboard/delete.rb +42 -0
  32. data/lib/superset/dashboard/embedded/get.rb +56 -0
  33. data/lib/superset/dashboard/embedded/put.rb +35 -0
  34. data/lib/superset/dashboard/export.rb +98 -0
  35. data/lib/superset/dashboard/get.rb +51 -0
  36. data/lib/superset/dashboard/info.rb +17 -0
  37. data/lib/superset/dashboard/list.rb +99 -0
  38. data/lib/superset/dashboard/put.rb +37 -0
  39. data/lib/superset/dashboard/warm_up_cache.rb +42 -0
  40. data/lib/superset/database/get.rb +30 -0
  41. data/lib/superset/database/get_schemas.rb +25 -0
  42. data/lib/superset/database/list.rb +51 -0
  43. data/lib/superset/dataset/bulk_delete.rb +41 -0
  44. data/lib/superset/dataset/create.rb +62 -0
  45. data/lib/superset/dataset/delete.rb +30 -0
  46. data/lib/superset/dataset/duplicate.rb +62 -0
  47. data/lib/superset/dataset/get.rb +56 -0
  48. data/lib/superset/dataset/list.rb +41 -0
  49. data/lib/superset/dataset/update_query.rb +56 -0
  50. data/lib/superset/dataset/update_schema.rb +120 -0
  51. data/lib/superset/dataset/warm_up_cache.rb +41 -0
  52. data/lib/superset/display.rb +42 -0
  53. data/lib/superset/enumerations/object_type.rb +11 -0
  54. data/lib/superset/file_utilities.rb +19 -0
  55. data/lib/superset/guest_token.rb +69 -0
  56. data/lib/superset/logger.rb +20 -0
  57. data/lib/superset/request.rb +62 -0
  58. data/lib/superset/route_info.rb +34 -0
  59. data/lib/superset/security/permissions_resources/list.rb +22 -0
  60. data/lib/superset/security/role/create.rb +25 -0
  61. data/lib/superset/security/role/get.rb +32 -0
  62. data/lib/superset/security/role/list.rb +45 -0
  63. data/lib/superset/security/role/permission/create.rb +35 -0
  64. data/lib/superset/security/role/permission/get.rb +37 -0
  65. data/lib/superset/security/user/create.rb +49 -0
  66. data/lib/superset/security/user/get.rb +27 -0
  67. data/lib/superset/security/user/list.rb +42 -0
  68. data/lib/superset/services/duplicate_dashboard.rb +298 -0
  69. data/lib/superset/sqllab/execute.rb +52 -0
  70. data/lib/superset/tag/add_to_object.rb +46 -0
  71. data/lib/superset/tag/get.rb +30 -0
  72. data/lib/superset/tag/list.rb +37 -0
  73. data/lib/superset/version.rb +5 -0
  74. data/lib/superset.rb +17 -0
  75. data/log/README.md +4 -0
  76. data/superset.gemspec +55 -0
  77. metadata +300 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 16bb352b533737ed4faed7d5b4360c850619d60b7997b12638019681a8b36bfd
4
+ data.tar.gz: e7dd50138ea34bd23969a61bf6f69f7eb98cc6174f67abdb05fdb9ba4eb60197
5
+ SHA512:
6
+ metadata.gz: ed7199d606cb33b4f30e79d6816ccd2d00c63061c88d630b8e9b538e540cbf4ae3ea50bfccf3acb8ba7e6d92ba09e51871a58b0ea3a84cbfc37d16641923d737
7
+ data.tar.gz: 50e1ed97a6fb3b698136c313b0384755f42eecf6b171aa7a02021919e59fc9d2bed6991fb03129d8f37a47df6ca4d825b542fe8d36b1410d1bbd284570014e01
@@ -0,0 +1,16 @@
1
+ steps:
2
+ - label: ":rspec:"
3
+ command: bin/setup && bundle exec rspec
4
+ plugins:
5
+ docker-compose#v3.0.3:
6
+ run: app
7
+ volumes:
8
+ - ./coverage:/app/coverage
9
+ - ./log:/app/log
10
+ timeout: 10
11
+ agents:
12
+ queue: docker-heavy
13
+ artifact_paths:
14
+ - "coverage/.resultset*.json"
15
+ - "log/*.log"
16
+ - "log/*.xml"
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
data/CHANGELOG.md ADDED
@@ -0,0 +1,48 @@
1
+ ## Change Log
2
+
3
+ ## 0.1.6 - 2024-07-10
4
+
5
+ * added a class **WarmUpCache** to hit the 'api/v1/dataset/warm_up_cache' endpoint to warm up the cache of all the datasets for a particular dashaboard being passed to the class - https://github.com/rdytech/superset-client/pull/28
6
+
7
+ ## 0.1.5 - 2024-05-10
8
+
9
+ * add multi config for multi env creds https://github.com/rdytech/superset-client/pull/22
10
+ * add endpoint for sqllab/execute https://github.com/rdytech/superset-client/pull/22
11
+ * add endpoint for database/list https://github.com/rdytech/superset-client/pull/22
12
+ * add delete cascade endpoint by @jbat in https://github.com/rdytech/superset-client/pull/21
13
+
14
+ ## 0.1.4 - 2024-05-01
15
+
16
+ * Filter dashboards by array of tags by @jbat in https://github.com/rdytech/superset-client/pull/20
17
+ * adds endpoints for Delete of dashboards, charts, datasets @jbat in https://github.com/rdytech/superset-client/pull/20
18
+ * adds endpoints for BulkDelete of dashboards, charts, datasets @jbat in https://github.com/rdytech/superset-client/pull/20
19
+
20
+ ## 0.1.3 - 2024-04-23
21
+
22
+ * duplicate dashboard should also create embedded setting by @jbat in https://github.com/rdytech/superset-client/pull/14
23
+ * Validate and duplicate filters to new dashboard by @vidishaweddy-readytech in https://github.com/rdytech/superset-client/pull/17
24
+ * duplicate cross filters by @jbat in https://github.com/rdytech/superset-client/pull/18
25
+
26
+ ## 0.1.2 - 2024-03-22
27
+
28
+ * adds export endpoint
29
+
30
+ ## 0.1.1 - 2024-03-14
31
+
32
+ * superset pipeline part 1 with supported endpoints by @jbat in https://github.com/rdytech/superset-client/pull/4
33
+ * API update chart to new dataset by @hanpeic in https://github.com/rdytech/superset-client/pull/5
34
+ * Adds DuplicateDashboard class and fixes by @jbat in https://github.com/rdytech/superset-client/pull/6
35
+ * Update Docs by @jbat in https://github.com/rdytech/superset-client/pull/7
36
+ * update cred docs by @jbat in https://github.com/rdytech/superset-client/pull/8
37
+ * more updates to DuplicateDashboard, extra endpoints by @jbat in https://github.com/rdytech/superset-client/pull/9
38
+
39
+ ## 0.1.0 - 2023-12-12
40
+
41
+ - add base classes for credentials, authentication, client, request
42
+ - add dashboard endpoints
43
+ - add security/user endpoints
44
+ - add security/role endpoints
45
+ - add security/role/permission endpoints
46
+
47
+
48
+
data/Dockerfile ADDED
@@ -0,0 +1,17 @@
1
+ # 1: Use ruby 2.7 as base:
2
+ FROM ruby:2.7
3
+
4
+ RUN apt-get update && \
5
+ apt-get install -y --no-install-recommends \
6
+ build-essential
7
+
8
+ ENV BUNDLER_VERSION='2.4.22'
9
+ RUN gem install bundler -v ${BUNDLER_VERSION}
10
+
11
+ # 2: We'll set the application path as the working directory
12
+ WORKDIR /app
13
+
14
+ # 3: We'll add the app's binaries path to $PATH:
15
+ ENV PATH=$PATH:/app/bin
16
+
17
+ ENV BUNDLE_GITHUB__HTTPS=true BUNDLE_MAJOR_DEPRECATIONS=true
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Jonathon Batson, ReadyTech
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,205 @@
1
+ # Superset Client
2
+
3
+ [![Build status](https://badge.buildkite.com/fc7ee4a03e119a5d859472865fc0bdc9a6e46d51b7f5b8cd62.svg)](https://buildkite.com/jobready/superset-client)
4
+
5
+ The Repo is `superset-client` with the ruby gem named `superset`
6
+
7
+ All ruby classes are namespaced under `Superset::`
8
+
9
+ # Installation
10
+
11
+ ## Docker Setup
12
+
13
+ Build, bundle and open a ruby console
14
+
15
+ ```
16
+ docker-compose build
17
+ docker-compose run --rm app bundle install
18
+ docker-compose run --rm app bin/console
19
+ ```
20
+
21
+ Run specs
22
+
23
+ ```
24
+ docker-compose run --rm app rspec
25
+ # or
26
+ docker-compose run --rm app bash # then run 'bundle exec rspec' from the container.
27
+ ```
28
+
29
+ ## Local setup or including in a Ruby/Rails app
30
+
31
+ Add to your Gemfile `gem 'superset'`
32
+ And then execute: `bundle install`
33
+ Or install it yourself as `gem install superset`
34
+
35
+ ## Setup API Credentials
36
+
37
+ Follow this doc setup your users API creds [setting_up_personal_api_credentials](https://github.com/rdytech/superset-client/tree/develop/doc/setting_up_personal_api_credentials.md)
38
+
39
+ Short version is .. copy the `env.sample` to `.env` and add edit values where applicable. Opening a console with `bin/console` will then auto load the `.env` file.
40
+
41
+ ## Usage
42
+
43
+ Experiment with the API calls directly by open a pry console using `bin/console`
44
+
45
+
46
+
47
+
48
+ ### API calls
49
+
50
+ Quickstart examples
51
+
52
+ ```ruby
53
+ Superset::Database::List.call
54
+ Superset::Database::GetSchemas.new(1).list # get schemas for database 1
55
+
56
+ Superset::Dashboard::List.call
57
+ Superset::Dashboard::List.new(title_contains: 'Sales').list
58
+
59
+ Superset::Dashboard::BulkDelete.new(dashboard_ids: [1,2,3]).perform # Dashboards only ( leaves all charts, datasets in place)
60
+ Superset::Dashboard::BulkDeleteCascade.new(dashboard_ids: [1,2,3]).perform # Dashboards and related charts and datasets.
61
+
62
+ Superset::Sqllab::Execute.new(database_id: 1, schema: 'public', query: 'select count(*) from birth_names').perform
63
+
64
+ Superset::Dashboard::Export.new(dashboard_id: 1, destination_path: '/tmp').perform
65
+
66
+ Superset::RouteInfo.new(route: 'dashboard/_info').perform # Get info on an API endpoint .. handy for getting available filters
67
+ Superset::RouteInfo.new(route: 'chart/_info').filters # OR just get the filters for an endpoint
68
+
69
+ superset_class_list # helper method to list all classes under Superset::
70
+
71
+ ```
72
+
73
+ ### Duplicating Dashboards
74
+
75
+ Primary motivation behind this library was to use the Superset API to duplicate dashboards, charts, datasets across multiple database connections.
76
+ See examples in [Duplicate Dashboards](https://github.com/rdytech/superset-client/tree/develop/doc/duplicate_dashboards.md)
77
+
78
+ ### API Examples with results
79
+
80
+ Generally classes follow the convention/path of the Superset API strucuture as per the swagger docs.
81
+
82
+ ref https://superset.apache.org/docs/api/
83
+
84
+ Limited support for filters is available on some list pages, primarily through param `title_contains`.
85
+ Pagination is supported via `page_num` param.
86
+
87
+ Primary methods across majority of api calls are
88
+ - response : the full API response
89
+ - result : just the result attribute array
90
+ - list : displays a formatted output to console, handy for quick investigation of objects
91
+ - call : is a class method to list on Get and List requests
92
+
93
+ ```ruby
94
+ # List all Databases
95
+ Superset::Database::List.call
96
+ # DEBUG -- : Happi: GET https://your-superset-host/api/v1/database/?q=(page:0,page_size:100), {}
97
+ +----+------------------------------------+------------+------------------+
98
+ | Superset::Database::List |
99
+ +----+------------------------------------+------------+------------------+
100
+ | Id | Database name | Backend | Expose in sqllab |
101
+ +----+------------------------------------+------------+------------------+
102
+ | 1 | examples | postgresql | true |
103
+ +----+------------------------------------+------------+------------------+
104
+
105
+ # List database schemas for Database 1
106
+ Superset::Database::GetSchemas.new(1).list
107
+ # DEBUG -- : Happi: GET https://your-superset-host/api/v1/database/1/schemas/, {}
108
+ => ["information_schema", "public"]
109
+
110
+ # List dashboards
111
+ Superset::Dashboard::List.call
112
+ # PAGE_SIZE is set to 100, so get the second set of 100 dashboards with
113
+ Superset::Dashboard::List.new(page_num: 1).list
114
+ # OR filter by title
115
+ Superset::Dashboard::List.new(title_contains: 'Sales').list
116
+ # DEBUG -- : Happi: GET https://your-superset-host/api/v1/dashboard/?q=(filters:!((col:dashboard_title,opr:ct,value:'Sales')),page:0,page_size:100), {}
117
+
118
+ +-----+------------------------------+-----------+--------------------------------------------------------------------+
119
+ | Superset::Dashboard::List |
120
+ +-----+------------------------------+-----------+--------------------------------------------------------------------+
121
+ | Id | Dashboard title | Status | Url |
122
+ +-----+------------------------------+-----------+--------------------------------------------------------------------+
123
+ | 6 | Video Game Sales | published | https://your-superset-host/superset/dashboard/6/ |
124
+ | 8 | Sales Dashboard | published | https://your-superset-host/superset/dashboard/8/ |
125
+ +-----+------------------------------+-----------+--------------------------------------------------------------------+
126
+
127
+
128
+ Superset::Dashboard::Get.call(1) # same as Superset::Dashboard::Get.new(1).list
129
+ +----------------------------+
130
+ | World Banks Data |
131
+ +----------------------------+
132
+ | Charts |
133
+ +----------------------------+
134
+ | % Rural |
135
+ | Region Filter |
136
+ | Life Expectancy VS Rural % |
137
+ | Box plot |
138
+ | Most Populated Countries |
139
+ | Worlds Population |
140
+ | Worlds Pop Growth |
141
+ | Rural Breakdown |
142
+ | Treemap |
143
+ | Growth Rate |
144
+ +----------------------------+
145
+
146
+
147
+ ```
148
+ ## Optional Credential setup for Embedded User
149
+
150
+ Primary usage is for api calls and/or for guest token retrieval when setting up applications to use the superset embedded dashboard workflow.
151
+
152
+ The Superset API users fall into 2 categories
153
+ - a user for general api calls to endpoints for Dashboards, Datasets, Charts, Users, Roles etc.
154
+ ref `Superset::Credential::ApiUser`
155
+ which pulls credentials from `ENV['SUPERSET_API_USERNAME']` and `ENV['SUPERSET_API_PASSWORD']`
156
+
157
+ - a user for guest token api call to use when embedding dashboards in a host application.
158
+ ref `Superset::Credential::EmbeddedUser`
159
+ which pulls credentials from `ENV['SUPERSET_EMBEDDED_USERNAME']` and `ENV['SUPERSET_EMBEDDED_PASSWORD']`
160
+
161
+
162
+ ### Fetch a Guest Token for Embedded user
163
+
164
+ Assuming you have setup your Dashboard in Superset to be embedded and that your creds are setup in
165
+ `ENV['SUPERSET_EMBEDDED_USERNAME']` and `ENV['SUPERSET_EMBEDDED_PASSWORD']`
166
+
167
+ ```
168
+ Superset::GuestToken.new(embedded_dashboard_id: '15').guest_token
169
+ => "eyJ0eXAiOi............VV4mrMfsvg"
170
+ ```
171
+
172
+ ## Releasing a new version
173
+
174
+ On develop branch make sure to update `Superset::VERSION` and `CHANGELOG.md` with the new version number and changes.
175
+ Build the new version and upload to gemfury.
176
+
177
+ `gem build superset.gemspec`
178
+
179
+ ### Publishing to RubyGems
180
+
181
+ WIP .. direction is for this gem to be made public
182
+
183
+ ### ReadyTech private Gemfury repo
184
+
185
+ ReadyTech hosts its own private gemfury remote repo.
186
+
187
+ Get the latest develop into master
188
+
189
+ git checkout master
190
+ git pull
191
+ git fetch
192
+ git merge origin/develop
193
+
194
+ Tag the version and push to github
195
+
196
+ git tag -a -m "Version 0.1.0" v0.1.0
197
+ git push origin master --tags
198
+
199
+ Push to gemfury or upload the build manually in the gemfury site.
200
+
201
+ git push fury master
202
+
203
+ ## License
204
+
205
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,214 @@
1
+ # Duplicating Dashboards to a new database or schema
2
+
3
+ The problem!
4
+
5
+ Given a multi tenant configuration where clients databases are logically separate dbs and or schemas all configured in Superset,
6
+ copying or duplicating an existing Superset dashboard to a new database is a fairly laborious operation with many manual steps.
7
+
8
+ Usually run in the Superset GUI something like :
9
+ - Create Dashboard (template)
10
+ - Duplicate the template in GUI with Edit->Save As (duplicate charts checked)
11
+ - Duplicate all Datasets from template, Edit each and point to the new target database
12
+ - Edit all the new charts created and link them to the new datasets.
13
+ - Setup the embedded settings for new dashboard
14
+ - Add new tags for the new dashboard
15
+
16
+ Give the need for multiple clients, 10s or 100s, or 1000s, this quickly becomes a laborious and time consuming feat.
17
+
18
+ Superset API to the rescue.
19
+
20
+ Note .. requires setup of your [superset environment credentials](https://github.com/rdytech/superset-client/blob/develop/doc/setting_up_personal_api_credentials.md)
21
+
22
+ ## The Solution
23
+
24
+ Essentially we perform the same points above but all via the Superset API.
25
+
26
+ The examples video game dashboard was adjusted to have only 1 chart.
27
+ Output is new new_dashboard_id and url. Logs provided in `log/superset-client.log`
28
+
29
+ Given you have a dashboard created, ie `source_dashboard_id`
30
+ and you know your `target_schema`
31
+ as well as your `target_database_id`
32
+ then you could go ahead and run something like this.
33
+
34
+
35
+
36
+ ```ruby
37
+ Superset::Services::DuplicateDashboard.new(
38
+ source_dashboard_id: 90,
39
+ target_schema: 'public',
40
+ target_database_id: 2
41
+ ).perform
42
+
43
+ => {:new_dashboard_id=>401, :new_dashboard_url=>"https://your-superset-host/superset/dashboard/401/", :published=>false}
44
+
45
+ # logfile shows the steps taken
46
+
47
+ # cat log/superset-client.log
48
+ # INFO -- : >>>>>>>>>>>>>>>>> Starting DuplicateDashboard Service <<<<<<<<<<<<<<<<<<<<<<
49
+ # INFO -- : Source Dashboard URL: https://your-superset-host/superset/dashboard/90/
50
+ # INFO -- : Duplicating dashboard 90 into Target Schema: public in database 2
51
+ # INFO -- : Copy Dashboard/Charts Completed - New Dashboard ID: 401
52
+ # INFO -- : Duplicating Source Dataset examples.video_game_sales with id 11
53
+ # INFO -- : Finished. Duplicate Dataset Name video_game_sales-example_two with id 542
54
+ # INFO -- : Validating Dataset ID: 542 schema update to public on Database: 2
55
+ # INFO -- : Successfully updated dataset schema to public on Database: 2
56
+ # INFO -- : Updating Charts to point to New Datasets and updating Dashboard json_metadata ...
57
+ # INFO -- : Update Chart 55752 to new dataset_id 542
58
+ # INFO -- : Updated new Dashboard json_metadata charts with new dataset ids
59
+ # INFO -- : Duplication Successful. New Dashboard URL: https://your-superset-host/superset/dashboard/401/
60
+ # INFO -- : >>>>>>>>>>>>>>>>> Finished DuplicateDashboard Service <<<<<<<<<<<<<<<<<<<<<<
61
+
62
+ ```
63
+
64
+ ## Other options for embedded workflow and tags
65
+
66
+ If your using the embedded dashboards you can also provied attributes for
67
+ - allowed domains for embeded dashboard settings
68
+ - database tags for ease of searching
69
+ - option to publish
70
+
71
+ ```ruby
72
+ Superset::Services::DuplicateDashboard.new(
73
+ source_dashboard_id: 37,
74
+ target_schema: 'public',
75
+ target_database_id: 2,
76
+ allowed_domains: ["https://wylee-coyote-domain/"],
77
+ tags: ["product:acme_fu", "client:wylee_coyote", "embedded"],
78
+ publish: true
79
+ ).perform
80
+ ```
81
+
82
+ ### What is my Database ID ?
83
+
84
+ ``` ruby
85
+ # list your available databases with
86
+ Superset::Database::List.call
87
+
88
+ # DEBUG -- : Happi: GET https://your-superset-host/api/v1/database/?q=(page:0,page_size:100), {}
89
+ +----+------------------------------------+------------+------------------+
90
+ | Superset::Database::List |
91
+ +----+------------------------------------+------------+------------------+
92
+ | Id | Database name | Backend | Expose in sqllab |
93
+ +----+------------------------------------+------------+------------------+
94
+ | 1 | examples | postgresql | true |
95
+ | 2 | examples_two | postgresql | true |
96
+ +----+------------------------------------+------------+------------------+
97
+
98
+ # optionally provide a title filter
99
+ Superset::Database::List.new(title_contains: 'examples_two').list
100
+
101
+ # DEBUG -- : Happi: GET https://your-superset-host/api/v1/database/?q=(filters:!((col:database_name,opr:ct,value:'examples')),page:0,page_size:100), {}
102
+ +----+------------------------------------+------------+------------------+
103
+ | Superset::Database::List |
104
+ +----+------------------------------------+------------+------------------+
105
+ | Id | Database name | Backend | Expose in sqllab |
106
+ +----+------------------------------------+------------+------------------+
107
+ | 2 | examples_two | postgresql | true |
108
+ +----+------------------------------------+------------+------------------+
109
+
110
+ ```
111
+
112
+ ### What Dashboards do I have access to ?
113
+
114
+ ```ruby
115
+ # list dashboard with
116
+ Superset::Dashboard::List.call
117
+ # DEBUG -- : Happi: GET https://your-superset-host/api/v1/dashboard/?q=(page:0,page_size:100), {}
118
+ +-----+------------------------------------------------------+-----------+--------------------------------------------------------------------+
119
+ | Superset::Dashboard::List |
120
+ +-----+------------------------------------------------------+-----------+--------------------------------------------------------------------+
121
+ | Id | Dashboard title | Status | Url |
122
+ +-----+------------------------------------------------------+-----------+--------------------------------------------------------------------+
123
+ | 20 | Baby Names | draft | https://your-superset-host/superset/dashboard/20/ |
124
+ | 6 | Video Game Sales | published | https://your-superset-host/superset/dashboard/6/ |
125
+ | 5 | COVID Vaccine Dashboard | published | https://your-superset-host/superset/dashboard/5/ |
126
+ | 9 | Superset Project Slack Dashboard | published | https://your-superset-host/superset/dashboard/9/ |
127
+ +-----+------------------------------------------------------+-----------+--------------------------------------------------------------------+
128
+
129
+ # or filter by title
130
+ Superset::Dashboard::List.new(title_contains: 'video').list
131
+ # DEBUG -- : Happi: GET https://your-superset-host/api/v1/dashboard/?q=(filters:!((col:dashboard_title,opr:ct,value:'video')),page:0,page_size:100), {}
132
+ +----+------------------+-----------+------------------------------------------------------------------+
133
+ | Superset::Dashboard::List |
134
+ +----+------------------+-----------+------------------------------------------------------------------+
135
+ | Id | Dashboard title | Status | Url |
136
+ +----+------------------+-----------+------------------------------------------------------------------+
137
+ | 6 | Video Game Sales | published | https://your-superset-host/superset/dashboard/6/ |
138
+ +----+------------------+-----------+------------------------------------------------------------------+
139
+
140
+ ```
141
+
142
+ ### Replicate a Dashboard across all schemas
143
+
144
+ With a bit of ruby ...
145
+
146
+ Duplicate dashboard across all schemas in acme pools 1,2,3.
147
+
148
+ ```ruby
149
+ acme_dbs = Superset::Database::List.new(title_contains: 'acme').rows
150
+ => [["7", "acme-pool1", "postgresql", "true"],
151
+ ["8", "acme-pool2", "postgresql", "true"],
152
+ ["9", "acme-pool3", "postgresql", "true"]]
153
+
154
+ ignore_system_tables = ['information_schema', 'shared_extensions'] # postgres system schemas
155
+
156
+ db_with_schemas = acme_dbs.map do |db_conn|
157
+ Superset::Database::GetSchemas.new(db_conn[0]).list.map do |schema|
158
+ { database_id: db_conn[0], schema: schema, database_name: db_conn[1] } unless ignore_system_tables.include?(schema)
159
+ end.compact
160
+ end.flatten
161
+
162
+ =>[{:database_id=>"7", :schema=>"client1", :database_name=>"acme-pool1"},
163
+ {:database_id=>"7", :schema=>"client2", :database_name=>"acme-pool1"},
164
+ {:database_id=>"7", :schema=>"client3", :database_name=>"acme-pool1"},
165
+ {:database_id=>"8", :schema=>"client4", :database_name=>"acme-pool1"},
166
+ {:database_id=>"8", :schema=>"client5", :database_name=>"acme-pool2"},
167
+ {:database_id=>"8", :schema=>"client6", :database_name=>"acme-pool2"},
168
+ {:database_id=>"9", :schema=>"client7", :database_name=>"acme-pool3"},
169
+ {:database_id=>"9", :schema=>"client8", :database_name=>"acme-pool3"},
170
+ {:database_id=>"9", :schema=>"client9", :database_name=>"acme-pool3"},
171
+ {:database_id=>"9", :schema=>"client10", :database_name=>"acme-pool3"}]
172
+
173
+ db_with_schemas.each do |conn|
174
+ Superset::Services::DuplicateDashboard.new(
175
+ source_dashboard_id: 90,
176
+ target_schema: conn[:schema],
177
+ target_database_id: conn[:database_id]
178
+ ).perform
179
+ end
180
+
181
+ ```
182
+
183
+ ## TODO / ISSUES
184
+
185
+ ### Handling Change
186
+
187
+ Dashboards are an ever evolving animal and they are expected to change.
188
+
189
+ This raises the question, given I have a template dashboard and I have X number of replicas of that dashboard
190
+ how do I make a change to the template and get the change updated to each of the replicas?
191
+
192
+ Current direction is to separate these "changes" in to 2 categories.
193
+
194
+ - Firstly: minor chages to a Dataset query that will not result in breaking a chart.
195
+ ie .. adjusting the logic of the query but not the output attributes.
196
+ - Secondly: ... everything else.
197
+ ie .. editing/adding charts, formating the dashboard, updating the datasets with new attributes for new charts
198
+
199
+ For the first case, the Superset API can easily locate each Dashboards Dataset and update the query with the changes.
200
+ This is a fairly simple procedure.
201
+
202
+ For the second case, currently we can see no easy/clear direction forward.
203
+ Very happy to have others with more experience in Superset pose suggestions.
204
+
205
+ Putting it simply, the current thinking is to delete all the replica dashboards and recreate them.
206
+
207
+ ### Bringing the Duplicate Dashboard process into Superset core
208
+
209
+ (WIP) The goal would be to have the DuplicateDashboard process as a part of the core superset codebase.
210
+
211
+ To that end this Superset Improvement Proposal (SIP) .. is a starting point.
212
+
213
+ {add SIP request here}
214
+