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

Get getQueryString to expect relative URLs too #50

Merged
5 commits merged into from
Aug 13, 2021

Conversation

laziob
Copy link
Contributor

@laziob laziob commented May 12, 2021

Change-type: Minor
Signed-off-by: Ezequiel Boehler [email protected]

@laziob laziob added the versionbot/pr-draft Draft PR - Don't merge this PR automatically label May 12, 2021
@laziob laziob requested review from gelbal and pranasziaukas May 12, 2021 13:33
@laziob
Copy link
Contributor Author

laziob commented May 12, 2021

@gelbal @pranasziaukas I added the logic to handle both relative and absolute Urls and corresponding tests that seem to be working. But as always, please give it a look since you might come up with a better way to handle this or notice something I missed.

Thanks!

@gelbal
Copy link
Contributor

gelbal commented May 12, 2021

@laziob I see balenaCI returns failed because of not-prettified code. Can you please run npm run prettify and then commit again to clear these errors?

Error: File src/url-params.ts hasn't been formatted with prettier
Error: File test/url-params.test.ts hasn't been formatted with prettier

I wonder if it makes sense to include prettify in lint to catch these issues earlier 🤔
(I'm reviewing the rest of PR now)

Copy link
Contributor

@gelbal gelbal left a comment

Choose a reason for hiding this comment

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

Good stuff pushing this forward Ezequiel. I typed couple of suggestions and discussion points.

}

// If its not a relative URL string, we make sure if its a string or an URL. It its a string, we convert it to an URL object.
if (typeof destinationUrl === 'string') {
Copy link
Contributor

Choose a reason for hiding this comment

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

You can combine this if statement with the one above to eliminate the double check for string. The code and comments will also read better.

if (typeof destinationUrl === 'string') {
    if (destinationUrl.match(relativeRegex)) {
        return '';
    } else {
        ....
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gelbal Lol I was going to do it that way first, but for some reason I remembered that once I saw the if statements one below the other and that that was the usual practice or something like that and went the other way. Sure I'll change that.

Copy link
Contributor

Choose a reason for hiding this comment

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

@laziob oh I see you made a major rework. Actually I liked your previous implementation as it was cleaner (once you combine the new if statements). So the code handles the string scenario first and the proceeds to handling the URL scenario. Can you please bring it back? : )

Copy link
Contributor

@gelbal gelbal May 13, 2021

Choose a reason for hiding this comment

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

Petros (ex-CTO) made a pretty good presentation about such design principle actually (he calls it normalizing if). I highly recommend listening to it:
https://docs.google.com/presentation/d/1hFV5YBL4FflfN7OIJr6eZrUV4Pk158wOXWzea1ANTnM/edit#slide=id.p
https://drive.google.com/file/d/1xtHev7HUwbASdasf8cWfG9O2oHdlXX43/view

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gelbal It still handles the string scenario first. The code above is for the other parameter that stays that way regardless of the destinationUrl. The reason I changed it was because with the previous design, I had to repeat much more code, once for each if and even then couldnt make it work properly. In fact I dont even like this design, since it still repeats code. But it repeated less than the previous one. I still also dont believe we should be handling relative URLs through this method. It kind of undermines the use of TypeScript and gives place to the bad use of the method in resin-site, since I still think they shoudnt be forcing this method in every link "just in case". Performance wise it doesnt make sense to me. resin-site should have a better way to identify outbound links from inbound links, and call this method only on outbound links.

Having said that, I could try go back to the previous design, but I could make it work with the previous design. This was so far the only way I achieved what I wanted lol.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To put an example, Hub handles it like this:

deployUrl = getExternalLinkWithTracking( 'https://dashboard.balena-cloud.com/deploy?repoUrl=${repoUrl}')

So it explicitly uses the method on the only domain where its needed. For example marketing site only needs to use it on the Login and Signup buttons, which exist only in 2 places, the header (for most of the resin-site pages) , like here and the box for on the landing page.

So its not that they need to detect relative urls in a simple way. Its that they have to detect URLs to another balena domain, not even including subdomains.

If using a list is the best way to do it I dont really know, but if its needed to be raised for further discussion Im up for that. Whats the proper way and place to raise it? ALthough It just seems too much for the task at hand tbh.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gelbal we need to work on this soon since its the only thing preventing marketing sites to update to the last analytics client. Its still using 0.12 so its not stiching sessions nor using the last referrer updates.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@iamsolankiamit @thgreasi @JSReds if you could take a look into the discussion too so we can decide on how we advance it would be really helpful and appreciated! thanks!

Copy link
Contributor

@gelbal gelbal Jun 7, 2021

Choose a reason for hiding this comment

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

Hey @laziob cc @thgreasi @JSReds @iamsolankiamit, how about introducing an optional parameter (in the analytics-client constructor) for a list of domains to track?

We could retrieve this list either directly from the client that calls analytics-client or indirectly from the projectName configuration stored in the analytics-backend. At first it'll have the following content:

*.balena.io
*.balena-cloud.com

We will probably end up updating this list seldom so it's not a big maintenance issue to store it on the analytics-backend side.


Edit: Thinking it further, part of my suggestion actually means that analytics-client needs to retrieve such stateful information from the analytics-backend at each initialization. So maybe that's a no-go. It's cleaner for the component to configure analytics-client directly (without dependency on the backend).

Copy link
Contributor

Choose a reason for hiding this comment

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

Having said these, let's still go ahead with working on this PR to add support for relative URL detection.

src/url-params.ts Show resolved Hide resolved

// If its not a relative URL string, we make sure if its a string or an URL. It its a string, we convert it to an URL object.
if (typeof destinationUrl === 'string') {
destinationUrl = new URL(destinationUrl);
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to handle the errors here when the incoming string cannot be translated to a URL. I'm not sure if relativeRegex ensures that the string with no match is actually a URL.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gelbal Ohh yeap you are right. let me look into this.

? destinationDomainMatch.toString()
: null;
} catch (err) {
return ''; //I dont know what we should do when an error like this happens. Any ideas??
Copy link
Contributor

Choose a reason for hiding this comment

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

Good question. We could do console.log(err) but I don't know how much that'd help. I think it's fine to at least catch it as you do here.

Copy link
Contributor

Choose a reason for hiding this comment

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

@thgreasi @iamsolankiamit any suggestions on handling such caught errors in modules?

It's OK to silently fail here but I wonder what's the best practice.

// this regex is based on the assumption that we wont be using TLDs longer than 3 characters. If we do, it will break
// the logic and take that longer TLD as the main domain, for example hub.balena.edge.io -> edge.io
const regex = /([a-zA-Z0-9-]+)(\.[a-zA-Z]{2,3})?(\.[a-zA-Z]+$)/g;

let actualDomainMatch;
Copy link
Contributor

Choose a reason for hiding this comment

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

I actually prefer it here, next to where it's first assigned, so that's easier to follow.
Also type it as:

let actualDomainMatch: RegExpMatchArray | null;

Comment on lines 181 to 184
let destinationDomainMatch;
let destinationDomain;
let actualDomainMatch;
let actualDomain;
Copy link
Contributor

Choose a reason for hiding this comment

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

All these are typed as any, which isn't good...
After the changes suggested bellow this will be:

Suggested change
let destinationDomainMatch;
let destinationDomain;
let actualDomainMatch;
let actualDomain;
let destinationDomain: string | undefined;

but I would suggest to push it lower, near the place it's first assinged.

const destinationDomainMatch = destinationUrl
? destinationUrl.hostname.match(regex)
: null;
actualDomain = actualDomainMatch ? actualDomainMatch.toString() : null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
actualDomain = actualDomainMatch ? actualDomainMatch.toString() : null;
const actualDomain = actualDomainMatch ? actualDomainMatch.toString() : null;

and if you have recent enough TS in this project, then you can do:

		const actualDomain = actualDomainMatch?.[0]; // this is inferred as `string | null` automatically

prefer explicitly reading the first match, that relying on toString().

if (typeof destinationUrl === 'string') {
try {
destinationUrl = new URL(destinationUrl);
destinationDomainMatch = destinationUrl
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
destinationDomainMatch = destinationUrl
const destinationDomainMatch = destinationUrl

Just declare it in this scope, since this is only used in this limited scope as a temp variable and its value isn't useful outside this context.

return ''; //I dont know what we should do when an error like this happens. Any ideas??
}
} else {
destinationDomainMatch = destinationUrl
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
destinationDomainMatch = destinationUrl
const destinationDomainMatch = destinationUrl

Just declare it in this scope, since this is only used in this limited scope as a temp variable and its value isn't useful outside this context.

Comment on lines 206 to 208
destinationDomain = destinationDomainMatch
? destinationDomainMatch.toString()
: null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
destinationDomain = destinationDomainMatch
? destinationDomainMatch.toString()
: null;
destinationDomain = destinationDomainMatch?.[0];

Comment on lines 217 to 219
destinationDomain = destinationDomainMatch
? destinationDomainMatch.toString()
: null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
destinationDomain = destinationDomainMatch
? destinationDomainMatch.toString()
: null;
destinationDomain = destinationDomainMatch?.[0];

@laziob laziob force-pushed the getQueryString_expect_relative_url branch from dd34960 to c6811c1 Compare June 23, 2021 16:37
@laziob
Copy link
Contributor Author

laziob commented Jun 23, 2021

@gelbal I think I properly reverted to the previous way we handled the relative URLs, hadnling string first and so but keeping some error handling. The unit tests are still working properly too. So please take a look when possible. On the other hand, I still dont know whats the best way to pass href and window.location.hostname as arguments to getQueryString() on the resin-site side here which is adressed on the PR though but with no solution yet

Copy link
Contributor

@gelbal gelbal left a comment

Choose a reason for hiding this comment

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

Good stuff @laziob. I like this version the best.

The error you get is:
Error: File src/url-params.ts hasn't been formatted with prettier

Can you please call npm run prettify and squash all your commits before pushing once more?

return '';
}

// If its not a relative URL string, we make sure if its a string or an URL. It its a string, we convert it to an URL object.
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need a comment here as the code is self explanatory.

? destinationDomainMatch.toString()
: null;
} catch (err) {
return ''; //I dont know what we should do when an error like this happens. Any ideas??
Copy link
Contributor

Choose a reason for hiding this comment

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

@thgreasi @iamsolankiamit any suggestions on handling such caught errors in modules?

It's OK to silently fail here but I wonder what's the best practice.

Change-type: Minor
Signed-off-by: Ezequiel Boehler [email protected]
@laziob laziob force-pushed the getQueryString_expect_relative_url branch from c6811c1 to 43e9be3 Compare June 24, 2021 15:32
@laziob laziob requested a review from gelbal June 28, 2021 12:44
@gelbal
Copy link
Contributor

gelbal commented Jun 29, 2021

Hey @laziob, clicking on the Details button next to the checks takes you to the logs of balena CI. We see the following lint error:

src/url-params.ts:192:18
ERROR: 192:18  comment-format  comment must start with a space

It's best to get rid of that comment anyhow. Can you please add console.error(err) before returning?

Exposing the error seems more useful than harmful.

On other news, is this PR waiting for some other changes?

@laziob
Copy link
Contributor Author

laziob commented Aug 13, 2021

@balena-ci I self certify!

ghost
ghost previously approved these changes Aug 13, 2021
@ghost ghost merged commit 3066820 into master Aug 13, 2021
@ghost ghost dismissed their stale review August 13, 2021 15:50

Approval reviews not allowed in Draft PRs

@ghost ghost deleted the getQueryString_expect_relative_url branch August 13, 2021 15:50
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
versionbot/pr-draft Draft PR - Don't merge this PR automatically
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants