forest_admin_agent 1.0.0.pre.beta.22 → 1.0.0.pre.beta.24

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: b5714273d6e7144f00eb531b7a93d0e908698bd1dac7984dc47affd15a7514f6
4
- data.tar.gz: 3b47af0daae4bc4e02b944f0d21be13aa18fe5e7abb9bfcfa03f2ea3272028bd
3
+ metadata.gz: 5366fcae628c5d313080f3218e187b1b5754b884d7e8cc38c85b905b4268e35e
4
+ data.tar.gz: b4778e1a8f354b96b9ce0be00afae2d3688b0565d73026be0b3c0e89425a7aaf
5
5
  SHA512:
6
- metadata.gz: 93044527fdfb1a06f49408044479258b1cccb6af15c8025cf26310f01c684ae6b5c4657bd25496eb69d911eaa77daae83ec82ec551469bd15cacea61a3b46687
7
- data.tar.gz: f93863c6d28342854e2e453795bca3c3892c6a09c0d91a44fcb42fae57b107c17f6daa3e9694d04e0862bb46e1f95ff2d14f04c199ab0c2a5436434ca5090ca4
6
+ metadata.gz: 1e150b17814b1d3d7bdf2a25cb4b9cfa9b88a80e29593a4307b452b5096d733360f264e4034da11e835c0c1c24534ea1b84feb7c0e4658dfd0f689ff3b9494bc
7
+ data.tar.gz: e626ef0f2022abc05884b5a529d77269c72bc2c8aa45f3e2d6484021fdd590fe6fc0fce8fdba30869a3ca18c434aad4a2ce614222096ad7e4bf4589848b6c191
@@ -34,6 +34,7 @@ admin work on any Ruby application."
34
34
  spec.require_paths = ["lib"]
35
35
 
36
36
  spec.add_dependency "activesupport", ">= 6.1"
37
+ spec.add_dependency "deepsort", "~> 0.4.5"
37
38
  spec.add_dependency "dry-container", "~> 0.11"
38
39
  spec.add_dependency "faraday", "~> 2.7"
39
40
  spec.add_dependency "filecache", "~> 1.0"
@@ -14,26 +14,31 @@ module ForestAdminAgent
14
14
  def setup(options)
15
15
  @options = options
16
16
  @has_env_secret = options.to_h.key?(:env_secret)
17
- @customizer = ForestAdminDatasourceToolkit::Datasource.new
17
+ @customizer = ForestAdminDatasourceCustomizer::DatasourceCustomizer.new
18
18
  build_container
19
19
  build_cache
20
20
  build_logger
21
21
  end
22
22
 
23
- def add_datasource(datasource)
24
- datasource.collections.each_value { |collection| @customizer.add_collection(collection) }
23
+ def add_datasource(datasource, options = {})
24
+ @customizer.add_datasource(datasource, options)
25
+
25
26
  self
26
27
  end
27
28
 
29
+ def customize_collection(name, handle)
30
+ @customizer.customize_collection(name, handle)
31
+ end
32
+
28
33
  def build
29
- @container.register(:datasource, @customizer)
34
+ @container.register(:datasource, @customizer.datasource)
30
35
  send_schema
31
36
  end
32
37
 
33
38
  def send_schema(force: false)
34
39
  return unless @has_env_secret
35
40
 
36
- schema = ForestAdminAgent::Utils::Schema::SchemaEmitter.get_serialized_schema(@customizer)
41
+ schema = ForestAdminAgent::Utils::Schema::SchemaEmitter.get_serialized_schema(@customizer.datasource)
37
42
  schema_is_know = @container.key?(:schema_file_hash) &&
38
43
  @container.resolve(:schema_file_hash).get('value') == schema[:meta][:schemaFileHash]
39
44
 
@@ -63,9 +68,7 @@ module ForestAdminAgent
63
68
  return unless @has_env_secret
64
69
 
65
70
  cache = @container.resolve(:cache)
66
- cache.get_or_set 'config' do
67
- @options.to_h
68
- end
71
+ cache.set('config', @options.to_h)
69
72
  end
70
73
 
71
74
  def build_logger
@@ -9,6 +9,7 @@ module ForestAdminAgent
9
9
  # api_charts_routes,
10
10
  System::HealthCheck.new.routes,
11
11
  Security::Authentication.new.routes,
12
+ Charts::Charts.new.routes,
12
13
  Resources::Count.new.routes,
13
14
  Resources::Delete.new.routes,
14
15
  Resources::List.new.routes,
@@ -14,7 +14,7 @@ module ForestAdminAgent
14
14
  record = args[:params][:data][:attributes]
15
15
 
16
16
  args[:params][:data][:relationships]&.map do |field, value|
17
- schema = @collection.fields[field]
17
+ schema = @collection.schema[:fields][field]
18
18
 
19
19
  record[schema.foreign_key] = value['data'][schema.foreign_key_target] if schema.type == 'ManyToOne'
20
20
  end
@@ -4,8 +4,8 @@ module ForestAdminAgent
4
4
  def build(args = {})
5
5
  super
6
6
 
7
- relation = @collection.fields[args[:params]['relation_name']]
8
- @child_collection = @datasource.collection(relation.foreign_collection)
7
+ relation = @collection.schema[:fields][args[:params]['relation_name']]
8
+ @child_collection = @datasource.get_collection(relation.foreign_collection)
9
9
  end
10
10
  end
11
11
  end
@@ -8,7 +8,7 @@ module ForestAdminAgent
8
8
 
9
9
  def build(args)
10
10
  @datasource = ForestAdminAgent::Facades::Container.datasource
11
- @collection = @datasource.collection(args[:params]['collection_name'])
11
+ @collection = @datasource.get_collection(args[:params]['collection_name'])
12
12
  end
13
13
 
14
14
  def routes
@@ -0,0 +1,214 @@
1
+ require 'jsonapi-serializers'
2
+ require 'active_support/inflector'
3
+
4
+ module ForestAdminAgent
5
+ module Routes
6
+ module Charts
7
+ class Charts < AbstractAuthenticatedRoute
8
+ include ForestAdminAgent::Builder
9
+ include ForestAdminAgent::Utils
10
+ include ForestAdminDatasourceToolkit::Components::Query
11
+ include ForestAdminDatasourceToolkit::Components::Query::ConditionTree
12
+ include ForestAdminDatasourceToolkit::Components::Charts
13
+
14
+ attr_reader :filter
15
+
16
+ FORMAT = {
17
+ Day: '%d/%m/%Y',
18
+ Week: 'W%W-%Y',
19
+ Month: '%b %y',
20
+ Year: '%Y'
21
+ }.freeze
22
+
23
+ def setup_routes
24
+ add_route('forest_chart', 'post', '/stats/:collection_name', lambda { |args|
25
+ handle_request(args)
26
+ })
27
+ self
28
+ end
29
+
30
+ def handle_request(args = {})
31
+ build(args)
32
+ @permissions.can_chart?(args[:params])
33
+ @args = args
34
+ self.type = args[:params][:type]
35
+ @filter = Filter.new(
36
+ condition_tree: ConditionTreeFactory.intersect(
37
+ [
38
+ @permissions.get_scope(@collection),
39
+ ForestAdminAgent::Utils::QueryStringParser.parse_condition_tree(
40
+ @collection, args
41
+ )
42
+ ]
43
+ )
44
+ )
45
+
46
+ inject_context_variables
47
+
48
+ { content: Serializer::ForestChartSerializer.serialize(send(:"make_#{@type}")) }
49
+ end
50
+
51
+ private
52
+
53
+ def type=(type)
54
+ chart_types = %w[Value Objective Pie Line Leaderboard]
55
+ unless chart_types.include?(type)
56
+ raise ForestAdminDatasourceToolkit::Exceptions::ForestException, "Invalid Chart type #{type}"
57
+ end
58
+
59
+ @type = type.downcase
60
+ end
61
+
62
+ def inject_context_variables
63
+ user = @permissions.get_user_data(@caller.id)
64
+ team = @permissions.get_team(@caller.rendering_id)
65
+
66
+ context_variables = ForestAdminAgent::Utils::ContextVariables.new(team, user,
67
+ @args[:params][:contextVariables])
68
+ return unless @args[:params][:filter]
69
+
70
+ @filter = @filter.override(condition_tree: ContextVariablesInjector.inject_context_in_filter(
71
+ @filter.condition_tree, context_variables
72
+ ))
73
+ end
74
+
75
+ def make_value
76
+ value = compute_value(@filter)
77
+ previous_value = nil
78
+ is_and_aggregator = @filter.condition_tree&.try(:aggregator) == 'And'
79
+ with_count_previous = @filter.condition_tree&.some_leaf(&:use_interval_operator)
80
+
81
+ if with_count_previous && !is_and_aggregator
82
+ previous_value = compute_value(FilterFactory.get_previous_period_filter(@filter, @caller.timezone))
83
+ end
84
+
85
+ ValueChart.new(value, previous_value)
86
+ end
87
+
88
+ def make_objective
89
+ ObjectiveChart.new(compute_value(@filter))
90
+ end
91
+
92
+ def make_pie
93
+ group_field = @args[:params][:groupByFieldName]
94
+ aggregation = Aggregation.new(
95
+ operation: @args[:params][:aggregator],
96
+ field: @args[:params][:aggregateFieldName],
97
+ groups: group_field ? [{ field: group_field }] : []
98
+ )
99
+
100
+ result = @collection.aggregate(@caller, @filter, aggregation)
101
+
102
+ PieChart.new(result.map { |row| { key: row[:group][group_field], value: row[:value] } })
103
+ end
104
+
105
+ def make_line
106
+ group_by_field_name = @args[:params][:groupByFieldName]
107
+ time_range = @args[:params][:timeRange]
108
+ filter_only_with_values = @filter.override(
109
+ condition_tree: ConditionTree::ConditionTreeFactory.intersect(
110
+ [
111
+ @filter.condition_tree,
112
+ ConditionTree::Nodes::ConditionTreeLeaf.new(group_by_field_name, ConditionTree::Operators::PRESENT)
113
+ ]
114
+ )
115
+ )
116
+ rows = @collection.aggregate(
117
+ @caller,
118
+ filter_only_with_values,
119
+ Aggregation.new(
120
+ operation: @args[:params][:aggregator],
121
+ field: @args[:params][:aggregateField],
122
+ groups: [{ field: group_by_field_name, operation: time_range }]
123
+ )
124
+ )
125
+
126
+ values = {}
127
+ rows.each { |row| values[row[:group][group_by_field_name]] = row[:value] }
128
+ dates = values.keys.sort
129
+ current = dates[0]
130
+ last = dates.last
131
+ result = []
132
+ while current <= last
133
+ result << {
134
+ label: current.strftime(FORMAT[time_range.to_sym]),
135
+ values: { value: values[current] || 0 }
136
+ }
137
+ current += 1.send(time_range.downcase.pluralize.to_sym)
138
+ end
139
+
140
+ LineChart.new(result)
141
+ end
142
+
143
+ def make_leaderboard
144
+ field = @collection.schema[:fields][@args[:params][:relationshipFieldName]]
145
+
146
+ if field && field.type == 'OneToMany'
147
+ inverse = ForestAdminDatasourceToolkit::Utils::Collection.get_inverse_relation(
148
+ @collection,
149
+ @args[:params][:relationshipFieldName]
150
+ )
151
+ if inverse
152
+ collection = field.foreign_collection
153
+ filter = @filter.nest(inverse)
154
+ aggregation = Aggregation.new(
155
+ operation: @args[:params][:aggregator],
156
+ field: @args[:params][:aggregateFieldName],
157
+ groups: [{ field: "#{inverse}:#{@args[:params][:labelFieldName]}" }]
158
+ )
159
+ end
160
+ end
161
+
162
+ if field && field.type == 'ManyToMany'
163
+ origin = ForestAdminDatasourceToolkit::Utils::Collection.get_through_origin(
164
+ @collection,
165
+ @args[:params][:relationshipFieldName]
166
+ )
167
+ target = ForestAdminDatasourceToolkit::Utils::Collection.get_through_target(
168
+ @collection,
169
+ @args[:params][:relationshipFieldName]
170
+ )
171
+ if origin && target
172
+ collection = field.through_collection
173
+ filter = @filter.nest(origin)
174
+ aggregation = Aggregation.new(
175
+ operation: @args[:params][:aggregator],
176
+ field: @args[:params][:aggregateFieldName] ? "#{target}:#{@args[:params][:aggregateFieldName]}" : nil,
177
+ groups: [{ field: "#{origin}:#{@args[:params][:labelFieldName]}" }]
178
+ )
179
+ end
180
+ end
181
+
182
+ if collection && filter && aggregation
183
+ rows = @datasource.get_collection(collection).aggregate(
184
+ @caller,
185
+ filter,
186
+ aggregation,
187
+ @args[:params][:limit]
188
+ )
189
+
190
+ result = rows.map do |row|
191
+ {
192
+ key: row[:group][aggregation.groups[0][:field]],
193
+ value: row[:value]
194
+ }
195
+ end
196
+
197
+ return LeaderboardChart.new(result)
198
+ end
199
+
200
+ raise ForestAdminDatasourceToolkit::Exceptions::ForestException,
201
+ 'Failed to generate leaderboard chart: parameters do not match pre-requisites'
202
+ end
203
+
204
+ def compute_value(filter)
205
+ aggregation = Aggregation.new(operation: @args[:params][:aggregator],
206
+ field: @args[:params][:aggregateFieldName])
207
+ result = @collection.aggregate(@caller, filter, aggregation)
208
+
209
+ result[0][:value] || 0
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
@@ -26,7 +26,7 @@ module ForestAdminAgent
26
26
  return {
27
27
  name: args[:params]['collection_name'],
28
28
  content: {
29
- count: result[0][:value]
29
+ count: result.empty? ? 0 : result[0][:value]
30
30
  }
31
31
  }
32
32
  end
@@ -62,7 +62,7 @@ module ForestAdminAgent
62
62
  origin_value = Collection.get_value(@collection, @caller, parent_id, id)
63
63
  record = { relation.origin_key => origin_value, relation.foreign_key => foreign_value }
64
64
 
65
- through_collection = @datasource.collection(relation.through_collection)
65
+ through_collection = @datasource.get_collection(relation.through_collection)
66
66
  through_collection.create(@caller, record)
67
67
  end
68
68
  end
@@ -52,7 +52,7 @@ module ForestAdminAgent
52
52
  end
53
53
 
54
54
  def dissociate_or_delete_many_to_many(relation, relation_name, parent_id, is_delete_mode, filter)
55
- through_collection = @datasource.collection(relation.through_collection)
55
+ through_collection = @datasource.get_collection(relation.through_collection)
56
56
 
57
57
  if is_delete_mode
58
58
  # Generate filters _BEFORE_ deleting stuff, otherwise things break.
@@ -23,7 +23,7 @@ module ForestAdminAgent
23
23
  build(args)
24
24
  @permissions.can?(:edit, @collection)
25
25
 
26
- relation = @collection.fields[args[:params]['relation_name']]
26
+ relation = @collection.schema[:fields][args[:params]['relation_name']]
27
27
  parent_id = Utils::Id.unpack_id(@collection, args[:params]['id'])
28
28
 
29
29
  linked_id = if (id = args.dig(:params, :data, :id))
@@ -32,18 +32,18 @@ module ForestAdminAgent
32
32
 
33
33
  def link_one_to_one_relations(args, record)
34
34
  args[:params][:data][:relationships]&.map do |field, value|
35
- schema = @collection.fields[field]
36
- if schema.type == 'OneToOne'
37
- id = Utils::Id.unpack_id(@collection, value['data']['id'], with_key: true)
38
- foreign_collection = @datasource.collection(schema.foreign_collection)
39
- # Load the value that will be used as origin_key
40
- origin_value = record[schema.origin_key_target]
35
+ schema = @collection.schema[:fields][field]
36
+ next unless schema.type == 'OneToOne'
41
37
 
42
- # update new relation (may update zero or one records).
43
- condition_tree = ConditionTree::ConditionTreeFactory.match_records(foreign_collection, [id])
44
- filter = Filter.new(condition_tree: condition_tree)
45
- foreign_collection.update(@caller, filter, { schema.origin_key => origin_value })
46
- end
38
+ id = Utils::Id.unpack_id(@collection, value['data']['id'], with_key: true)
39
+ foreign_collection = @datasource.get_collection(schema.foreign_collection)
40
+ # Load the value that will be used as origin_key
41
+ origin_value = record[schema.origin_key_target]
42
+
43
+ # update new relation (may update zero or one records).
44
+ condition_tree = ConditionTree::ConditionTreeFactory.match_records(foreign_collection, [id])
45
+ filter = Filter.new(condition_tree: condition_tree)
46
+ foreign_collection.update(@caller, filter, { schema.origin_key => origin_value })
47
47
  end
48
48
  end
49
49
  end
@@ -0,0 +1,19 @@
1
+ require 'securerandom'
2
+
3
+ module ForestAdminAgent
4
+ module Serializer
5
+ class ForestChartSerializer
6
+ def self.serialize(chart)
7
+ {
8
+ data: {
9
+ id: SecureRandom.uuid,
10
+ type: 'stats',
11
+ attributes: {
12
+ value: chart.serialize
13
+ }
14
+ }
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -41,8 +41,8 @@ module ForestAdminAgent
41
41
  end
42
42
 
43
43
  def attributes
44
- forest_collection = ForestAdminAgent::Facades::Container.datasource.collection(object.class.name.demodulize.underscore)
45
- fields = forest_collection.fields.select { |_field_name, field| field.type == 'Column' }
44
+ forest_collection = ForestAdminAgent::Facades::Container.datasource.get_collection(object.class.name.demodulize.underscore)
45
+ fields = forest_collection.schema[:fields].select { |_field_name, field| field.type == 'Column' }
46
46
  fields.each { |field_name, _field| add_attribute(field_name) }
47
47
  return {} if attributes_map.nil?
48
48
  attributes = {}
@@ -104,9 +104,9 @@ module ForestAdminAgent
104
104
  end
105
105
 
106
106
  def relationships
107
- forest_collection = ForestAdminAgent::Facades::Container.datasource.collection(object.class.name.demodulize.underscore)
108
- relations_to_many = forest_collection.fields.select { |_field_name, field| field.type == 'OneToMany' || field.type == 'ManyToMany' }
109
- relations_to_one = forest_collection.fields.select { |_field_name, field| field.type == 'OneToOne' || field.type == 'ManyToOne' }
107
+ forest_collection = ForestAdminAgent::Facades::Container.datasource.get_collection(object.class.name.demodulize.underscore)
108
+ relations_to_many = forest_collection.schema[:fields].select { |_field_name, field| field.type == 'OneToMany' || field.type == 'ManyToMany' }
109
+ relations_to_one = forest_collection.schema[:fields].select { |_field_name, field| field.type == 'OneToOne' || field.type == 'ManyToOne' }
110
110
 
111
111
  relations_to_one.each { |field_name, _field| add_to_one_association(field_name) }
112
112
 
@@ -1,4 +1,5 @@
1
1
  require 'filecache'
2
+ require 'deepsort'
2
3
 
3
4
  module ForestAdminAgent
4
5
  module Services
@@ -56,7 +57,7 @@ module ForestAdminAgent
56
57
  end
57
58
 
58
59
  def can_chart?(parameters)
59
- attributes = sanitize_chart_parameters(parameters)
60
+ attributes = sanitize_chart_parameters(parameters.deep_symbolize_keys)
60
61
  hash_request = "#{attributes[:type]}:#{array_hash(attributes)}"
61
62
  is_allowed = get_chart_data(caller.rendering_id).include?(hash_request)
62
63
 
@@ -99,8 +100,6 @@ module ForestAdminAgent
99
100
  def get_scope(collection)
100
101
  permissions = get_scope_and_team_data(caller.rendering_id)
101
102
  scope = permissions[:scopes][collection.name.to_sym]
102
- team = permissions[:team]
103
- user = get_user_data(caller.id)
104
103
 
105
104
  return nil if scope.nil?
106
105
 
@@ -170,16 +169,21 @@ module ForestAdminAgent
170
169
  end
171
170
 
172
171
  def sanitize_chart_parameters(parameters)
173
- # parameters = parameters.to_h
174
172
  parameters.delete(:timezone)
175
173
  parameters.delete(:collection)
176
174
  parameters.delete(:contextVariables)
175
+ # rails
176
+ parameters.delete(:route_alias)
177
+ parameters.delete(:controller)
178
+ parameters.delete(:action)
179
+ parameters.delete(:collection_name)
180
+ parameters.delete(:forest)
177
181
 
178
182
  parameters.select { |_, value| !value.nil? && value != '' }
179
183
  end
180
184
 
181
185
  def array_hash(data)
182
- Digest::SHA1.hexdigest(data.sort.to_h.to_s)
186
+ Digest::SHA1.hexdigest(data.deep_sort.to_h.to_s)
183
187
  end
184
188
 
185
189
  def get_scope_and_team_data(rendering_id)
@@ -197,7 +201,7 @@ module ForestAdminAgent
197
201
  def permission_system?
198
202
  cache.get_or_set('forest.has_permission') do
199
203
  response = fetch('/liana/v4/permissions/environment')
200
- { enable: !response.nil? }
204
+ { enable: response != true }
201
205
  end[:enable]
202
206
  end
203
207
 
@@ -11,7 +11,7 @@ module ForestAdminAgent
11
11
  end
12
12
 
13
13
  result = primary_keys.map.with_index do |pk_name, index|
14
- field = collection.fields[pk_name]
14
+ field = collection.schema[:fields][pk_name]
15
15
  value = primary_key_values[index]
16
16
  casted_value = field.column_type == 'Number' ? value.to_i : value
17
17
  # TODO: call FieldValidator::validateValue($value, $field, $castedValue);
@@ -1,4 +1,5 @@
1
1
  require 'jwt'
2
+ require 'active_support'
2
3
  require 'active_support/time'
3
4
 
4
5
  module ForestAdminAgent
@@ -56,7 +57,7 @@ module ForestAdminAgent
56
57
  return ProjectionFactory.all(collection) unless fields != '' && !fields.nil?
57
58
 
58
59
  fields = fields.split(',').map do |field_name|
59
- column = collection.fields[field_name.strip]
60
+ column = collection.schema[:fields][field_name.strip]
60
61
  column.type == 'Column' ? field_name.strip : "#{field_name.strip}:#{args[:params][:fields][field_name.strip]}"
61
62
  end
62
63
 
@@ -10,7 +10,7 @@ module ForestAdminAgent
10
10
  fields: build_fields(collection),
11
11
  icon: nil,
12
12
  integration: nil,
13
- isReadOnly: collection.fields.all? { |_k, field| field.type != 'Column' || field.is_read_only },
13
+ isReadOnly: collection.schema[:fields].all? { |_k, field| field.type != 'Column' || field.is_read_only },
14
14
  isSearchable: true,
15
15
  isVirtual: false,
16
16
  name: collection.name,
@@ -21,7 +21,7 @@ module ForestAdminAgent
21
21
  end
22
22
 
23
23
  def self.build_fields(collection)
24
- fields = collection.fields.select do |name, _field|
24
+ fields = collection.schema[:fields].select do |name, _field|
25
25
  !ForestAdminDatasourceToolkit::Utils::Schema.foreign_key?(collection, name) ||
26
26
  ForestAdminDatasourceToolkit::Utils::Schema.primary_key?(collection, name)
27
27
  end
@@ -10,7 +10,7 @@ module ForestAdminAgent
10
10
  }.freeze
11
11
 
12
12
  def self.build_schema(collection, name)
13
- type = collection.fields[name].type
13
+ type = collection.schema[:fields][name].type
14
14
 
15
15
  case type
16
16
  when 'Column'
@@ -26,7 +26,7 @@ module ForestAdminAgent
26
26
  private
27
27
 
28
28
  def build_column_schema(collection, name)
29
- column = collection.fields[name]
29
+ column = collection.schema[:fields][name]
30
30
  is_foreign_key = ForestAdminDatasourceToolkit::Utils::Schema.foreign_key?(collection, name)
31
31
 
32
32
  {
@@ -74,10 +74,10 @@ module ForestAdminAgent
74
74
 
75
75
  def build_many_to_many_schema(relation, collection, foreign_collection, base_schema)
76
76
  target_name = relation.foreign_key_target
77
- target_field = foreign_collection.fields[target_name]
78
- through_schema = collection.datasource.collection(relation.through_collection)
79
- foreign_schema = through_schema.fields[relation.foreign_key]
80
- origin_key = through_schema.fields[relation.origin_key]
77
+ target_field = foreign_collection.schema[:fields][target_name]
78
+ through_schema = collection.datasource.get_collection(relation.through_collection)
79
+ foreign_schema = through_schema.schema[:fields][relation.foreign_key]
80
+ origin_key = through_schema.schema[:fields][relation.origin_key]
81
81
 
82
82
  base_schema.merge(
83
83
  {
@@ -96,8 +96,8 @@ module ForestAdminAgent
96
96
 
97
97
  def build_one_to_many_schema(relation, collection, foreign_collection, base_schema)
98
98
  target_name = relation.origin_key_target
99
- target_field = collection.fields[target_name]
100
- origin_key = foreign_collection.fields[relation.origin_key]
99
+ target_field = collection.schema[:fields][target_name]
100
+ origin_key = foreign_collection.schema[:fields][relation.origin_key]
101
101
 
102
102
  base_schema.merge(
103
103
  {
@@ -115,8 +115,8 @@ module ForestAdminAgent
115
115
  end
116
116
 
117
117
  def build_one_to_one_schema(relation, collection, foreign_collection, base_schema)
118
- target_field = collection.fields[relation.origin_key_target]
119
- key_field = foreign_collection.fields[relation.origin_key]
118
+ target_field = collection.schema[:fields][relation.origin_key_target]
119
+ key_field = foreign_collection.schema[:fields][relation.origin_key]
120
120
 
121
121
  base_schema.merge(
122
122
  {
@@ -134,7 +134,7 @@ module ForestAdminAgent
134
134
  end
135
135
 
136
136
  def build_many_to_one_schema(relation, collection, foreign_collection, base_schema)
137
- key_field = collection.fields[relation.foreign_key]
137
+ key_field = collection.schema[:fields][relation.foreign_key]
138
138
 
139
139
  base_schema.merge(
140
140
  {
@@ -152,8 +152,8 @@ module ForestAdminAgent
152
152
  end
153
153
 
154
154
  def build_relation_schema(collection, name)
155
- relation = collection.fields[name]
156
- foreign_collection = collection.datasource.collection(relation.foreign_collection)
155
+ relation = collection.schema[:fields][name]
156
+ foreign_collection = collection.datasource.get_collection(relation.foreign_collection)
157
157
 
158
158
  relation_schema = {
159
159
  field: name,
@@ -7,7 +7,7 @@ module ForestAdminAgent
7
7
  class SchemaEmitter
8
8
  LIANA_NAME = "forest-rails"
9
9
 
10
- LIANA_VERSION = "1.0.0-beta.22"
10
+ LIANA_VERSION = "1.0.0-beta.24"
11
11
 
12
12
  def self.get_serialized_schema(datasource)
13
13
  schema_path = Facades::Container.cache(:schema_path)
@@ -1,3 +1,3 @@
1
1
  module ForestAdminAgent
2
- VERSION = "1.0.0-beta.22"
2
+ VERSION = "1.0.0-beta.24"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forest_admin_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.beta.22
4
+ version: 1.0.0.pre.beta.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthieu
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-12-08 00:00:00.000000000 Z
12
+ date: 2023-12-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -25,6 +25,20 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '6.1'
28
+ - !ruby/object:Gem::Dependency
29
+ name: deepsort
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 0.4.5
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 0.4.5
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: dry-container
30
44
  requirement: !ruby/object:Gem::Requirement
@@ -204,7 +218,6 @@ extensions: []
204
218
  extra_rdoc_files: []
205
219
  files:
206
220
  - ".rspec"
207
- - CHANGELOG.md
208
221
  - README.md
209
222
  - Rakefile
210
223
  - forest_admin
@@ -229,6 +242,7 @@ files:
229
242
  - lib/forest_admin_agent/routes/abstract_authenticated_route.rb
230
243
  - lib/forest_admin_agent/routes/abstract_related_route.rb
231
244
  - lib/forest_admin_agent/routes/abstract_route.rb
245
+ - lib/forest_admin_agent/routes/charts/charts.rb
232
246
  - lib/forest_admin_agent/routes/resources/count.rb
233
247
  - lib/forest_admin_agent/routes/resources/delete.rb
234
248
  - lib/forest_admin_agent/routes/resources/list.rb
@@ -242,6 +256,7 @@ files:
242
256
  - lib/forest_admin_agent/routes/resources/update.rb
243
257
  - lib/forest_admin_agent/routes/security/authentication.rb
244
258
  - lib/forest_admin_agent/routes/system/health_check.rb
259
+ - lib/forest_admin_agent/serializer/forest_chart_serializer.rb
245
260
  - lib/forest_admin_agent/serializer/forest_serializer.rb
246
261
  - lib/forest_admin_agent/serializer/forest_serializer_override.rb
247
262
  - lib/forest_admin_agent/services/ip_whitelist.rb
data/CHANGELOG.md DELETED
@@ -1,5 +0,0 @@
1
- ## [Unreleased]
2
-
3
- ## [0.1.0] - 2023-08-28
4
-
5
- - Initial release