Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions app/src/__tests__/router-panels.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import type { NavigationRecord, RouterPage } from '../pages/router-types';

type Call = (name: string, arg: Record<string, unknown>) => Promise<unknown>;

function fakeClient(call: Call): DevframeRpcClient {
function fakeClient(call: Call, connectionMeta: object = {}): DevframeRpcClient {
const rpc = { call, callEvent: () => Promise.resolve() };
return { connectionMeta: {}, scope: () => ({ rpc }) } as unknown as DevframeRpcClient;
return { connectionMeta, scope: () => ({ rpc }) } as unknown as DevframeRpcClient;
}

const routerActionsOff = { configs: { 'ng-devtools': { actions: { router: false } } } };

const offline: Call = () => Promise.reject(new Error('offline'));

function nav(id: number, url: string): NavigationRecord {
Expand Down Expand Up @@ -54,10 +56,10 @@ function button(fixture: ComponentFixture<unknown>, name: string): HTMLButtonEle
return found;
}

function mount<T>(type: Type<T>, data: RouterPage, call: Call) {
function mount<T>(type: Type<T>, data: RouterPage, call: Call, connectionMeta?: object) {
const fixture = TestBed.createComponent(type);
fixture.componentRef.setInput('page', data);
fixture.componentRef.setInput('rpc', fakeClient(call));
fixture.componentRef.setInput('rpc', fakeClient(call, connectionMeta));
document.body.append(el(fixture));
return fixture;
}
Expand Down Expand Up @@ -109,6 +111,20 @@ describe('RouteTree row actions', () => {
);
});

it('turns Probe off with the config hint when router actions are off and keeps Read lazy', async () => {
const fixture = mount(RouteTree, config, offline, routerActionsOff);
await settle(fixture);
const probe = button(fixture, 'Probe in app');
const hint = el(fixture).querySelector('#route-tree-writes-off');
expect(probe.disabled).toBe(true);
expect(probe.getAttribute('aria-describedby')).toBe('route-tree-writes-off');
expect(hint?.textContent?.trim()).toBe(
'Navigating is turned off in the devtools config (actions.router).',
);
expect(button(fixture, 'Navigate to users/:id').disabled).toBe(true);
expect(button(fixture, 'Read lazy routes of lazy').disabled).toBe(false);
});

it('shows Read lazy results and unreachable pages under the row', async () => {
const fixture = mount(RouteTree, config, offline);
await settle(fixture);
Expand Down
10 changes: 9 additions & 1 deletion app/src/pages/route-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,15 @@ interface MatchResult {
(input)="testUrl.set($any($event.target).value)"
/>
<button type="submit" class="small primary">Predict</button>
<button type="button" class="small" (click)="probe()">Probe in app</button>
<button
type="button"
class="small"
[disabled]="!navigationAllowed()"
[attr.aria-describedby]="navigationAllowed() ? null : 'route-tree-writes-off'"
(click)="probe()"
>
Probe in app
</button>
</form>
@if (match(); as result) {
<div class="result" role="status" [attr.data-matched]="result.matched">
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/src/content/agents/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Lists the tabs that report to the server, newest first: page id, URL, seconds si

### Turn tools off

The server decides which tools exist. Set `agent.readOnly` to drop the six action tools. Set `agent.tools.<inspector>` to `false` to hide one inspector's tools and resources, and keep its tab. Turning an inspector off with `inspectors`, or blocking an action with `actions`, drops the matching tools too. See [Inspectors and agent tools](../getting-started/configuration.md#inspectors-and-agent-tools).
The server decides which tools exist. Set `agent.readOnly` to drop the six action tools. Set `agent.tools.<inspector>` to `false` to hide one inspector's tools and resources, and keep its tab. Turning an inspector off with `inspectors`, or blocking an action with `actions`, drops the matching tools too. `actions.router` is the exception: `navigate` stays and refuses `navigate`, `abort`, `replay` and `probe`. See [Inspectors and agent tools](../getting-started/configuration.md#inspectors-and-agent-tools).

## Source scan

Expand Down Expand Up @@ -191,7 +191,7 @@ Use `explain-navigation` for "why was I redirected". Pass `perf: true` for "why
| `instrument` | Turns per-guard and per-resolver recording on or off. | `on` |
| `resolve-lazy` | Reads the routes of an unloaded lazy route without registering them. | `routeId`, from `list-routes` |

`action` is required. Only same-origin URLs that start with `/` are accepted.
`action` is required. Only same-origin URLs that start with `/` are accepted. With `actions.router` set to `false`, `navigate`, `abort`, `replay` and `probe` answer **Navigating is turned off in the devtools config (actions.router).** `instrument` and `resolve-lazy` still work. `agent.readOnly` drops the whole tool.

`waitFor` sets when `navigate` answers:

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/src/content/getting-started/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ Actions are the writes that the panel and agents make to your app or the server.
| Option | Default | What `false` blocks |
| ---------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `actions.forms` | `true` | Form writes: set value, fill, mark touched, untouched, dirty or pristine, touch all, revalidate, reset, enable, disable, submit and restore. Drops `form-action` and `fill-form`. |
| `actions.router` | `true` | Navigate, abort and replay. Drops the `navigate` agent tool. |
| `actions.router` | `true` | Navigate, abort, replay and probe. Probe runs your app's `canMatch` guards. The `navigate` agent tool stays for `instrument` and `resolve-lazy` and refuses the other four. |
| `actions.ngrx` | `true` | Restoring NgRx state from the change log and dispatching `@ngrx/store` actions. Drops the `dispatch-ngrx-action` agent tool. |
| `actions.http` | `true` | Editing fault injection rules and clearing the HTTP timeline. |
| `actions.analog` | `true` | The Analog request playground. Drops the `analog-call-api` agent tool. |
Expand Down
5 changes: 4 additions & 1 deletion apps/docs/src/content/inspectors/router.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ Without that recording, the guards listed for a navigation are candidates: the `
| `ng-devtools:navigate` | Acts on the router: `navigate`, `abort`, `replay`, `probe`, `instrument` and `resolve-lazy`. |
| `ng-devtools:router` (resource) | The active route tree and recent navigations of each page. |

`navigate` only accepts same-origin relative URLs that start with `/`. `resolve-lazy` needs a `routeId`. See [Tools](../agents/tools.md).
`navigate` only accepts same-origin relative URLs that start with `/`. `resolve-lazy` needs a `routeId`. With [`actions.router`](../getting-started/configuration.md#actions) set to `false`, the tool refuses `navigate`, `abort`, `replay` and `probe`, and keeps `instrument` and `resolve-lazy`. See [Tools](../agents/tools.md).

## Limits and gotchas

Expand Down Expand Up @@ -231,6 +231,9 @@ The page keeps the last 50 navigations and 50 preloads. Set the navigation count
<ngmd-accordion-item title="Does Probe in app change the URL?">
No. It runs the real matcher with <code>skipLocationChange</code> and stops after recognition. <code>canActivate</code>, <code>canDeactivate</code> and resolvers do not run. If a <code>canMatch</code> guard or the navigation error handler redirects, the probe stops the redirected navigation too and names its target.
</ngmd-accordion-item>
<ngmd-accordion-item title="Why is Probe in app turned off?">
The probe runs your app's <code>canMatch</code> guards, so <a href="../getting-started/configuration.md#actions"><code>actions.router</code></a> set to <code>false</code> turns it off, along with <strong>Go</strong>, <strong>Abort</strong> and <strong>Replay</strong>. <strong>Record each guard and resolver</strong> and <strong>Read lazy</strong> stay on.
</ngmd-accordion-item>
<ngmd-accordion-item title="Why is the source table collapsed?">
The live config is available, so it is the better source. Click <strong>Show table</strong> to open the source list.
</ngmd-accordion-item>
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading