gazer 0.2.36 → 0.2.41

Sign up to get free protection for your applications and to get access to all the features.
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.