gazer 0.2.36 → 0.2.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +12 -0
- data/lib/gzr/command.rb +143 -3
- data/lib/gzr/commands/dashboard/cat.rb +13 -3
- data/lib/gzr/commands/dashboard/import.rb +66 -135
- data/lib/gzr/commands/look/cat.rb +10 -4
- data/lib/gzr/commands/look/import.rb +1 -1
- data/lib/gzr/commands/space/export.rb +28 -13
- data/lib/gzr/commands/space/ls.rb +37 -22
- data/lib/gzr/modules/dashboard.rb +11 -0
- data/lib/gzr/modules/look.rb +30 -15
- data/lib/gzr/modules/session.rb +3 -3
- data/lib/gzr/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63f0133a6db8baa3e1cbb77432444b11b51a9d3f63746b1e18018b9da52ffba1
|
4
|
+
data.tar.gz: b1128abc82113482b0bbc5956f680b4b6e633d26ab9204988e87ce45a83f5cdb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c94dda1c71d32c8441c7eeba27c230a5ec35e5b96e3b8b3dd897aa1f4c38f685c4edee7961beb8fe67e4e091922d697e55fd36d8f47fd907c1fa0f4f3a92c48
|
7
|
+
data.tar.gz: 5e56640ba557897596eec20cf99b5465ec8760dba904bc01d0e82e67af97ce559dcc85f7e5a2b286c0aa3c96bd882d350d04c6cac3b431ab8bc44fc12656b188
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -34,6 +34,18 @@ machine foo.bar.mycompany.com
|
|
34
34
|
|
35
35
|
Make sure that the `~/.netrc` file has restricted permissions by running `chmod 600 ~/.netrc`.
|
36
36
|
|
37
|
+
### API port
|
38
|
+
Most instances of Looker use port 19999 for the API. Gazer will use that port by default when executing a command.
|
39
|
+
Looker instances that are hosted in Google Cloud direct both the API and the web
|
40
|
+
interface traffic through port 443, the standard https port. Some other
|
41
|
+
installations may also use port 443.
|
42
|
+
|
43
|
+
If your Looker instance is GCP-hosted (*.cloud.looker.com), you must specify `--port 443`, eg:
|
44
|
+
|
45
|
+
```
|
46
|
+
$ gzr user me --host mycompany.cloud.looker.com --port 443
|
47
|
+
```
|
48
|
+
|
37
49
|
### Options that apply to many commands
|
38
50
|
|
39
51
|
#### --su option
|
data/lib/gzr/command.rb
CHANGED
@@ -116,6 +116,146 @@ module Gzr
|
|
116
116
|
data
|
117
117
|
end
|
118
118
|
|
119
|
+
def all_color_collections()
|
120
|
+
data = nil
|
121
|
+
begin
|
122
|
+
data = @sdk.all_color_collections()
|
123
|
+
rescue NoMethodError => nme
|
124
|
+
say_warning "The api endpoint all_color_collections() is not implemented on this Looker instance"
|
125
|
+
rescue LookerSDK::NotFound => nf
|
126
|
+
say_warning "The current user can't query all color collections"
|
127
|
+
rescue LookerSDK::Error => e
|
128
|
+
say_error "Error querying all_color_collections()"
|
129
|
+
say_error e.message
|
130
|
+
raise
|
131
|
+
end
|
132
|
+
data
|
133
|
+
end
|
134
|
+
|
135
|
+
def default_color_collection()
|
136
|
+
return @dcc if @dcc
|
137
|
+
data = nil
|
138
|
+
begin
|
139
|
+
data = @sdk.default_color_collection()
|
140
|
+
@dcc = data
|
141
|
+
rescue NoMethodError => nme
|
142
|
+
say_warning "The api endpoint default_color_collection() is not implemented on this Looker instance"
|
143
|
+
rescue LookerSDK::NotFound => nf
|
144
|
+
say_warning "The current user can't query the default color collection"
|
145
|
+
rescue LookerSDK::Error => e
|
146
|
+
say_error "Error querying default_color_collection()"
|
147
|
+
say_error e.message
|
148
|
+
raise
|
149
|
+
end
|
150
|
+
data
|
151
|
+
end
|
152
|
+
|
153
|
+
def color_collection(collection_id)
|
154
|
+
data = nil
|
155
|
+
begin
|
156
|
+
data = @sdk.color_collection(collection_id)
|
157
|
+
rescue NoMethodError => nme
|
158
|
+
say_warning "The api endpoint color_collection(collection_id) is not implemented on this Looker instance"
|
159
|
+
rescue LookerSDK::NotFound => nf
|
160
|
+
say_warning "The color_collection(#{collection_id}) is not found"
|
161
|
+
rescue LookerSDK::Error => e
|
162
|
+
say_error "Error querying color_collection(#{collection_id})"
|
163
|
+
say_error e.message
|
164
|
+
raise
|
165
|
+
end
|
166
|
+
data
|
167
|
+
end
|
168
|
+
|
169
|
+
def find_vis_config_reference(obj, &block)
|
170
|
+
if obj.respond_to?(:'has_key?') && obj.has_key?(:vis_config)
|
171
|
+
yield (obj[:vis_config])
|
172
|
+
end
|
173
|
+
if obj.is_a? Enumerable
|
174
|
+
obj.each { |o| find_vis_config_reference(o,&block) }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def find_color_palette_reference(obj, default_colors=nil, &block)
|
179
|
+
begin
|
180
|
+
dcc = default_color_collection()
|
181
|
+
if dcc.nil?
|
182
|
+
say_warning "You do not have access to query color palettes so these won't be processed."
|
183
|
+
return
|
184
|
+
end
|
185
|
+
default_colors=color_palette_lookup!(dcc)
|
186
|
+
end unless default_colors
|
187
|
+
|
188
|
+
if obj.respond_to?(:'has_key?') && obj.has_key?(:collection_id) && obj.has_key?(:palette_id)
|
189
|
+
yield(obj,default_colors)
|
190
|
+
end
|
191
|
+
if obj.is_a? Enumerable
|
192
|
+
obj.each { |o| find_color_palette_reference(o,default_colors,&block) }
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def color_palette_lookup!(obj)
|
197
|
+
return nil unless obj
|
198
|
+
palettes = []
|
199
|
+
palettes += obj[:categoricalPalettes] if obj[:categoricalPalettes]
|
200
|
+
palettes += obj[:sequentialPalettes] if obj[:sequentialPalettes]
|
201
|
+
palettes += obj[:divergingPalettes] if obj[:divergingPalettes]
|
202
|
+
obj[:palettes]=palettes
|
203
|
+
obj
|
204
|
+
end
|
205
|
+
|
206
|
+
def rewrite_color_palette!(o,default_colors)
|
207
|
+
cc = nil
|
208
|
+
if o[:collection_id] == default_colors[:id]
|
209
|
+
o[:collection_default] = true
|
210
|
+
cc = default_colors
|
211
|
+
else
|
212
|
+
o[:collection_default] = false
|
213
|
+
cc = color_palette_lookup!(color_collection(o[:collection_id]))
|
214
|
+
end
|
215
|
+
return unless cc
|
216
|
+
o[:collection_label] = cc[:label]
|
217
|
+
ps = cc[:palettes].select { |p| p[:id] == o[:palette_id] }
|
218
|
+
if ps.length > 0
|
219
|
+
o[:palette_label] = ps.first[:label]
|
220
|
+
o[:palette_type] = ps.first[:type]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def update_color_palette!(o,default_colors,force_default=false)
|
225
|
+
return unless o.has_key?(:collection_label) && o.has_key?(:palette_type)
|
226
|
+
|
227
|
+
cc = default_colors
|
228
|
+
if !(force_default && o[:collection_default])
|
229
|
+
# look up color collection by id
|
230
|
+
cc = color_palette_lookup!(color_collection(o[:collection_id]))
|
231
|
+
if cc.nil?
|
232
|
+
# find color collection by name
|
233
|
+
ccs = all_color_collections()&.select { |cc| o[:collection_label] == cc[:label]}
|
234
|
+
if ccs.nil? || ccs.length == 0
|
235
|
+
# no color collection found. Use default.
|
236
|
+
say_warning "Color collection #{o[:collection_label]} not found. Using default."
|
237
|
+
cc = default_colors
|
238
|
+
else
|
239
|
+
cc = color_palette_lookup!(ccs.first)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
o[:collection_id] = cc[:id]
|
244
|
+
|
245
|
+
# look up palette by id
|
246
|
+
ps = cc[:palettes].select {|p| p[:id] == o[:palette_id]}
|
247
|
+
if ps.length == 0
|
248
|
+
# find palette by type
|
249
|
+
ps = cc[:palettes].select {|p| p[:type] == o[:palette_type]}
|
250
|
+
if ps.length > 0
|
251
|
+
o[:palette_id] = ps.first[:id]
|
252
|
+
else
|
253
|
+
# no palette found
|
254
|
+
say_warning "Color palette #{o[:palette_type]} not found."
|
255
|
+
o.delete(:palette_id)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
119
259
|
|
120
260
|
##
|
121
261
|
# This method accepts the name of an sdk operation, then finds the parameter for that
|
@@ -131,7 +271,7 @@ module Gzr
|
|
131
271
|
# new_obj_hash = existing_obj_hash.select do |k,v|
|
132
272
|
# keys_to_keep('create_new_obj').include? k
|
133
273
|
# end
|
134
|
-
|
274
|
+
|
135
275
|
def keys_to_keep(operation)
|
136
276
|
o = @sdk.operations[operation]
|
137
277
|
begin
|
@@ -145,12 +285,12 @@ module Gzr
|
|
145
285
|
schema_ref = parameters[0][:schema][:$ref].split(/\//)
|
146
286
|
return @sdk.swagger[schema_ref[1].to_sym][schema_ref[2].to_sym][:properties].reject { |k,v| v[:readOnly] }.keys
|
147
287
|
end
|
148
|
-
|
288
|
+
|
149
289
|
##
|
150
290
|
# The tty-table gem is normally used to output tabular data. This method accepts a Table
|
151
291
|
# object as used by the tty-table gem, and generates CSV output. It returns a string
|
152
292
|
# with crlf encoding
|
153
|
-
|
293
|
+
|
154
294
|
def render_csv(t)
|
155
295
|
io = StringIO.new
|
156
296
|
io.puts (
|
@@ -46,12 +46,22 @@ module Gzr
|
|
46
46
|
data = query_dashboard(@dashboard_id).to_attrs
|
47
47
|
data[:dashboard_elements].each_index do |i|
|
48
48
|
element = data[:dashboard_elements][i]
|
49
|
-
|
50
|
-
|
49
|
+
find_vis_config_reference(element) do |vis_config|
|
50
|
+
find_color_palette_reference(vis_config) do |o,default_colors|
|
51
|
+
rewrite_color_palette!(o,default_colors)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
merge_result = merge_query(element[:merge_result_id])&.to_attrs if element[:merge_result_id]
|
55
|
+
if merge_result
|
51
56
|
merge_result[:source_queries].each_index do |j|
|
52
57
|
source_query = merge_result[:source_queries][j]
|
53
58
|
merge_result[:source_queries][j][:query] = query(source_query[:query_id]).to_attrs
|
54
59
|
end
|
60
|
+
find_vis_config_reference(merge_result) do |vis_config|
|
61
|
+
find_color_palette_reference(vis_config) do |o,default_colors|
|
62
|
+
rewrite_color_palette!(o,default_colors)
|
63
|
+
end
|
64
|
+
end
|
55
65
|
data[:dashboard_elements][i][:merge_result] = merge_result
|
56
66
|
end
|
57
67
|
end
|
@@ -86,7 +96,7 @@ module Gzr
|
|
86
96
|
elsif e[:position] === 'bottom'
|
87
97
|
row = max_row.to_s
|
88
98
|
end
|
89
|
-
|
99
|
+
|
90
100
|
column = '0'
|
91
101
|
width = e[:width].to_s
|
92
102
|
height = e[:height].to_s
|
@@ -55,31 +55,60 @@ module Gzr
|
|
55
55
|
|
56
56
|
dashboard = sync_dashboard(data,@dest_space_id, output: output)
|
57
57
|
|
58
|
+
|
59
|
+
dashboard[:dashboard_filters] ||= []
|
58
60
|
source_filters = data[:dashboard_filters].sort { |a,b| a[:row] <=> b[:row] }
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
if matches_by_name_title.length > 0
|
63
|
-
delete_dashboard_filter(e.id)
|
64
|
-
nil
|
65
|
-
else
|
66
|
-
e
|
61
|
+
source_filters.each do |new_filter|
|
62
|
+
filter = new_filter.select do |k,v|
|
63
|
+
(keys_to_keep('create_dashboard_filter') + [:row]).include? k
|
67
64
|
end
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
sync_dashboard_filter(source,target,id)
|
65
|
+
filter[:dashboard_id] = dashboard.id
|
66
|
+
say_warning "Creating filter" if @options[:debug]
|
67
|
+
dashboard[:dashboard_filters].push create_dashboard_filter(filter)
|
72
68
|
end
|
73
69
|
|
74
|
-
|
75
|
-
|
70
|
+
dashboard[:dashboard_elements] ||= []
|
71
|
+
elem_table = data[:dashboard_elements].map do |new_element|
|
72
|
+
element = new_element.select do |k,v|
|
73
|
+
(keys_to_keep('create_dashboard_element') - [:dashboard_id, :look_id, :query_id, :merge_result_id, :result_maker_id]).include? k
|
74
|
+
end
|
75
|
+
(element[:query_id],element[:look_id],element[:merge_result_id]) = process_dashboard_element(new_element)
|
76
|
+
say_warning "Creating dashboard element #{element.inspect}" if @options[:debug]
|
77
|
+
element[:dashboard_id] = dashboard.id
|
78
|
+
result_maker = copy_result_maker_filterables(new_element)
|
79
|
+
element[:result_maker] = result_maker if result_maker
|
80
|
+
dashboard_element = create_dashboard_element(element)
|
81
|
+
dashboard[:dashboard_elements].push dashboard_element
|
82
|
+
[new_element[:id], dashboard_element.id]
|
76
83
|
end
|
77
84
|
|
78
|
-
source_dashboard_layouts = data[:dashboard_layouts].
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
85
|
+
source_dashboard_layouts = data[:dashboard_layouts].map do |new_layout|
|
86
|
+
layout_obj = nil
|
87
|
+
if new_layout[:active]
|
88
|
+
layout_obj = get_dashboard_layout(dashboard[:dashboard_layouts].first.id)
|
89
|
+
say_warning "Updating layout #{layout_obj.id}" if @options[:debug]
|
90
|
+
else
|
91
|
+
layout = new_layout.select do |k,v|
|
92
|
+
(keys_to_keep('create_dashboard_layout') - [:dashboard_id]).include? k
|
93
|
+
end
|
94
|
+
layout[:dashboard_id] = dashboard.id
|
95
|
+
say_warning "Creating dashboard layout #{layout}" if @options[:debug]
|
96
|
+
layout_obj = create_dashboard_layout(layout)
|
97
|
+
end
|
98
|
+
layout_components = new_layout[:dashboard_layout_components].zip(layout_obj.dashboard_layout_components)
|
99
|
+
layout_components.each do |source,target|
|
100
|
+
component = keys_to_keep('update_dashboard_layout_component').collect do |e|
|
101
|
+
[e,nil]
|
102
|
+
end.to_h
|
103
|
+
component[:dashboard_layout_id] = target.dashboard_layout_id
|
104
|
+
|
105
|
+
component.merge!(source.select do |k,v|
|
106
|
+
(keys_to_keep('update_dashboard_layout_component') - [:id,:dashboard_layout_id]).include? k
|
107
|
+
end)
|
108
|
+
|
109
|
+
component[:dashboard_element_id] = elem_table.assoc(source[:dashboard_element_id])[1]
|
110
|
+
say_warning "Updating dashboard layout component #{target.id}" if @options[:debug]
|
111
|
+
update_dashboard_layout_component(target.id,component)
|
83
112
|
end
|
84
113
|
end
|
85
114
|
upsert_plans_for_dashboard(dashboard.id,@me.id,data[:scheduled_plans]) if data[:scheduled_plans]
|
@@ -127,7 +156,24 @@ module Gzr
|
|
127
156
|
end
|
128
157
|
new_dash[:slug] = source[:slug] unless slug_used
|
129
158
|
new_dash[:deleted] = false if existing_dashboard[:deleted]
|
130
|
-
|
159
|
+
d = update_dashboard(existing_dashboard.id,new_dash)
|
160
|
+
|
161
|
+
d.dashboard_filters.each do |f|
|
162
|
+
delete_dashboard_filter(f.id)
|
163
|
+
end
|
164
|
+
d.dashboard_filters = []
|
165
|
+
|
166
|
+
d.dashboard_elements.each do |e|
|
167
|
+
delete_dashboard_element(e.id)
|
168
|
+
end
|
169
|
+
d.dashboard_elements = []
|
170
|
+
|
171
|
+
d.dashboard_layouts.each do |l|
|
172
|
+
delete_dashboard_layout(l.id) unless l.active
|
173
|
+
end
|
174
|
+
d.dashboard_layouts.select! { |l| l.active }
|
175
|
+
|
176
|
+
return d
|
131
177
|
else
|
132
178
|
new_dash = source.select do |k,v|
|
133
179
|
(keys_to_keep('create_dashboard') - [:space_id,:folder_id,:user_id,:slug]).include? k
|
@@ -139,26 +185,6 @@ module Gzr
|
|
139
185
|
end
|
140
186
|
end
|
141
187
|
|
142
|
-
def sync_dashboard_filter(new_filter,existing_filter,dashboard_id)
|
143
|
-
if new_filter && !existing_filter then
|
144
|
-
filter = new_filter.select do |k,v|
|
145
|
-
(keys_to_keep('create_dashboard_filter') + [:row]).include? k
|
146
|
-
end
|
147
|
-
filter[:dashboard_id] = dashboard_id
|
148
|
-
say_warning "Creating filter" if @options[:debug]
|
149
|
-
return create_dashboard_filter(filter)
|
150
|
-
end
|
151
|
-
if existing_filter && new_filter then
|
152
|
-
filter = new_filter.select do |k,v|
|
153
|
-
(keys_to_keep('update_dashboard_filter') + [:row]).include? k
|
154
|
-
end
|
155
|
-
say_warning "Updating filter #{existing_filter.id}" if @options[:debug]
|
156
|
-
return update_dashboard_filter(existing_filter.id,filter)
|
157
|
-
end
|
158
|
-
say_warning "Deleting filter #{existing_filter.id}" if @options[:debug]
|
159
|
-
return delete_dashboard_filter(existing_filter.id)
|
160
|
-
end
|
161
|
-
|
162
188
|
def copy_result_maker_filterables(new_element)
|
163
189
|
return nil unless new_element[:result_maker]
|
164
190
|
if new_element[:result_maker].fetch(:filterables,[]).length > 0
|
@@ -173,51 +199,6 @@ module Gzr
|
|
173
199
|
nil
|
174
200
|
end
|
175
201
|
|
176
|
-
def sync_dashboard_element(new_element,existing_element,dashboard_id)
|
177
|
-
if (new_element&.fetch(:type) == 'text' && existing_element && existing_element[:type] != 'text')
|
178
|
-
say_warning "Deleting dashboard element #{existing_element.id} to recreate it" if @options[:debug]
|
179
|
-
delete_dashboard_element(existing_element.id)
|
180
|
-
existing_element = nil
|
181
|
-
end
|
182
|
-
|
183
|
-
if new_element && !existing_element then
|
184
|
-
element = new_element.select do |k,v|
|
185
|
-
(keys_to_keep('create_dashboard_element') - [:dashboard_id, :look_id, :query_id, :merge_result_id]).include? k
|
186
|
-
end
|
187
|
-
(element[:query_id],element[:look_id],element[:merge_result_id]) = process_dashboard_element(new_element)
|
188
|
-
say_warning "Creating dashboard element #{element.inspect}" if @options[:debug]
|
189
|
-
element[:dashboard_id] = dashboard_id
|
190
|
-
result_maker = copy_result_maker_filterables(new_element)
|
191
|
-
element[:result_maker] = result_maker if result_maker
|
192
|
-
return [new_element[:id], create_dashboard_element(element).id]
|
193
|
-
end
|
194
|
-
if existing_element && new_element then
|
195
|
-
element = keys_to_keep('update_dashboard_element').collect do |e|
|
196
|
-
[e,nil]
|
197
|
-
end.to_h
|
198
|
-
|
199
|
-
element[:dashboard_id] = dashboard_id
|
200
|
-
|
201
|
-
element.merge!( new_element.select do |k,v|
|
202
|
-
(keys_to_keep('update_dashboard_element') - [:dashboard_id, :look_id, :query_id, :merge_result_id]).include? k
|
203
|
-
end
|
204
|
-
)
|
205
|
-
(element[:query_id],element[:look_id],element[:merge_result_id]) = process_dashboard_element(new_element)
|
206
|
-
if existing_element[:result_maker] && !new_element[:result_maker]
|
207
|
-
element[:result_maker] = nil
|
208
|
-
elsif new_element[:result_maker]
|
209
|
-
result_maker = copy_result_maker_filterables(new_element)
|
210
|
-
element[:result_maker] = result_maker if result_maker
|
211
|
-
end
|
212
|
-
|
213
|
-
say_warning "Updating dashboard element #{existing_element.id}" if @options[:debug]
|
214
|
-
return [new_element[:id], update_dashboard_element(existing_element.id,element).id]
|
215
|
-
end
|
216
|
-
say_warning "Deleting dashboard element #{existing_element.id}" if @options[:debug]
|
217
|
-
delete_dashboard_element(existing_element.id)
|
218
|
-
return [nil,existing_element.id]
|
219
|
-
end
|
220
|
-
|
221
202
|
def process_dashboard_element(dash_elem)
|
222
203
|
return [nil, upsert_look(@me.id, create_fetch_query(dash_elem[:look][:query]).id, @dest_space_id, dash_elem[:look]).id, nil] if dash_elem[:look]
|
223
204
|
|
@@ -230,56 +211,6 @@ module Gzr
|
|
230
211
|
[nil,nil,nil]
|
231
212
|
end
|
232
213
|
|
233
|
-
def sync_dashboard_layout(dashboard_id,new_layout,existing_layout)
|
234
|
-
layout_obj = nil
|
235
|
-
if new_layout && !existing_layout then
|
236
|
-
layout = new_layout.select do |k,v|
|
237
|
-
(keys_to_keep('create_dashboard_layout') - [:dashboard_id]).include? k
|
238
|
-
end
|
239
|
-
layout[:dashboard_id] = dashboard_id
|
240
|
-
say_warning "Creating dashboard layout #{layout}" if @options[:debug]
|
241
|
-
layout_obj = create_dashboard_layout(layout)
|
242
|
-
end
|
243
|
-
if new_layout && existing_layout then
|
244
|
-
layout = new_layout.select do |k,v|
|
245
|
-
(keys_to_keep('update_dashboard_layout') - [:dashboard_id]).include? k
|
246
|
-
end
|
247
|
-
say_warning "Updating dashboard layout #{existing_layout.id}" if @options[:debug]
|
248
|
-
layout_obj = update_dashboard_layout(existing_layout.id,layout)
|
249
|
-
end
|
250
|
-
if !new_layout && existing_layout then
|
251
|
-
say_warning "Deleting dashboard layout #{existing_layout.id}" if @options[:debug]
|
252
|
-
delete_dashboard_layout(existing_layout.id)
|
253
|
-
end
|
254
|
-
|
255
|
-
return unless layout_obj
|
256
|
-
|
257
|
-
#say_warning "new_layout[:active] is #{new_layout&.fetch(:active)} for #{layout_obj.id}"
|
258
|
-
#if layout_obj && new_layout&.fetch(:active,false)
|
259
|
-
# say_warning "Setting layout #{layout_obj.id} active"
|
260
|
-
# update_dashboard_layout(layout_obj.id, { :active => true })
|
261
|
-
#end
|
262
|
-
|
263
|
-
layout_components = new_layout[:dashboard_layout_components].zip(layout_obj.dashboard_layout_components)
|
264
|
-
return layout_components unless block_given?
|
265
|
-
|
266
|
-
layout_components.each { |s,t| yield(s,t) }
|
267
|
-
end
|
268
|
-
|
269
|
-
def sync_dashboard_layout_component(source, target, elem_table)
|
270
|
-
component = keys_to_keep('update_dashboard_layout_component').collect do |e|
|
271
|
-
[e,nil]
|
272
|
-
end.to_h
|
273
|
-
component[:dashboard_layout_id] = target.dashboard_layout_id
|
274
|
-
|
275
|
-
component.merge!(source.select do |k,v|
|
276
|
-
(keys_to_keep('update_dashboard_layout_component') - [:id,:dashboard_layout_id]).include? k
|
277
|
-
end)
|
278
|
-
|
279
|
-
component[:dashboard_element_id] = elem_table.assoc(source[:dashboard_element_id])[1]
|
280
|
-
say_warning "Updating dashboard layout component #{target.id}" if @options[:debug]
|
281
|
-
update_dashboard_layout_component(target.id,component)
|
282
|
-
end
|
283
214
|
end
|
284
215
|
end
|
285
216
|
end
|
@@ -42,10 +42,16 @@ module Gzr
|
|
42
42
|
def execute(input: $stdin, output: $stdout)
|
43
43
|
say_warning("options: #{@options.inspect}") if @options[:debug]
|
44
44
|
with_session do
|
45
|
-
data = query_look(@look_id)
|
46
|
-
data
|
47
|
-
|
48
|
-
|
45
|
+
data = query_look(@look_id).to_attrs
|
46
|
+
find_vis_config_reference(data) do |vis_config|
|
47
|
+
find_color_palette_reference(vis_config) do |o,default_colors|
|
48
|
+
rewrite_color_palette!(o,default_colors)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
data[:scheduled_plans] = query_scheduled_plans_for_look(@look_id,"all").to_attrs if @options[:plans]
|
53
|
+
write_file(@options[:dir] ? "Look_#{data[:id]}_#{data[:title]}.json" : nil, @options[:dir],nil, output) do |f|
|
54
|
+
f.puts JSON.pretty_generate(data)
|
49
55
|
end
|
50
56
|
end
|
51
57
|
end
|
@@ -47,7 +47,7 @@ module Gzr
|
|
47
47
|
with_session do
|
48
48
|
|
49
49
|
@me ||= query_me("id")
|
50
|
-
|
50
|
+
|
51
51
|
read_file(@file) do |data|
|
52
52
|
look = upsert_look(@me.id,create_fetch_query(data[:query]).id,@dest_space_id,data,output: output)
|
53
53
|
upsert_plans_for_look(look.id,@me.id,data[:scheduled_plans]) if data[:scheduled_plans]
|
@@ -84,33 +84,48 @@ module Gzr
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def process_space(space_id, base, rel_path = nil)
|
87
|
-
space = query_space(space_id)
|
88
|
-
name = space
|
87
|
+
space = query_space(space_id).to_attrs
|
88
|
+
name = space[:name]
|
89
89
|
name = "nil (#{space_id})" if name.nil?
|
90
90
|
path = Pathname.new(name.gsub('/',"\u{2215}"))
|
91
91
|
path = rel_path + path if rel_path
|
92
92
|
|
93
|
-
write_file("Space_#{space
|
94
|
-
f.write JSON.pretty_generate(space.
|
93
|
+
write_file("Space_#{space[:id]}_#{name}.json", base, path) do |f|
|
94
|
+
f.write JSON.pretty_generate(space.reject do |k,v|
|
95
95
|
[:looks, :dashboards].include?(k)
|
96
96
|
end)
|
97
97
|
end
|
98
|
-
space
|
99
|
-
look = query_look(l
|
100
|
-
|
101
|
-
|
98
|
+
space[:looks].each do |l|
|
99
|
+
look = query_look(l[:id]).to_attrs
|
100
|
+
find_vis_config_reference(look) do |vis_config|
|
101
|
+
find_color_palette_reference(vis_config) do |o,default_colors|
|
102
|
+
rewrite_color_palette!(o,default_colors)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
write_file("Look_#{look[:id]}_#{look[:title]}.json", base, path) do |f|
|
106
|
+
f.write JSON.pretty_generate(look)
|
102
107
|
end
|
103
108
|
end
|
104
|
-
space
|
105
|
-
data = query_dashboard(d
|
109
|
+
space[:dashboards].each do |d|
|
110
|
+
data = query_dashboard(d[:id]).to_attrs()
|
106
111
|
data[:dashboard_elements].each_index do |i|
|
107
112
|
element = data[:dashboard_elements][i]
|
108
|
-
|
109
|
-
|
113
|
+
find_vis_config_reference(element) do |vis_config|
|
114
|
+
find_color_palette_reference(vis_config) do |o,default_colors|
|
115
|
+
rewrite_color_palette!(o,default_colors)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
merge_result = merge_query(element[:merge_result_id])&.to_attrs() if element[:merge_result_id]
|
119
|
+
if merge_result
|
110
120
|
merge_result[:source_queries].each_index do |j|
|
111
121
|
source_query = merge_result[:source_queries][j]
|
112
122
|
merge_result[:source_queries][j][:query] = query(source_query[:query_id]).to_attrs()
|
113
123
|
end
|
124
|
+
find_vis_config_reference(merge_result) do |vis_config|
|
125
|
+
find_color_palette_reference(vis_config) do |o,default_colors|
|
126
|
+
rewrite_color_palette!(o,default_colors)
|
127
|
+
end
|
128
|
+
end
|
114
129
|
data[:dashboard_elements][i][:merge_result] = merge_result
|
115
130
|
end
|
116
131
|
end
|
@@ -120,7 +135,7 @@ module Gzr
|
|
120
135
|
end
|
121
136
|
space_children = query_space_children(space_id)
|
122
137
|
space_children.each do |child_space|
|
123
|
-
process_space(child_space
|
138
|
+
process_space(child_space[:id], base, path)
|
124
139
|
end
|
125
140
|
end
|
126
141
|
end
|
@@ -36,6 +36,28 @@ module Gzr
|
|
36
36
|
@options = options
|
37
37
|
end
|
38
38
|
|
39
|
+
def flatten_data(raw_array)
|
40
|
+
rows = raw_array.map do |entry|
|
41
|
+
entry.select do |k,v|
|
42
|
+
!(v.kind_of?(Array) || v.kind_of?(Hash))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
raw_array.map do |entry|
|
46
|
+
entry.select do |k,v|
|
47
|
+
v.kind_of? Array
|
48
|
+
end.each do |section,section_value|
|
49
|
+
section_value.each do |section_entry|
|
50
|
+
h = {}
|
51
|
+
section_entry.each_pair do |k,v|
|
52
|
+
h[:"#{section}.#{k}"] = v
|
53
|
+
end
|
54
|
+
rows.push(h)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
rows
|
59
|
+
end
|
60
|
+
|
39
61
|
def execute(input: $stdin, output: $stdout)
|
40
62
|
say_warning("options: #{@options.inspect}") if @options[:debug]
|
41
63
|
with_session do
|
@@ -45,40 +67,33 @@ module Gzr
|
|
45
67
|
return nil
|
46
68
|
end unless space_ids && space_ids.length > 0
|
47
69
|
|
70
|
+
@options[:fields] = 'dashboards(id,title)' if @filter_spec == 'lookml'
|
71
|
+
f = @options[:fields]
|
72
|
+
|
48
73
|
data = space_ids.map do |space_id|
|
49
|
-
query_space(space_id,
|
74
|
+
query_space(space_id, f).to_attrs
|
50
75
|
end.compact
|
76
|
+
space_ids.each do |space_id|
|
77
|
+
query_space_children(space_id, 'id,name,parent_id').map {|child| child.to_attrs}.each do |child|
|
78
|
+
data.push child
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
51
82
|
|
52
83
|
begin
|
53
84
|
puts "No data returned for spaces #{space_ids.inspect}"
|
54
85
|
return nil
|
55
86
|
end unless data && data.length > 0
|
56
87
|
|
57
|
-
@options[:fields] = 'dashboards(id,title)' if @filter_spec == 'lookml'
|
58
88
|
table_hash = Hash.new
|
59
89
|
fields = field_names(@options[:fields])
|
60
|
-
table_hash[:header] =
|
61
|
-
rows =
|
62
|
-
|
63
|
-
|
64
|
-
if @filter_spec != 'lookml' then
|
65
|
-
rows << [h[:parent_id],h[:id],h[:name], nil, nil, nil, nil]
|
66
|
-
subspaces = query_space_children(h[:id], "id,name,parent_id")
|
67
|
-
rows += subspaces.map do |r|
|
68
|
-
h1 = r.to_attrs
|
69
|
-
[h1[:parent_id], h1[:id], h1[:name], nil, nil, nil, nil]
|
70
|
-
end
|
90
|
+
table_hash[:header] = fields unless @options[:plain]
|
91
|
+
table_hash[:rows] = flatten_data(data).map do |row|
|
92
|
+
fields.collect do |e|
|
93
|
+
row.fetch(e.to_sym,nil)
|
71
94
|
end
|
72
|
-
h[:looks].each do |r|
|
73
|
-
rows << [h[:parent_id],h[:id],h[:name], r[:id], r[:title], nil, nil]
|
74
|
-
end if h[:looks]
|
75
|
-
h[:dashboards].each do |r|
|
76
|
-
rows << [h[:parent_id],h[:id],h[:name], nil, nil, r[:id], r[:title]] unless @filter_spec == 'lookml'
|
77
|
-
rows << [r[:id], r[:title]] if @filter_spec == 'lookml'
|
78
|
-
end if h[:dashboards]
|
79
95
|
end
|
80
|
-
|
81
|
-
table = TTY::Table.new(table_hash) if data[0]
|
96
|
+
table = TTY::Table.new(table_hash)
|
82
97
|
alignments = fields.collect do |k|
|
83
98
|
(k =~ /id\)*$/) ? :right : :left
|
84
99
|
end
|
@@ -139,6 +139,17 @@ module Gzr
|
|
139
139
|
data
|
140
140
|
end
|
141
141
|
|
142
|
+
def get_dashboard_layout(id)
|
143
|
+
begin
|
144
|
+
data = @sdk.dashboard_layout(id)
|
145
|
+
rescue LookerSDK::Error => e
|
146
|
+
say_error "Error getting dashboard_layout(#{id})"
|
147
|
+
say_error e.message
|
148
|
+
raise
|
149
|
+
end
|
150
|
+
data
|
151
|
+
end
|
152
|
+
|
142
153
|
def create_dashboard_layout(dash_layout)
|
143
154
|
begin
|
144
155
|
data = @sdk.create_dashboard_layout(dash_layout)
|
data/lib/gzr/modules/look.rb
CHANGED
@@ -136,34 +136,44 @@ module Gzr
|
|
136
136
|
new_look = source.select do |k,v|
|
137
137
|
(keys_to_keep('update_look') - [:space_id,:folder_id,:user_id,:query_id,:slug]).include? k
|
138
138
|
end
|
139
|
-
new_look[:slug] = source[:slug] if source[:slug] && !slug_used
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
139
|
+
new_look[:slug] = source[:slug] if source[:slug] && !slug_used
|
140
|
+
new_look[:deleted] = false if existing_look[:deleted]
|
141
|
+
new_look[:query_id] = query_id
|
142
|
+
return update_look(existing_look.id,new_look)
|
143
|
+
else
|
144
|
+
new_look = source.select do |k,v|
|
145
|
+
(keys_to_keep('create_look') - [:space_id,:folder_id,:user_id,:query_id,:slug]).include? k
|
146
|
+
end
|
147
|
+
new_look[:slug] = source[:slug] unless slug_used
|
148
|
+
new_look[:query_id] = query_id
|
149
|
+
new_look[:user_id] = user_id
|
150
|
+
new_look[:space_id] = space_id
|
151
|
+
|
152
|
+
find_vis_config_reference(new_look) do |vis_config|
|
153
|
+
find_color_palette_reference(vis_config) do |o,default_colors|
|
154
|
+
update_color_palette!(o,default_colors)
|
146
155
|
end
|
147
|
-
|
148
|
-
|
149
|
-
new_look[:user_id] = user_id
|
150
|
-
new_look[:space_id] = space_id
|
151
|
-
|
152
|
-
return create_look(new_look)
|
156
|
+
end
|
157
|
+
return create_look(new_look)
|
153
158
|
end
|
154
159
|
end
|
155
160
|
|
156
161
|
def create_fetch_query(source_query)
|
157
162
|
new_query = source_query.select do |k,v|
|
158
163
|
(keys_to_keep('create_query') - [:client_id]).include? k
|
159
|
-
end
|
164
|
+
end
|
165
|
+
find_vis_config_reference(new_query) do |vis_config|
|
166
|
+
find_color_palette_reference(vis_config) do |o,default_colors|
|
167
|
+
update_color_palette!(o,default_colors)
|
168
|
+
end
|
169
|
+
end
|
160
170
|
return create_query(new_query)
|
161
171
|
end
|
162
172
|
|
163
173
|
def create_merge_result(merge_result)
|
164
174
|
new_merge_result = merge_result.select do |k,v|
|
165
175
|
(keys_to_keep('create_merge_query') - [:client_id,:source_queries]).include? k
|
166
|
-
end
|
176
|
+
end
|
167
177
|
new_merge_result[:source_queries] = merge_result[:source_queries].map do |query|
|
168
178
|
new_query = {}
|
169
179
|
new_query[:query_id] = create_fetch_query(query[:query]).id
|
@@ -171,6 +181,11 @@ module Gzr
|
|
171
181
|
new_query[:merge_fields] = query[:merge_fields]
|
172
182
|
new_query
|
173
183
|
end
|
184
|
+
find_vis_config_reference(new_merge_result) do |vis_config|
|
185
|
+
find_color_palette_reference(vis_config) do |o,default_colors|
|
186
|
+
update_color_palette!(o,default_colors)
|
187
|
+
end
|
188
|
+
end
|
174
189
|
return create_merge_query(new_merge_result)
|
175
190
|
end
|
176
191
|
end
|
data/lib/gzr/modules/session.rb
CHANGED
@@ -116,15 +116,15 @@ module Gzr
|
|
116
116
|
http.headers[:accept] = 'application/json'
|
117
117
|
http.headers[:user_agent] = conn_hash[:user_agent]
|
118
118
|
end
|
119
|
-
|
120
|
-
begin
|
119
|
+
|
120
|
+
begin
|
121
121
|
versions_response = agent.call(:get,"/versions")
|
122
122
|
versions = versions_response.data.supported_versions
|
123
123
|
current_version = versions_response.data.current_version
|
124
124
|
rescue Faraday::SSLError => e
|
125
125
|
raise Gzr::CLI::Error, "SSL Certificate could not be verified\nDo you need the --no-verify-ssl option or the --no-ssl option?"
|
126
126
|
rescue Faraday::ConnectionFailed => cf
|
127
|
-
raise Gzr::CLI::Error, "Connection Failed.\nDid you specify the --no-ssl option for an ssl secured server
|
127
|
+
raise Gzr::CLI::Error, "Connection Failed.\nDid you specify the --no-ssl option for an ssl secured server?\nYou may need to use --port=443 in some cases as well."
|
128
128
|
rescue LookerSDK::NotFound => nf
|
129
129
|
say_warning "endpoint #{root}/versions was not found"
|
130
130
|
end
|
data/lib/gzr/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gazer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.41
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike DeAngelo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-03
|
11
|
+
date: 2020-06-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tty-reader
|
@@ -357,7 +357,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
357
357
|
- !ruby/object:Gem::Version
|
358
358
|
version: '0'
|
359
359
|
requirements: []
|
360
|
-
rubygems_version: 3.0.
|
360
|
+
rubygems_version: 3.0.8
|
361
361
|
signing_key:
|
362
362
|
specification_version: 4
|
363
363
|
summary: Command line tool to manage the content of a Looker instance.
|