Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hooks for other specifications to observe navigation #6496

Merged
merged 7 commits into from
Jul 13, 2021

Conversation

jgraham
Copy link
Member

@jgraham jgraham commented Mar 15, 2021

This change is motivated by specifications, notably WebDriver-BiDi,
that want to observe the progress of navigations. Currently
specifications that want to do this effectively monkeypatch HTML by
writing "when , run the following:". The aim
here is to provide more definite integration points.

Implementation wise, this adds a single new concept; a navigation id
which is a unique id generated for each navigation. This enables
consumers to tell when events are from the same navigation.

On top of that, a navigation status struct is defined, with an id, a
URL and a status. This is used as a uniform interface for
communicating the navigation progress through all the integration
points, even though not all fields are useful in all cases.

The actual integration points added are:

  • Navigation started
  • Navigation failed
  • Download started
  • DOM load complete
  • Load complete

In addition the navigate algorithm itself returns a navigation status,
so that external specifications which initiate a navigation can get
the associated navigation id (or find out that the navigation
completed in the case of a fragment navigation).

Closes #6429.


💥 Error: connect ETIMEDOUT 128.30.52.141:443 💥

PR Preview failed to build. (Last tried on Jul 8, 2021, 7:11 PM UTC).

More

PR Preview relies on a number of web services to run. There seems to be an issue with the following one:

🚨 HTML Diff Service - The HTML Diff Service is used to create HTML diffs of the spec changes suggested in a pull request.

🔗 Related URL

If you don't have enough information above to solve the error by yourself (or to understand to which web service the error is related to, if any), please file an issue.

@domenic
Copy link
Member

domenic commented Mar 16, 2021

Cross-linking to #6429. I'll try to help review this soon, but also discuss over there.

@jgraham jgraham marked this pull request as ready for review March 17, 2021 09:44
Copy link
Member

@foolip foolip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've skimmed parts and looked at others more carefully. Integrating like this makes a lot of sense to me, and I think the main question is how generic we make it. I'll comment separately on that.

source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
@foolip
Copy link
Member

foolip commented Apr 30, 2021

On the multiple "other applicable specifications" hooks, I wonder if we could call out WebDriver BiDi specifically, but keep the hook names generic. This way, any other specs that wants to start using this would need to raise it here, or monkey-patch in a pretty obvious way.

(Making the mechanism very generic and inviting for use right away seems risky.)

source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated
<dl>
<dt><dfn data-x="navigation-status-id">id</dfn></dt>
<dd>The <span data-x="navigation-params-id">navigation id</span> for the navigation, or null if
the navigation is canceled early or is a synchronous fragment navigation</dd>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the way to detect "synchronous fragment navigation" is that status is "complete" but there's no ID? Or is it possible for a "synchronous fragment navigation" to be canceled in some manner, leading to ambiguity?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

w3c/webdriver-bidi#93 refers to "fragment navigated steps" which aren't defined anywhere, but maybe that's the right approach, it would be more explicit even status could be used to distinguish.

Increasingly I'm thinking that the status should only be used for the regular navigation hook that goes through multiple stages, not the one-off hooks.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think complete with no id only happens in the fragment case.

source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated
data-x="navigation-status-id">id</span> is the <code>Document</code> object's <span
data-x="concept-document-navigation-id">navigation id</span>, <span
data-x="navigation-status-status">status</span> is "<code data-x="navigation-status-pending"
>pending</code>", and <span data-x="navigation-status-url">url</span> is the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might it be important to distinguish this DOMContentLoaded hook from the start of navigation hook? The hook is different, but the navigation status struct has the same contents.

I guess that's fine, but the status actually seems like it's not needed here or for the "load complete steps" since they'll never be called with any other status. Perhaps making status nullable would make it more clear that it's not always meaningful?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not sure. To me it seemed easier to have a consistent data structure where some of the fields are only really relevant in some cases (but the data is correct). If we were going to make the status null in the cases where you're really using the event name, it might be better to just have (id, url) in the struct and the status only in the sync return value for the navigate algorithm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is like the "download started steps" steps, where the hook itself is conveying part of the information. This is all fine. I guess other options would be (1) just one hook and conveying everything through the struct or (2) each hook has its own argument list and no shared struct.

source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
@jgraham
Copy link
Member Author

jgraham commented May 14, 2021

I updated this a bit. I don't quite understand how you want the hooks phrased in the end, so if you can give a concrete example of wording that would help.

@jgraham jgraham requested a review from foolip May 20, 2021 19:32
source Outdated
<code>Document</code>. User agents may do this before the complete document has been parsed (thus
achieving <i>incremental rendering</i>), and must do this before any scripts are to be
executed.</p>
<p>Then, with <var>document</var>, the user agent must <span>update the session history with the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<p>Then, with <var>document</var>, the user agent must <span>update the session history with the
<p>Then, the user agent must <span>update the session history with the

The "with document" here seemed off to me, almost as if we're going for a JavaScript or Python with statement.

@foolip
Copy link
Member

foolip commented May 27, 2021

Alright, I think this is in good shape now, and here's what needs to be resolved to land it:

  • Generic "other applicable specifications" hooks or calls to BiDi? I can live with either, so will kick the question to @domenic.
  • I'm not entirely sure will how BiDi will deal with the synchronous cases where a hook is invoked and immediately after the same struct is returned. I guess by setting a global (or stack-allocated) "now invoking navigate" flag an ignoring the callbacks then?

@domenic
Copy link
Member

domenic commented May 27, 2021

Generic "other applicable specifications" hooks or calls to BiDi? I can live with either, so will kick the question to @domenic.

I'd prefer calls into Bidi :)

@foolip
Copy link
Member

foolip commented May 27, 2021

Let's go with that then :) @jgraham is it unambiguous what that change would look like, other than naming choices?

@jgraham
Copy link
Member Author

jgraham commented May 27, 2021

Well I can copy the existing examples. I assume it just means moving the definitions into BiDi and using wording like e.g. "Call the navigation started steps defined in [WebDriver-BiDi]".

@jgraham
Copy link
Member Author

jgraham commented May 27, 2021

I'm not entirely sure will how BiDi will deal with the synchronous cases where a hook is invoked and immediately after the same struct is returned. I guess by setting a global (or stack-allocated) "now invoking navigate" flag an ignoring the callbacks then?

I think that's a question for the BiDi side of the patch, but I don't think it should be handled specially at all (or at least I think the event should always be emitted; we still need a consensus on the order). Not emitting the event requires strong coupling at the client level between the code that's starting a navigation and the code recieving events (e.g. it makes it impossible to have a tool that just listens for navigation events active at the same time as a tool that runs tests).

@domenic
Copy link
Member

domenic commented May 27, 2021

Well I can copy the existing examples. I assume it just means moving the definitions into BiDi and using wording like e.g. "Call the navigation started steps defined in [WebDriver-BiDi]".

Yeah, with "navigation started steps" being a cross-spec-link. (You could also give them more descriptive names if that'd be helpful, saying what the steps do instead of naming them after their location within the calling algorithm.)

@foolip
Copy link
Member

foolip commented May 28, 2021

I think that's a question for the BiDi side of the patch, but I don't think it should be handled specially at all (or at least I think the event should always be emitted; we still need a consensus on the order). Not emitting the event requires strong coupling at the client level between the code that's starting a navigation and the code recieving events (e.g. it makes it impossible to have a tool that just listens for navigation events active at the same time as a tool that runs tests).

Aha, I see what you're intending. That makes sense as long as the ordering will end up the desired one. If we want the order to be something other than the emergent one, then it might be a bit complicated, but we'll see. We can change the HTML side of this if it turns out unsightly in BiDi ultimately.

Copy link
Member

@foolip foolip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically good to go I think, just some formatting nits really.

source Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated
@@ -86123,6 +86209,14 @@ interface <dfn>Location</dfn> { // but see also <a href="#the-location-interface
<li><p>If <var>allowedToDownload</var> is true, then handle <var>response</var> <span>as a
download</span>.</p></li>

<li><p>Call <span>WebDriver-BiDi download started</span> with <var>browsingContext</var> and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for other reviewers: yes communicating this case as a suddenly-complete navigation will make for mysterious-looking logic on the BiDi side, and maybe it should be more explicit, but we'll see when that side is written if it's fine or not.

source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
@jgraham jgraham requested a review from foolip June 9, 2021 13:10
Copy link
Member

@foolip foolip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me now, I have no further nits. I think we should merge it at the same time as we land the BiDi side of the change, so not merging now.

@foolip
Copy link
Member

foolip commented Jun 17, 2021

@jgraham there's a build error due to a misplaced <li> somewhere, can you spot where it is?

@domenic I've reviewed this pretty carefully, but if you want to give it a read over to make sure you like how we structured the hooks that would be nice.

Copy link
Member

@domenic domenic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this looks quite nice; I just found a few minor things.

source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated Show resolved Hide resolved
source Outdated
data-x="concept-document-navigation-id">navigation id</span> is not null, let
<var>navigationId</var> be <var>browingContext</var>'s <span>active document</span>'s
<span data-x="concept-document-navigation-id">navigation id</span>. Otherwise let <var>navigation
id</var> be the string representation of a UUID based on truly random, or pseudo-random numbers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and below, I think referencing the UUID URN spec isn't quite right. Instead I suggest using generate a random UUID.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why it's wrong. The RFC specifies an algorithm for generating the UUID and a string representation that's independent of the use as a URN. In particular the ABNF for the string representation in section 3 only includes the formatted hex digits, and not the urn:uuid: prefix. I am definitely more inclined to link to that than some WICG draft which has unknown levels of buy-in, and for which the proposed API surface isn't otherwise a dependency of this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to switch the reference if you're not comfortable doing so; that's the web platform definition we're planning on using in HTML and other specs since it's more rigorous and clear.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that definition is clearer, but I'm not keen to be the first one to link to WICG drafts from HTML. Indeed, if the plan is to use that definition everywhere I'd propose we lift just the UUID generation algorithm into another spec e.g. infra.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said, I'm happy to push a commit to this PR to update the reference if you're not comfortable doing so.

source Show resolved Hide resolved
source Outdated
also create a corresponding <span>XML parser</span>. <ref spec=XML> <ref spec=XMLNS> <ref
spec=RFC7303> <ref spec=DOM></p>
data-x="create-the-document-object">create and initialize a <code>Document</code> object</span>,
<var>document</var> given "<code data-x="">xml</code>", <var>type</var>, and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO move comma after document

source Outdated
this before the complete document has been parsed (thus achieving <i>incremental rendering</i>),
and must do this before any scripts are to be executed.</p>

<p>Once parsing is complete, the user agent must set <var>document</var>'s <span
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it null by default? Couldn't this whole section be left as-is?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We set it when we initalize the document.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Why is it important to set it to null for XML documents in particular? Maybe worth a note?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For HTML documents we end up setting it to null when we abort the document or finish parsing. Since parsing XML seems to still be undefined, I don't know where else to set it back to null once the navigation is complete.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, that makes sense then. Can you add a note to that effect?

source Outdated
<var>document</var>'s <span data-x="concept-document-navigation-id">navigation id</span>, <span
data-x="navigation-status-status">status</span> is "<code data-x="navigation-status-canceled"
>canceled</code>", and <span data-x="navigation-status-url">url</span> is
<var>document</var>'s <span data-x="concept-document-url">URL</span>.</p></li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not so sure about this section. I'm guessing it's trying to handle the stop button but I think it's doing it wrong?

The stop button can do one of two things:

  • Abort a navigation which hasn't yet created a document. In this case it'll happen via step 3 of https://html.spec.whatwg.org/#stop-document-loading .

  • Abort the parser while it's busy filling the document. In that case it'll hit this abort algorithm. (window.stop() goes down the same path.)

Which ones do you want to capture here? Do you want to capture window.stop()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was just in the wrong order; we should emit the event before unsetting the navigation id. I think we want to always emit something to indicate that the navigation was interrupted (in particular: if it's a WebDriver-initiated navigation we need to be sure we return from the command even if stop() is called).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My question is what you mean by "navigation is interrupted". As you've specced it here, you will fire "canceled" if the navigation response comes back, the document is created, etc., but then the user or script on the web page aborts the parser while it's still parsing. And you will also fire "canceled" if the navigate response comes back, the document is created and totally finishes parsing, but the user or script on the webpage aborts while some slow subresource is downloading.

Is that the intent? It doesn't map to how I normally think of "navigation", but maybe it maps to what WebDriver BiDi wants.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this to call a specific hook and let the WebDriver side deal with the semantics.

source Outdated
<dd>A status code that is either
"<dfn data-x="navigation-status-canceled"><code>canceled</code></dfn>",
"<dfn data-x="navigation-status-pending"><code>pending</code></dfn>", or
"<dfn data-x="navigation-status-complete"><code>complete</code></dfn>".</dd>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the majority of navigations will never reach "complete", right? Maybe that's worth noting here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A majority by what measure? Anything that ends emitting a load event will reach complete, unless there's a mistake in the patch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, that actually will be a separate navigation status that gets created, disconnected from the first one which stays as "pending". I can see how that works for Web BiDi, where "navigation status" is just a packaging for sending information but it seems like it would make it hard to use this struct as something reflecting the actual ongoing status of the navigation throughout all callers and specs.

Given that, maybe it'd make the most sense to move this struct into the WebDriver BiDi spec and give it a name like WebDriver BiDi navigation signal?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you mean that it's a stateless thing rather than being something stateful? Yes that's true. I've added a note to clarify that. Design wise communicating by broadcasting a message at defined points in the navigation lifecycle seems better than adding additional internal state that needs to be kept up to date (and closer to modern browser architecture where there can be multiple processes involved and synchronous access to internal state isn't possible).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Since this message-broadcasting infrastructure isn't something we can use in other specs or other parts of HTML, can you make the change to move the struct to Web BiDi and give it a name like WebDriver BiDi navigation signal?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would make more sense to me to try and align on a single set of lifecycle events for navigation, and allow different to consumers to extract the information they require, rather than having a bespoke set of events for every spec. That seems more likely to end up with a platform that behaves consistently across different APIs.

Anyway I guess I will refactor if that's what's needed to get this landed, but it isn't very encouraging to be three months, a hundred+ comments, and one approval, into a PR, only to be asked to make a large change that's essentially editorial in nature.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more detailed questions:

  • Is it OK for HTML to define Navigation ID? We end up storing that on the document, and passing it around the various navigation functions, so it seems pretty strange for it to be defined elsewhere, but like the struct it's currently only used by WebDriver.
  • Is it OK for the navigate algorithm to continue to return a "WebDriver BiDi Navigation Signal", or do we also need additional changes to communicate the synchronous result of calling navigate via integration points rather than just using the call stack?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defining navigation ID in HTML seems reasonable.

I can't actually find anything that uses the return value of the navigate algorithm being the signal. Can you help me find where the return value is used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this. I'm honestly not convined it makes things better; it now means that if you add an extra return point from navigate you don't just need to get the return type of the algorithm right, you also need to add in an extra WebDriver BiDI call otherwise we will wait forever for the navigation to complete.

@jgraham jgraham requested a review from domenic June 24, 2021 14:44
source Outdated
data-x="concept-document-navigation-id">navigation id</span> is not null, let
<var>navigationId</var> be <var>browingContext</var>'s <span>active document</span>'s
<span data-x="concept-document-navigation-id">navigation id</span>. Otherwise let <var>navigation
id</var> be the string representation of a UUID based on truly random, or pseudo-random numbers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to switch the reference if you're not comfortable doing so; that's the web platform definition we're planning on using in HTML and other specs since it's more rigorous and clear.

source Show resolved Hide resolved
source Show resolved Hide resolved
source Outdated
this before the complete document has been parsed (thus achieving <i>incremental rendering</i>),
and must do this before any scripts are to be executed.</p>

<p>Once parsing is complete, the user agent must set <var>document</var>'s <span
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Why is it important to set it to null for XML documents in particular? Maybe worth a note?

source Outdated
<dd>A status code that is either
"<dfn data-x="navigation-status-canceled"><code>canceled</code></dfn>",
"<dfn data-x="navigation-status-pending"><code>pending</code></dfn>", or
"<dfn data-x="navigation-status-complete"><code>complete</code></dfn>".</dd>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, that actually will be a separate navigation status that gets created, disconnected from the first one which stays as "pending". I can see how that works for Web BiDi, where "navigation status" is just a packaging for sending information but it seems like it would make it hard to use this struct as something reflecting the actual ongoing status of the navigation throughout all callers and specs.

Given that, maybe it'd make the most sense to move this struct into the WebDriver BiDi spec and give it a name like WebDriver BiDi navigation signal?

This change is motivated by specifications, notably WebDriver-BiDi,
that want to observe the progress of navigations. Currently
specifications that want to do this effectively monkeypatch HTML by
writing "when <some stageis reached>, run the following:". The aim
here is to provide more definite integration points.

Implementation wise, this adds a single new concept; a navigation id
which is a unique id generated for each navigation. This enables
consumers to tell when events are from the same navigation.

On top of that, a navigation status struct is defined, with an id, a
URL and a status. This is used as a uniform interface for
communicating the navigation progress through all the integration
points, even though not all fields are useful in all cases.

The actual integration points added are:

* Navigation started
* Navigation failed
* Download started
* DOM load complete
* Load complete

In addition the navigate algorithm itself returns a navigation status,
so that external specifications which initiate a navigation can get
the associated navigation id (or find out that the navigation
completed in the case of a fragment navigation).
@jgraham jgraham requested a review from foolip July 6, 2021 18:40
Copy link
Member

@domenic domenic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This looks a lot cleaner now. I appreciate all the work you did to revise this to integrate better.

Do you want us to merge this right away, or wait for w3c/webdriver-bidi#93 ? I assume they should land at around the same time.

@foolip
Copy link
Member

foolip commented Jul 13, 2021

w3c/webdriver-bidi#93 is good to go now, so I'll merge both.

@foolip
Copy link
Member

foolip commented Jul 13, 2021

Here's the commit message I'm going with:

Add WebDriver BiDi navigation callbacks

This change is motivated by WebDriver BiDi needing to observe the
progress of navigations, in order to support commands and events related
to navigation: https://github.com/w3c/webdriver-bidi/pull/93

In HTML, this adds a single new concept; a navigation id which is a
unique id generated for each navigation. This enables WebDriver BiDi to
tell when events are from the same navigation.

In WebDriver BiDi, a navigation status struct is defined, with an id, a
URL and a status. This is used as a uniform interface for communicating
the navigation progress through all the integration points, even though
not all fields are useful in all cases.

The actual integration points added are:

* Navigation started
* Navigation aborted
* Navigation failed
* Download started
* Fragment navigated
* DOM load complete
* Load complete

I hope (and think) that captures all of the recent changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Add hooks for observing navigation lifecycle from other specs
3 participants