admin_suite 0.2.8 → 0.3.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 +38 -1
- data/CONTRIBUTING.md +2 -2
- data/Gemfile +3 -0
- data/README.md +10 -24
- data/app/controllers/admin_suite/application_controller.rb +53 -11
- data/app/controllers/admin_suite/resources_controller.rb +63 -9
- 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/auth/host_hook.rb +25 -0
- data/lib/admin_suite/auth/http_basic.rb +46 -0
- data/lib/admin_suite/auth/strategy.rb +25 -0
- data/lib/admin_suite/auth.rb +33 -0
- data/lib/admin_suite/configuration.rb +8 -0
- data/lib/admin_suite/ui/show_value_formatter.rb +2 -2
- data/lib/admin_suite/version.rb +1 -1
- data/lib/admin_suite.rb +16 -0
- data/lib/generators/admin_suite/install/templates/admin_suite.rb +24 -7
- data/test/controllers/resources_controller_test.rb +80 -0
- data/test/dummy/config/initializers/admin_suite_auth.rb +8 -0
- data/test/integration/authentication_test.rb +99 -0
- data/test/integration/authorization_test.rb +131 -0
- data/test/integration/read_only_resource_test.rb +130 -0
- data/test/lib/auth_http_basic_test.rb +62 -0
- data/test/lib/auth_resolution_test.rb +75 -0
- data/test/lib/auth_test.rb +29 -0
- data/test/lib/resource_observability_extensions_test.rb +53 -0
- data/test/test_helper.rb +43 -0
- metadata +15 -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/docs_viewer.md
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# Docs viewer
|
|
2
|
-
|
|
3
|
-
AdminSuite includes a built-in docs viewer at:
|
|
4
|
-
|
|
5
|
-
- `/docs` (relative to the mount path)
|
|
6
|
-
|
|
7
|
-
It renders Markdown (`.md`) files from a folder on your host app filesystem.
|
|
8
|
-
|
|
9
|
-
## Quick start
|
|
10
|
-
|
|
11
|
-
1. Create `docs/` in your host app:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
mkdir -p docs
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
2. Add a markdown file:
|
|
18
|
-
|
|
19
|
-
```md
|
|
20
|
-
<!-- docs/getting_started.md -->
|
|
21
|
-
# Getting started
|
|
22
|
-
|
|
23
|
-
Hello from AdminSuite docs.
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
3. Visit:
|
|
27
|
-
|
|
28
|
-
- `/internal/admin/docs`
|
|
29
|
-
|
|
30
|
-
## Configuring the docs root (`config.docs_path`)
|
|
31
|
-
|
|
32
|
-
By default:
|
|
33
|
-
|
|
34
|
-
- `AdminSuite.config.docs_path = Rails.root.join("docs")`
|
|
35
|
-
|
|
36
|
-
You can point it somewhere else:
|
|
37
|
-
|
|
38
|
-
```ruby
|
|
39
|
-
AdminSuite.configure do |config|
|
|
40
|
-
config.docs_path = Rails.root.join("admin_docs")
|
|
41
|
-
end
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Or compute per-request:
|
|
45
|
-
|
|
46
|
-
```ruby
|
|
47
|
-
AdminSuite.configure do |config|
|
|
48
|
-
config.docs_path = ->(_controller) { Rails.root.join("docs") }
|
|
49
|
-
end
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Sidebar “Docs” link (`config.docs_url`)
|
|
53
|
-
|
|
54
|
-
If you want a persistent docs link in the AdminSuite sidebar, set:
|
|
55
|
-
|
|
56
|
-
```ruby
|
|
57
|
-
AdminSuite.configure do |config|
|
|
58
|
-
config.docs_url = "/internal/admin/docs"
|
|
59
|
-
end
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
This can also point to external docs.
|
|
63
|
-
|
|
64
|
-
## Organization
|
|
65
|
-
|
|
66
|
-
Docs are grouped by their first folder name. For example:
|
|
67
|
-
|
|
68
|
-
- `docs/ops/runbooks.md` → group “Ops”
|
|
69
|
-
- `docs/api/authentication.md` → group “API”
|
|
70
|
-
- `docs/getting_started.md` → group “Docs”
|
|
71
|
-
|
|
72
|
-
## Security notes
|
|
73
|
-
|
|
74
|
-
The docs viewer defends against path traversal:
|
|
75
|
-
|
|
76
|
-
- Rejects any path containing `..`
|
|
77
|
-
- Requires a `.md` extension
|
|
78
|
-
- Resolves realpaths and ensures the requested file stays under the docs root
|
|
79
|
-
|
data/docs/fields.md
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
# Fields
|
|
2
|
-
|
|
3
|
-
Fields are defined in the resource `form do ... end` block:
|
|
4
|
-
|
|
5
|
-
```ruby
|
|
6
|
-
form do
|
|
7
|
-
field :name
|
|
8
|
-
field :status, type: :select, collection: [["Active", "active"], ["Inactive", "inactive"]]
|
|
9
|
-
end
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
## Common options
|
|
13
|
-
|
|
14
|
-
All fields support:
|
|
15
|
-
|
|
16
|
-
- `type:` (defaults to `:text`)
|
|
17
|
-
- `required:` (`true/false`)
|
|
18
|
-
- `label:` (String)
|
|
19
|
-
- `help:` (String)
|
|
20
|
-
- `placeholder:` (String)
|
|
21
|
-
- `readonly:` (`true/false`)
|
|
22
|
-
- `if:` Proc (render only if truthy)
|
|
23
|
-
- `unless:` Proc (render only if falsy)
|
|
24
|
-
|
|
25
|
-
Example conditional field:
|
|
26
|
-
|
|
27
|
-
```ruby
|
|
28
|
-
field :admin_notes, type: :textarea, if: ->(record) { record.admin? }
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Supported field types
|
|
32
|
-
|
|
33
|
-
### Text-like
|
|
34
|
-
|
|
35
|
-
- `:text` (default)
|
|
36
|
-
- `:textarea` (`rows:` supported)
|
|
37
|
-
- `:email`
|
|
38
|
-
- `:url`
|
|
39
|
-
- `:number`
|
|
40
|
-
- `:date`
|
|
41
|
-
- `:time`
|
|
42
|
-
- `:datetime`
|
|
43
|
-
|
|
44
|
-
### Toggle
|
|
45
|
-
|
|
46
|
-
- `:toggle` (renders a switch)
|
|
47
|
-
|
|
48
|
-
```ruby
|
|
49
|
-
field :enabled, type: :toggle
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Select
|
|
53
|
-
|
|
54
|
-
- `:select` (uses Rails `select`)
|
|
55
|
-
|
|
56
|
-
Options:
|
|
57
|
-
|
|
58
|
-
- `collection:` Array of `[label, value]` or simple values
|
|
59
|
-
|
|
60
|
-
```ruby
|
|
61
|
-
field :status, type: :select, collection: [["Active", "active"], ["Inactive", "inactive"]]
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Searchable select
|
|
65
|
-
|
|
66
|
-
- `:searchable_select` (Stimulus-powered searchable dropdown)
|
|
67
|
-
|
|
68
|
-
Options:
|
|
69
|
-
|
|
70
|
-
- `collection:` either:
|
|
71
|
-
- an Array (static options), or
|
|
72
|
-
- a String URL (advanced; used by the JS controller as a “search URL”)
|
|
73
|
-
- `create_url:` (String) enables “creatable” behavior in the UI
|
|
74
|
-
|
|
75
|
-
```ruby
|
|
76
|
-
field :company_id,
|
|
77
|
-
type: :searchable_select,
|
|
78
|
-
collection: Company.order(:name).pluck(:name, :id),
|
|
79
|
-
placeholder: "Search companies..."
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Multi-select & tags
|
|
83
|
-
|
|
84
|
-
- `:multi_select`
|
|
85
|
-
- `:tags`
|
|
86
|
-
|
|
87
|
-
Options:
|
|
88
|
-
|
|
89
|
-
- `collection:` Array of options (used for suggestions)
|
|
90
|
-
- `create_url:` enables “creatable” behavior
|
|
91
|
-
- `multiple:` boolean (reserved; arrays are permitted automatically)
|
|
92
|
-
|
|
93
|
-
Notes:
|
|
94
|
-
|
|
95
|
-
- These submit arrays and are permitted automatically by AdminSuite.
|
|
96
|
-
- For `:tags`, AdminSuite uses a `tag_list` parameter by default (or `#{field_name}_list` if your model exposes it).
|
|
97
|
-
|
|
98
|
-
```ruby
|
|
99
|
-
field :tag_list, type: :tags, placeholder: "Add tags..."
|
|
100
|
-
field :roles, type: :multi_select, collection: %w[admin editor viewer]
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### File uploads / attachments
|
|
104
|
-
|
|
105
|
-
- `:file`
|
|
106
|
-
- `:attachment`
|
|
107
|
-
- `:image`
|
|
108
|
-
|
|
109
|
-
Options:
|
|
110
|
-
|
|
111
|
-
- `accept:` MIME accept string (e.g. `"image/*"`, `"application/pdf"`)
|
|
112
|
-
|
|
113
|
-
These assume your host app uses **Active Storage**.
|
|
114
|
-
|
|
115
|
-
```ruby
|
|
116
|
-
field :avatar, type: :image, accept: "image/*"
|
|
117
|
-
field :resume, type: :file, accept: "application/pdf"
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### Rich text
|
|
121
|
-
|
|
122
|
-
- `:trix`
|
|
123
|
-
- `:rich_text`
|
|
124
|
-
|
|
125
|
-
These assume your host app uses **Action Text**.
|
|
126
|
-
|
|
127
|
-
```ruby
|
|
128
|
-
field :bio, type: :rich_text
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### Markdown
|
|
132
|
-
|
|
133
|
-
- `:markdown` (textarea enhanced by EasyMDE via CDN in the engine layout)
|
|
134
|
-
|
|
135
|
-
```ruby
|
|
136
|
-
field :prompt_template, type: :markdown, rows: 16
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### JSON editor
|
|
140
|
-
|
|
141
|
-
- `:json` (renders the engine’s JSON editor partial)
|
|
142
|
-
|
|
143
|
-
```ruby
|
|
144
|
-
field :settings, type: :json
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Code editor
|
|
148
|
-
|
|
149
|
-
- `:code` (monospace editor container; enhanced by engine JS)
|
|
150
|
-
|
|
151
|
-
```ruby
|
|
152
|
-
field :ruby_code, type: :code, rows: 20
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### Label (read-only)
|
|
156
|
-
|
|
157
|
-
- `:label` renders a badge-like value (useful for status fields)
|
|
158
|
-
|
|
159
|
-
Options:
|
|
160
|
-
|
|
161
|
-
- `label_color:` Symbol or Proc
|
|
162
|
-
- `label_size:` `:sm`/`:md` or Proc
|
|
163
|
-
|
|
164
|
-
```ruby
|
|
165
|
-
field :status, type: :label, label_color: ->(r) { r.active? ? :emerald : :slate }, label_size: :sm
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
## Layout helpers
|
|
169
|
-
|
|
170
|
-
Inside `form do ... end` you can group fields:
|
|
171
|
-
|
|
172
|
-
### `section`
|
|
173
|
-
|
|
174
|
-
```ruby
|
|
175
|
-
section "Billing", description: "Payment settings", collapsible: true do
|
|
176
|
-
field :stripe_customer_id, readonly: true
|
|
177
|
-
end
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### `row`
|
|
181
|
-
|
|
182
|
-
```ruby
|
|
183
|
-
row cols: 2 do
|
|
184
|
-
field :first_name
|
|
185
|
-
field :last_name
|
|
186
|
-
end
|
|
187
|
-
```
|
|
188
|
-
|
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
|
-
|