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 +4 -4
- data/README.md +13 -2
- data/app/controllers/keystone_ui/preferences/component_preferences_controller.rb +9 -1
- data/app/models/keystone_ui/preferences/component_preference.rb +6 -0
- data/app/models/keystone_ui/preferences/layout_choice.rb +22 -1
- data/app/views/keystone_ui/preferences/settings/_account_layouts.html.erb +1 -1
- data/lib/keystone_ui/preferences/configuration.rb +11 -1
- data/lib/keystone_ui/preferences/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 497f7eeb505b63450d4e41595648c92f9acaba75494eb27c76ee901de7c60f9d
|
|
4
|
+
data.tar.gz: 80e5ffc7ecfa86e0ef011b14cd939e4c2d39c9c4d3e8e086d6efd22756d8542d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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:
|
|
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 ||=
|
|
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
|
|
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
|
|