avo 4.1.10 → 4.1.12
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/Gemfile.lock +1 -1
- data/app/assets/builds/avo/application.js +1 -1
- data/app/assets/builds/avo/application.js.map +2 -2
- data/app/components/avo/field_wrapper_component.rb +5 -4
- data/app/javascript/js/controllers/filter_controller.js +4 -6
- data/app/views/avo/base/_boolean_filter.html.erb +1 -1
- data/lib/avo/fields/base_field.rb +1 -1
- data/lib/avo/skills/avo-fields/SKILL.md +1 -1
- data/lib/avo/skills/bin/docs_drift.rb +91 -0
- data/lib/avo/skills/docs-index.json +7 -0
- data/lib/avo/version.rb +1 -1
- metadata +3 -1
|
@@ -122,12 +122,13 @@ class Avo::FieldWrapperComponent < Avo::BaseComponent
|
|
|
122
122
|
end
|
|
123
123
|
|
|
124
124
|
def stacked?
|
|
125
|
-
#
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
# Fetch it from the field
|
|
125
|
+
# The field declaration is the user's explicit intent, so it wins over the
|
|
126
|
+
# layout default a parent component passes in (sidebars, preview, etc.).
|
|
129
127
|
return @field.stacked unless @field.stacked.nil?
|
|
130
128
|
|
|
129
|
+
# Fallback to what the rendering component asked for
|
|
130
|
+
return @stacked unless @stacked.nil?
|
|
131
|
+
|
|
131
132
|
# Fallback to defaults
|
|
132
133
|
Avo.configuration.field_wrapper_layout == :stacked
|
|
133
134
|
end
|
|
@@ -81,12 +81,10 @@ export default class extends Controller {
|
|
|
81
81
|
return obj
|
|
82
82
|
}, {})
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
encodedFilters = this.encode(filtered)
|
|
89
|
-
}
|
|
84
|
+
// Encode the filters and their values. The empty set is encoded too, so
|
|
85
|
+
// the backend can tell "the user cleared the filters" apart from "the URL
|
|
86
|
+
// carries no filters" and overwrite the session-persisted value.
|
|
87
|
+
const encodedFilters = this.encode(filtered)
|
|
90
88
|
|
|
91
89
|
this.navigateToURLWithFilters(encodedFilters)
|
|
92
90
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
data-boolean-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>">
|
|
6
6
|
<div class="flex items-center">
|
|
7
7
|
<% if filter.options.empty? %>
|
|
8
|
-
<div class="filters-section__empty-state"><%= filter.class.
|
|
8
|
+
<div class="filters-section__empty-state"><%= filter.class.get_empty_message %></div>
|
|
9
9
|
<% else %>
|
|
10
10
|
<div class="filters-boolean-options">
|
|
11
11
|
<% filter.options.each do |value, label| %>
|
|
@@ -143,7 +143,7 @@ Every field accepts these common options (full list + types at the field-options
|
|
|
143
143
|
- **`copyable:`** — clipboard icon on Show/Index. Copies the **displayed** (formatted) value.
|
|
144
144
|
- **`link_to_record:`** — make the Index cell a link to the record. Only on `:id`, `:text`, `:gravatar`, and `belongs_to`.
|
|
145
145
|
- **`for_attribute:`** — back the field with a different attribute than its id (lets you show one column two ways).
|
|
146
|
-
- **`width:`** / **`stacked:`** — column width (`25/33/50/66/75/100`; any value <100 auto-stacks) and label-above-value layout.
|
|
146
|
+
- **`width:`** / **`stacked:`** — column width (`25/33/50/66/75/100`; any value <100 auto-stacks) and label-above-value layout. `stacked:` on the field wins everywhere, so `stacked: false` opts out of the auto-stacking and of sidebars/preview stacking too.
|
|
147
147
|
- **`html:`** — attach `style`/`classes`/`data` to the field's wrapper/label/input per view (e.g. right-align a number: `html: {index: {wrapper: {classes: "text-right"}}}`). See the html page.
|
|
148
148
|
|
|
149
149
|
### Computed (block) fields
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# Which docs pages changed since the last indexing run, and which shipped skills
|
|
3
|
+
# cite them. The docs repo already hashes every page for us — its git history
|
|
4
|
+
# *is* the lock file, so `docs-index.json` only has to remember one commit.
|
|
5
|
+
#
|
|
6
|
+
# Audits the skills that ship in this gem (the directories beside this bin/).
|
|
7
|
+
# Add-on gems carry their own skills and are out of this script's scope.
|
|
8
|
+
#
|
|
9
|
+
# ruby lib/avo/skills/bin/docs_drift.rb # report; finds the docs checkout itself
|
|
10
|
+
# ruby lib/avo/skills/bin/docs_drift.rb path/to/docs # or point it at one ($AVO_DOCS_PATH works too)
|
|
11
|
+
# ruby lib/avo/skills/bin/docs_drift.rb --update # mark the checkout's HEAD as indexed
|
|
12
|
+
require "json"
|
|
13
|
+
|
|
14
|
+
skills_root = File.expand_path("..", __dir__)
|
|
15
|
+
repo_root = File.expand_path("../../..", skills_root)
|
|
16
|
+
marker_path = "#{skills_root}/docs-index.json"
|
|
17
|
+
marker = JSON.parse(File.read(marker_path))
|
|
18
|
+
|
|
19
|
+
update = ARGV.delete("--update")
|
|
20
|
+
|
|
21
|
+
def git(dir, *args) = `git -C '#{dir}' #{args.join(" ")}`.strip
|
|
22
|
+
|
|
23
|
+
# A docs checkout is any clone of the marker's repo that has the docs path in it.
|
|
24
|
+
# Look next to and above this checkout so the script works from whatever layout a
|
|
25
|
+
# machine or CI runner happens to use.
|
|
26
|
+
def find_docs(repo_root, marker)
|
|
27
|
+
search = ["#{repo_root}/..", "#{repo_root}/../..", "#{repo_root}/../../.."]
|
|
28
|
+
candidates = search.flat_map { |base| Dir.glob("#{base}/*") }.uniq.sort
|
|
29
|
+
candidates.find do |dir|
|
|
30
|
+
next false if dir == repo_root || !Dir.exist?("#{dir}/.git") || !Dir.exist?("#{dir}/#{marker["docs_path"]}")
|
|
31
|
+
|
|
32
|
+
git(dir, "remote", "get-url", "origin").include?(marker["repo"])
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
docs = ARGV[0] || ENV["AVO_DOCS_PATH"] || find_docs(repo_root, marker)
|
|
37
|
+
|
|
38
|
+
if docs.nil? || !Dir.exist?("#{docs}/.git")
|
|
39
|
+
abort "No #{marker["repo"]} checkout found near #{repo_root} — pass its path as an argument or set AVO_DOCS_PATH."
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
docs = File.expand_path(docs)
|
|
43
|
+
|
|
44
|
+
head = git(docs, "rev-parse", "HEAD")
|
|
45
|
+
head_date = git(docs, "log", "-1", "--format=%cs", "HEAD")
|
|
46
|
+
|
|
47
|
+
if update
|
|
48
|
+
File.write(marker_path, JSON.pretty_generate(marker.merge("commit" => head, "date" => head_date)) + "\n")
|
|
49
|
+
puts "Indexed at #{head[0, 12]} (#{head_date})."
|
|
50
|
+
exit
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
unless git(docs, "cat-file", "-t", marker["commit"]) == "commit"
|
|
54
|
+
abort "#{docs} doesn't have commit #{marker["commit"]} — `git fetch` it first."
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if head == marker["commit"]
|
|
58
|
+
puts "Up to date with #{head[0, 12]} (#{head_date})."
|
|
59
|
+
exit
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# --no-renames: a renamed page is a delete + an add, which is exactly how a skill
|
|
63
|
+
# citing the old URL has to treat it.
|
|
64
|
+
changed = git(docs, "diff", "--name-status", "--no-renames", "#{marker["commit"]}..HEAD", "--", marker["docs_path"])
|
|
65
|
+
.lines.map { |line| line.split("\t") }
|
|
66
|
+
.map { |status, path| [status[0], File.basename(path.strip)] }
|
|
67
|
+
.reject { |_, page| page == "docs-map.md" }
|
|
68
|
+
.uniq
|
|
69
|
+
|
|
70
|
+
# The Docs lines in each SKILL.md are the provenance record. Skills cite pages
|
|
71
|
+
# both with and without the .md extension; normalize to the diff's basename form.
|
|
72
|
+
version = Regexp.escape(File.basename(marker["docs_path"]))
|
|
73
|
+
citations = Dir.glob("#{skills_root}/*/SKILL.md").each_with_object(Hash.new { |h, k| h[k] = [] }) do |path, acc|
|
|
74
|
+
skill = File.basename(File.dirname(path))
|
|
75
|
+
File.read(path).scan(%r{docs\.avohq\.io/#{version}/([A-Za-z0-9_/-]+)}).flatten.uniq.each do |page|
|
|
76
|
+
acc["#{File.basename(page)}.md"] << skill
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
puts "#{changed.size} pages changed between #{marker["commit"][0, 12]} (#{marker["date"]}) and #{head[0, 12]} (#{head_date}):", ""
|
|
81
|
+
|
|
82
|
+
stale = []
|
|
83
|
+
changed.sort_by(&:last).each do |status, page|
|
|
84
|
+
skills = citations[page]
|
|
85
|
+
stale.concat(skills)
|
|
86
|
+
puts " #{status} #{page.ljust(34)} #{skills.empty? ? "— not cited by any skill" : skills.join(", ")}"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
puts "", "Skills to review: #{stale.uniq.sort.join(", ")}" if stale.any?
|
|
90
|
+
puts "", "Commits: git -C #{docs} log --oneline #{marker["commit"][0, 12]}..HEAD -- #{marker["docs_path"]}"
|
|
91
|
+
puts "Then: ruby lib/avo/skills/bin/docs_drift.rb --update"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"repo": "avo-hq/docs.avohq.io",
|
|
3
|
+
"docs_path": "docs/4.0",
|
|
4
|
+
"commit": "3350dbef7b2da94b410d6a678f9551e16901411e",
|
|
5
|
+
"date": "2026-07-28",
|
|
6
|
+
"note": "The docs commit these skills were last indexed from. Run ruby lib/avo/skills/bin/docs_drift.rb to see what changed since, and --update after a refresh."
|
|
7
|
+
}
|
data/lib/avo/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: avo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.1.
|
|
4
|
+
version: 4.1.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adrian Marin
|
|
@@ -1123,6 +1123,8 @@ files:
|
|
|
1123
1123
|
- lib/avo/skills/avo-troubleshoot/SKILL.md
|
|
1124
1124
|
- lib/avo/skills/avo-update/SKILL.md
|
|
1125
1125
|
- lib/avo/skills/bin/avo-skills-resolve
|
|
1126
|
+
- lib/avo/skills/bin/docs_drift.rb
|
|
1127
|
+
- lib/avo/skills/docs-index.json
|
|
1126
1128
|
- lib/avo/skills/index.md
|
|
1127
1129
|
- lib/avo/skills/package-map.md
|
|
1128
1130
|
- lib/avo/table_row_options.rb
|