keystone_ui-preferences 0.1.0 → 0.2.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: dffbd18d9f90fc3020e69bfbb093379b348a2acd0b8d12d805d751c40c59f1ca
4
- data.tar.gz: 8ecb76a3a5fa72a67c7751e14c73a6af4b2e7fb5343b9582cc10a341de886542
3
+ metadata.gz: 01e15e5f655d70c8bfd4b7b0d1c976705de25a0f0c0d24645e5aa3afe5c9e8ee
4
+ data.tar.gz: ec05d21e7991ff5378e817f8f70be35fbae4f92f6a141467fc188447176b1850
5
5
  SHA512:
6
- metadata.gz: ad669daede81eed26e2134742d0cb8ee84fb9f931e1777e26e49a9e9167dcce4731fc6bb8b607c0c742e9f1773146f98c07e8e29666f809c8d6ea5ffc84dae9f
7
- data.tar.gz: cd87ce9b9ce0e390ca927d88a7f3b3e7b02a5bbc667147cf352dff22467c45e25c2e6a93fdc8b328b268fb4134c08f7f5cb0614920804bcc65404d45d3439eef
6
+ metadata.gz: b82309fb9a0f5881748b3de2152973e348076aa1ae474fceb55be7476929e771732a3f023f655e22e8f4e34b3725218ff15a2d8c092a64a46842b5f94b9943c3
7
+ data.tar.gz: d6617f9f3c90e2931f7ef5a29fcd6b103b4e32da8a2d4c5f1026828831d31609e8ac3af82fe390953c7e01c12c986c890ca988b760872aab22fcf8f37c8d4b53
data/README.md CHANGED
@@ -40,6 +40,7 @@ The gem asks the host for the signed-in person and for its sign-in check. Both d
40
40
  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
+ config.current_account_method = :current_account # returns the account; nil (the default) skips the account level
43
44
  end
44
45
  ```
45
46
 
@@ -59,7 +60,28 @@ Give a table a key, and the hidden columns it shows a person with nothing saved:
59
60
  ) %>
60
61
  ```
61
62
 
62
- A signed-in person sees a Columns menu above the table. Ticking or unticking a column saves `{ "hidden_columns": [...] }` for that person and key, replacing what they saved before, and reloads the page. Another person viewing the same table sees only their own saved layout. With nobody signed in, the table renders from its own call and shows no menu.
63
+ A signed-in person sees a Columns menu above the table. Their changes save `{ "hidden_columns": [...], "column_order": [...] }` for that person and key when the menu closes, replacing what they saved before, and reload the page. Another person viewing the same table sees only their own saved layout. With nobody signed in, the table renders from its own call and shows no menu.
64
+
65
+ ## Account layouts
66
+
67
+ With `current_account_method` set, an account can keep its own layout for a key, and a members-choose switch saying whether its members may keep their own. A table shows, in this order:
68
+
69
+ 1. The person's own layout, when the account lets members choose.
70
+ 2. Otherwise the account's layout, when it has one.
71
+ 3. Otherwise the table's default layout, from its own call.
72
+
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.
74
+
75
+ 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
+
77
+ ```ruby
78
+ SettingsHub.section :account_layouts, area: :account, title: "Table layouts",
79
+ capability: :configure_site,
80
+ renders: "keystone_ui/preferences/settings/account_layouts",
81
+ runs: "KeystoneUi::Preferences::PickAccountLayouts"
82
+ ```
83
+
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.
63
85
 
64
86
  ## What is stored
65
87
 
@@ -67,7 +89,7 @@ One row per owner and component key, in `keystone_ui_preferences_component_prefe
67
89
 
68
90
  | Column | Holds |
69
91
  |--------|-------|
70
- | `owner` | the person the value belongs to (polymorphic) |
92
+ | `owner` | the person or account the value belongs to (polymorphic) |
71
93
  | `component_key` | the key the page gave the component |
72
94
  | `value` | the JSON object last saved |
73
95
  | `members_choose` | whether an account's members may keep their own value, on by default |
@@ -15,11 +15,21 @@ module KeystoneUi
15
15
  owner = send(KeystoneUi::Preferences.configuration.current_owner_method)
16
16
  return unless owner
17
17
 
18
+ choice = keystone_layout_choice(component_key)
18
19
  {
19
- value: ComponentPreference.find_by(owner: owner, component_key: component_key.to_s)&.value,
20
- save_url: keystone_ui_preferences.component_preference_path(component_key: component_key)
20
+ value: choice.value,
21
+ save_url: (keystone_ui_preferences.component_preference_path(component_key: component_key) if choice.members_choose?)
21
22
  }
22
23
  end
24
+
25
+ def keystone_layout_choice(component_key)
26
+ LayoutChoice.new(person: send(KeystoneUi::Preferences.configuration.current_owner_method), account: keystone_preferences_account, component_key: component_key)
27
+ end
28
+
29
+ def keystone_preferences_account
30
+ method = KeystoneUi::Preferences.configuration.current_account_method
31
+ send(method) if method
32
+ end
23
33
  end
24
34
  end
25
35
  end
@@ -4,6 +4,8 @@ module KeystoneUi
4
4
  module Preferences
5
5
  class ComponentPreferencesController < ApplicationController
6
6
  def update
7
+ return head :forbidden unless keystone_layout_choice(params[:component_key]).members_choose?
8
+
7
9
  preference = ComponentPreference.find_or_initialize_by(owner: current_owner, component_key: params[:component_key])
8
10
  preference.update!(value: JSON.parse(request.raw_post))
9
11
  head :no_content
@@ -6,6 +6,10 @@ module KeystoneUi
6
6
  self.table_name = "keystone_ui_preferences_component_preferences"
7
7
 
8
8
  belongs_to :owner, polymorphic: true
9
+
10
+ def owned_by?(record)
11
+ owner_type == record.class.base_class.name && owner_id == record.id
12
+ end
9
13
  end
10
14
  end
11
15
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KeystoneUi
4
+ module Preferences
5
+ class Kept
6
+ def ok? = true
7
+
8
+ def message = nil
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KeystoneUi
4
+ module Preferences
5
+ class LayoutChoice
6
+ def initialize(person:, account:, component_key:)
7
+ @person = person
8
+ @account = account
9
+ @component_key = component_key.to_s
10
+ end
11
+
12
+ def value
13
+ return account_preference.value unless members_choose?
14
+
15
+ (own_preference || account_preference)&.value
16
+ end
17
+
18
+ def members_choose?
19
+ account_preference.nil? || account_preference.members_choose
20
+ end
21
+
22
+ private
23
+
24
+ def own_preference
25
+ preferences.find { |preference| preference.owned_by?(@person) }
26
+ end
27
+
28
+ def account_preference
29
+ return nil unless @account
30
+
31
+ preferences.find { |preference| preference.owned_by?(@account) }
32
+ end
33
+
34
+ def preferences
35
+ @preferences ||= ComponentPreference.where(owner: [ @person, @account ].compact, component_key: @component_key).to_a
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KeystoneUi
4
+ module Preferences
5
+ class PickAccountLayouts
6
+ def initialize(values:, person: nil, account: nil)
7
+ @person = person
8
+ @account = account
9
+ @values = values
10
+ end
11
+
12
+ def call
13
+ return Refusal.new("There is no account to save this layout on.") unless @account
14
+
15
+ @values[:use_mine] == "1" ? share_mine : set_members_choose
16
+ end
17
+
18
+ private
19
+
20
+ def share_mine
21
+ mine = ComponentPreference.find_by(owner: @person, component_key: component_key)
22
+ return Refusal.new("You have no saved layout for this table to share.") unless mine
23
+
24
+ account_preference.update!(value: mine.value)
25
+ Kept.new
26
+ end
27
+
28
+ def set_members_choose
29
+ account_preference.update!(members_choose: @values[:members_choose] == "1")
30
+ Kept.new
31
+ end
32
+
33
+ def account_preference
34
+ @account_preference ||= ComponentPreference.find_or_initialize_by(owner: @account, component_key: component_key)
35
+ end
36
+
37
+ def component_key
38
+ @values[:component_key]
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KeystoneUi
4
+ module Preferences
5
+ class Refusal
6
+ attr_reader :message
7
+
8
+ def initialize(message)
9
+ @message = message
10
+ end
11
+
12
+ def ok? = false
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ <% preferences = KeystoneUi::Preferences::ComponentPreference.where(owner: [ person, account ]).to_a %>
2
+ <% component_keys = preferences.map(&:component_key).uniq.sort %>
3
+
4
+ <% component_keys.each do |component_key| %>
5
+ <div data-component-key="<%= component_key %>">
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 %>
8
+ <%= form_with(url: submit_url, method: :patch, data: { turbo: false }) do %>
9
+ <%= hidden_field_tag "component_key", component_key, id: nil %>
10
+ <%= hidden_field_tag "members_choose", "0", id: nil %>
11
+ <%= ui_checkbox_row(name: "members_choose", value: "1", label: "Members choose their own layout", checked: account_preference.nil? || account_preference.members_choose) %>
12
+ <%= ui_button(label: "Save", type: :submit) %>
13
+ <% end %>
14
+ <% if preferences.any? { |preference| preference.component_key == component_key && preference.owned_by?(person) } %>
15
+ <%= form_with(url: submit_url, method: :patch, data: { turbo: false }) do %>
16
+ <%= hidden_field_tag "component_key", component_key, id: nil %>
17
+ <%= hidden_field_tag "use_mine", "1", id: nil %>
18
+ <%= ui_button(label: "Use my layout for everyone", type: :submit, variant: :secondary) %>
19
+ <% end %>
20
+ <% end %>
21
+ <% end %>
22
+ </div>
23
+ <% end %>
@@ -3,7 +3,7 @@
3
3
  module KeystoneUi
4
4
  module Preferences
5
5
  class Configuration
6
- attr_accessor :current_owner_method, :authentication_method
6
+ attr_accessor :current_owner_method, :authentication_method, :current_account_method
7
7
 
8
8
  def initialize
9
9
  @current_owner_method = :current_user
@@ -2,6 +2,6 @@
2
2
 
3
3
  module KeystoneUi
4
4
  module Preferences
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.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.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Schneider
@@ -81,6 +81,11 @@ files:
81
81
  - app/controllers/keystone_ui/preferences/component_preferences_controller.rb
82
82
  - app/models/keystone_ui/preferences/application_record.rb
83
83
  - app/models/keystone_ui/preferences/component_preference.rb
84
+ - app/models/keystone_ui/preferences/kept.rb
85
+ - app/models/keystone_ui/preferences/layout_choice.rb
86
+ - app/models/keystone_ui/preferences/pick_account_layouts.rb
87
+ - app/models/keystone_ui/preferences/refusal.rb
88
+ - app/views/keystone_ui/preferences/settings/_account_layouts.html.erb
84
89
  - config/routes.rb
85
90
  - lib/generators/keystone_ui/preferences/install/install_generator.rb
86
91
  - lib/generators/keystone_ui/preferences/install/templates/create_keystone_ui_preferences_component_preferences.rb.erb