dash_kit 2.1.0 → 2.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0cfb78242c30e17c1eaedd518a9f5fd1af0886d019506d04f6959c4bf91d7ef0
4
- data.tar.gz: 45f2cb90222190e06ee5310754abd3e8e265c50c91f54dbdfc9f148717bac89a
3
+ metadata.gz: 752a3c52f25de0472afd8d1143e5066c7e2d6bc62b31d4542417313cc94310e6
4
+ data.tar.gz: 783e9571276247d55b6bbcb779f475688b3b0897885b784135df0df81c179dfc
5
5
  SHA512:
6
- metadata.gz: 88d1e0a9aa4ac99d547c55e4605ad8d422e2301c35809dded1601a4f7b82d9c830afb2afa6a723c8d9f445b9e8f8e134176d40233fe01b0e812acf78c06ef758
7
- data.tar.gz: d7556f33269eff33c48bf9fc37f86e9fae047744e6e8a6c75ee07c43d3f3f94ce961a7ae3be50fd552c9fba65ada04237a0ebf6090f8a35b188957f1b5b86ddd
6
+ metadata.gz: 74532c9d76d342563918d0b8542a2dc9c84b1ce7145162171f01564dc973b9e04184f4aaebc26423ad11d9b9db1c11aeb4f7e7b69038af1a9f7d125dc6956251
7
+ data.tar.gz: e6676dbc1e78d966e6a56f49189b010147fa4b4eaf414d7598a5332d976a59184e123a1683b5c4f0f0bb137a1762bfb15d1b05336b1ca14b501bd9260964f2a7
data/README.md CHANGED
@@ -168,3 +168,16 @@ end
168
168
  ## Design Philosophy
169
169
 
170
170
  DashKit avoids data semantics by design. It treats datasets as opaque structures that can be rendered consistently, allowing teams to replace or evolve backends without rewriting dashboards. This deliberate decoupling keeps DashKit focused, composable, and stable over time.
171
+
172
+ ## Setting up to work on DashKit
173
+
174
+ After cloning, install the bundle and run the setup command:
175
+
176
+ ```
177
+ bundle install
178
+ bundle exec dev_onboarder
179
+ ```
180
+
181
+ It runs the test suite and checks the Claude Code tooling the repo expects, and records what it found
182
+ inside the clone's git directory, where nothing is committed. `bundle exec dev_onboarder status` lists what the repo
183
+ requires now that it did not at your last run. The requirements are declared in `Setupfile`.
@@ -39,11 +39,11 @@ module DashKit
39
39
  config.available_widgets.dig(widget_key.to_sym, :label) || widget_key.to_s.humanize
40
40
  end
41
41
 
42
- def dash_kit_render_widgets(config:)
42
+ def dash_kit_render_widgets(config:, &draw)
43
43
  return content_tag(:div, "", id: "dashboard-widgets") unless config
44
44
 
45
45
  content_tag(:div, id: dash_kit_widgets_id(config)) do
46
- dash_kit_arrangeable?(config) ? dash_kit_widget_grid(config) : dash_kit_drawn_widgets(config)
46
+ dash_kit_arrangeable?(config) ? dash_kit_widget_grid(config, &draw) : dash_kit_drawn_widgets(config, &draw)
47
47
  end
48
48
  end
49
49
 
@@ -55,10 +55,10 @@ module DashKit
55
55
  DashKit.editable?(config, dash_kit_current_viewer)
56
56
  end
57
57
 
58
- def dash_kit_widget_grid(config)
58
+ def dash_kit_widget_grid(config, &draw)
59
59
  safe_join([
60
60
  react_ui("dash_kit/dashboard-grid", config.layout_data.merge(base: dash_kit.dashboard_path(config), token: dash_kit_form_token)),
61
- block_contents(config.blocks) { |block| dash_kit_block_frame(config, block) }
61
+ block_contents(config.blocks) { |block| dash_kit_block_frame(config, block, &draw) }
62
62
  ])
63
63
  end
64
64
 
@@ -66,14 +66,16 @@ module DashKit
66
66
  controller.send(:form_authenticity_token) if controller.respond_to?(:form_authenticity_token, true)
67
67
  end
68
68
 
69
- def dash_kit_drawn_widgets(config)
69
+ def dash_kit_drawn_widgets(config, &draw)
70
70
  block_layout(config.blocks, kind: config.dashboard_type.to_sym) do |block|
71
- dash_kit_block_frame(config, block)
71
+ dash_kit_block_frame(config, block, &draw)
72
72
  end
73
73
  end
74
74
 
75
- def dash_kit_block_frame(config, block)
76
- return dash_kit_widget_frame(block["type"], dashboard_id: config.id) unless block["type"] == WidgetRegistry::BUILT_WIDGET.to_s
75
+ def dash_kit_block_frame(config, block, &draw)
76
+ unless block["type"] == WidgetRegistry::BUILT_WIDGET.to_s
77
+ return draw ? capture(block["type"], &draw) : dash_kit_widget_frame(block["type"], dashboard_id: config.id)
78
+ end
77
79
 
78
80
  definition = config.widget_definitions.find_by(id: block.dig("content", "definition_id"))
79
81
  definition ? dash_kit_widget_definition_frame(definition) : dash_kit_loading_skeleton
@@ -12,8 +12,9 @@ coupling the UI to any specific data backend.
12
12
  - A widget registry: dashboard types map to the widgets available on them.
13
13
  - A persistence layer for user preferences (which widgets show, in what order,
14
14
  with which filters) via an ActiveRecord `Dashboard` model.
15
- - A rendering layer that lazy-loads each widget through a Turbo Frame and
16
- refreshes on configuration change.
15
+ - A rendering layer that lazy-loads each widget through a Turbo Frame, or hands
16
+ each widget to a block the host passes so the host draws it inside the page,
17
+ and refreshes on configuration change.
17
18
 
18
19
  A dashboard renders two kinds of widget side by side:
19
20
 
@@ -81,16 +82,19 @@ The layers, all under the `DashKit` namespace:
81
82
  `dash_kit_available_sources`, `dash_kit_visualizations`, and
82
83
  `dash_kit_widget_definition_frame(definition)`. `dash_kit_render_widgets`
83
84
  renders the registered widgets in order, then appends one lazy Turbo Frame per
84
- `widget_definition`.
85
+ `widget_definition`. Given a block, it calls the block with each shown
86
+ registered widget's key and draws what the block returns in that widget's
87
+ place, inside the page's own request and with no Turbo Frame.
85
88
 
86
89
  ### Data flow
87
90
 
88
91
  UI events -> dashboard update -> Turbo refresh -> widgets re-render via
89
- lazy-loaded Turbo Frames. A widget is never rendered inline; it loads through a
92
+ lazy-loaded Turbo Frames. Without a block, a widget loads through a
90
93
  `<turbo-frame loading="lazy">` pointing at the widget's own route. The frame
91
94
  carries its dashboard's id, so the widget partial is handed the dashboard's
92
95
  `filter_state` to render against (DashKit passes the blob; the host interprets
93
- it).
96
+ it). With a block, DashKit decides only which widgets show and where, and the
97
+ host draws each one from data it has already loaded for the page.
94
98
 
95
99
  Built widgets follow the same flow. Each `widget_definition` lazy-loads through
96
100
  its own `<turbo-frame>` at `/widget_definitions/:id`;
@@ -255,7 +259,7 @@ The following manual steps remain:
255
259
  display order.
256
260
  - **Supply the data yourself.** A widget's partial is responsible for fetching
257
261
  and rendering its own data; DashKit only renders the partial inside a lazy
258
- Turbo Frame. Keep partials self-contained around the owner DashKit scopes to.
262
+ Turbo Frame, or calls the host's block with the widget's key. Keep partials self-contained around the owner DashKit scopes to.
259
263
  This holds for registered widgets and for built-widget renderer partials
260
264
  alike — both receive `filter_state` and read it to shape their own request.
261
265
  - **Register a renderer for every visualization the builder offers.** A built
@@ -274,9 +278,10 @@ The following manual steps remain:
274
278
  `WidgetManagement` methods (`toggle_widget`, `move_widget_up`,
275
279
  `move_widget_down`, `update_filter`) or the engine routes; do not write
276
280
  `widget_order` / `hidden_widgets` / `filter_state` directly.
277
- - **Let widgets lazy-load.** Render through `dash_kit_render_widgets` /
278
- `dash_kit_widget_frame` so each widget loads in its own Turbo Frame; do not
279
- inline widget bodies.
281
+ - **Draw widgets through `dash_kit_render_widgets`.** Without a block, each
282
+ widget loads in its own Turbo Frame. Pass a block when the page already holds
283
+ the widgets' data, so every widget is drawn in the page's own request rather
284
+ than one request per widget.
280
285
  - **Mobile-first, Tailwind, dark mode.** The shipped UI is styled with Tailwind
281
286
  and supports dark mode; host styling should match. The primary surface is
282
287
  often a native webview.
@@ -20,8 +20,9 @@ coupling the UI to any specific data backend.
20
20
  - A widget registry: dashboard types map to the widgets available on them.
21
21
  - A persistence layer for user preferences (which widgets show, in what order,
22
22
  with which filters) via an ActiveRecord `Dashboard` model.
23
- - A rendering layer that lazy-loads each widget through a Turbo Frame and
24
- refreshes on configuration change.
23
+ - A rendering layer that lazy-loads each widget through a Turbo Frame, or hands
24
+ each widget to a block the host passes so the host draws it inside the page,
25
+ and refreshes on configuration change.
25
26
 
26
27
  A dashboard renders two kinds of widget side by side:
27
28
 
@@ -89,16 +90,19 @@ The layers, all under the `DashKit` namespace:
89
90
  `dash_kit_available_sources`, `dash_kit_visualizations`, and
90
91
  `dash_kit_widget_definition_frame(definition)`. `dash_kit_render_widgets`
91
92
  renders the registered widgets in order, then appends one lazy Turbo Frame per
92
- `widget_definition`.
93
+ `widget_definition`. Given a block, it calls the block with each shown
94
+ registered widget's key and draws what the block returns in that widget's
95
+ place, inside the page's own request and with no Turbo Frame.
93
96
 
94
97
  ### Data flow
95
98
 
96
99
  UI events -> dashboard update -> Turbo refresh -> widgets re-render via
97
- lazy-loaded Turbo Frames. A widget is never rendered inline; it loads through a
100
+ lazy-loaded Turbo Frames. Without a block, a widget loads through a
98
101
  `<turbo-frame loading="lazy">` pointing at the widget's own route. The frame
99
102
  carries its dashboard's id, so the widget partial is handed the dashboard's
100
103
  `filter_state` to render against (DashKit passes the blob; the host interprets
101
- it).
104
+ it). With a block, DashKit decides only which widgets show and where, and the
105
+ host draws each one from data it has already loaded for the page.
102
106
 
103
107
  Built widgets follow the same flow. Each `widget_definition` lazy-loads through
104
108
  its own `<turbo-frame>` at `/widget_definitions/:id`;
@@ -263,7 +267,7 @@ The following manual steps remain:
263
267
  display order.
264
268
  - **Supply the data yourself.** A widget's partial is responsible for fetching
265
269
  and rendering its own data; DashKit only renders the partial inside a lazy
266
- Turbo Frame. Keep partials self-contained around the owner DashKit scopes to.
270
+ Turbo Frame, or calls the host's block with the widget's key. Keep partials self-contained around the owner DashKit scopes to.
267
271
  This holds for registered widgets and for built-widget renderer partials
268
272
  alike — both receive `filter_state` and read it to shape their own request.
269
273
  - **Register a renderer for every visualization the builder offers.** A built
@@ -282,9 +286,10 @@ The following manual steps remain:
282
286
  `WidgetManagement` methods (`toggle_widget`, `move_widget_up`,
283
287
  `move_widget_down`, `update_filter`) or the engine routes; do not write
284
288
  `widget_order` / `hidden_widgets` / `filter_state` directly.
285
- - **Let widgets lazy-load.** Render through `dash_kit_render_widgets` /
286
- `dash_kit_widget_frame` so each widget loads in its own Turbo Frame; do not
287
- inline widget bodies.
289
+ - **Draw widgets through `dash_kit_render_widgets`.** Without a block, each
290
+ widget loads in its own Turbo Frame. Pass a block when the page already holds
291
+ the widgets' data, so every widget is drawn in the page's own request rather
292
+ than one request per widget.
288
293
  - **Mobile-first, Tailwind, dark mode.** The shipped UI is styled with Tailwind
289
294
  and supports dark mode; host styling should match. The primary surface is
290
295
  often a native webview.
@@ -20,8 +20,9 @@ coupling the UI to any specific data backend.
20
20
  - A widget registry: dashboard types map to the widgets available on them.
21
21
  - A persistence layer for user preferences (which widgets show, in what order,
22
22
  with which filters) via an ActiveRecord `Dashboard` model.
23
- - A rendering layer that lazy-loads each widget through a Turbo Frame and
24
- refreshes on configuration change.
23
+ - A rendering layer that lazy-loads each widget through a Turbo Frame, or hands
24
+ each widget to a block the host passes so the host draws it inside the page,
25
+ and refreshes on configuration change.
25
26
 
26
27
  A dashboard renders two kinds of widget side by side:
27
28
 
@@ -89,16 +90,19 @@ The layers, all under the `DashKit` namespace:
89
90
  `dash_kit_available_sources`, `dash_kit_visualizations`, and
90
91
  `dash_kit_widget_definition_frame(definition)`. `dash_kit_render_widgets`
91
92
  renders the registered widgets in order, then appends one lazy Turbo Frame per
92
- `widget_definition`.
93
+ `widget_definition`. Given a block, it calls the block with each shown
94
+ registered widget's key and draws what the block returns in that widget's
95
+ place, inside the page's own request and with no Turbo Frame.
93
96
 
94
97
  ### Data flow
95
98
 
96
99
  UI events -> dashboard update -> Turbo refresh -> widgets re-render via
97
- lazy-loaded Turbo Frames. A widget is never rendered inline; it loads through a
100
+ lazy-loaded Turbo Frames. Without a block, a widget loads through a
98
101
  `<turbo-frame loading="lazy">` pointing at the widget's own route. The frame
99
102
  carries its dashboard's id, so the widget partial is handed the dashboard's
100
103
  `filter_state` to render against (DashKit passes the blob; the host interprets
101
- it).
104
+ it). With a block, DashKit decides only which widgets show and where, and the
105
+ host draws each one from data it has already loaded for the page.
102
106
 
103
107
  Built widgets follow the same flow. Each `widget_definition` lazy-loads through
104
108
  its own `<turbo-frame>` at `/widget_definitions/:id`;
@@ -263,7 +267,7 @@ The following manual steps remain:
263
267
  display order.
264
268
  - **Supply the data yourself.** A widget's partial is responsible for fetching
265
269
  and rendering its own data; DashKit only renders the partial inside a lazy
266
- Turbo Frame. Keep partials self-contained around the owner DashKit scopes to.
270
+ Turbo Frame, or calls the host's block with the widget's key. Keep partials self-contained around the owner DashKit scopes to.
267
271
  This holds for registered widgets and for built-widget renderer partials
268
272
  alike — both receive `filter_state` and read it to shape their own request.
269
273
  - **Register a renderer for every visualization the builder offers.** A built
@@ -282,9 +286,10 @@ The following manual steps remain:
282
286
  `WidgetManagement` methods (`toggle_widget`, `move_widget_up`,
283
287
  `move_widget_down`, `update_filter`) or the engine routes; do not write
284
288
  `widget_order` / `hidden_widgets` / `filter_state` directly.
285
- - **Let widgets lazy-load.** Render through `dash_kit_render_widgets` /
286
- `dash_kit_widget_frame` so each widget loads in its own Turbo Frame; do not
287
- inline widget bodies.
289
+ - **Draw widgets through `dash_kit_render_widgets`.** Without a block, each
290
+ widget loads in its own Turbo Frame. Pass a block when the page already holds
291
+ the widgets' data, so every widget is drawn in the page's own request rather
292
+ than one request per widget.
288
293
  - **Mobile-first, Tailwind, dark mode.** The shipped UI is styled with Tailwind
289
294
  and supports dark mode; host styling should match. The primary surface is
290
295
  often a native webview.
@@ -20,8 +20,9 @@ coupling the UI to any specific data backend.
20
20
  - A widget registry: dashboard types map to the widgets available on them.
21
21
  - A persistence layer for user preferences (which widgets show, in what order,
22
22
  with which filters) via an ActiveRecord `Dashboard` model.
23
- - A rendering layer that lazy-loads each widget through a Turbo Frame and
24
- refreshes on configuration change.
23
+ - A rendering layer that lazy-loads each widget through a Turbo Frame, or hands
24
+ each widget to a block the host passes so the host draws it inside the page,
25
+ and refreshes on configuration change.
25
26
 
26
27
  A dashboard renders two kinds of widget side by side:
27
28
 
@@ -89,16 +90,19 @@ The layers, all under the `DashKit` namespace:
89
90
  `dash_kit_available_sources`, `dash_kit_visualizations`, and
90
91
  `dash_kit_widget_definition_frame(definition)`. `dash_kit_render_widgets`
91
92
  renders the registered widgets in order, then appends one lazy Turbo Frame per
92
- `widget_definition`.
93
+ `widget_definition`. Given a block, it calls the block with each shown
94
+ registered widget's key and draws what the block returns in that widget's
95
+ place, inside the page's own request and with no Turbo Frame.
93
96
 
94
97
  ### Data flow
95
98
 
96
99
  UI events -> dashboard update -> Turbo refresh -> widgets re-render via
97
- lazy-loaded Turbo Frames. A widget is never rendered inline; it loads through a
100
+ lazy-loaded Turbo Frames. Without a block, a widget loads through a
98
101
  `<turbo-frame loading="lazy">` pointing at the widget's own route. The frame
99
102
  carries its dashboard's id, so the widget partial is handed the dashboard's
100
103
  `filter_state` to render against (DashKit passes the blob; the host interprets
101
- it).
104
+ it). With a block, DashKit decides only which widgets show and where, and the
105
+ host draws each one from data it has already loaded for the page.
102
106
 
103
107
  Built widgets follow the same flow. Each `widget_definition` lazy-loads through
104
108
  its own `<turbo-frame>` at `/widget_definitions/:id`;
@@ -263,7 +267,7 @@ The following manual steps remain:
263
267
  display order.
264
268
  - **Supply the data yourself.** A widget's partial is responsible for fetching
265
269
  and rendering its own data; DashKit only renders the partial inside a lazy
266
- Turbo Frame. Keep partials self-contained around the owner DashKit scopes to.
270
+ Turbo Frame, or calls the host's block with the widget's key. Keep partials self-contained around the owner DashKit scopes to.
267
271
  This holds for registered widgets and for built-widget renderer partials
268
272
  alike — both receive `filter_state` and read it to shape their own request.
269
273
  - **Register a renderer for every visualization the builder offers.** A built
@@ -282,9 +286,10 @@ The following manual steps remain:
282
286
  `WidgetManagement` methods (`toggle_widget`, `move_widget_up`,
283
287
  `move_widget_down`, `update_filter`) or the engine routes; do not write
284
288
  `widget_order` / `hidden_widgets` / `filter_state` directly.
285
- - **Let widgets lazy-load.** Render through `dash_kit_render_widgets` /
286
- `dash_kit_widget_frame` so each widget loads in its own Turbo Frame; do not
287
- inline widget bodies.
289
+ - **Draw widgets through `dash_kit_render_widgets`.** Without a block, each
290
+ widget loads in its own Turbo Frame. Pass a block when the page already holds
291
+ the widgets' data, so every widget is drawn in the page's own request rather
292
+ than one request per widget.
288
293
  - **Mobile-first, Tailwind, dark mode.** The shipped UI is styled with Tailwind
289
294
  and supports dark mode; host styling should match. The primary surface is
290
295
  often a native webview.
@@ -1,3 +1,3 @@
1
1
  module DashKit
2
- VERSION = "2.1.0"
2
+ VERSION = "2.2.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dash_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Schneider