plutonium 0.62.2 → 0.63.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/.claude/skills/plutonium/SKILL.md +44 -0
- data/.claude/skills/plutonium-app/SKILL.md +3 -3
- data/.claude/skills/plutonium-async-interactions/SKILL.md +191 -0
- data/.claude/skills/plutonium-auth/SKILL.md +36 -0
- data/.claude/skills/plutonium-behavior/SKILL.md +121 -24
- data/.claude/skills/plutonium-kanban/SKILL.md +17 -3
- data/.claude/skills/plutonium-resource/SKILL.md +259 -12
- data/.claude/skills/plutonium-tenancy/SKILL.md +32 -3
- data/.claude/skills/plutonium-ui/SKILL.md +115 -14
- data/.claude/skills/plutonium-wizard/SKILL.md +73 -4
- data/CHANGELOG.md +67 -0
- data/CLAUDE.md +87 -0
- data/Rakefile +34 -0
- data/SECURITY.md +1 -1
- data/app/assets/plutonium.css +1 -1
- data/app/assets/plutonium.js +685 -102
- data/app/assets/plutonium.js.map +4 -4
- data/app/assets/plutonium.min.js +53 -53
- data/app/assets/plutonium.min.js.map +4 -4
- data/app/views/rodauth/_login_form.html.erb +13 -0
- data/db/migrate/async_interactions/20260817000001_create_plutonium_async_runs.rb +170 -0
- data/docs/.vitepress/config.ts +81 -3
- data/docs/.vitepress/theme/blog.data.ts +44 -0
- data/docs/.vitepress/theme/components/BlogIndex.vue +87 -0
- data/docs/.vitepress/theme/components/BlogMeta.vue +47 -0
- data/docs/.vitepress/theme/components/HomeFeatureTour.vue +293 -0
- data/docs/.vitepress/theme/components/HomeHero.vue +3 -3
- data/docs/.vitepress/theme/components/HomeInTheBox.vue +8 -0
- data/docs/.vitepress/theme/components/HomeStopWriting.vue +1 -0
- data/docs/.vitepress/theme/components/HomeWhyPlutonium.vue +84 -0
- data/docs/.vitepress/theme/index.ts +8 -4
- data/docs/blog/association-inputs-post-signed-ids.md +70 -0
- data/docs/blog/fix-the-model-not-the-policy.md +122 -0
- data/docs/blog/fractional-ordering-runs-out-of-room.md +67 -0
- data/docs/blog/half-finished-forms-are-pii.md +76 -0
- data/docs/blog/index.md +13 -0
- data/docs/blog/interactions-are-presentation-objects.md +152 -0
- data/docs/blog/introducing-plutonium.md +253 -0
- data/docs/blog/jobs-are-not-permission-snapshots.md +100 -0
- data/docs/blog/plutonium-and-ai-agents.md +48 -0
- data/docs/blog/realtime-is-one-line-and-four-dependencies.md +70 -0
- data/docs/blog/two-forms-one-dom-id.md +69 -0
- data/docs/blog/whats-new-async-kanban-wizards.md +130 -0
- data/docs/getting-started/tutorial/04-authorization.md +12 -3
- data/docs/getting-started/tutorial/06-nested-resources.md +3 -1
- data/docs/getting-started/tutorial/07-author-portal.md +2 -2
- data/docs/guides/authentication.md +73 -0
- data/docs/guides/authorization.md +2 -0
- data/docs/guides/creating-packages.md +5 -3
- data/docs/guides/custom-actions.md +74 -12
- data/docs/guides/customizing-ui.md +9 -2
- data/docs/guides/index.md +1 -0
- data/docs/guides/kanban.md +7 -5
- data/docs/guides/nested-resources.md +11 -1
- data/docs/guides/performance.md +104 -0
- data/docs/guides/user-invites.md +1 -1
- data/docs/guides/wizards.md +9 -1
- data/docs/index.md +3 -3
- data/docs/public/images/home/tour-actions.png +0 -0
- data/docs/public/images/home/tour-async.png +0 -0
- data/docs/public/images/home/tour-kanban.png +0 -0
- data/docs/public/images/home/tour-tenancy.png +0 -0
- data/docs/public/images/home/tour-wizard.png +0 -0
- data/docs/public/images/reference/async-progress-page.png +0 -0
- data/docs/public/images/reference/async-running-banner.png +0 -0
- data/docs/public/templates/experimental.rb +34 -0
- data/docs/public/templates/pluton8.rb +14 -0
- data/docs/reference/app/portals.md +15 -3
- data/docs/reference/auth/accounts.md +19 -0
- data/docs/reference/behavior/async-interactions.md +295 -0
- data/docs/reference/behavior/controllers.md +17 -4
- data/docs/reference/behavior/index.md +7 -1
- data/docs/reference/behavior/interactions.md +152 -22
- data/docs/reference/configuration.md +5 -0
- data/docs/reference/index.md +1 -0
- data/docs/reference/kanban/dsl.md +7 -4
- data/docs/reference/kanban/index.md +1 -1
- data/docs/reference/kanban/positioning.md +26 -4
- data/docs/reference/positioning.md +568 -0
- data/docs/reference/resource/actions.md +97 -4
- data/docs/reference/resource/definition.md +181 -9
- data/docs/reference/tenancy/invites.md +1 -1
- data/docs/reference/tenancy/nested-resources.md +60 -2
- data/docs/reference/ui/assets.md +4 -0
- data/docs/reference/ui/components.md +57 -4
- data/docs/reference/ui/displays.md +20 -10
- data/docs/reference/ui/index.md +1 -1
- data/docs/reference/wizard/dsl.md +33 -0
- data/docs/reference/wizard/storage-config.md +1 -0
- data/docs/superpowers/plans/2026-07-16-homepage-depth-upgrade.md +624 -0
- data/docs/superpowers/plans/2026-07-16-homepage-depth-upgrade.md.tasks.json +32 -0
- data/docs/superpowers/plans/2026-07-31-positioned-drag-and-drop.md +1787 -0
- data/docs/superpowers/plans/2026-07-31-positioned-drag-and-drop.md.tasks.json +91 -0
- data/docs/superpowers/plans/2026-08-17-async-interactions.md +1414 -0
- data/docs/superpowers/plans/2026-08-17-async-interactions.md.tasks.json +66 -0
- data/docs/superpowers/specs/2026-07-16-homepage-depth-upgrade-design.md +111 -0
- data/docs/superpowers/specs/2026-07-17-action-html-attributes-design.md +124 -0
- data/docs/superpowers/specs/2026-07-31-positioned-drag-and-drop-design.md +506 -0
- data/docs/superpowers/specs/2026-08-17-async-interactions-design.md +185 -0
- data/gemfiles/postgres.gemfile.lock +85 -85
- data/gemfiles/rails_7.gemfile.lock +322 -140
- data/gemfiles/rails_8.0.gemfile.lock +125 -115
- data/gemfiles/rails_8.1.gemfile.lock +126 -116
- data/lib/generators/pu/async_interactions/install_generator.rb +111 -0
- data/lib/generators/pu/async_interactions/templates/app/controllers/async_runs_controller.rb.tt +15 -0
- data/lib/generators/pu/core/typespec/typespec_generator.rb +7 -4
- data/lib/generators/pu/invites/install_generator.rb +3 -3
- data/lib/generators/pu/invites/templates/packages/invites/app/views/layouts/invites/invitation.html.erb.tt +2 -2
- data/lib/generators/pu/lib/plutonium_generators/concerns/mounts_engines.rb +47 -2
- data/lib/generators/pu/lib/plutonium_generators/concerns/resource_registration.rb +41 -0
- data/lib/generators/pu/lite/litestream/litestream_generator.rb +1 -1
- data/lib/generators/pu/lite/solid_queue/solid_queue_generator.rb +1 -1
- data/lib/generators/pu/res/conn/conn_generator.rb +19 -39
- data/lib/generators/pu/res/conn/templates/app/controllers/resource_controller.rb.tt +4 -0
- data/lib/generators/pu/rodauth/templates/app/rodauth/account_rodauth_plugin.rb.tt +15 -6
- data/lib/generators/pu/rodauth/templates/app/rodauth/rodauth_plugin.rb.tt +7 -0
- data/lib/generators/pu/saas/welcome/templates/app/views/layouts/welcome.html.erb.tt +2 -2
- data/lib/generators/pu/wizards/install_generator.rb +78 -0
- data/lib/plutonium/action/base.rb +71 -9
- data/lib/plutonium/action/interactive.rb +9 -0
- data/lib/plutonium/attachments.rb +254 -0
- data/lib/plutonium/configuration.rb +82 -1
- data/lib/plutonium/core/controller.rb +50 -7
- data/lib/plutonium/core/controllers/authorizable.rb +16 -0
- data/lib/plutonium/core/controllers/entity_scoping.rb +12 -2
- data/lib/plutonium/definition/base.rb +51 -0
- data/lib/plutonium/definition/display_layout.rb +112 -0
- data/lib/plutonium/definition/index_views.rb +8 -7
- data/lib/plutonium/definition/input_aliases.rb +38 -0
- data/lib/plutonium/definition/page_widths.rb +65 -0
- data/lib/plutonium/definition/positioning.rb +126 -0
- data/lib/plutonium/definition/sorting.rb +17 -2
- data/lib/plutonium/helpers/turbo_helper.rb +7 -0
- data/lib/plutonium/interaction/README.md +61 -24
- data/lib/plutonium/interaction/async/configuration.rb +38 -0
- data/lib/plutonium/interaction/async/context.rb +419 -0
- data/lib/plutonium/interaction/async/executor.rb +422 -0
- data/lib/plutonium/interaction/async/job.rb +80 -0
- data/lib/plutonium/interaction/async/reap_job.rb +81 -0
- data/lib/plutonium/interaction/async/run.rb +394 -0
- data/lib/plutonium/interaction/async/run_definition.rb +155 -0
- data/lib/plutonium/interaction/async/run_policy.rb +86 -0
- data/lib/plutonium/interaction/base.rb +34 -7
- data/lib/plutonium/interaction/concerns/dispatchable.rb +518 -0
- data/lib/plutonium/interaction/concerns/scoping.rb +70 -9
- data/lib/plutonium/interaction/response/redirect.rb +11 -3
- data/lib/plutonium/kanban/board.rb +14 -0
- data/lib/plutonium/kanban/column.rb +4 -2
- data/lib/plutonium/kanban/dsl.rb +4 -1
- data/lib/plutonium/kanban/grouping.rb +9 -22
- data/lib/plutonium/kanban/positioning.rb +5 -65
- data/lib/plutonium/positioning/config.rb +94 -0
- data/lib/plutonium/positioning/model.rb +128 -0
- data/lib/plutonium/positioning.rb +25 -86
- data/lib/plutonium/railtie.rb +1 -0
- data/lib/plutonium/resource/controller.rb +118 -38
- data/lib/plutonium/resource/controllers/crud_actions/index_action.rb +32 -2
- data/lib/plutonium/resource/controllers/crud_actions.rb +30 -2
- data/lib/plutonium/resource/controllers/eager_loading.rb +87 -0
- data/lib/plutonium/resource/controllers/export_csv.rb +10 -1
- data/lib/plutonium/resource/controllers/kanban_actions.rb +53 -14
- data/lib/plutonium/resource/controllers/position_actions.rb +390 -0
- data/lib/plutonium/resource/controllers/presentable.rb +19 -13
- data/lib/plutonium/resource/controllers/queryable.rb +5 -1
- data/lib/plutonium/resource/controllers/wizard_actions.rb +21 -0
- data/lib/plutonium/resource/policy.rb +33 -0
- data/lib/plutonium/resource/query_object.rb +36 -0
- data/lib/plutonium/routing/mapper_extensions.rb +100 -8
- data/lib/plutonium/routing/route_set_extensions.rb +15 -1
- data/lib/plutonium/routing/wizard_registration.rb +4 -0
- data/lib/plutonium/testing/resource_policy.rb +6 -2
- data/lib/plutonium/ui/action_button.rb +12 -7
- data/lib/plutonium/ui/actions_dropdown.rb +1 -1
- data/lib/plutonium/ui/block.rb +21 -1
- data/lib/plutonium/ui/breadcrumbs.rb +187 -55
- data/lib/plutonium/ui/component/methods.rb +5 -0
- data/lib/plutonium/ui/component/positionable.rb +112 -0
- data/lib/plutonium/ui/component/resolves_tags.rb +57 -0
- data/lib/plutonium/ui/component/section.rb +185 -0
- data/lib/plutonium/ui/display/base.rb +13 -1
- data/lib/plutonium/ui/display/components/formatted_value.rb +26 -0
- data/lib/plutonium/ui/display/components/section.rb +18 -0
- data/lib/plutonium/ui/display/resource.rb +141 -22
- data/lib/plutonium/ui/display/theme.rb +20 -1
- data/lib/plutonium/ui/export_button.rb +1 -1
- data/lib/plutonium/ui/form/base.rb +8 -7
- data/lib/plutonium/ui/form/components/intl_tel_input.rb +1 -1
- data/lib/plutonium/ui/form/components/section.rb +7 -62
- data/lib/plutonium/ui/form/components/uppy.rb +12 -1
- data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +16 -3
- data/lib/plutonium/ui/form/concerns/renders_structured_inputs.rb +5 -1
- data/lib/plutonium/ui/form/query.rb +2 -4
- data/lib/plutonium/ui/form/resource.rb +92 -15
- data/lib/plutonium/ui/form/theme.rb +17 -0
- data/lib/plutonium/ui/form/wizard.rb +25 -1
- data/lib/plutonium/ui/grid/card.rb +79 -11
- data/lib/plutonium/ui/grid/resource.rb +47 -5
- data/lib/plutonium/ui/interaction/async/run_progress.rb +227 -0
- data/lib/plutonium/ui/interaction/async/running_banner.rb +65 -0
- data/lib/plutonium/ui/kanban/card.rb +2 -1
- data/lib/plutonium/ui/kanban/column.rb +12 -6
- data/lib/plutonium/ui/kanban/resource.rb +6 -7
- data/lib/plutonium/ui/layout/base.rb +10 -3
- data/lib/plutonium/ui/nav_grid_menu.rb +1 -0
- data/lib/plutonium/ui/page/base.rb +19 -0
- data/lib/plutonium/ui/page/edit.rb +4 -1
- data/lib/plutonium/ui/page/index.rb +69 -18
- data/lib/plutonium/ui/page/interactive_action.rb +5 -1
- data/lib/plutonium/ui/page/new.rb +4 -1
- data/lib/plutonium/ui/page/show.rb +27 -10
- data/lib/plutonium/ui/page/wizard.rb +10 -1
- data/lib/plutonium/ui/page/wizard_chooser.rb +36 -11
- data/lib/plutonium/ui/page_width.rb +58 -0
- data/lib/plutonium/ui/table/base.rb +34 -1
- data/lib/plutonium/ui/table/components/attachment.rb +1 -1
- data/lib/plutonium/ui/table/components/bulk_actions_toolbar.rb +32 -8
- data/lib/plutonium/ui/table/components/drag_handle.rb +120 -0
- data/lib/plutonium/ui/table/components/filter_form.rb +1 -4
- data/lib/plutonium/ui/table/components/filter_pills.rb +1 -1
- data/lib/plutonium/ui/table/components/row_actions_dropdown.rb +1 -1
- data/lib/plutonium/ui/table/resource.rb +50 -5
- data/lib/plutonium/ui/table/theme.rb +59 -2
- data/lib/plutonium/ui/wizard/review.rb +4 -2
- data/lib/plutonium/ui/wizard/summary_display.rb +42 -14
- data/lib/plutonium/version.rb +1 -1
- data/lib/plutonium/wizard/attachments.rb +32 -197
- data/lib/plutonium/wizard/base.rb +6 -1
- data/lib/plutonium/wizard/configuration.rb +12 -0
- data/lib/plutonium/wizard/controller.rb +14 -0
- data/lib/plutonium/wizard/driving.rb +99 -15
- data/lib/plutonium/wizard/dsl.rb +23 -0
- data/lib/plutonium/wizard/resume.rb +127 -49
- data/lib/plutonium/wizard/runner.rb +46 -2
- data/lib/plutonium/wizard/step_adapter.rb +1 -1
- data/lib/plutonium/wizard/sweep_job.rb +16 -0
- data/lib/plutonium.rb +21 -0
- data/lib/rodauth/features/session_isolation.rb +92 -0
- data/lib/rodauth/plugins.rb +1 -0
- data/package.json +2 -1
- data/plutonium.gemspec +29 -11
- data/src/css/components.css +89 -1
- data/src/css/slim_select.css +20 -0
- data/src/js/controllers/breadcrumbs_controller.js +112 -0
- data/src/js/controllers/bulk_actions_controller.js +10 -2
- data/src/js/controllers/kanban_controller.js +30 -21
- data/src/js/controllers/positioned_controller.js +452 -0
- data/src/js/controllers/register_controllers.js +6 -0
- data/src/js/controllers/resource_drop_down_controller.js +5 -0
- data/src/js/controllers/run_progress_controller.js +73 -0
- data/src/js/drag/sortable.js +186 -0
- data/yarn.lock +108 -63
- metadata +103 -16
- data/docs/.vitepress/theme/components/HomeAudienceSplit.vue +0 -53
- data/docs/.vitepress/theme/components/HomePillars.vue +0 -42
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"planPath": "docs/superpowers/plans/2026-07-31-positioned-drag-and-drop.md",
|
|
3
|
+
"specPath": "docs/superpowers/specs/2026-07-31-positioned-drag-and-drop-design.md",
|
|
4
|
+
"tasks": [
|
|
5
|
+
{
|
|
6
|
+
"id": 1,
|
|
7
|
+
"subject": "Task 1: Promote Positioning::Config out of the kanban namespace",
|
|
8
|
+
"status": "completed",
|
|
9
|
+
"description": "**Goal:** One strategy machine, in `Plutonium::Positioning`, with kanban's public surface unchanged.\n\n**Verify:** `bundle exec appraisal rails-8.1 ruby -Itest test/plutonium/kanban/positioning_test.rb` (file must be UNMODIFIED)\n\n```json:metadata\n{\"files\": [\"lib/plutonium/positioning/config.rb\", \"lib/plutonium/kanban/positioning.rb\", \"lib/plutonium/positioning.rb\", \"test/plutonium/positioning/config_test.rb\"], \"verifyCommand\": \"bundle exec appraisal rails-8.1 ruby -Itest test/plutonium/kanban/positioning_test.rb\", \"acceptanceCriteria\": [\"promoted constants exist\", \"kanban namespace aliases them\", \"Move#column defaults nil\", \"kanban positioning test passes unmodified\"], \"requiresUserVerification\": false}\n```"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": 2,
|
|
13
|
+
"subject": "Task 2: reposition! reports whether it rebalanced",
|
|
14
|
+
"status": "completed",
|
|
15
|
+
"blockedBy": [
|
|
16
|
+
1
|
|
17
|
+
],
|
|
18
|
+
"description": "**Goal:** The controller can tell a clean drop from one that renumbered the group.\n\n**Verify:** `bundle exec appraisal rails-8.1 ruby -Itest test/plutonium/positioning_test.rb`\n\n```json:metadata\n{\"files\": [\"lib/plutonium/positioning.rb\", \"lib/plutonium/positioning/config.rb\", \"test/plutonium/positioning_test.rb\", \"test/plutonium/positioning/config_test.rb\"], \"verifyCommand\": \"bundle exec appraisal rails-8.1 ruby -Itest test/plutonium/positioning_test.rb\", \"acceptanceCriteria\": [\"reposition! returns rebalanced?\", \"true only on exhausted gap\", \"Config surfaces per-mode reconcile signal\"], \"requiresUserVerification\": false}\n```"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": 3,
|
|
22
|
+
"subject": "Task 3: Hidden actions",
|
|
23
|
+
"status": "completed",
|
|
24
|
+
"description": "**Goal:** `hidden: true` is a general action flag; `kanban_drop` disappears; both bulk-action selectors stop leaking hidden actions.\n\n**Verify:** `rg -n \"kanban_drop\\b\" lib app test` \u2192 no output; then `bundle exec appraisal rails-8.1 rake test`\n\n```json:metadata\n{\"files\": [\"lib/plutonium/action/base.rb\", \"lib/plutonium/definition/index_views.rb\", \"lib/plutonium/ui/page/index.rb\", \"lib/plutonium/ui/page/show.rb\", \"lib/plutonium/ui/table/resource.rb\", \"lib/plutonium/ui/grid/card.rb\", \"lib/plutonium/ui/grid/resource.rb\", \"lib/plutonium/kanban/column.rb\", \"test/plutonium/action/hidden_action_test.rb\"], \"verifyCommand\": \"bundle exec appraisal rails-8.1 rake test\", \"acceptanceCriteria\": [\"hidden? replaces kanban_drop?\", \"survives with() round-trip\", \"all six selectors filter\", \"both bulk bars filter\"], \"requiresUserVerification\": false}\n```"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": 4,
|
|
28
|
+
"subject": "Task 4: The position_on definition DSL + board inheritance",
|
|
29
|
+
"status": "completed",
|
|
30
|
+
"blockedBy": [
|
|
31
|
+
1,
|
|
32
|
+
3
|
|
33
|
+
],
|
|
34
|
+
"description": "**Goal:** `position_on` declares a resource drag-orderable and expands to sort + default_sort + a hidden reposition action. Kanban boards inherit it.\n\n**Naming:** `position_on` deliberately reuses kanban's verb rather than adding a third (`positioned_on` on the model, `position_on` in the definition layer).\n\n**Board inheritance:** `dsl.rb:18` must stop seeding `Config.default` (nil = not declared); `Board#position_config_for(definition)` resolves LAZILY, mirroring `show_in_for` (board.rb:37). Lazy because `kanban` compiles the board eagerly at class-load (index_views.rb:121), so eager resolution would make declaration order matter. Update the 5 call sites in kanban_actions.rb (136, 259, 581, 733, 784).\n\n**Check:** `rg -n \"position_config\\b\" lib/plutonium/resource/controllers/kanban_actions.rb` \u2192 every hit must be `position_config_for(current_definition)`.\n\n**Verify:** `bundle exec appraisal rails-8.1 rake test`\n\n```json:metadata\n{\"files\": [\"lib/plutonium/definition/positioning.rb\", \"lib/plutonium/definition/base.rb\", \"lib/plutonium/kanban/dsl.rb\", \"lib/plutonium/kanban/board.rb\", \"lib/plutonium/resource/controllers/kanban_actions.rb\", \"test/plutonium/definition/positioning_test.rb\"], \"verifyCommand\": \"bundle exec appraisal rails-8.1 rake test\", \"acceptanceCriteria\": [\"four DSL forms\", \"Mode A boot check\", \"Mode B skips check\", \"expansion correct\", \"Mode C inert\", \"board inherits definition\", \"board block overrides\", \"lazy resolution\"], \"requiresUserVerification\": false}\n```"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": 5,
|
|
38
|
+
"subject": "Task 5: The reposition endpoint",
|
|
39
|
+
"status": "completed",
|
|
40
|
+
"blockedBy": [
|
|
41
|
+
2,
|
|
42
|
+
4
|
|
43
|
+
],
|
|
44
|
+
"description": "**Goal:** `POST <member>/reposition` moves a record between two neighbours, authorized and scoped.\n\n**OPEN POINT:** `position_collection_frame_id` / `render_position_collection_html` must reuse CrudActions' existing collection-rendering path. Read `lib/plutonium/resource/controllers/crud_actions.rb`; model on `KanbanActions#render_kanban_column_html` (kanban_actions.rb:568).\n\n**Verify:** `bundle exec appraisal rails-8.1 ruby -Itest test/plutonium/resource/controllers/position_actions_test.rb`\n\n```json:metadata\n{\"files\": [\"lib/plutonium/resource/controllers/position_actions.rb\", \"lib/plutonium/routing/mapper_extensions.rb\", \"lib/plutonium/resource/policy.rb\", \"lib/plutonium/resource/controller.rb\", \"test/plutonium/resource/controllers/position_actions_test.rb\"], \"verifyCommand\": \"bundle exec appraisal rails-8.1 ruby -Itest test/plutonium/resource/controllers/position_actions_test.rb\", \"acceptanceCriteria\": [\"reposition? defaults to update?\", \"neighbours scope-resolved\", \"204 on clean drop\", \"reconcile on rebalance/drift/ModeB\", \"rescues stream not error pages\", \"404 when not positioned\"], \"requiresUserVerification\": false}\n```"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": 6,
|
|
48
|
+
"subject": "Task 6: Extract the shared drag core",
|
|
49
|
+
"status": "completed",
|
|
50
|
+
"description": "**Goal:** One native-DnD implementation in `src/js/drag/sortable.js`, kanban behaviour unchanged.\n\n**RISK:** Riskiest task in the plan. Behaviour-preserving extraction ONLY. Can be abandoned without losing Tasks 1-5.\n\n**Verify:** `yarn build && bundle exec appraisal rails-8.1 rake test` + manual kanban drag\n\n```json:metadata\n{\"files\": [\"src/js/drag/sortable.js\", \"src/js/controllers/kanban_controller.js\"], \"verifyCommand\": \"yarn build && bundle exec appraisal rails-8.1 rake test\", \"acceptanceCriteria\": [\"shared module has no kanban knowledge\", \"kanban consumes it\", \"board-specific methods stay put\", \"kanban suite passes\", \"manual drag unchanged\"], \"requiresUserVerification\": false}\n```"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": 7,
|
|
54
|
+
"subject": "Task 7: The positioned Stimulus controller and table grip",
|
|
55
|
+
"status": "completed",
|
|
56
|
+
"blockedBy": [
|
|
57
|
+
5,
|
|
58
|
+
6
|
|
59
|
+
],
|
|
60
|
+
"description": "**Goal:** A hover grip in each row's first cell drags to reorder; disabled and offering a sort when the table is not in position order.\n\n**OPEN POINTS:** (1) active-sort accessor on `query_object.rb`; (2) where the table wrapper's attributes are built; (3) whether `<tr>` carries `group/row`. Read each file.\n\n**Verify:** `yarn build` + manual drag on `/tasks` + nested collection\n\n```json:metadata\n{\"files\": [\"src/js/controllers/positioned_controller.js\", \"lib/plutonium/ui/table/components/drag_handle.rb\", \"src/js/controllers/register_controllers.js\", \"lib/plutonium/ui/table/resource.rb\", \"lib/plutonium/ui/table/theme.rb\", \"lib/plutonium/ui/table/base.rb\"], \"verifyCommand\": \"yarn build\", \"acceptanceCriteria\": [\"only grip draggable\", \"hover + focus visibility\", \"disabled grip sorts\", \"posts and applies response\", \"keyboard reorder\", \"nested URL correct\"], \"requiresUserVerification\": false}\n```"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"id": 8,
|
|
64
|
+
"subject": "Task 8: Grid/card surface",
|
|
65
|
+
"status": "completed",
|
|
66
|
+
"blockedBy": [
|
|
67
|
+
7
|
|
68
|
+
],
|
|
69
|
+
"description": "**Goal:** The same grip and controller on grid/card index views.\n\n**Verify:** `yarn build` + manual drag on a grid index\n\n```json:metadata\n{\"files\": [\"lib/plutonium/ui/grid/card.rb\", \"lib/plutonium/ui/grid/resource.rb\", \"src/js/controllers/positioned_controller.js\"], \"verifyCommand\": \"yarn build\", \"acceptanceCriteria\": [\"reuses DragHandle\", \"grid wiring matches table\", \"horizontal axis honoured\"], \"requiresUserVerification\": false}\n```"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": 9,
|
|
73
|
+
"subject": "Task 9: System test",
|
|
74
|
+
"status": "completed",
|
|
75
|
+
"blockedBy": [
|
|
76
|
+
7
|
|
77
|
+
],
|
|
78
|
+
"description": "**Goal:** End-to-end proof that a real drag and a real keyboard reorder both persist.\n\n**HAZARD:** `test/dummy` is git-cleaned by the generator tests. STAGE the task_definition.rb change before running the suite.\n\n**Verify:** `bundle exec appraisal rake test`\n\n```json:metadata\n{\"files\": [\"test/system/positioned_drag_test.rb\", \"test/dummy/app/definitions/task_definition.rb\"], \"verifyCommand\": \"bundle exec appraisal rake test\", \"acceptanceCriteria\": [\"drag persists\", \"keyboard reorder persists\", \"foreign sort disables grip\", \"all Rails versions pass\"], \"requiresUserVerification\": false}\n```"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": 10,
|
|
82
|
+
"subject": "Task 10: Documentation and skills",
|
|
83
|
+
"status": "completed",
|
|
84
|
+
"blockedBy": [
|
|
85
|
+
9
|
|
86
|
+
],
|
|
87
|
+
"description": "**Goal:** The feature is discoverable, and the Mode B escape hatch is documented with a worked third-party example.\n\n**Verify:** `yarn docs:build`\n\n```json:metadata\n{\"files\": [\"docs/reference/positioning.md\", \"docs/reference/actions.md\", \".claude/skills/plutonium-resource/SKILL.md\", \".claude/skills/plutonium-ui/SKILL.md\"], \"verifyCommand\": \"yarn docs:build\", \"acceptanceCriteria\": [\"model/definition split\", \"three modes + acts_as_list example\", \"default_sort warning\", \"affordance difference\", \"hidden actions not an auth boundary\"], \"requiresUserVerification\": false}\n```"
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"lastUpdated": "2026-07-31"
|
|
91
|
+
}
|