admin_suite 0.2.8 → 0.2.9
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 +6 -1
- data/CONTRIBUTING.md +2 -2
- data/README.md +10 -24
- data/app/controllers/admin_suite/resources_controller.rb +14 -4
- data/app/views/admin_suite/resources/index.html.erb +3 -1
- data/app/views/admin_suite/resources/show.html.erb +2 -2
- data/lib/admin/base/filter_builder.rb +2 -1
- data/lib/admin/base/resource.rb +14 -2
- data/lib/admin_suite/version.rb +1 -1
- data/test/controllers/resources_controller_test.rb +80 -0
- data/test/integration/read_only_resource_test.rb +143 -0
- data/test/lib/resource_observability_extensions_test.rb +53 -0
- metadata +5 -14
- data/docs/README.md +0 -26
- data/docs/actions.md +0 -98
- data/docs/configuration.md +0 -284
- data/docs/development.md +0 -64
- data/docs/docs_viewer.md +0 -79
- data/docs/fields.md +0 -188
- data/docs/installation.md +0 -80
- data/docs/portals.md +0 -140
- data/docs/releasing.md +0 -67
- data/docs/resources.md +0 -237
- data/docs/theming.md +0 -63
- data/docs/troubleshooting.md +0 -50
data/docs/installation.md
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
# Installation
|
|
2
|
-
|
|
3
|
-
## Requirements
|
|
4
|
-
|
|
5
|
-
- Ruby **3.2+**
|
|
6
|
-
- Rails **8.0+**
|
|
7
|
-
|
|
8
|
-
AdminSuite is a mountable engine. You mount it under a path in your host app’s `config/routes.rb`.
|
|
9
|
-
|
|
10
|
-
## Add the gem
|
|
11
|
-
|
|
12
|
-
In your host app `Gemfile`:
|
|
13
|
-
|
|
14
|
-
```ruby
|
|
15
|
-
gem "admin_suite"
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Then:
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
bundle install
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Install into your app
|
|
25
|
-
|
|
26
|
-
Run the install generator (creates an initializer and mounts the engine):
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
bin/rails g admin_suite:install
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
To mount at a custom path:
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
bin/rails g admin_suite:install --mount-path=/internal/admin
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
This will:
|
|
39
|
-
|
|
40
|
-
- Create `config/initializers/admin_suite.rb`
|
|
41
|
-
- Add a route like `mount AdminSuite::Engine => "/internal/admin"`
|
|
42
|
-
|
|
43
|
-
## First run checklist
|
|
44
|
-
|
|
45
|
-
- **Auth**: set `config.authenticate` so only permitted users can access AdminSuite.
|
|
46
|
-
- **Actor**: set `config.current_actor` if you want actions/auditing to know “who did it”.
|
|
47
|
-
- **Resources**: add at least one resource definition file (see [Resources](resources.md)).
|
|
48
|
-
- **Portals**: set up portal metadata and dashboards (see [Portals](portals.md)).
|
|
49
|
-
|
|
50
|
-
## Assets (CSS/JS)
|
|
51
|
-
|
|
52
|
-
AdminSuite ships with:
|
|
53
|
-
|
|
54
|
-
- A small baseline stylesheet (`admin_suite.css`)
|
|
55
|
-
- A compiled Tailwind stylesheet (`admin_suite_tailwind.css`) that is built into the host app at asset precompile time
|
|
56
|
-
- Engine-provided Stimulus controllers via importmap
|
|
57
|
-
|
|
58
|
-
### CSS build behavior
|
|
59
|
-
|
|
60
|
-
When your app runs `assets:precompile`, AdminSuite automatically runs:
|
|
61
|
-
|
|
62
|
-
- `admin_suite:tailwind:build` → writes `app/assets/builds/admin_suite_tailwind.css` in your **host app**
|
|
63
|
-
|
|
64
|
-
So in production you typically just need to ensure your deployment runs `assets:precompile` as usual.
|
|
65
|
-
|
|
66
|
-
### Host stylesheet overrides (optional)
|
|
67
|
-
|
|
68
|
-
If your app already uses Tailwind (or you want custom branding), you can include your app stylesheet after AdminSuite:
|
|
69
|
-
|
|
70
|
-
- Set `config.host_stylesheet` (see [Theming & assets](theming.md))
|
|
71
|
-
|
|
72
|
-
## Routes and URLs
|
|
73
|
-
|
|
74
|
-
Assuming you mounted at `/internal/admin`:
|
|
75
|
-
|
|
76
|
-
- `/internal/admin` → AdminSuite dashboard
|
|
77
|
-
- `/internal/admin/docs` → docs viewer (optional)
|
|
78
|
-
- `/internal/admin/:portal` → portal dashboard (optional)
|
|
79
|
-
- `/internal/admin/:portal/:resource_name` → resource index
|
|
80
|
-
|
data/docs/portals.md
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# Portals & dashboards
|
|
2
|
-
|
|
3
|
-
AdminSuite navigation is organized by **portal** and **section**:
|
|
4
|
-
|
|
5
|
-
- A **portal** is the top-level grouping (e.g. `:ops`, `:ai`)
|
|
6
|
-
- A **section** is a grouping within a portal (e.g. `:billing`, `:users`)
|
|
7
|
-
- A **resource** belongs to exactly one portal + section via the resource DSL
|
|
8
|
-
|
|
9
|
-
You can configure portals in two complementary ways:
|
|
10
|
-
|
|
11
|
-
1. **Portal metadata** via `AdminSuite.config.portals` (label/icon/color/order)
|
|
12
|
-
2. **Portal DSL** via `AdminSuite.portal(:key) { ... }` (metadata + dashboard layout)
|
|
13
|
-
|
|
14
|
-
## Portal metadata (`config.portals`)
|
|
15
|
-
|
|
16
|
-
```ruby
|
|
17
|
-
AdminSuite.configure do |config|
|
|
18
|
-
config.portals = {
|
|
19
|
-
ops: { label: "Ops", icon: "settings", color: :amber, order: 10 },
|
|
20
|
-
ai: { label: "AI", icon: "cpu", color: :cyan, order: 20 }
|
|
21
|
-
}
|
|
22
|
-
end
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### Portal fields
|
|
26
|
-
|
|
27
|
-
- `label` (String): display label
|
|
28
|
-
- `icon` (String/Symbol): lucide icon name (e.g. `"settings"`)
|
|
29
|
-
- `color` (Symbol/String): used for accents (`:amber`, `:emerald`, `:cyan`, `:violet`, `:slate`)
|
|
30
|
-
- `order` (Integer): sort order in the root dashboard and sidebar
|
|
31
|
-
- `description` (String, optional): shown on the root dashboard cards when present
|
|
32
|
-
|
|
33
|
-
## Portal DSL (`AdminSuite.portal`)
|
|
34
|
-
|
|
35
|
-
Portal DSL files are loaded from `AdminSuite.config.portal_globs` (defaults include
|
|
36
|
-
`config/admin_suite/portals/*.rb`, `app/admin/portals/*.rb`, `app/admin_suite/portals/*.rb`).
|
|
37
|
-
|
|
38
|
-
Example file:
|
|
39
|
-
|
|
40
|
-
```ruby
|
|
41
|
-
# config/admin_suite/portals/ops.rb
|
|
42
|
-
AdminSuite.portal :ops do
|
|
43
|
-
label "Ops Portal"
|
|
44
|
-
icon "settings"
|
|
45
|
-
color :amber
|
|
46
|
-
order 10
|
|
47
|
-
description "Operational tools and internal resources."
|
|
48
|
-
|
|
49
|
-
dashboard do
|
|
50
|
-
row do
|
|
51
|
-
stat_panel "New users (24h)", -> { User.where("created_at > ?", 24.hours.ago).count }, color: :emerald, span: 3
|
|
52
|
-
stat_panel "Failed jobs", -> { SolidQueue::FailedExecution.count }, color: :red, span: 3
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
row do
|
|
56
|
-
recent_panel "Recent signups", scope: -> { User.order(created_at: :desc).limit(5) }, span: 6
|
|
57
|
-
table_panel "Queue summary",
|
|
58
|
-
rows: -> { SolidQueue::Job.order(created_at: :desc).limit(10) },
|
|
59
|
-
columns: %i[id class_name created_at],
|
|
60
|
-
span: 6
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Dashboard DSL
|
|
67
|
-
|
|
68
|
-
The dashboard DSL is available inside `portal.dashboard do ... end`.
|
|
69
|
-
|
|
70
|
-
- `dashboard` contains `row { ... }`
|
|
71
|
-
- each `row` contains one or more `panel(...)` calls
|
|
72
|
-
|
|
73
|
-
### Panel helpers
|
|
74
|
-
|
|
75
|
-
These are convenience helpers that all create a `panel` under the hood:
|
|
76
|
-
|
|
77
|
-
- `stat_panel(title, value=nil, span: nil, **options, &block)`
|
|
78
|
-
- `health_panel(title, status: nil, metrics: nil, span: nil, **options, &block)`
|
|
79
|
-
- `chart_panel(title, data: nil, span: nil, **options, &block)`
|
|
80
|
-
- `cards_panel(title, resources: nil, span: nil, **options, &block)`
|
|
81
|
-
- `recent_panel(title, scope: nil, link: nil, span: nil, **options, &block)`
|
|
82
|
-
- `table_panel(title, rows: nil, columns: nil, span: nil, **options, &block)`
|
|
83
|
-
|
|
84
|
-
### `span`
|
|
85
|
-
|
|
86
|
-
`span` controls width in a 12-column grid. Typical values: `3`, `4`, `6`, `12`.
|
|
87
|
-
|
|
88
|
-
## Portal pages
|
|
89
|
-
|
|
90
|
-
Once mounted, portal pages are served at:
|
|
91
|
-
|
|
92
|
-
- `/:portal` (relative to the mount path)
|
|
93
|
-
|
|
94
|
-
Example:
|
|
95
|
-
|
|
96
|
-
- `/internal/admin/ops`
|
|
97
|
-
- `/internal/admin/ai`
|
|
98
|
-
|
|
99
|
-
## Root dashboard (`AdminSuite.root_dashboard`)
|
|
100
|
-
|
|
101
|
-
The engine root (`/`, relative to the mount path) renders a default dashboard (portal cards + basic stats).
|
|
102
|
-
|
|
103
|
-
To customize it, create a dashboard definition file (loaded from `AdminSuite.config.dashboard_globs`, which defaults to paths like `config/admin_suite/dashboard.rb` and `app/admin_suite/dashboard.rb`):
|
|
104
|
-
|
|
105
|
-
```ruby
|
|
106
|
-
# config/admin_suite/dashboard.rb
|
|
107
|
-
AdminSuite.configure do |config|
|
|
108
|
-
config.root_dashboard_title = "Developer Portal"
|
|
109
|
-
config.root_dashboard_description = "Internal tools for managing application resources."
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
AdminSuite.root_dashboard do
|
|
113
|
-
row do
|
|
114
|
-
cards_panel "Portals",
|
|
115
|
-
span: 12,
|
|
116
|
-
variant: :portals,
|
|
117
|
-
resources: ->(view) do
|
|
118
|
-
view.navigation_items
|
|
119
|
-
.sort_by { |(_k, meta)| (meta[:order] || 100).to_i }
|
|
120
|
-
.map do |portal_key, portal|
|
|
121
|
-
{
|
|
122
|
-
key: portal_key,
|
|
123
|
-
label: portal[:label] || portal_key.to_s.humanize,
|
|
124
|
-
description: portal[:description],
|
|
125
|
-
color: view.portal_color(portal_key),
|
|
126
|
-
icon: portal[:icon],
|
|
127
|
-
path: view.portal_path(portal: portal_key),
|
|
128
|
-
count: (portal[:sections] || {}).values.sum { |s| Array(s[:items]).size }
|
|
129
|
-
}
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
row do
|
|
135
|
-
stat_panel "Portals", ->(view) { view.navigation_items.keys.count }, span: 6, variant: :mini, color: :slate
|
|
136
|
-
stat_panel "Resources", -> { Admin::Base::Resource.registered_resources.count }, span: 6, variant: :mini, color: :slate
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
```
|
|
140
|
-
|
data/docs/releasing.md
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
# Releasing
|
|
2
|
-
|
|
3
|
-
This page is intended for maintainers publishing `admin_suite` to RubyGems.
|
|
4
|
-
|
|
5
|
-
## Automated Release Process (Recommended)
|
|
6
|
-
|
|
7
|
-
The gem is automatically published to RubyGems when changes are merged to `main`, provided the version has been bumped.
|
|
8
|
-
|
|
9
|
-
### Steps
|
|
10
|
-
|
|
11
|
-
1. **Bump the version**
|
|
12
|
-
- Update `lib/admin_suite/version.rb`
|
|
13
|
-
|
|
14
|
-
2. **Update changelog**
|
|
15
|
-
- Add an entry to `CHANGELOG.md`
|
|
16
|
-
|
|
17
|
-
3. **Create a PR and get it merged**
|
|
18
|
-
- The CI workflow will run tests automatically on the PR
|
|
19
|
-
- Once merged to `main`, after CI passes, the publish workflow will:
|
|
20
|
-
- Check if the version already exists on RubyGems
|
|
21
|
-
- Build and publish the gem (if it's a new version)
|
|
22
|
-
- Create a Git tag for the release (if it doesn't already exist)
|
|
23
|
-
- Create a GitHub Release with notes extracted from `CHANGELOG.md`, or auto-generated from commits since the previous tag if no CHANGELOG entry exists
|
|
24
|
-
|
|
25
|
-
### Requirements
|
|
26
|
-
|
|
27
|
-
- The `RUBYGEMS_API_KEY` secret must be configured in the repository settings
|
|
28
|
-
- The version in `lib/admin_suite/version.rb` must be unique (not already published)
|
|
29
|
-
|
|
30
|
-
## Manual Release Process
|
|
31
|
-
|
|
32
|
-
If you need to publish manually:
|
|
33
|
-
|
|
34
|
-
1. Bump the version
|
|
35
|
-
- Update `lib/admin_suite/version.rb`
|
|
36
|
-
|
|
37
|
-
2. Update changelog
|
|
38
|
-
- Add an entry to `CHANGELOG.md`
|
|
39
|
-
|
|
40
|
-
3. Run tests and build the gem
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
bundle exec rake test
|
|
44
|
-
gem build admin_suite.gemspec
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
4. Tag the release
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
git tag -a "vX.Y.Z" -m "AdminSuite vX.Y.Z"
|
|
51
|
-
git push --tags
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
5. Publish to RubyGems
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
gem push "admin_suite-X.Y.Z.gem"
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Notes
|
|
61
|
-
|
|
62
|
-
- RubyGems commonly requires MFA/OTP for pushes (this gem is configured with `rubygems_mfa_required`)
|
|
63
|
-
- The automated workflow uses a GitHub Actions bot to push tags and create GitHub Releases
|
|
64
|
-
- The publish workflow only runs after the CI workflow completes successfully
|
|
65
|
-
- GitHub Release notes are sourced from the matching version section in `CHANGELOG.md`; if no entry exists, they are auto-generated from commits since the previous tag; a plain "Release vX.Y.Z" string is used only as a final fallback when no previous tag or commit-generated notes are available
|
|
66
|
-
- You can manually trigger the publish workflow from the GitHub Actions tab if needed
|
|
67
|
-
|
data/docs/resources.md
DELETED
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
# Resources
|
|
2
|
-
|
|
3
|
-
Resources are defined using `Admin::Base::Resource`.
|
|
4
|
-
|
|
5
|
-
AdminSuite loads resource definition files from `AdminSuite.config.resource_globs`
|
|
6
|
-
(defaults include `config/admin_suite/resources/*.rb` and `app/admin/resources/*.rb`).
|
|
7
|
-
|
|
8
|
-
## Create a resource
|
|
9
|
-
|
|
10
|
-
A resource is a Ruby class under `Admin::Resources` ending in `Resource`.
|
|
11
|
-
|
|
12
|
-
Example:
|
|
13
|
-
|
|
14
|
-
```ruby
|
|
15
|
-
# config/admin_suite/resources/user.rb
|
|
16
|
-
module Admin
|
|
17
|
-
module Resources
|
|
18
|
-
class UserResource < Admin::Base::Resource
|
|
19
|
-
model ::User
|
|
20
|
-
portal :ops
|
|
21
|
-
section :accounts
|
|
22
|
-
|
|
23
|
-
nav label: "Users", icon: "users", order: 10
|
|
24
|
-
|
|
25
|
-
index do
|
|
26
|
-
searchable :email, :name
|
|
27
|
-
sortable :created_at, :email, default: :created_at, direction: :desc
|
|
28
|
-
paginate 50
|
|
29
|
-
|
|
30
|
-
columns do
|
|
31
|
-
column :id
|
|
32
|
-
column :email
|
|
33
|
-
column :created_at
|
|
34
|
-
column :admin, type: :toggle, toggle_field: :admin, header: "Admin?"
|
|
35
|
-
column :status, type: :label, label_color: ->(u) { u.active? ? :emerald : :slate }, label_size: :sm
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
filters do
|
|
39
|
-
filter :search, type: :text, placeholder: "Search users..."
|
|
40
|
-
filter :status, type: :select, options: [["Active", "active"], ["Inactive", "inactive"]]
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
stats do
|
|
44
|
-
stat :total, -> { User.count }, color: :slate
|
|
45
|
-
stat :new_24h, -> { User.where("created_at > ?", 24.hours.ago).count }, color: :emerald
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
form do
|
|
50
|
-
section "Basics", description: "Core account fields" do
|
|
51
|
-
field :email, type: :email, required: true
|
|
52
|
-
field :name, required: true
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
row cols: 2 do
|
|
56
|
-
field :admin, type: :toggle, help: "Grants access to internal tools."
|
|
57
|
-
field :status, type: :select, collection: [["Active", "active"], ["Inactive", "inactive"]]
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
show do
|
|
62
|
-
main do
|
|
63
|
-
panel :details, title: "User details", fields: %i[email name status created_at]
|
|
64
|
-
panel :activity, title: "Activity", render: :custom_activity_timeline
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
sidebar do
|
|
68
|
-
panel :summary, title: "Summary", fields: %i[id admin]
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
actions do
|
|
73
|
-
action :reset_password, label: "Reset password", icon: "key", confirm: "Send reset email?"
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Core DSL
|
|
81
|
-
|
|
82
|
-
### Model
|
|
83
|
-
|
|
84
|
-
```ruby
|
|
85
|
-
model ::User
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### Navigation placement
|
|
89
|
-
|
|
90
|
-
```ruby
|
|
91
|
-
portal :ops
|
|
92
|
-
section :accounts
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
These determine:
|
|
96
|
-
|
|
97
|
-
- URL: `/:portal/:resource_name`
|
|
98
|
-
- Sidebar placement: portal group → section group → resource link
|
|
99
|
-
|
|
100
|
-
### Navigation metadata
|
|
101
|
-
|
|
102
|
-
```ruby
|
|
103
|
-
nav label: "Users", icon: "users", order: 10
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Also available as convenience setters:
|
|
107
|
-
|
|
108
|
-
```ruby
|
|
109
|
-
label "Users"
|
|
110
|
-
icon "users"
|
|
111
|
-
order 10
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Index DSL (`index do ... end`)
|
|
115
|
-
|
|
116
|
-
### Search
|
|
117
|
-
|
|
118
|
-
```ruby
|
|
119
|
-
searchable :name, :email
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Search uses `ILIKE` across the configured fields.
|
|
123
|
-
|
|
124
|
-
### Sort
|
|
125
|
-
|
|
126
|
-
```ruby
|
|
127
|
-
sortable :created_at, :email, default: :created_at, direction: :desc
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Pagination
|
|
131
|
-
|
|
132
|
-
```ruby
|
|
133
|
-
paginate 25
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### Columns
|
|
137
|
-
|
|
138
|
-
```ruby
|
|
139
|
-
columns do
|
|
140
|
-
column :email
|
|
141
|
-
column :job_listings, ->(u) { u.job_listings.count }
|
|
142
|
-
end
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
`column` options:
|
|
146
|
-
|
|
147
|
-
- `header:` string (defaults to a humanized name)
|
|
148
|
-
- `class:` css class for the cell
|
|
149
|
-
- `render:` custom render key (advanced)
|
|
150
|
-
- `type:` `:toggle` or `:label` (special rendering)
|
|
151
|
-
- `toggle_field:` field to flip when `type: :toggle`
|
|
152
|
-
- `label_color:` color for `type: :label` (Symbol or Proc)
|
|
153
|
-
- `label_size:` `:sm`/`:md` (or Proc)
|
|
154
|
-
- `sortable:` boolean (reserved for future per-column sorting UI)
|
|
155
|
-
|
|
156
|
-
### Filters
|
|
157
|
-
|
|
158
|
-
```ruby
|
|
159
|
-
filters do
|
|
160
|
-
filter :status, type: :select, options: [["Active", "active"], ["Inactive", "inactive"]]
|
|
161
|
-
end
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
Filter options:
|
|
165
|
-
|
|
166
|
-
- `type:` (default `:text`)
|
|
167
|
-
- `label:`
|
|
168
|
-
- `placeholder:`
|
|
169
|
-
- `options:` / `collection:` (for select-like UI)
|
|
170
|
-
- `field:` which model field to filter on (defaults to the filter name)
|
|
171
|
-
- `apply:` Proc that receives the scope (advanced)
|
|
172
|
-
|
|
173
|
-
### Stats
|
|
174
|
-
|
|
175
|
-
```ruby
|
|
176
|
-
stats do
|
|
177
|
-
stat :total, -> { User.count }, color: :slate
|
|
178
|
-
end
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
## Form DSL (`form do ... end`)
|
|
182
|
-
|
|
183
|
-
```ruby
|
|
184
|
-
form do
|
|
185
|
-
field :name, required: true
|
|
186
|
-
field :website, type: :url
|
|
187
|
-
end
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
See [Fields](fields.md) for supported types and options.
|
|
191
|
-
|
|
192
|
-
AdminSuite also supports basic layout helpers in forms:
|
|
193
|
-
|
|
194
|
-
- `section "Title" do ... end`
|
|
195
|
-
- `row cols: 2 do ... end`
|
|
196
|
-
|
|
197
|
-
## Show DSL (`show do ... end`)
|
|
198
|
-
|
|
199
|
-
Show is section-based. Sections can live in the main column or sidebar.
|
|
200
|
-
|
|
201
|
-
```ruby
|
|
202
|
-
show do
|
|
203
|
-
main do
|
|
204
|
-
panel :details, title: "Details", fields: %i[name email]
|
|
205
|
-
panel :related, title: "Projects", association: :projects, display: :table, columns: %i[id name status], paginate: true
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
sidebar do
|
|
209
|
-
panel :meta, title: "Meta", fields: %i[id created_at updated_at]
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Panel options:
|
|
215
|
-
|
|
216
|
-
- `title:` (defaults to a humanized name)
|
|
217
|
-
- `fields:` array of field names to display
|
|
218
|
-
- `render:` custom renderer key (see `custom_renderers` in [Configuration](configuration.md))
|
|
219
|
-
- `association:` association name to render (`has_many`, `belongs_to`, etc.)
|
|
220
|
-
- `display:` `:list` (default), `:table`, or `:cards` for associations
|
|
221
|
-
- `columns:` columns for association `:table` display
|
|
222
|
-
- `link_to:` helper method name to build links for association items (optional)
|
|
223
|
-
- `paginate:` boolean, enables pagination within the association section
|
|
224
|
-
- `per_page:` items per page for association pagination
|
|
225
|
-
- `limit:` max items (if not paginating)
|
|
226
|
-
- `collapsible:` / `collapsed:` (reserved for future UI toggles)
|
|
227
|
-
|
|
228
|
-
## Actions DSL (`actions do ... end`)
|
|
229
|
-
|
|
230
|
-
```ruby
|
|
231
|
-
actions do
|
|
232
|
-
action :reindex, label: "Reindex", method: :post, confirm: "Reindex this record?"
|
|
233
|
-
end
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
See [Actions](actions.md) for how actions execute and how to define handlers.
|
|
237
|
-
|
data/docs/theming.md
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
# Theming & assets
|
|
2
|
-
|
|
3
|
-
AdminSuite is designed to work in two modes:
|
|
4
|
-
|
|
5
|
-
1. **Engine-build mode (default)**: AdminSuite builds and ships its own Tailwind CSS into your host app at `assets:precompile` time.
|
|
6
|
-
2. **Host-themed mode (optional)**: your host app includes a stylesheet after AdminSuite for branding/overrides.
|
|
7
|
-
|
|
8
|
-
## Theme colors (`config.theme`)
|
|
9
|
-
|
|
10
|
-
AdminSuite uses CSS variables scoped to `body.admin-suite`.
|
|
11
|
-
|
|
12
|
-
```ruby
|
|
13
|
-
AdminSuite.configure do |config|
|
|
14
|
-
config.theme = { primary: :emerald, secondary: :cyan }
|
|
15
|
-
end
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
### Allowed values
|
|
19
|
-
|
|
20
|
-
- **Named colors**: symbols/strings like `:indigo`, `:emerald`, `:cyan`, `:amber`, `:violet`, `:slate`, etc.
|
|
21
|
-
- **Hex**: `"#4f46e5"` (uses that exact color as primary/secondary in key places)
|
|
22
|
-
|
|
23
|
-
The theme primarily drives:
|
|
24
|
-
|
|
25
|
-
- Primary links/buttons (`--admin-suite-primary`, `--admin-suite-primary-hover`)
|
|
26
|
-
- Sidebar gradient (`--admin-suite-sidebar-from/via/to`)
|
|
27
|
-
|
|
28
|
-
## Host stylesheet (`config.host_stylesheet`)
|
|
29
|
-
|
|
30
|
-
If your host app already has Tailwind (or you want to override the engine UI), you can include an additional stylesheet after AdminSuite in the engine layout:
|
|
31
|
-
|
|
32
|
-
```ruby
|
|
33
|
-
AdminSuite.configure do |config|
|
|
34
|
-
config.host_stylesheet = :app
|
|
35
|
-
end
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
This calls `stylesheet_link_tag :app` after `admin_suite.css` and `admin_suite_tailwind.css`.
|
|
39
|
-
|
|
40
|
-
## Tailwind build
|
|
41
|
-
|
|
42
|
-
AdminSuite writes an engine stylesheet into your host app during `assets:precompile`:
|
|
43
|
-
|
|
44
|
-
- Input: `AdminSuite::Engine.root/app/assets/tailwind/admin_suite.css`
|
|
45
|
-
- Output: `Rails.root/app/assets/builds/admin_suite_tailwind.css`
|
|
46
|
-
|
|
47
|
-
In development, the engine also makes a best-effort to create the output file if it’s missing, so the UI stays usable.
|
|
48
|
-
|
|
49
|
-
## Icons
|
|
50
|
-
|
|
51
|
-
AdminSuite uses lucide icons by default via `lucide-rails`.
|
|
52
|
-
|
|
53
|
-
If you need a different icon provider:
|
|
54
|
-
|
|
55
|
-
```ruby
|
|
56
|
-
AdminSuite.configure do |config|
|
|
57
|
-
config.icon_renderer = ->(name, view, **opts) do
|
|
58
|
-
# return HTML-safe SVG (string or ActiveSupport::SafeBuffer)
|
|
59
|
-
view.content_tag(:span, name, class: opts[:class])
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
```
|
|
63
|
-
|
data/docs/troubleshooting.md
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Troubleshooting
|
|
2
|
-
|
|
3
|
-
## “My resources don’t show up in the sidebar”
|
|
4
|
-
|
|
5
|
-
Checklist:
|
|
6
|
-
|
|
7
|
-
- Your resource class:
|
|
8
|
-
- is under `Admin::Resources`
|
|
9
|
-
- ends with `Resource` (e.g. `UserResource`)
|
|
10
|
-
- sets both `portal :...` and `section :...`
|
|
11
|
-
- The file is located under one of the configured `resource_globs` paths (see [Configuration](configuration.md)).
|
|
12
|
-
|
|
13
|
-
In development, AdminSuite loads resources on-demand when building navigation. In non-development environments, you should ensure your resource files are loaded at boot (using the globs) and are not excluded by your deployment setup.
|
|
14
|
-
|
|
15
|
-
## “Constant not found” / Zeitwerk errors for host DSL files
|
|
16
|
-
|
|
17
|
-
If you store AdminSuite DSL files under `app/admin_suite/**` in the host app, those files are not constant definitions.
|
|
18
|
-
|
|
19
|
-
AdminSuite ignores `Rails.root/app/admin_suite` in Zeitwerk to prevent eager-load errors. If you still see issues:
|
|
20
|
-
|
|
21
|
-
- Ensure the DSL folder really is `app/admin_suite` (not a different path)
|
|
22
|
-
- Prefer `config/admin_suite/resources/*.rb` and `config/admin_suite/portals/*.rb` for DSL files
|
|
23
|
-
|
|
24
|
-
## “Docs viewer shows no files”
|
|
25
|
-
|
|
26
|
-
- Confirm `AdminSuite.config.docs_path` exists
|
|
27
|
-
- Ensure files are `*.md`
|
|
28
|
-
- Visit `/docs` relative to your mount path (e.g. `/internal/admin/docs`)
|
|
29
|
-
|
|
30
|
-
## “Tailwind styles are missing in production”
|
|
31
|
-
|
|
32
|
-
AdminSuite expects `assets:precompile` to run and generate:
|
|
33
|
-
|
|
34
|
-
- `app/assets/builds/admin_suite_tailwind.css` in your host app
|
|
35
|
-
|
|
36
|
-
If you don’t run precompile in your deployment pipeline, you can:
|
|
37
|
-
|
|
38
|
-
- Start running `assets:precompile`, or
|
|
39
|
-
- Build the file manually by running:
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
bin/rails admin_suite:tailwind:build
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## “Icons don’t render”
|
|
46
|
-
|
|
47
|
-
AdminSuite defaults to `lucide-rails`.
|
|
48
|
-
|
|
49
|
-
If your host app excludes it, set `AdminSuite.config.icon_renderer` to provide icons (see [Theming & assets](theming.md)).
|
|
50
|
-
|