recourse 4.6.4 → 4.7.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/CHANGELOG.md +20 -0
- data/app/controllers/concerns/recourse/landing.rb +13 -3
- data/app/controllers/recourse/base_controller.rb +3 -4
- data/app/views/recourses/_flash.html.erb +3 -2
- data/config/locales/recourse.en.yml +2 -2
- data/lib/recourse/helpers/flashes.rb +36 -0
- data/lib/recourse/helpers/parents.rb +2 -8
- data/lib/recourse/helpers/sorts.rb +5 -1
- data/lib/recourse/helpers.rb +2 -17
- data/lib/recourse/limits.rb +4 -4
- data/lib/recourse/titles.rb +8 -0
- data/lib/recourse/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ba211bbbb2cad39fb435db7af8c982733056778da14b2617ed01616d7b471643
|
|
4
|
+
data.tar.gz: 3b847c74cb62a88425a882a839fc6d264581ab3f7e8aed661f53e03b184a12ed
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7ba31e2730714820fa039e61ba649fc91e3b944b01703ded5c4a006b52068b0b5dc8997f667481994adb4d4fb4370660b3d2eed5fa0bb882d8307a44b0bc82ab
|
|
7
|
+
data.tar.gz: 99f83b13ef7fb727d140dcb6fbd44a3abb160fd10b2bd21d441fa4cb609e985463b66e044047503acdb69375645c8dc408ab2559d4faa00d62416a8dea95a9a9
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
For more information about changelogs, check [Keep a Changelog](http://keepachangelog.com) and
|
|
6
6
|
[Vandamme](http://tech-angels.github.io/vandamme).
|
|
7
7
|
|
|
8
|
+
## 4.7.0 - 2026-09-11
|
|
9
|
+
|
|
10
|
+
* [Feature] The toast after a create or an update names the record and links it to its page
|
|
11
|
+
|
|
12
|
+
`Blue Crew was updated.` rather than `Team was updated.`, with the label led to the
|
|
13
|
+
record's show page where the routes drew one, so a reader can go and look the row over.
|
|
14
|
+
The words are the label the model picked, or the model's own name where a record says
|
|
15
|
+
nothing. A rejected write and a delete still name the model. A host asserting the old
|
|
16
|
+
wording in its own tests updates the sentence.
|
|
17
|
+
|
|
18
|
+
* [Feature] The first click on a heading sorts the table downward, and the second turns it back up
|
|
19
|
+
|
|
20
|
+
The newest, the most and the latest are what a reader clicks a heading to find, and
|
|
21
|
+
ascending put them on the last page. A host asserting a heading's `asc` link in its
|
|
22
|
+
own tests now reads `desc`.
|
|
23
|
+
|
|
24
|
+
## 4.6.5 - 2026-09-09
|
|
25
|
+
|
|
26
|
+
* [Fix] A table opens at 15 rows a page rather than 20; the 100-row page stays
|
|
27
|
+
|
|
8
28
|
## 4.6.4 - 2026-09-08
|
|
9
29
|
|
|
10
30
|
* [Fix] On a phone the arrows that put the words back reload the page outright: the visit 4.6.1 made to the same address was morphed in place under an index's refresh metas, and Safari drew the sidebar's entries one over the next all the same
|
|
@@ -5,14 +5,24 @@ module Recourse
|
|
|
5
5
|
module Landing
|
|
6
6
|
private
|
|
7
7
|
|
|
8
|
-
# What a write says once it has landed: the message, and the
|
|
9
|
-
# one survives, for the page to mark while that message stands.
|
|
8
|
+
# What a write says once it has landed: the message, and the record it landed on
|
|
9
|
+
# where one survives, for the page to mark and lead to while that message stands.
|
|
10
10
|
def wrote(message, record = nil)
|
|
11
11
|
flash.notice = message
|
|
12
|
-
flash[Recourse::WRITTEN] =
|
|
12
|
+
flash[Recourse::WRITTEN] = written record if record
|
|
13
13
|
redirect_to written_url, status: :see_other
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# What the page is told about that record: the row to mark, the words the message
|
|
17
|
+
# calls it by, and its own page where the routes drew one — nil where they did not,
|
|
18
|
+
# so the words stay words. String keys: the flash rides the session as JSON.
|
|
19
|
+
def written(record)
|
|
20
|
+
shown = Recourse.routed? controller_path, 'show'
|
|
21
|
+
url = url_for(action: :show, id: record, only_path: true) if shown
|
|
22
|
+
|
|
23
|
+
{ 'row' => Recourse.row_id(record), 'label' => Recourse.record_title(record), 'url' => url }
|
|
24
|
+
end
|
|
25
|
+
|
|
16
26
|
# What a rejected write does instead: the form again, with the message over it and
|
|
17
27
|
# the errors beside the fields that earned them.
|
|
18
28
|
def rejected(record, page, message)
|
|
@@ -36,12 +36,11 @@ module Recourse
|
|
|
36
36
|
def create
|
|
37
37
|
record = assign resource_class.new
|
|
38
38
|
record.assign_attributes resource_params
|
|
39
|
-
model = human_name
|
|
40
39
|
|
|
41
40
|
if create_resource record
|
|
42
|
-
wrote t('recourse.created',
|
|
41
|
+
wrote t('recourse.created', record: Recourse.record_title(record)), record
|
|
43
42
|
else
|
|
44
|
-
rejected record, :new, t('recourse.created_error', model:
|
|
43
|
+
rejected record, :new, t('recourse.created_error', model: human_name)
|
|
45
44
|
end
|
|
46
45
|
end
|
|
47
46
|
|
|
@@ -54,7 +53,7 @@ module Recourse
|
|
|
54
53
|
# Saves changes to a record, then shows the index again or says what turned it down.
|
|
55
54
|
def update
|
|
56
55
|
if update_resource @recourse
|
|
57
|
-
wrote t('recourse.updated',
|
|
56
|
+
wrote t('recourse.updated', record: Recourse.record_title(@recourse)), @recourse
|
|
58
57
|
else
|
|
59
58
|
rejected @recourse, :edit, t('recourse.updated_error', model: human_name)
|
|
60
59
|
end
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
page snapshot on every Back, announcing a save that happened a page ago. -%>
|
|
4
4
|
<%# The row a write landed on rides here rather than on a toast: this exists once
|
|
5
5
|
per page, `hidden.bs.toast` bubbles up to it from whichever toast hides, and
|
|
6
|
-
`data-turbo-temporary` already takes the whole thing away on a Back.
|
|
6
|
+
`data-turbo-temporary` already takes the whole thing away on a Back. The same
|
|
7
|
+
key carries the record's words and its page, which the notice below links. -%>
|
|
7
8
|
<div class='toast-container position-fixed bottom-0 end-0 p-3' data-turbo-temporary
|
|
8
9
|
<%= tag.attributes data: written_data %>>
|
|
9
10
|
<%# Every key here becomes a toast, whoever invented it — so the one carrying the
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
data-controller='toast'
|
|
17
18
|
data-action='mouseenter->toast#stopTimer mouseleave->toast#startTimer focusin->toast#stopTimer focusout->toast#startTimer'>
|
|
18
19
|
<div class='toast-header border-0'>
|
|
19
|
-
<span class='me-auto'><%= message %></span>
|
|
20
|
+
<span class='me-auto'><%= written_message key, message %></span>
|
|
20
21
|
<button type='button' class='btn-close' data-bs-dismiss='toast' aria-label='Close'></button>
|
|
21
22
|
</div>
|
|
22
23
|
<div class='toast-body d-none'></div>
|
|
@@ -20,7 +20,7 @@ en:
|
|
|
20
20
|
clear: Clear search
|
|
21
21
|
compact: Compact
|
|
22
22
|
create: Create
|
|
23
|
-
created: "%{
|
|
23
|
+
created: "%{record} was created."
|
|
24
24
|
created_error: "%{model} could not be created."
|
|
25
25
|
darken: Dark
|
|
26
26
|
delete: Delete %{model}
|
|
@@ -65,7 +65,7 @@ en:
|
|
|
65
65
|
blue. It cannot be %{color}."
|
|
66
66
|
unknown_theme: "`Recourse.theme` is one of %{themes}, or nil for Bootstrap's own
|
|
67
67
|
palette. It cannot be %{theme}."
|
|
68
|
-
updated: "%{
|
|
68
|
+
updated: "%{record} was updated."
|
|
69
69
|
updated_error: "%{model} could not be updated."
|
|
70
70
|
unset: None
|
|
71
71
|
deletion:
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Recourse
|
|
2
|
+
module Helpers
|
|
3
|
+
# What a flash message is drawn as: its toast's theme, the row it marks, and the
|
|
4
|
+
# words it leads somewhere.
|
|
5
|
+
module Flashes
|
|
6
|
+
# Bootstrap theme for each flash key, so a notice and an alert read apart.
|
|
7
|
+
FLASH_THEMES = { 'notice' => 'theme-success', 'alert' => 'theme-danger' }
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# Theme for one flash entry, falling back to a neutral one for a host's key.
|
|
12
|
+
def flash_theme(key)
|
|
13
|
+
FLASH_THEMES.fetch key.to_s, 'theme-primary'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# What marks the row a write just landed on, and nothing at all on a page no write
|
|
17
|
+
# brought about — which is every page but the one after a create or an update.
|
|
18
|
+
def written_data
|
|
19
|
+
written = flash[Recourse::WRITTEN]
|
|
20
|
+
|
|
21
|
+
{ controller: 'written', written_row_value: written['row'] } if written.present?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# The message with the record it names led to that record's page, where a write
|
|
25
|
+
# landed on one the routes can show. Spliced around the label rather than rebuilt,
|
|
26
|
+
# so the flash keeps the plain sentence for whoever else reads it.
|
|
27
|
+
def written_message(key, message)
|
|
28
|
+
written = flash[Recourse::WRITTEN]
|
|
29
|
+
return message unless key.to_s == 'notice' && written&.dig('url')
|
|
30
|
+
|
|
31
|
+
before, label, after = message.partition written['label']
|
|
32
|
+
safe_join [before, label.presence && link_to(label, written['url']), after]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -58,15 +58,9 @@ module Recourse
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def parent_title(parent)
|
|
61
|
-
#
|
|
62
|
-
# `truncate` has no patience for an Integer — and where a record says
|
|
63
|
-
# nothing at all, the model's own name stands in, as the delete warning's
|
|
64
|
-
# title already does.
|
|
65
|
-
label = parent.attributes[parent.class.recourse_label.to_s]
|
|
66
|
-
|
|
67
|
-
# Forty characters of the label, no more: a record named by an address or a
|
|
61
|
+
# Forty characters of the title, no more: a record named by an address or a
|
|
68
62
|
# sentence would otherwise walk the crumb into the navbar's search form.
|
|
69
|
-
truncate
|
|
63
|
+
truncate Recourse.record_title(parent), length: 40
|
|
70
64
|
end
|
|
71
65
|
|
|
72
66
|
# One of the parent's own pages, or nil where the host drew no route to it —
|
|
@@ -10,13 +10,17 @@ module Recourse
|
|
|
10
10
|
# allows that, and the plain title everywhere else. Only the header row draws
|
|
11
11
|
# the link, so the `data-cell` on every other row stays readable text.
|
|
12
12
|
#
|
|
13
|
+
# The first click sorts descending, the second back up: the newest, the most
|
|
14
|
+
# and the latest are what a reader clicks a heading to find.
|
|
15
|
+
#
|
|
13
16
|
# Named apart from Ransack's `sort_link`, which it calls: sharing the name
|
|
14
17
|
# would take that helper away from every view this gem's controllers render.
|
|
15
18
|
def sort_header(column, title = nil)
|
|
16
19
|
title ||= sort_title column
|
|
17
20
|
return title unless @recourse_headers && sortable_column?(column)
|
|
18
21
|
|
|
19
|
-
sort_link resource_search, column.to_sym,
|
|
22
|
+
sort_link resource_search, column.to_sym,
|
|
23
|
+
hide_indicator: true, page: nil, default_order: :desc do
|
|
20
24
|
safe_join [title, sort_caret(column)].compact, ' '
|
|
21
25
|
end
|
|
22
26
|
end
|
data/lib/recourse/helpers.rb
CHANGED
|
@@ -14,6 +14,7 @@ require_relative 'helpers/details'
|
|
|
14
14
|
require_relative 'helpers/examples'
|
|
15
15
|
require_relative 'helpers/fields'
|
|
16
16
|
require_relative 'helpers/filters'
|
|
17
|
+
require_relative 'helpers/flashes'
|
|
17
18
|
require_relative 'helpers/formats'
|
|
18
19
|
require_relative 'helpers/inputs'
|
|
19
20
|
require_relative 'helpers/kinds'
|
|
@@ -43,7 +44,7 @@ module Recourse
|
|
|
43
44
|
include Actions, Bookmarks, Buttons, Cards,
|
|
44
45
|
Cells, Choices, Colors, Comboboxes, Constraints, Counters, Deletions, Densities,
|
|
45
46
|
Details,
|
|
46
|
-
Examples, Fields, Filters, Formats, Inputs, Kinds, Limits,
|
|
47
|
+
Examples, Fields, Filters, Flashes, Formats, Inputs, Kinds, Limits,
|
|
47
48
|
Names, Navigation, Parents, Pictures, References, Refreshes,
|
|
48
49
|
Routing,
|
|
49
50
|
Resources, Rows, Searches, Shortcuts, Sidebars, Sorts, Tabs, Themes,
|
|
@@ -55,24 +56,8 @@ module Recourse
|
|
|
55
56
|
# show page alone — `.recourse-values` in the layout draws it.
|
|
56
57
|
ROW = 'recourse-row pb-2 mb-3 lg:col-6'
|
|
57
58
|
|
|
58
|
-
# Bootstrap theme for each flash key, so a notice and an alert read apart.
|
|
59
|
-
FLASH_THEMES = { 'notice' => 'theme-success', 'alert' => 'theme-danger' }
|
|
60
|
-
|
|
61
|
-
# Theme for one flash entry, falling back to a neutral one for a host's key.
|
|
62
|
-
def flash_theme(key)
|
|
63
|
-
FLASH_THEMES.fetch key.to_s, 'theme-primary'
|
|
64
|
-
end
|
|
65
|
-
|
|
66
59
|
private
|
|
67
60
|
|
|
68
|
-
# What marks the row a write just landed on, and nothing at all on a page no write
|
|
69
|
-
# brought about — which is every page but the one after a create or an update.
|
|
70
|
-
def written_data
|
|
71
|
-
row = flash[Recourse::WRITTEN]
|
|
72
|
-
|
|
73
|
-
{ controller: 'written', written_row_value: row } if row.present?
|
|
74
|
-
end
|
|
75
|
-
|
|
76
61
|
# `?q=anything` arrives as a String, which has no parameters to read — the
|
|
77
62
|
# same test `Recourse::Search` makes, spelled the same way.
|
|
78
63
|
def query_params
|
data/lib/recourse/limits.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Reopened for how much of a table a page shows at once.
|
|
2
2
|
module Recourse
|
|
3
|
-
# Rows to a page, in the order the menu offers them:
|
|
4
|
-
# step up for a reader scanning
|
|
5
|
-
#
|
|
6
|
-
LIMITS = [
|
|
3
|
+
# Rows to a page, in the order the menu offers them: a screenful for a reader reading
|
|
4
|
+
# a table, and the one step up for a reader scanning it. Named once — the controller
|
|
5
|
+
# checks a cookie against this list, and the menu is drawn from it.
|
|
6
|
+
LIMITS = [15, 100].freeze
|
|
7
7
|
|
|
8
8
|
# Where a reader's chosen page size is kept in their browser. A cookie rather than
|
|
9
9
|
# local storage, which the scheme is kept in: pagy runs on the server, and a cookie
|
data/lib/recourse/titles.rb
CHANGED
|
@@ -50,6 +50,14 @@ module Recourse
|
|
|
50
50
|
|
|
51
51
|
lower ? downcase(title) : title
|
|
52
52
|
end
|
|
53
|
+
|
|
54
|
+
# What one record is called: its label, spoken as a string — a numeric one is not
|
|
55
|
+
# words — or the model's own name where it says nothing at all.
|
|
56
|
+
def record_title(record)
|
|
57
|
+
label = record.attributes[record.class.recourse_label.to_s]
|
|
58
|
+
|
|
59
|
+
label.presence&.to_s || record.class.model_name.human
|
|
60
|
+
end
|
|
53
61
|
end
|
|
54
62
|
|
|
55
63
|
extend Titles
|
data/lib/recourse/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: recourse
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- claudiob
|
|
@@ -208,6 +208,7 @@ files:
|
|
|
208
208
|
- lib/recourse/helpers/examples.rb
|
|
209
209
|
- lib/recourse/helpers/fields.rb
|
|
210
210
|
- lib/recourse/helpers/filters.rb
|
|
211
|
+
- lib/recourse/helpers/flashes.rb
|
|
211
212
|
- lib/recourse/helpers/formats.rb
|
|
212
213
|
- lib/recourse/helpers/inputs.rb
|
|
213
214
|
- lib/recourse/helpers/kinds.rb
|