keystone_ui-preferences 0.2.0 → 0.4.0

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: 01e15e5f655d70c8bfd4b7b0d1c976705de25a0f0c0d24645e5aa3afe5c9e8ee
4
- data.tar.gz: ec05d21e7991ff5378e817f8f70be35fbae4f92f6a141467fc188447176b1850
3
+ metadata.gz: 497f7eeb505b63450d4e41595648c92f9acaba75494eb27c76ee901de7c60f9d
4
+ data.tar.gz: 80e5ffc7ecfa86e0ef011b14cd939e4c2d39c9c4d3e8e086d6efd22756d8542d
5
5
  SHA512:
6
- metadata.gz: b82309fb9a0f5881748b3de2152973e348076aa1ae474fceb55be7476929e771732a3f023f655e22e8f4e34b3725218ff15a2d8c092a64a46842b5f94b9943c3
7
- data.tar.gz: d6617f9f3c90e2931f7ef5a29fcd6b103b4e32da8a2d4c5f1026828831d31609e8ac3af82fe390953c7e01c12c986c890ca988b760872aab22fcf8f37c8d4b53
6
+ metadata.gz: c79c4d859ae6f1aaa84cb608c626e69a13fb0aa908c8f373a6b11f07a49c8302d39bbcce5ac02228f94b5dd521a89225f000fd3c88277ef48b5e93053d840394
7
+ data.tar.gz: f89d730b80476e7c455cc8eba394adab7b3a9c39199395143236cad08dca89e9331032b8fea268be0ee2f506643b3cf9fbbc105a7fac1b24ddc27e150f1b19d8
data/README.md CHANGED
@@ -41,9 +41,12 @@ KeystoneUi::Preferences.configure do |config|
41
41
  config.current_owner_method = :current_user # returns the person a value is saved for
42
42
  config.authentication_method = :authenticate_user! # runs before every save
43
43
  config.current_account_method = :current_account # returns the account; nil (the default) skips the account level
44
+ config.max_value_bytes = 10_000 # the largest saved value accepted, in bytes
44
45
  end
45
46
  ```
46
47
 
48
+ The save address refuses, with a 422 and nothing saved, a body that is not a JSON object, a body larger than `max_value_bytes`, and a component key that is not 1 to 64 letters, digits and underscores.
49
+
47
50
  ## Using it
48
51
 
49
52
  Give a table a key, and the hidden columns it shows a person with nothing saved:
@@ -70,7 +73,7 @@ With `current_account_method` set, an account can keep its own layout for a key,
70
73
  2. Otherwise the account's layout, when it has one.
71
74
  3. Otherwise the table's default layout, from its own call.
72
75
 
73
- A person whose account does not let members choose sees no Columns menu, and a save they send is refused. Reading the layout that applies makes one query.
76
+ A person whose account does not let members choose sees no Columns menu, and a save they send is refused. Reading the layout that applies makes one query, and each owner's row for a key, or the fact that there is none, is then kept in `Rails.cache` until that row is saved through the gem, so a later view makes no query. A row changed outside the gem keeps its old cache entry until it expires. With no cache configured, every view reads the rows.
74
77
 
75
78
  An admin sets an account's layouts in a settings_hub section. Who may open it is the app's decision, so register it behind a capability of the app's choosing:
76
79
 
@@ -81,7 +84,15 @@ SettingsHub.section :account_layouts, area: :account, title: "Table layouts",
81
84
  runs: "KeystoneUi::Preferences::PickAccountLayouts"
82
85
  ```
83
86
 
84
- The section lists each component key the admin or the account has a saved layout for. Each key has the members-choose switch and, when the admin has a saved layout of their own, a button that makes it the account's layout.
87
+ The section lists each component key the admin or the account has a saved layout for, by the name the app gives it, or by the key in words when it has none:
88
+
89
+ ```ruby
90
+ KeystoneUi::Preferences.configure do |config|
91
+ config.name_component :revenue_projection_months, "Revenue projection – By month"
92
+ end
93
+ ```
94
+
95
+ Each key has the members-choose switch and, when the admin has a saved layout of their own, a button that makes it the account's layout.
85
96
 
86
97
  ## What is stored
87
98
 
@@ -4,11 +4,19 @@ module KeystoneUi
4
4
  module Preferences
5
5
  class ComponentPreferencesController < ApplicationController
6
6
  def update
7
+ return head 422 unless params[:component_key].match?(/\A\w{1,64}\z/)
7
8
  return head :forbidden unless keystone_layout_choice(params[:component_key]).members_choose?
8
9
 
10
+ return head 422 if request.raw_post.bytesize > KeystoneUi::Preferences.configuration.max_value_bytes
11
+
12
+ value = JSON.parse(request.raw_post)
13
+ return head 422 unless value.is_a?(Hash)
14
+
9
15
  preference = ComponentPreference.find_or_initialize_by(owner: current_owner, component_key: params[:component_key])
10
- preference.update!(value: JSON.parse(request.raw_post))
16
+ preference.update!(value: value)
11
17
  head :no_content
18
+ rescue ActionDispatch::Http::Parameters::ParseError
19
+ head 422
12
20
  end
13
21
  end
14
22
  end
@@ -7,6 +7,12 @@ module KeystoneUi
7
7
 
8
8
  belongs_to :owner, polymorphic: true
9
9
 
10
+ after_commit { Rails.cache.delete(self.class.cache_key_for(owner_type, owner_id, component_key)) }
11
+
12
+ def self.cache_key_for(owner_type, owner_id, component_key)
13
+ [ "keystone_ui_preferences", owner_type, owner_id, component_key ].join("/")
14
+ end
15
+
10
16
  def owned_by?(record)
11
17
  owner_type == record.class.base_class.name && owner_id == record.id
12
18
  end
@@ -3,6 +3,8 @@
3
3
  module KeystoneUi
4
4
  module Preferences
5
5
  class LayoutChoice
6
+ NOTHING_SAVED = "nothing saved"
7
+
6
8
  def initialize(person:, account:, component_key:)
7
9
  @person = person
8
10
  @account = account
@@ -32,7 +34,26 @@ module KeystoneUi
32
34
  end
33
35
 
34
36
  def preferences
35
- @preferences ||= ComponentPreference.where(owner: [ @person, @account ].compact, component_key: @component_key).to_a
37
+ @preferences ||= begin
38
+ owners = [ @person, @account ].compact
39
+ cached = owners.index_with { |owner| Rails.cache.read(cache_key(owner)) }
40
+ missing = cached.select { |_owner, entry| entry.nil? }.keys
41
+ cached.values.grep(ComponentPreference) + read_and_cache(missing)
42
+ end
43
+ end
44
+
45
+ def read_and_cache(owners)
46
+ return [] if owners.empty?
47
+
48
+ found = ComponentPreference.where(owner: owners, component_key: @component_key).to_a
49
+ owners.each do |owner|
50
+ Rails.cache.write(cache_key(owner), found.find { |preference| preference.owned_by?(owner) } || NOTHING_SAVED)
51
+ end
52
+ found
53
+ end
54
+
55
+ def cache_key(owner)
56
+ ComponentPreference.cache_key_for(owner.class.base_class.name, owner.id, @component_key)
36
57
  end
37
58
  end
38
59
  end
@@ -4,7 +4,7 @@
4
4
  <% component_keys.each do |component_key| %>
5
5
  <div data-component-key="<%= component_key %>">
6
6
  <% account_preference = preferences.find { |preference| preference.component_key == component_key && preference.owned_by?(account) } %>
7
- <%= ui_section(title: component_key.humanize, spacing: :sm) do %>
7
+ <%= ui_section(title: KeystoneUi::Preferences.configuration.component_name(component_key), spacing: :sm) do %>
8
8
  <%= form_with(url: submit_url, method: :patch, data: { turbo: false }) do %>
9
9
  <%= hidden_field_tag "component_key", component_key, id: nil %>
10
10
  <%= hidden_field_tag "members_choose", "0", id: nil %>
@@ -3,11 +3,21 @@
3
3
  module KeystoneUi
4
4
  module Preferences
5
5
  class Configuration
6
- attr_accessor :current_owner_method, :authentication_method, :current_account_method
6
+ attr_accessor :current_owner_method, :authentication_method, :current_account_method, :max_value_bytes
7
7
 
8
8
  def initialize
9
9
  @current_owner_method = :current_user
10
10
  @authentication_method = :authenticate_user!
11
+ @component_names = {}
12
+ @max_value_bytes = 10_000
13
+ end
14
+
15
+ def name_component(component_key, name)
16
+ @component_names[component_key.to_s] = name
17
+ end
18
+
19
+ def component_name(component_key)
20
+ @component_names.fetch(component_key.to_s) { component_key.to_s.humanize }
11
21
  end
12
22
  end
13
23
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module KeystoneUi
4
4
  module Preferences
5
- VERSION = "0.2.0"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keystone_ui-preferences
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Schneider