ExternalStatePlugin allows overrides#817
Conversation
c1f2faa to
4808f90
Compare
Maybe out of scope for this PR but |
4808f90 to
bd30886
Compare
c3be8cb to
2f4f1cf
Compare
|
Reopening to see if I can trigger Claude. |
099a17e to
b516643
Compare
|
@claude You are a principal engineer specialized in https://player-ui.github.io/next/ who follows best practices. Review this PR. Please follow these additional guidelines:
|
|
Claude finished @KVSRoyal's task in 2m 2s —— View job PR Review: ExternalAction Handler Allows Overrides
SummaryGood work overall. The registry-based approach is clean and follows existing Player patterns. Found a few bugs and design concerns below. Bugs1. Logger set too late in
|
| Scenario | Behavior |
|---|---|
| Two entries, same key | Later one wins (replaces) |
| Two entries, different specificity | More specific always wins |
| Same specificity, different values | Latest registration wins |
The set logic uses both matchers to check mutual equality. This is correct:
const existingIndex = this.store.findIndex(
(entry) => entry.matcher(match) && matcher(entry.key),
);This handles asymmetry in partial matching. Good approach.
Minor Nits
entry && entry.matcher(query)inget— theentry &&check is unnecessary.storeonly holdsRegistryIndex<V>objects. Remove for clarity.- Missing test: no handler registered for an external state. What happens? The handler is
undefined, sohandler?.(...)returnsundefined. No transition. This should be a test case. - The
Registryconstructorloggerparam has redundant| undefined— TypeScript adds that for optional params.
What's Good
- The registry-based API is clean and follows Player's
AssetRegistrypattern. - Tests cover: specificity ordering, override behavior, async, error, and edge cases.
- Docs are updated with examples and cross-links.
- Debug logging on override is a good DX addition.
- The
shouldTransitionhelper is clear and reusable.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## player-1-dot-zero #817 +/- ##
========================================
========================================
☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
d6688f0 to
4330417
Compare
Bundle ReportChanges will increase total bundle size by 63.5kB (1.13%) ⬆️. This is within the configured threshold ✅ Detailed changes
ℹ️ *Bundle size includes cached data from a previous commit Affected Assets, Files, and Routes:view changes for bundle: plugins/async-node/coreAssets Changed:
view changes for bundle: plugins/common-expressions/coreAssets Changed:
view changes for bundle: plugins/reference-assets/coreAssets Changed:
view changes for bundle: plugins/check-path/coreAssets Changed:
view changes for bundle: core/partial-match-registryAssets Changed:
view changes for bundle: plugins/common-types/coreAssets Changed:
view changes for bundle: plugins/stage-revert-data/coreAssets Changed:
view changes for bundle: plugins/markdown/coreAssets Changed:
view changes for bundle: plugins/beacon/coreAssets Changed:
view changes for bundle: plugins/external-action/coreAssets Changed:
view changes for bundle: plugins/metrics/coreAssets Changed:
view changes for bundle: core/playerAssets Changed:
view changes for bundle: plugins/auto-scroll/reactAssets Changed:
|
ExternalStatePlugin allows overrides
|
@claude Review this PR |
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
|
/docs |
sugarmanz
left a comment
There was a problem hiding this comment.
Small comments regarding documentation, otherwise looks good!
| ] | ||
| ``` | ||
|
|
||
| ### `ExternalActionPlugin` renamed to `ExternalStatePlugin` with new handler API |
There was a problem hiding this comment.
Can these be added to the PR # Release Notes section so they get picked up and added to the CHANGELOG.md?
There was a problem hiding this comment.
Yeah, sure, adding. Although for the 1.0 stuff I think we've so far just been putting things in the migration docs file.
| ExternalStateHandler( | ||
| ref = "my-action", | ||
| handlerFunction = ExternalStateHandler.Function { state, options, transition -> | ||
| transition("Next") | ||
| } | ||
| ) |
There was a problem hiding this comment.
Does the trailing lambda syntax work here?
ExternalStateHandler(ref = "my-action") { state, options, transition ->
transition("Next")
}| ExternalStatePlugin( | ||
| ExternalStateHandler( | ||
| ref = "my-action", | ||
| handlerFunction = ExternalStateHandler.Function { state, options, transition -> |
There was a problem hiding this comment.
Ditto about using trailing lambda syntax as suggested implementation format if it works
|
|
||
| player.hooks.flowController.tap(this.name, (flowController) => { | ||
| flowController.hooks.flow.tap(this.name, (flow) => { | ||
| flow.hooks.transition.tap(this.name, (fromState, toNamedState) => { |
There was a problem hiding this comment.
We either need to port these over or add a followup to get rid of the setTimeout: https://github.com/player-ui/player/blob/main/plugins/external-action/core/src/index.ts#L39
There was a problem hiding this comment.
Update! I also tried to remove the param stuff from the web docs.
Co-authored-by: Spencer Hamm <spentacular@gmail.com>
e99c423 to
fafcd7a
Compare
This is now the jumbo PR covering all 3 platforms. (Was previously just for core.)
What
Please review the release notes that are part of the PR. (Putting them there helps me keep redundancy down and keep the docs accurate.)
Why
Deterministic Overrides: Users want predictable behaviour when multiple plugins or handlers are registered. The registry ensures that:
Existing Patterns: We chose to reuse
Registryas this follows established patterns in Player for Asset registration. Hopefully this will make it easier for users to understand the logic.Visibility: We chose to add
debuglogging when handlers are overridden to make it clear to developers what's happening during plugin composition.Change Type (required)
Indicate the type of change your pull request is:
patchminormajorN/A(part of 1.0)Does your PR have any documentation updates?
Release Notes
ExternalActionPluginrenamed toExternalStatePluginwith new handler APIThe plugin has been renamed from
ExternalActionPlugintoExternalStatePlugin. The nameExternalStatebetter reflects what the plugin does — it handlesEXTERNALnavigation states — and is now used consistently across all platforms.The handler API has changed. Instead of a single function that receives all external states, you now provide an array of handlers. Each handler requires a
ref(matching the external state'sreffield) and ahandlerFunction. An optionalmatchobject can be provided to match on additional state properties beyondref. See docs site for full examples.Handler matching and specificity
Handlers are matched against the external state using partial object matching on
refand any additional properties inmatch. When multiple handlers could match a state, the most specific one wins (the one with the most matching properties).This allows you to register a general handler for a
refand a more specific one for a particular variant:Overriding handlers across plugins
Overriding handlers is now supported. When multiple
ExternalStatePlugininstances register a handler for the same state, the last registered handler wins. Adebuglog is emitted when a handler is replaced, so you can tell when an override is happening.To add more handlers after initial setup, register a new
ExternalStatePlugininstance. Plugins are typically grouped together and easy to find by name. This makes it straightforward to determine the override order.We considered allowing more handlers to be added to an
ExternalStatePluginafter creation, however, this would make it more difficult to figure out the override order. So we do not support that.Missing handlers
For now, If no handler matches an external state, the Player remains on that state and no transition occurs. Ensure every
EXTERNALstate in your flow has a registered handler.Note
In a future release, unhandled external states will automatically report an error via the Error Controller.