keystone_ui-preferences 0.4.1 → 0.5.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 +30 -0
- data/app/models/keystone_ui/preferences/navigation_arrangement.rb +29 -0
- data/app/models/keystone_ui/preferences/pick_navigation_order.rb +48 -0
- data/app/models/keystone_ui/preferences/pick_navigation_placement.rb +30 -0
- data/app/views/keystone_ui/preferences/settings/_navigation_order.html.erb +58 -0
- data/app/views/keystone_ui/preferences/settings/_navigation_placement.html.erb +15 -0
- data/lib/keystone_ui/preferences/version.rb +1 -1
- data/lib/keystone_ui/preferences.rb +1 -0
- metadata +8 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 132478f987e0dbbf12eeda5ac9c9e9fe14a9ca1ec8b8ce60618b29e272f5db8f
|
|
4
|
+
data.tar.gz: eefd3cd44bce3d9aa5f3dab0c3ff4f5ad4a882e15ab9fbd836964e46e631724a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: da15030c2de6a478df7106c48218dfe8bcd2197f592f68ea8147b5b6fa389b5c65b4e30699a1480df86f13ec1d8069a2da2058c38550e8ed539e74ccab8dfe74
|
|
7
|
+
data.tar.gz: be3c817d9c47d16df821adeb5cf7fbe2e6cb884ad48e3711e00f2d270619c25368a202d0364593fa15bea9f7eefc2651027a3f80fa225fd4fe4645b6c692d732
|
data/README.md
CHANGED
|
@@ -101,6 +101,36 @@ end
|
|
|
101
101
|
|
|
102
102
|
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.
|
|
103
103
|
|
|
104
|
+
## Navigation placement
|
|
105
|
+
|
|
106
|
+
A person chooses where keystone_ui draws the desktop navigation, at the top or as a sidebar on the left or the right, in a settings_hub section the app registers:
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
SettingsHub.section :navigation_placement, area: :user, title: "Navigation",
|
|
110
|
+
renders: "keystone_ui/preferences/settings/navigation_placement",
|
|
111
|
+
runs: "KeystoneUi::Preferences::PickNavigationPlacement"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The section offers Top, Left and Right, with the placement that applies to the person selected, or Top when nothing is saved. Saving keeps `"placement": "left"` for that person under the `navigation` key, leaving any saved tab order as it was, and keystone_ui's navigation reads it on the next page they open. A placement other than `top`, `left` or `right` is refused with a message, and nothing is saved.
|
|
115
|
+
|
|
116
|
+
The `navigation` key follows the account layouts above, so an account that turns off members-choose for it draws its own placement and tab order for every member.
|
|
117
|
+
|
|
118
|
+
While it is off, the placement and tab order sections say the account sets the navigation for everyone and offer no save. A placement, tab order or reset sent anyway is refused with a message, and nothing is saved.
|
|
119
|
+
|
|
120
|
+
## Tab order
|
|
121
|
+
|
|
122
|
+
A person sets the order of the navigation's groups, and of the tabs in each group, in a settings_hub section the app registers:
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
SettingsHub.section :navigation_order, area: :user, title: "Tab order",
|
|
126
|
+
renders: "keystone_ui/preferences/settings/navigation_order",
|
|
127
|
+
runs: "KeystoneUi::Preferences::PickNavigationOrder"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The section lists the groups declared with keystone_ui's `navigation_group`, each with the tabs the person may see, in the order that applies to them. A group with no tab they may see is left out. Each group and tab has an Up and a Down button, and pressing one saves the order with it moved one place, so the page works in a Hotwire Native web view with no script and nothing to drag. At phone width each row's buttons sit under its name.
|
|
131
|
+
|
|
132
|
+
Saving keeps `"order": [{ "group": "Admin" }, { "group": "Sales", "tabs": ["orders", "quotes"] }]` for that person under the `navigation` key, naming groups by label and tabs by key, and leaves their saved placement as it was. keystone_ui draws the navigation in that order on the next page they open, with anything the order does not name after it in its declared order. Reset removes the saved order, so the navigation goes back to the declared order. An order that is not a list of groups is refused with a message, and nothing is saved.
|
|
133
|
+
|
|
104
134
|
## What is stored
|
|
105
135
|
|
|
106
136
|
One row per owner and component key, in `keystone_ui_preferences_component_preferences`:
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KeystoneUi
|
|
4
|
+
module Preferences
|
|
5
|
+
class NavigationArrangement
|
|
6
|
+
def initialize(arranged)
|
|
7
|
+
@arranged = arranged
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def group_moved(index, step)
|
|
11
|
+
moved(order, index, step)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def tab_moved(group_index, tab_index, step)
|
|
15
|
+
order.tap { |groups| moved(groups[group_index]["tabs"], tab_index, step) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def order
|
|
19
|
+
@arranged.map { |group, tabs| { "group" => group.label, "tabs" => tabs.map { |tab| tab.key.to_s } } }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def moved(items, index, step)
|
|
25
|
+
items.insert(index + step, items.delete_at(index))
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module KeystoneUi
|
|
6
|
+
module Preferences
|
|
7
|
+
class PickNavigationOrder
|
|
8
|
+
def initialize(values:, person: nil, account: nil)
|
|
9
|
+
@person = person
|
|
10
|
+
@account = account
|
|
11
|
+
@values = values
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
return Refusal.new("Your account sets the navigation for everyone, so this was not saved.") unless members_choose?
|
|
16
|
+
return reset if @values[:reset] == "1"
|
|
17
|
+
return Refusal.new("That navigation order is too large to save.") if @values[:order].to_s.bytesize > KeystoneUi::Preferences.configuration.max_value_bytes
|
|
18
|
+
|
|
19
|
+
order = submitted_order
|
|
20
|
+
return Refusal.new("Choose an order for the navigation's groups and tabs.") unless order.is_a?(Array)
|
|
21
|
+
|
|
22
|
+
preference.update!(value: preference.value.to_h.merge("order" => order))
|
|
23
|
+
Kept.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def members_choose?
|
|
29
|
+
LayoutChoice.new(person: @person, account: @account, component_key: "navigation").members_choose?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def reset
|
|
33
|
+
preference.update!(value: preference.value.to_h.except("order"))
|
|
34
|
+
Kept.new
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def preference
|
|
38
|
+
@preference ||= ComponentPreference.find_or_initialize_by(owner: @person, component_key: "navigation")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def submitted_order
|
|
42
|
+
JSON.parse(@values[:order].to_s)
|
|
43
|
+
rescue JSON::ParserError
|
|
44
|
+
nil
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KeystoneUi
|
|
4
|
+
module Preferences
|
|
5
|
+
class PickNavigationPlacement
|
|
6
|
+
PLACEMENTS = %w[top left right].freeze
|
|
7
|
+
|
|
8
|
+
def initialize(values:, person: nil, account: nil)
|
|
9
|
+
@person = person
|
|
10
|
+
@account = account
|
|
11
|
+
@values = values
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
return Refusal.new("Your account sets the navigation for everyone, so this was not saved.") unless members_choose?
|
|
16
|
+
return Refusal.new("Choose Top, Left or Right for the navigation.") unless PLACEMENTS.include?(@values[:placement])
|
|
17
|
+
|
|
18
|
+
preference = ComponentPreference.find_or_initialize_by(owner: @person, component_key: "navigation")
|
|
19
|
+
preference.update!(value: preference.value.to_h.merge("placement" => @values[:placement]))
|
|
20
|
+
Kept.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def members_choose?
|
|
26
|
+
LayoutChoice.new(person: @person, account: @account, component_key: "navigation").members_choose?
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<% choice = KeystoneUi::Preferences::LayoutChoice.new(person: person, account: account, component_key: "navigation") %>
|
|
2
|
+
<% saved_order = choice.value&.dig("order") || [] %>
|
|
3
|
+
|
|
4
|
+
<% if choice.members_choose? %>
|
|
5
|
+
<% permitted = KeystoneUi.configuration.navigation_groups.map { |group| [ group, group.tabs_permitted_for(self) ] }.reject { |_group, tabs| tabs.empty? } %>
|
|
6
|
+
<% arranged = KeystoneUi::NavigationOrder.new(saved_order).arrange(permitted) %>
|
|
7
|
+
<% arrangement = KeystoneUi::Preferences::NavigationArrangement.new(arranged) %>
|
|
8
|
+
|
|
9
|
+
<% arranged.each_with_index do |(group, tabs), group_index| %>
|
|
10
|
+
<div data-navigation-group="<%= group.label %>">
|
|
11
|
+
<%= ui_grid(cols: { default: 1, sm: 2 }, gap: :sm) do %>
|
|
12
|
+
<p data-group-label><strong><%= group.label %></strong></p>
|
|
13
|
+
<%= ui_grid(cols: { default: 2 }, gap: :sm) do %>
|
|
14
|
+
<% if group_index.positive? %>
|
|
15
|
+
<%= form_with(url: submit_url, method: :patch, data: { turbo: false, group_move: "up" }) do %>
|
|
16
|
+
<%= hidden_field_tag "order", arrangement.group_moved(group_index, -1).to_json, id: nil %>
|
|
17
|
+
<%= ui_button(label: "Up", type: :submit, variant: :secondary, size: :sm) %>
|
|
18
|
+
<% end %>
|
|
19
|
+
<% end %>
|
|
20
|
+
<% if group_index < arranged.size - 1 %>
|
|
21
|
+
<%= form_with(url: submit_url, method: :patch, data: { turbo: false, group_move: "down" }) do %>
|
|
22
|
+
<%= hidden_field_tag "order", arrangement.group_moved(group_index, 1).to_json, id: nil %>
|
|
23
|
+
<%= ui_button(label: "Down", type: :submit, variant: :secondary, size: :sm) %>
|
|
24
|
+
<% end %>
|
|
25
|
+
<% end %>
|
|
26
|
+
<% end %>
|
|
27
|
+
<% end %>
|
|
28
|
+
<% tabs.each_with_index do |tab, tab_index| %>
|
|
29
|
+
<div data-navigation-tab="<%= tab.key %>">
|
|
30
|
+
<%= ui_grid(cols: { default: 1, sm: 2 }, gap: :sm) do %>
|
|
31
|
+
<span data-tab-label><%= tab.label %></span>
|
|
32
|
+
<%= ui_grid(cols: { default: 2 }, gap: :sm) do %>
|
|
33
|
+
<% if tab_index.positive? %>
|
|
34
|
+
<%= form_with(url: submit_url, method: :patch, data: { turbo: false, tab_move: "up" }) do %>
|
|
35
|
+
<%= hidden_field_tag "order", arrangement.tab_moved(group_index, tab_index, -1).to_json, id: nil %>
|
|
36
|
+
<%= ui_button(label: "Up", type: :submit, variant: :secondary, size: :sm) %>
|
|
37
|
+
<% end %>
|
|
38
|
+
<% end %>
|
|
39
|
+
<% if tab_index < tabs.size - 1 %>
|
|
40
|
+
<%= form_with(url: submit_url, method: :patch, data: { turbo: false, tab_move: "down" }) do %>
|
|
41
|
+
<%= hidden_field_tag "order", arrangement.tab_moved(group_index, tab_index, 1).to_json, id: nil %>
|
|
42
|
+
<%= ui_button(label: "Down", type: :submit, variant: :secondary, size: :sm) %>
|
|
43
|
+
<% end %>
|
|
44
|
+
<% end %>
|
|
45
|
+
<% end %>
|
|
46
|
+
<% end %>
|
|
47
|
+
</div>
|
|
48
|
+
<% end %>
|
|
49
|
+
</div>
|
|
50
|
+
<% end %>
|
|
51
|
+
|
|
52
|
+
<%= form_with(url: submit_url, method: :patch, data: { turbo: false }) do %>
|
|
53
|
+
<%= hidden_field_tag "reset", "1", id: nil %>
|
|
54
|
+
<%= ui_button(label: "Reset", type: :submit, variant: :secondary) %>
|
|
55
|
+
<% end %>
|
|
56
|
+
<% else %>
|
|
57
|
+
<%= ui_alert(message: "Your account sets the navigation for everyone.") %>
|
|
58
|
+
<% end %>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<% choice = KeystoneUi::Preferences::LayoutChoice.new(person: person, account: account, component_key: "navigation") %>
|
|
2
|
+
<% current = choice.value&.dig("placement") || "top" %>
|
|
3
|
+
|
|
4
|
+
<% if choice.members_choose? %>
|
|
5
|
+
<%= form_with(url: submit_url, method: :patch, data: { turbo: false }) do %>
|
|
6
|
+
<%= ui_grid(cols: { default: 1, sm: 3 }, gap: :sm) do %>
|
|
7
|
+
<% { "top" => "Top", "left" => "Left", "right" => "Right" }.each do |placement, label| %>
|
|
8
|
+
<%= ui_radio_card(name: "placement", value: placement, label: label, checked: placement == current) %>
|
|
9
|
+
<% end %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<%= ui_button(label: "Save", type: :submit) %>
|
|
12
|
+
<% end %>
|
|
13
|
+
<% else %>
|
|
14
|
+
<%= ui_alert(message: "Your account sets the navigation for everyone.") %>
|
|
15
|
+
<% 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.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tyler Schneider
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.38.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.38.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: railties
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -83,9 +83,14 @@ files:
|
|
|
83
83
|
- app/models/keystone_ui/preferences/component_preference.rb
|
|
84
84
|
- app/models/keystone_ui/preferences/kept.rb
|
|
85
85
|
- app/models/keystone_ui/preferences/layout_choice.rb
|
|
86
|
+
- app/models/keystone_ui/preferences/navigation_arrangement.rb
|
|
86
87
|
- app/models/keystone_ui/preferences/pick_account_layouts.rb
|
|
88
|
+
- app/models/keystone_ui/preferences/pick_navigation_order.rb
|
|
89
|
+
- app/models/keystone_ui/preferences/pick_navigation_placement.rb
|
|
87
90
|
- app/models/keystone_ui/preferences/refusal.rb
|
|
88
91
|
- app/views/keystone_ui/preferences/settings/_account_layouts.html.erb
|
|
92
|
+
- app/views/keystone_ui/preferences/settings/_navigation_order.html.erb
|
|
93
|
+
- app/views/keystone_ui/preferences/settings/_navigation_placement.html.erb
|
|
89
94
|
- config/routes.rb
|
|
90
95
|
- lib/generators/keystone_ui/preferences/install/install_generator.rb
|
|
91
96
|
- lib/generators/keystone_ui/preferences/install/templates/create_keystone_ui_preferences_component_preferences.rb.erb
|