klastera 1.3 → 1.3.1

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: 999d5c067d080b90f56c82a36cbeb286e08000bf09af922845bdd67df023d16c
4
- data.tar.gz: e4e105b33d55b228cc4d515e0167586b7b962218860d78593a29f6a71b436712
3
+ metadata.gz: a8ffbcdd772da4880e6fac3a2fa9165754a873673afb5f2108161d099e634622
4
+ data.tar.gz: 8541bb3c9c26b8e0084e42b91ef9262b443dbaf1250e4bd209a2fde9db6d92a9
5
5
  SHA512:
6
- metadata.gz: 6902637aaf11219cff0b3ed2f9dcdf1f86c74d2e6c43211d683c559177da39498220d5fca6b987418b936a89c6b08dde5d49a0014d0b86d1fe3c258612912f92
7
- data.tar.gz: 1ec8aad0c6793c426c01969bcdb9f04deed692b06499b0726ee047f13932fda3fe5046067432604947cf85e68662269569d61c482971b8855595a92dc87d1d29
6
+ metadata.gz: e43f85ef19e054e32274ad4c5c99db112333c76fa831383e72f3e0f7d7ad312d5b48519c33794a46ad3148dd4d50cca62117620e756b12933f0889a9891ad631
7
+ data.tar.gz: dc98ab10fc1588bec841af4b1e3a4caee5b976986e8023b7528c70190ee2b27fb2e230855773aaa1fcf1a28392380b9f63d186b9165e4f5704acf2631cd3d40f
@@ -8,4 +8,39 @@
8
8
  background: none;
9
9
  }
10
10
  }
11
- }
11
+ }
12
+
13
+ #cluster-remote-table {
14
+ .cluster-id { width: 70px; }
15
+ .cluster-order { width: 70px; }
16
+ .cluster-color { width: 70px; }
17
+ .odd .colorless { color: #F9F9F9 }
18
+ .even .colorless { color: #FFF }
19
+ tr:hover .colorless { color: #444; opacity: 0.2;}
20
+ }
21
+
22
+ #cluster-remote-form {
23
+ h4.blank-modal-title {
24
+ margin: 0;
25
+ line-height: 28px;
26
+ letter-spacing: 0.05rem;
27
+ font-size: 21px;
28
+ font-weight: 400;
29
+ color: #666;
30
+ }
31
+ }
32
+
33
+
34
+ ul.klastera-option-help {
35
+ padding-left: 20px;
36
+ list-style-type: disc;
37
+ }
38
+
39
+ ul.klastera-option-help li {
40
+ margin-bottom: 10px;
41
+ padding-bottom: 5px;
42
+ border-bottom: 1px solid #DDD;
43
+ }
44
+
45
+ ul.klastera-option-help li b { color: #8A8A8A; font-weight: 400; }
46
+ ul.klastera-option-help li b:first-child { color: #2E5F9B; font-weight: bold; }
@@ -33,13 +33,11 @@ module Klastera
33
33
 
34
34
  def destroy
35
35
  new_cluster_id = params.require(:transfer).permit(:new_cluster_id).values.first rescue nil
36
- @transfer = Transfer.new(
37
- current_cluster: @cluster,
38
- new_cluster_id: new_cluster_id
39
- )
36
+ @transfer = Transfer.new( current_cluster: @cluster, new_cluster_id: new_cluster_id )
40
37
  if @transfer.valid?
41
- @transfer.to!(::Cluster.related_entities.map{|re|re.constantize})
42
- @cluster.destroy
38
+ if @transfer.apply!
39
+ @cluster.destroy
40
+ end
43
41
  set_clusters
44
42
  end
45
43
  end
@@ -12,6 +12,7 @@ module Klastera::Concerns::Cluster
12
12
 
13
13
  belongs_to :organization, class_name: Klastera.organization_class
14
14
  has_many :cluster_users
15
+ has_many :cluster_entities, dependent: :destroy
15
16
 
16
17
  scope :of, -> (organization,except_ids=[]) {
17
18
  _scope = where(organization: organization)
@@ -42,7 +43,7 @@ module Klastera::Concerns::Cluster
42
43
  end
43
44
 
44
45
  def has_related_entities_using_it?
45
- ::Cluster.total_records_assign_to(self) > 0
46
+ self.cluster_entities.size > 0
46
47
  end
47
48
 
48
49
  def can_transfer_and_destroy?
@@ -60,24 +61,5 @@ module Klastera::Concerns::Cluster
60
61
  end
61
62
 
62
63
  module ClassMethods
63
- def related_entities(attr_needed: :class_name, macro: :has_many)
64
- ::Cluster.reflections.map do |association_name, reflection|
65
- reflection.send(attr_needed) if reflection.macro == macro
66
- end.compact
67
- end
68
-
69
- def total_records_assign_to(cluster_instance)
70
- related_entities(attr_needed: :name).inject(0) do |total, association_name|
71
- entity = cluster_instance.send(association_name)
72
- if entity.respond_to?(:cluster_id)
73
- total+=entity.where(cluster_id: cluster_instance.id).count
74
- end
75
- total
76
- end
77
- end
78
-
79
- def modes_as_strings
80
- ::Cluster::MODES.map{|m|m.to_s}
81
- end
82
64
  end
83
65
  end
@@ -4,7 +4,7 @@ module Klastera::Concerns::Organization
4
4
 
5
5
  has_many :clusters
6
6
 
7
- validates :use_cluster_as, inclusion: { in: ::Cluster.modes_as_strings , message: I18n.t('klastera.clusters.wrong_option') }, if: proc{ use_cluster_as.present? }
7
+ validates :use_cluster_as, inclusion: { in: ::Cluster::MODES.map{|m|m.to_s}, message: I18n.t('klastera.clusters.wrong_option') }, if: proc{ use_cluster_as.present? }
8
8
 
9
9
  # Return a symbol version of use_cluster_as value
10
10
  def cluster_mode
@@ -7,20 +7,14 @@ module Klastera::Concerns::Transfer
7
7
  include ActiveModel::Model
8
8
  include ActiveModel::Validations::Callbacks
9
9
 
10
- attr_accessor :current_cluster, :new_cluster_id, :entities_transfered
10
+ attr_accessor :current_cluster, :new_cluster_id
11
11
 
12
12
  validates :current_cluster, presence: true
13
13
  validates :new_cluster_id, presence: true, if: proc { self.required_transfer? }
14
14
 
15
15
  validate do
16
16
  new_cluster = ::Cluster.find(self.new_cluster_id.to_i) rescue nil
17
- #
18
- # In my time, to_a? didnt work
19
- # current_cluster.class returned:
20
- # Cluster(id: integer, name: string, nid: text, organization_id: integer, created_at: datetime, updated_at: datetime, color: string)
21
- #
22
- # If you see this, please fixe it. Thanks
23
- #
17
+
24
18
  if current_cluster.class.name != 'Cluster' || current_cluster.try(:is_the_last_record_in_required_suborganization_mode?)
25
19
  errors.add(:current_cluster, I18n.t('klastera.messages.current_cluster.cant_transfer'))
26
20
  elsif self.required_transfer? && new_cluster_id.present? && new_cluster.nil?
@@ -33,22 +27,19 @@ module Klastera::Concerns::Transfer
33
27
  end
34
28
  end
35
29
 
36
- ##
37
- #
38
- #
39
- def to!(related_entities)
40
- self.entities_transfered = 0
41
- related_entities.each do |entity|
42
- if entity.is_a?(Class) && entity.respond_to?(:cluster_id)
43
- self.entities_transfered += entity.where(
44
- cluster_id: self.current_cluster.id
45
- ).update_all(cluster_id: self.new_cluster_id)
46
- end
47
- end
48
- end
49
-
50
30
  def required_transfer?
51
31
  self.current_cluster.required_transfer? && self.current_cluster.has_related_entities_using_it?
52
32
  end
33
+
34
+ ##
35
+ # A returned boolean is expected. It should always be true even nothing is
36
+ # transfered, and it only will return false if creation fails.
37
+ #
38
+ def apply!
39
+ Klastera::ClusterEntity.create(current_cluster.cluster_entities.map{ |relation|
40
+ next if self.new_cluster_id.blank?
41
+ { cluster_id: self.new_cluster_id, entity_id: relation.entity_id, entity_type: relation.entity_type }
42
+ }.compact)
43
+ end
53
44
  end
54
45
  end
@@ -3,16 +3,16 @@
3
3
 
4
4
  <div class="<%=classes_for_remote_modal_body()%>">
5
5
  <div class="row">
6
- <div class="col-xs-12">
6
+ <div class="col-xs-6">
7
7
  <%= f.input :name, as: :string, label: t('klastera.cluster_name') %>
8
8
  </div>
9
- <div class="col-xs-12">
9
+ <div class="col-xs-6">
10
10
  <%= f.input :nid, as: :string, label: t('klastera.cluster_nid') %>
11
11
  </div>
12
- <div class="col-xs-12">
12
+ <div class="col-xs-6">
13
13
  <%= f.input :color, as: :string, label: t('klastera.cluster_color'), input_html: { class: 'color-picker'} %>
14
14
  </div>
15
- <div class="col-xs-12">
15
+ <div class="col-xs-6">
16
16
  <%= f.input :order, as: :string, label: t('klastera.cluster_order') %>
17
17
  </div>
18
18
  </div>
@@ -2,8 +2,8 @@
2
2
  <%= simple_form_for( @transfer, url: cluster_path(@cluster), method: :delete, remote: true, html: { autocomplete: :off, class: 'destroy-form slim-form-field' } ) do |f| %>
3
3
  <%=render 'layouts/remote_form/header', o: @cluster, title: title, fa: :qrcode %>
4
4
  <div class="<%=classes_for_remote_modal_body()%>">
5
- <h4 class="text-center">Esta acción es irreversible.<br/>¿Está seguro?</h4>
6
- <% if ::Cluster.total_records_assign_to(@cluster) > 0 %>
5
+ <h4 class="blank-modal-title text-center">Esta acción es irreversible<br/>¿Está seguro?</h4>
6
+ <% if @cluster.cluster_entities.size > 0 %>
7
7
  <br />
8
8
  <div class="row">
9
9
  <% if can_transfer_and_destroy %>
@@ -1,4 +1,4 @@
1
- <table class="table table-striped table-hover table-condensed table-bordered datatable">
1
+ <table class="table table-striped table-hover table-condensed table-bordered datatable table">
2
2
  <thead>
3
3
  <tr>
4
4
  <th class="text-center cluster-id"><%=t('klastera.cluster_id')%></th>
@@ -6,7 +6,7 @@
6
6
  <th class="text-center cluster-color"><%=t('klastera.cluster_color')%></th>
7
7
  <th class="text-center cluster-name"><%=t('klastera.cluster_name')%></th>
8
8
  <th class="text-center cluster-nid"><%=t('klastera.cluster_nid')%></th>
9
- <th class="cogs-actions four-icons"><span class="fa fa-cogs"></span></th>
9
+ <th class="cogs-actions two-icons"><span class="fa fa-cogs"></span></th>
10
10
  </tr>
11
11
  </thead>
12
12
  <tbody>
@@ -19,7 +19,7 @@
19
19
  </td>
20
20
  <td class="text-center cluster-name"><%= cluster.name %></td>
21
21
  <td class="text-center cluster-nid"><%= cluster.nid %></td>
22
- <td class="cogs-actions four-icons">
22
+ <td class="cogs-actions two-icons">
23
23
  <%= link_to edit_cluster_path(cluster), class:'btn btn-primary btn-xs', title: t('shared.actions.edit'), "data-toggle": "modal", "data-target": "#remote-modal-block" do %>
24
24
  <span class="fa fa-pencil-square-o"></span>
25
25
  <% end %>
@@ -30,12 +30,4 @@
30
30
  </tr>
31
31
  <% end %>
32
32
  </tbody>
33
- </table>
34
- <style type="text/css">
35
- .cluster-id { width: 70px; }
36
- .cluster-order { width: 70px; }
37
- .cluster-color { width: 70px; }
38
- .odd .colorless { color: #F9F9F9 }
39
- .even .colorless { color: #FFF }
40
- tr:hover .colorless { color: #F5F5F5 }
41
- </style>
33
+ </table>
@@ -18,4 +18,4 @@
18
18
 
19
19
  </div>
20
20
 
21
- <%= render 'layouts/remote_form/modal'%>
21
+ <%= render 'layouts/remote_form/modal', width: 'md' %>
@@ -19,20 +19,4 @@
19
19
  <script type="text/javascript">
20
20
  var popoverTemplate = '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
21
21
  $('.klastera-cluster-option').popover({ template: popoverTemplate, html: true, trigger: 'click', });
22
- </script>
23
-
24
- <style type="text/css">
25
- ul.klastera-option-help {
26
- padding-left: 20px;
27
- list-style-type: disc;
28
- }
29
-
30
- ul.klastera-option-help li {
31
- margin-bottom: 10px;
32
- padding-bottom: 5px;
33
- border-bottom: 1px solid #DDD;
34
- }
35
-
36
- ul.klastera-option-help li b { color: #8A8A8A; font-weight: 400; }
37
- ul.klastera-option-help li b:first-child { color: #2E5F9B; font-weight: bold; }
38
- </style>
22
+ </script>
@@ -8,7 +8,7 @@ module Klastera
8
8
  UNCLUSTERED_ENTITY = 'without_cluster'
9
9
  KLSTR_HELPERS = %i[
10
10
  cluster_user cluster_organization user_has_more_than_one_cluster cluster_scope cluster_of_my_own
11
- user_clusters_string_list set_collection_before_group_by_entity
11
+ user_clusters_string_list set_collection_before_group_by_entity __cluster_scope
12
12
  ]
13
13
 
14
14
  class << self
@@ -50,7 +50,7 @@ module Klastera
50
50
  if model_relations.include?(entity_params[0])
51
51
  entity_params << "#{entity_params[0]}_id".to_sym
52
52
  if entity_params[0] == 'cluster'
53
- entity_params << :unclustered if organization.is_in_cluster_mode?
53
+ entity_params << I18n.t("klastera.#{UNCLUSTERED_ENTITY}") if organization.is_in_cluster_mode?
54
54
  active_record_collection = Klastera.filter_clusterized!(
55
55
  active_record_collection,
56
56
  entity_params[2],
@@ -113,6 +113,44 @@ module Klastera
113
113
  scope_klass
114
114
  end
115
115
 
116
+
117
+ # Untested version for more optimized queries
118
+ #
119
+ def __cluster_scope!(scope,user,organization,cluster_id=nil,same_scope:false)
120
+ scope_klass = scope_class(scope)
121
+ if organization.is_in_cluster_mode?
122
+ scope_klass = scope_klass.includes(:organization)
123
+
124
+ if cluster_id.present?
125
+ cluster_ids = cluster_id.is_a?(Array) ? cluster_id : [cluster_id]
126
+ else
127
+ clusters = cluster_of!(user,organization)
128
+ cluster_ids = clusters.map(&:id).compact
129
+ end
130
+
131
+ scope_klass = scope_klass.select("DISTINCT ON (#{scope.table_name}.id) #{scope.table_name}.id, #{scope.table_name}.*, clusters.*")
132
+
133
+ if organization.required_suborganization_mode?
134
+ scope_klass = scope_klass.includes(cluster_entities: :cluster).where( cluster_entities: { cluster_id: cluster_ids } )
135
+ else
136
+ or_these_cluster_ids = cluster_ids.present? ? " OR cluster_entities.cluster_id IN (#{cluster_ids.join(",")})" : ""
137
+ scope_klass = scope_klass.joins("
138
+ LEFT OUTER JOIN cluster_entities
139
+ ON entity_id = #{scope.table_name}.id
140
+ AND entity_type = '#{scope}'
141
+ ").joins("
142
+ LEFT OUTER JOIN clusters
143
+ ON clusters.id = cluster_entities.cluster_id
144
+ ").where("cluster_entities.id IS NULL#{or_these_cluster_ids}")
145
+ end
146
+ # Provisional fix to avoid unresolved SQL clashes with the main application due to DISTINCT ON clause
147
+ unless same_scope
148
+ scope_klass = scope_class(scope).eager_load(:cluster_entities).where(id: scope_klass.map(&:id))
149
+ end
150
+ end
151
+ scope_klass.where(organization_id: organization)
152
+ end
153
+
116
154
  ##
117
155
  # TODO:
118
156
  # Implement a validation to ensure that
@@ -207,6 +245,10 @@ module Klastera
207
245
  Klastera.cluster_scope!(scope, cluster_user, cluster_organization, cluster_id)
208
246
  end
209
247
 
248
+ def __cluster_scope(scope,cluster_id=nil,same_scope:false)
249
+ Klastera.__cluster_scope!(scope, cluster_user, cluster_organization, cluster_id, same_scope: same_scope)
250
+ end
251
+
210
252
  def cluster_of_my_own
211
253
  Klastera.cluster_of!(cluster_user, cluster_organization)
212
254
  end
@@ -1,3 +1,3 @@
1
1
  module Klastera
2
- VERSION = "1.3"
3
- end
2
+ VERSION = "1.3.1"
3
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klastera
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.3'
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gino Barahona
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-16 00:00:00.000000000 Z
11
+ date: 2020-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails