plutonium 0.23.4 → 0.23.5
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/app/assets/plutonium.css +2 -2
- data/config/initializers/sqlite_json_alias.rb +1 -1
- data/docs/.vitepress/config.ts +60 -19
- data/docs/guide/cursor-rules.md +75 -0
- data/docs/guide/deep-dive/authorization.md +189 -0
- data/docs/guide/{getting-started → deep-dive}/resources.md +137 -0
- data/docs/guide/getting-started/{installation.md → 01-installation.md} +0 -105
- data/docs/guide/index.md +28 -0
- data/docs/guide/introduction/02-core-concepts.md +440 -0
- data/docs/guide/tutorial/01-project-setup.md +75 -0
- data/docs/guide/tutorial/02-creating-a-feature-package.md +45 -0
- data/docs/guide/tutorial/03-defining-resources.md +90 -0
- data/docs/guide/tutorial/04-creating-a-portal.md +101 -0
- data/docs/guide/tutorial/05-customizing-the-ui.md +128 -0
- data/docs/guide/tutorial/06-adding-custom-actions.md +101 -0
- data/docs/guide/tutorial/07-implementing-authorization.md +90 -0
- data/docs/index.md +24 -31
- data/docs/modules/action.md +190 -0
- data/docs/modules/authentication.md +236 -0
- data/docs/modules/configuration.md +599 -0
- data/docs/modules/controller.md +398 -0
- data/docs/modules/core.md +316 -0
- data/docs/modules/definition.md +876 -0
- data/docs/modules/display.md +759 -0
- data/docs/modules/form.md +605 -0
- data/docs/modules/generator.md +288 -0
- data/docs/modules/index.md +167 -0
- data/docs/modules/interaction.md +470 -0
- data/docs/modules/package.md +151 -0
- data/docs/modules/policy.md +176 -0
- data/docs/modules/portal.md +710 -0
- data/docs/modules/query.md +287 -0
- data/docs/modules/resource_record.md +618 -0
- data/docs/modules/routing.md +641 -0
- data/docs/modules/table.md +293 -0
- data/docs/modules/ui.md +631 -0
- data/docs/public/plutonium.mdc +667 -0
- data/lib/generators/pu/core/assets/assets_generator.rb +0 -5
- data/lib/plutonium/ui/display/resource.rb +7 -2
- data/lib/plutonium/ui/table/resource.rb +8 -3
- data/lib/plutonium/version.rb +1 -1
- metadata +36 -9
- data/docs/guide/getting-started/authorization.md +0 -296
- data/docs/guide/getting-started/core-concepts.md +0 -432
- data/docs/guide/getting-started/index.md +0 -21
- data/docs/guide/tutorial.md +0 -401
- /data/docs/guide/{what-is-plutonium.md → introduction/01-what-is-plutonium.md} +0 -0
@@ -0,0 +1,293 @@
|
|
1
|
+
---
|
2
|
+
title: Table Module
|
3
|
+
---
|
4
|
+
|
5
|
+
# Table Module
|
6
|
+
|
7
|
+
The Table module is a powerful system for creating data tables in Plutonium. It leverages `Phlexi::Table` to provide a rich set of features including smart column rendering, pagination, sorting, filtering, and search. It's designed to work seamlessly with Plutonium's resource definitions to help you build complex data displays with minimal effort.
|
8
|
+
|
9
|
+
::: tip Architecture
|
10
|
+
The Table module lives in `lib/plutonium/ui/table/` and is composed of several key parts:
|
11
|
+
- **`Plutonium::UI::Table::Resource`**: The primary component for rendering resource-based tables.
|
12
|
+
- **Components**: UI elements like search bars, scope selectors, and pagination controls.
|
13
|
+
- **Themes**: Centralized styling for a consistent look and feel.
|
14
|
+
:::
|
15
|
+
|
16
|
+
## Getting Started: Defining a Table
|
17
|
+
|
18
|
+
Everything about a table—its columns, filters, and behaviors—is defined within a resource definition file. You can use `display`, `column`, or `field` to define what data to show.
|
19
|
+
|
20
|
+
Here's a basic example for a `Post` resource:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
# app/definitions/post_definition.rb
|
24
|
+
class PostDefinition < Plutonium::Resource::Definition
|
25
|
+
# Use `display` or `column` to define table columns.
|
26
|
+
display :author, as: :association
|
27
|
+
display :published_at, as: :datetime
|
28
|
+
display :status, as: :badge
|
29
|
+
display :actions, as: :actions, align: :right
|
30
|
+
|
31
|
+
# Define sorting
|
32
|
+
sort :title
|
33
|
+
sort :published_at
|
34
|
+
|
35
|
+
# Enable search
|
36
|
+
search do |scope, query|
|
37
|
+
scope.where("title ILIKE ?", "%#{query}%")
|
38
|
+
end
|
39
|
+
|
40
|
+
# Define filters
|
41
|
+
filter :published, with: Plutonium::Query::Filters::Text, predicate: :eq
|
42
|
+
filter :author, with: Plutonium::Query::Filters::Text, predicate: :eq
|
43
|
+
|
44
|
+
# Define query scopes
|
45
|
+
scope :published
|
46
|
+
scope :draft
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
This configuration is all you need to render a feature-rich table for your posts.
|
51
|
+
|
52
|
+
## Configuring Columns
|
53
|
+
|
54
|
+
Columns are the heart of your table. Plutonium offers flexible ways to configure them.
|
55
|
+
|
56
|
+
### Column Types
|
57
|
+
|
58
|
+
You can render data in various formats using the `as:` option:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
column :name, as: :string
|
62
|
+
column :email, as: :email
|
63
|
+
column :website, as: :link
|
64
|
+
column :published_at, as: :datetime
|
65
|
+
column :is_active, as: :boolean
|
66
|
+
column :priority, as: :badge
|
67
|
+
column :profile_picture, as: :attachment
|
68
|
+
column :metadata, as: :json
|
69
|
+
```
|
70
|
+
|
71
|
+
### Alignment
|
72
|
+
|
73
|
+
Control column alignment with the `align:` option.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
column :title, align: :start # Left-aligned (default)
|
77
|
+
column :price, align: :end # Right-aligned
|
78
|
+
column :status, align: :center # Center-aligned
|
79
|
+
```
|
80
|
+
|
81
|
+
### Custom Column Rendering
|
82
|
+
|
83
|
+
For complete control over a column's output, provide a block. The block receives a wrapped record object.
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
class PostDefinition < Plutonium::Resource::Definition
|
87
|
+
# Basic custom rendering with a block
|
88
|
+
column :full_name do |wrapped_record|
|
89
|
+
# `unwrapped` gives you the original AR record
|
90
|
+
record = wrapped_record.unwrapped
|
91
|
+
"#{record.first_name} #{record.last_name}"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Render a custom component for more complex UI
|
95
|
+
column :status do |wrapped_record|
|
96
|
+
# The `field` method provides access to the field's value and definition
|
97
|
+
field = wrapped_record.field(:status)
|
98
|
+
render StatusBadgeComponent.new(field.value)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
### Conditional Columns
|
104
|
+
|
105
|
+
You can show or hide columns dynamically using the `condition` option. It accepts a lambda that is evaluated in the view context.
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
# Show a column only in the development environment
|
109
|
+
column :debug_info, condition: -> { Rails.env.development? }
|
110
|
+
|
111
|
+
# Show a column based on user permissions
|
112
|
+
column :admin_notes, condition: -> { current_user.admin? }
|
113
|
+
```
|
114
|
+
|
115
|
+
::: warning Security
|
116
|
+
Use `condition` for display logic, not for security. To control data visibility, you should filter `permitted_attributes_for_read` within your authorization policies.
|
117
|
+
:::
|
118
|
+
|
119
|
+
## Searching and Filtering
|
120
|
+
|
121
|
+
Plutonium makes it easy to add powerful search and filtering capabilities to your tables.
|
122
|
+
|
123
|
+
### Search
|
124
|
+
|
125
|
+
Define your search logic with the `search` method in your resource definition. The search bar will appear automatically.
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
class PostDefinition < Plutonium::Resource::Definition
|
129
|
+
# Simple search on a single field
|
130
|
+
search do |scope, search_term|
|
131
|
+
scope.where("title ILIKE ?", "%#{search_term}%")
|
132
|
+
end
|
133
|
+
|
134
|
+
# More complex search across multiple fields and associations
|
135
|
+
search do |scope, search_term|
|
136
|
+
scope.joins(:author)
|
137
|
+
.where(
|
138
|
+
"posts.title ILIKE :q OR posts.content ILIKE :q OR users.name ILIKE :q",
|
139
|
+
q: "%#{search_term}%"
|
140
|
+
)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
### Filters
|
146
|
+
|
147
|
+
Declare filters using the `filter` method. Currently, Plutonium provides the Text filter with various predicates.
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
class PostDefinition < Plutonium::Resource::Definition
|
151
|
+
# Text filter with exact match
|
152
|
+
filter :status, with: Plutonium::Query::Filters::Text, predicate: :eq
|
153
|
+
|
154
|
+
# Text filter with contains matching
|
155
|
+
filter :title, with: Plutonium::Query::Filters::Text, predicate: :contains
|
156
|
+
|
157
|
+
# Text filter with starts_with matching
|
158
|
+
filter :category, with: Plutonium::Query::Filters::Text, predicate: :starts_with
|
159
|
+
|
160
|
+
# Custom filter with lambda
|
161
|
+
filter :published, with: ->(scope, value) {
|
162
|
+
value ? scope.where.not(published_at: nil) : scope.where(published_at: nil)
|
163
|
+
}
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
Available Text filter predicates include: `:eq`, `:not_eq`, `:matches`, `:not_matches`, `:starts_with`, `:ends_with`, `:contains`, `:not_contains`.
|
168
|
+
|
169
|
+
## Query Scopes
|
170
|
+
|
171
|
+
Scopes allow users to apply predefined queries with a single click. Define them using the `scope` method, which can reference an existing model scope or a new lambda.
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
class PostDefinition < Plutonium::Resource::Definition
|
175
|
+
# Reference existing scopes from the Post model
|
176
|
+
scope :published
|
177
|
+
scope :featured
|
178
|
+
|
179
|
+
# Define a custom scope with a lambda
|
180
|
+
scope :recent, -> { where("created_at > ?", 1.week.ago) }
|
181
|
+
|
182
|
+
# Set a default scope
|
183
|
+
scope :active, default: true
|
184
|
+
end
|
185
|
+
```
|
186
|
+
A scopes bar will automatically be displayed above the table.
|
187
|
+
|
188
|
+
## Sorting
|
189
|
+
|
190
|
+
Enable sorting on columns by defining a `sort` rule. Columns automatically become sortable when a sort definition exists for them.
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
class PostDefinition < Plutonium::Resource::Definition
|
194
|
+
# Define sort rules for columns
|
195
|
+
sort :title
|
196
|
+
sort :created_at
|
197
|
+
sort :updated_at
|
198
|
+
|
199
|
+
# Custom sorting logic
|
200
|
+
sort :author_name, using: "users.name" do |scope, direction:|
|
201
|
+
scope.joins(:author).order("users.name #{direction}")
|
202
|
+
end
|
203
|
+
end
|
204
|
+
```
|
205
|
+
|
206
|
+
Plutonium's tables support both tri-state and multi-column sorting, providing flexible data exploration.
|
207
|
+
|
208
|
+
* **Tri-state Sorting**: Clicking a column header cycles through ascending (`ASC`), descending (`DESC`), and unsorted states for that column.
|
209
|
+
* **Multi-column Sorting**: You can apply sorting to multiple columns. Simply click on the headers of the columns you wish to sort by. The order in which you select them determines their priority. An indicator next to the column title shows the sort order and priority.
|
210
|
+
|
211
|
+
## Pagination
|
212
|
+
|
213
|
+
Pagination is handled automatically by the excellent [Pagy](https://github.com/ddnexus/pagy) gem. In your controller, the `pagy` helper method prepares your records for pagination.
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
# In your controller (usually handled by Plutonium::Controller::CrudActions)
|
217
|
+
@pagy, @resource_records = pagy(current_authorized_scope)
|
218
|
+
```
|
219
|
+
|
220
|
+
The table component renders pagination controls and an info bar, allowing users to navigate through pages and change the number of items per page.
|
221
|
+
|
222
|
+
## Actions
|
223
|
+
|
224
|
+
Actions defined on your resource will automatically appear in the `actions` column for each row.
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
class PostDefinition < Plutonium::Resource::Definition
|
228
|
+
# Standard CRUD actions are available by default
|
229
|
+
# action :show
|
230
|
+
# action :edit
|
231
|
+
# action :destroy
|
232
|
+
|
233
|
+
# Add custom actions
|
234
|
+
action :publish, interaction: PublishPostInteraction
|
235
|
+
action :archive, interaction: ArchivePostInteraction
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
Plutonium checks the user's permissions for each action and only displays the ones they are allowed to perform.
|
240
|
+
|
241
|
+
## Customization
|
242
|
+
|
243
|
+
### Overriding the Table View
|
244
|
+
|
245
|
+
For deep customization, you can define a nested `Table` class within your resource definition. This allows you to override any part of the table rendering process.
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
class PostDefinition < Plutonium::Resource::Definition
|
249
|
+
# Define a custom table class
|
250
|
+
class Table < Plutonium::UI::Table::Resource
|
251
|
+
private
|
252
|
+
|
253
|
+
# Customize the footer
|
254
|
+
def render_footer
|
255
|
+
div(class: "custom-footer") do
|
256
|
+
super # Render the original footer (pagination, etc.)
|
257
|
+
render_custom_stats
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def render_custom_stats
|
262
|
+
div(class: "mt-4 text-sm text-gray-500") do
|
263
|
+
"Total Posts: #{collection.size}"
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
```
|
269
|
+
|
270
|
+
### Empty State
|
271
|
+
|
272
|
+
When a query returns no results, the table displays a helpful message. You can customize this by overriding `render_empty_card`.
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
class PostDefinition < Plutonium::Resource::Definition
|
276
|
+
class Table < Plutonium::UI::Table::Resource
|
277
|
+
private
|
278
|
+
|
279
|
+
def render_empty_card
|
280
|
+
EmptyCard("No posts were found.") {
|
281
|
+
# Optionally, add a call to action
|
282
|
+
if current_policy.allowed_to?(:create?)
|
283
|
+
# ... render a "Create Post" button
|
284
|
+
end
|
285
|
+
}
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
```
|
290
|
+
|
291
|
+
### Theming
|
292
|
+
|
293
|
+
The table's appearance is controlled by a central theme. You can inspect `lib/plutonium/ui/table/theme.rb` and `lib/plutonium/ui/table/display_theme.rb` to see the default Tailwind CSS classes and override them if needed.
|