Add transfer state tab, which is taking transfer state script by using APP_ID. Created internal api ɵgetTransferState to retrieve transfer state value from app into devtools app.
PR Close#62465
Use the packaged versions of the packages instead of the local ts_project dependencies to prevent multiple versions of the deps to enter test bundles
PR Close#62413
The serialization of route data does not support cyclic data objects. We sanitize nested route data object by replacing invalid values with a placeholder string.
PR Close#62339
Fixes: #61900
Previously in DevTools we would read signal values to display preview values in the UI without safely catching any errors thrown in their evaluations.
Now those signal functions are run in a safe context, their errors are caught and handled in the UI as well as replayed in the console.
PR Close#61911
On clicking a route in the router tree, the route details panel is displayed.
- The panel shows the details of the selected route, including the path, component, providers, guards etc.
- Clicking on a chip will navigate to the corresponding source file in the editor.
- Clicking on the path will navigate to the corresponding route in the router tree.
Demo Application Source: https://github.com/sumitarora/angular-routes-demo
Demo Application Deployed: https://sumitarora.github.io/angular-routes-demo/#/
PR Close#59999
This commit adds the support for defer block in the Angular DevTools.
@defer block are now visible in the directive tree and give access to defer & hydration details.
This feature also brings support of incrementation hydration.
PR Close#60629
`ng.getDirectiveMetadata` receives the component instance, not the raw DOM element.
This assumes that `ng.getComponent` is implemented in all environments and that the root element itself is a component.
PR Close#60991
Currently, highlighting works only when a directive explorer node is hovered. The change enables this feature on node selection as well.
PR Close#60744
This updates the DevTools protocol to send Wiz/ACX metadata in addition to Angular metadata. Fortunately we don't need to worry about backwards compatibility here (`framework` is required for example), but the design roughly mirrors `DirectiveDebugMetadata` in `@angular/core`.
Beyond that, this is mostly plumbing through an extra data slice in the form of `props` provided by Wiz. An earlier version implemented `events` as their own slice as well, but was removed as there is currently no generic way to disambiguate events from any other form of callback passed in as a prop. Instead, event callbacks are visualized as functions under the "Props" category.
Working with `DirectiveMetadata` as a union is unfortunately a bit annoying since it requires casting to more specific `{Angular,Acx,Wiz}DirectiveMetadata` types for TS to allow property access, even when the properties are optional anyways.
This commit is mostly for adding Wiz, but does add a bit of ACX functionality which is not fully tested.
PR Close#60475
This type was incorrect, as only components have `encapsulation` and `onPush` values. `ng.getDirectiveMetadata` does not return these properties for directive inputs.
Unfortunately the `| Partial<AngularComponentDebugMetadata>` is necessary to reference these properties or else TypeScript will reject their usage.
PR Close#60475
This allows `ng.getDirectiveMetadata` to be implemented by Wiz and ACX with subtly different shapes to match the nuances of those frameworks.
Existing usage of `{Component,Directive}DebugMetadata` was moved over to `Angular{Component,Directive}DebugMetadata` as appropriate, since the implementation of `ng` in `@angular/core` is specific to Angular. Only the types support Wiz and ACX.
I opted to merge `ComponentDebugMetadata` and `DirectiveDebugMetadata` into a single type of all the frameworks including both components and directives (recall that components extend directives). The reasoning for this is because Wiz does not support directives (you can kind of think of "Wiz Directive" as an abstract class extended by "Wiz Components"). I felt that a `DirectiveDebugMetadata` containing only Angular and ACX types would be a bit of a trap and lead to bugs when used. It's safer to just have the single type containing all the possible results from `ng.getDirectiveMetadata`.
I also chose to leave the `ng` type as is internally, since `@angular/core` implements a specific concrete version of it narrowed to Angular types. Separately I defined an expanded `FrameworkAgnosticGlobalUtils` which redefines `ng.getDirectiveMetadata` to include Wiz and ACX. We want this type to exist in the Angular GitHub repo so it can be referenced as a common primitive across all three frameworks. This is sufficient for now, however longer term we will likely want to actually manually define the function types in this framework-agnostic interface and make Angular's version properly implement it rather than extend and overwrite Angular's type.
PR Close#60475
Angular DevTools now supports mutating objects underneath signals in the property explorer view.
This is done by performing an "immutable update" by recursively copying objects underneath a signal and overwriting the one property specified. For example, if the user attempted to set `foo.bar.baz[2].hello = 'world'` and `bar` was a signal, this would effectively become:
```typescript
foo.bar.set({
...foo.bar(),
baz: [
...foo.bar().baz.slice(0, 2),
{
...foo.bar().baz[2],
hello: 'world',
},
...foo.bar().baz.slice(3),
],
})
```
The motivation for immutable updates is because signals and Angular change detection don't really like interior mutability of signal values. If we didn't do this, any kind of comparison or dirty check would prevent the UI from updating. If an application attempts to change a deeply nested property inside a signal, it doesn't work today. DevTools should generally be limited to operations an application could do itself, and the recommended approach to make such a change like this is an immutable update. Creating entirely new objects intentionally breaks referential equality such that the application can properly react to the change.
Unfortunately, it is not possible to make immutable updates in a truly generic sense. You can't just copy a class for instance `({...new MyFoo()}).doSomething()`. We could do something fancier like manually copying over the prototype or something like that, but there is no way to do this without breaking class semantics (ex. the class might reasonably rely on the constructor being called). Therefore we instead reject any mutations to non-primitive objects. In the future, we might expand the set of "primitives" to include other built-ins and well-known objects like `URL` or `Element`, but those are out of scope for now.
I opted to ban mutating the result of a readonly/computed signal. While the mutation is likely to succeed, a subsequent rerun of the `computed` will immediately drop the change. However, I opted to allow mutating the result of a getter property. This has a similar problem because it might be returning a synthetic object which will be invalidated on the next execution, but it is possible and reasonable for a getter to return the same object multiple times such that a mutation may reasonably survive other updates. DevTools can't easily know whether a getter actually will return the same object on each execution or not, so we optimistically assume the reference is stable. If it isn't, the mutation will be lost whenever the getter is re-executed.
PR Close#60381
Sometimes `forest` can be empty if the provided roots are empty, and was leading to a "Cannot read `resolutionPath` of `undefined`" error. Now we check the forest has a tree in it before looking up `resolutionPath`.
There might be a separate issue with the fact that the backend script likely shouldn't be emitting an empty forest in the first place. However we already check that a resolution path exists at all, so I think it's fair to also check that a tree was provided. We can separately look into making sure the backend is emitting valid data.
PR Close#60403
Previously, if `ng.getDirectives` was not implemented, Angular DevTools won't throw when attempting to load the component tree. Now it safely ignores the function and assumes no directives exist on the page.
PR Close#60209
In general, we can't assume all applications implement the full `ng` contract as many are older Angular application which pre-date the current interface. As a result, it is safer to type this as a `Partial`.
For now, I just added non-null assertions at all current usage locations, as we do generally feature detect before using these fields. However, hopefully this `Partial` type will make it harder to accidentally call a function which might not be supported.
PR Close#60209
Previously Angular DevTools would throw when run on an application which does not support `getInjector`, now it safely ignores it and assumes dependency injection is not supported.
PR Close#60206
Previously this was throwing errors in applications with no Router token.
Now it skips emitting events for the router tree when it is unable to find the Router token.
Note: If these events don't emit, DevTools treats the RouterTree feature as disabled.
PR Close#60221
Previously Angular DevTools would throw if `ng.applyChanges` was not defined. Now DevTools silently ignores the issue, assuming `mutateComponentOrDirective` was sufficient to update the application.
PR Close#60207
Previously, the profiler would only emit the specific template event and context when a template is created/updated, but not the template function related to the event.
This commit emits this function by using the third argument of the profiler function, which previously was only used for lifecycle hooks and output listeners. This commit also renames this arg to eventFn to express that it varies depending on the event type emitting from the profiler.
Note: this change is fully backwards compatible, since previously these template events did not use the third arg of the profiler function.
PR Close#60174
Use the new UI and drop the `InjectorTreeVisualizer` dependency. Additionally, use concrete values for `SerializedInjector.type` type instead of `string`.
PR Close#60011
This commit solves two cases
Bug: When a directive of the same name is selected, the property view tab would not update properly. This was caused by a signals refactor that changed the behaviour of a string input property to not re-render because the underlying signal did not change (string equality). This is fixed by converting this input into an object.
Bug: When a selected element is removed from the component tree, DevTools would not rerender the component tree properly and deselect that component. Now if DevTools detects that a component is removed, it re-renders the tree and deselects the component.
PR Close#59873
Several profiler calls don't have any meaningful instance when
producing a profiling event. This commit changes the default
instance value to null to sreamline profiler invocations.
PR Close#59233
Several profiler calls don't have any meaningful instance when
producing a profiling event. This commit changes the default
instance value to null to sreamline profiler invocations.
PR Close#59233