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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b171fe3c480e72780a9b90a0373654e7e9e3dafc2e22e148f229fae80cbacdb
4
- data.tar.gz: 1e46749fc5a805f9a3632ff832bd147530d5da7c651e90aa4b6f6baaceaa39d6
3
+ metadata.gz: 63f0133a6db8baa3e1cbb77432444b11b51a9d3f63746b1e18018b9da52ffba1
4
+ data.tar.gz: b1128abc82113482b0bbc5956f680b4b6e633d26ab9204988e87ce45a83f5cdb
5
5
  SHA512:
6
- metadata.gz: 64ff99189d390dd6d98bdad6339a094c3b2aa0565c498c6af38b0b81ffe595ace06531e9482b580c83c5916e812459fb507901d8906caf0699687e0579c59fa3
7
- data.tar.gz: 6b7cb1b39903606563c13f79ca9c7467c70108840fbe9a00e8a3594ccad4c4506235f434dba054751285ed328b7949a176cbe540cdf68f86eb1b671a9b6a916f
6
+ metadata.gz: 0c94dda1c71d32c8441c7eeba27c230a5ec35e5b96e3b8b3dd897aa1f4c38f685c4edee7961beb8fe67e4e091922d697e55fd36d8f47fd907c1fa0f4f3a92c48
7
+ data.tar.gz: 5e56640ba557897596eec20cf99b5465ec8760dba904bc01d0e82e67af97ce559dcc85f7e5a2b286c0aa3c96bd882d350d04c6cac3b431ab8bc44fc12656b188
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gazer (0.2.36)
4
+ gazer (0.2.41)
5
5
  looker-sdk (~> 0.0.7)
6
6
  netrc (~> 0.11.0)
7
7
  pastel (~> 0.7.2)
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
@@ -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
- if element[:merge_result_id]
50
- merge_result = merge_query(element[:merge_result_id]).to_attrs
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
- existing_filters = dashboard.dashboard_filters.sort { |a,b| a.row <=> b.row }
60
- existing_filters.collect! do |e|
61
- matches_by_name_title = source_filters.select { |s| s[:row] != e.row && (s[:title] == e.title || s[:name] == e.name) }
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
- end
69
- pairs(source_filters,existing_filters,dashboard.id) do |source,target,id|
70
- say_warning("Synching dashboard filter for dashboard #{id}", output: output) if @options[:debug]
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
- elem_table = pairs(data[:dashboard_elements],dashboard.dashboard_elements,dashboard.id) do |source,target,id|
75
- sync_dashboard_element(source,target,id)
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].sort_by { |v| (v[:active] ? 0 : 1) }
79
- existing_dashboard_layouts = dashboard.dashboard_layouts.sort_by { |v| (v.active ? 0 : 1) }
80
- pairs(source_dashboard_layouts,existing_dashboard_layouts) do |s,t|
81
- sync_dashboard_layout(dashboard.id,s,t) do |s,t|
82
- sync_dashboard_layout_component(s,t,elem_table)
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
- return update_dashboard(existing_dashboard.id,new_dash)
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[:scheduled_plans] = query_scheduled_plans_for_look(@look_id,"all") if @options[:plans]
47
- write_file(@options[:dir] ? "Look_#{data.id}_#{data.title}.json" : nil, @options[:dir],nil, output) do |f|
48
- f.puts JSON.pretty_generate(data.to_attrs)
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.name
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.id}_#{name}.json", base, path) do |f|
94
- f.write JSON.pretty_generate(space.to_attrs.reject do |k,v|
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.looks.each do |l|
99
- look = query_look(l.id)
100
- write_file("Look_#{look.id}_#{look.title}.json", base, path) do |f|
101
- f.write JSON.pretty_generate(look.to_attrs)
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.dashboards.each do |d|
105
- data = query_dashboard(d.id).to_attrs()
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
- if element[:merge_result_id]
109
- merge_result = merge_query(element[:merge_result_id]).to_attrs()
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.id, base, path)
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, @options[:fields])
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] = field_names(@options[:fields]) unless @options[:plain]
61
- rows = []
62
- data.each do |r|
63
- h = r.to_attrs
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
- table_hash[:rows] = rows
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)
@@ -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
- 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
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
- 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
- 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
@@ -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
@@ -20,5 +20,5 @@
20
20
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  module Gzr
23
- VERSION = "0.2.36"
23
+ VERSION = "0.2.41"
24
24
  end
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.36
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-04 00:00:00.000000000 Z
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.6
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.