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

feat: improved UX when opening IPFS URIs #1966

Closed
wants to merge 29 commits into from
Closed

Conversation

hacdias
Copy link
Member

@hacdias hacdias commented Jan 28, 2022

This fixes #1646 by adding a dialog when opening an IPFS or IPNS with IPFS Desktop:

image

The UI matches the other dialogs we use on IPFS Desktop, which try to resemble a native dialog the most it can.

The option to ask when opening is also added under the preferences in the menubar tool:

image

Note: the Explore section does not support IPNS. Thus, I decided to open on the Files page if the user opens an IPNS URL and selects the Explore section by default.

The other option is to ask separately for IPNS and IPFS. That is possible but will duplicate the options in the settings.

@hacdias hacdias marked this pull request as ready for review February 2, 2022 11:27
@hacdias hacdias requested a review from lidel February 2, 2022 12:00
Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

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

Thank you, this is long time due!

Small asks

  • replace "URI" with "address" (diffs inline)
  • add IPFS cube logo to the Ask window (centered, above "How would you like.." sentence)

Note: the Explore section does not support IPNS. Thus, I decided to open on the Files page if the user opens an IPNS URL and selects the Explore section by default.
The other option is to ask separately for IPNS and IPFS. That is possible but will duplicate the options in the settings.

Hm.. we don't want to duplicate settings, and opening Files instead of Explore looks like a bug.
I think we should fix ipfs/ipfs-webui#1884 before merging this PR, so there are no surprises around the way IPFS addresses are handled.

.. or just hide "Explore" option for now, so we don't need to wait for ipfs/ipfs-webui#1884

}

const action = await getAction()
let base = 'https://dweb.link'
Copy link
Member

Choose a reason for hiding this comment

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

💭 hardcoding this may be confusing because ipfs-webui now allows user to customize the public gateway (added in ipfs/ipfs-webui#1834):

Screenshot 2022-02-04 at 02-39-30 Settings IPFS

I think Electron should be able to reach out to the renderer and see if custom public gateway was set in window.localStorage under ipfsPublicGateway (+ JSON unwrapping due to local-storage.js weirdness).

That way we could respect user choice (and if not present, default to dweb.link

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a great idea, but I will also need to work on a hook to make sure this value gets updated on IPFS Desktop every time it is updated on IPFS Web UI.

Copy link
Member

@lidel lidel Feb 11, 2022

Choose a reason for hiding this comment

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

@hacdias I was thinking about simple, low-effort implementation that respects user choice made in ipfs-webui Settings:

  • every time you need to generate shareable link in ipfs-desktop, read the value from localStorage in ipfs-webui in renderer process.
  • not need for copy of the value does not be stored/updated in ipfs-desktop

Copy link
Member Author

Choose a reason for hiding this comment

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

@lidel that is reasonably simple if we wait for the Web UI window to be ready. We have to wait for it to be ready to have that working. So if you open an IPFS link, IPFS Desktop has to boot up and wait for the Web UI window to be ready until the link is actually open. That could feel quite slow. That's why I thought about keeping a copy on Desktop's settings such that we do not need to wait.

Copy link
Member Author

@hacdias hacdias Feb 18, 2022

Choose a reason for hiding this comment

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

On 90b25e0 I made a best effort attempt. If the web ui window hasn't been created yet, we use the default public gateway. I can, however, rearrange Desktop's startup logic to ensure the window always exists. Note that this would also stop working if we decide to go on with #1929.

assets/locales/en.json Outdated Show resolved Hide resolved
assets/locales/en.json Outdated Show resolved Hide resolved
assets/locales/en.json Outdated Show resolved Hide resolved
assets/locales/en.json Outdated Show resolved Hide resolved
@hacdias
Copy link
Member Author

hacdias commented Feb 9, 2022

@lidel

add IPFS cube logo to the Ask window

Then, should we do the same for the "Download CID" window? We're using the same template after all.

.. or just hide "Explore" option for now, so we don't need to wait for ipfs/ipfs-webui#1884

I'll do that.

Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

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

Polishing the UX

I took it for a spin via npm start -- ipns://en.wikipedia-on-ipfs.org to trigger the one-time choice dialog, current options are:

2022-02-11_16-45

My initial impressions:

  • 🎨 small UX asks
    • 🧊 needs IPFS cube as a visual hint to indicate where the question comes from
      • Then, should we do the same for the "Download CID" window? We're using the same template, after all.

        @hacdias yes, sounds sensible and it would look good there too

    • 🆔 could we show the UR Ithat triggered the dialog as part of the question? I'm thinking How would you like to open IPFS addresses like ipns://en.wikipedia-on-ipfs.org?
      • makes it easier to connect the dots ("i clicked on this ipns:// thing and this happened")
  • 💭 I started questioning myself: is there a value in having separate browser options for public and local gateway?
    • 💢 Beginner/casual users would not even know what this choice means
      • 💡 this could be mitigated by adding "(safe default choice)" next to pre-selected "public gateway" option
    • 💢 If user selected "public" but their browser has redirect to local (Brave, Companion) that looks like a bug, because they wanted public link, and ended up on local
    • 💢 If user selected "local" but the node is down, then links either fail or we need to use public gateway anyway
      • I've seen folks strugging with this in ipfs-companion – the bug reports go away only if we redirect to public gw when local is dead.
    • 💡 My gut feeling is that we should only have the public gateway option (simple "In my web browser") – kicking the routing decision to the browser.
      • 💚 Browsers with IPFS support (Brave or IPFS Companion) would redirect public gateway link to local gateway anyway
      • 💚 regular browsers would load the original URL, there is no footgun when local node is offline

Thoughts?

cc'ing @autonome @SgtPooki (not urgent, but before we ship this, would appreciate more 👀 on this, both from the perspective of a native speaker, and general UX)

src/i18n.js Outdated Show resolved Hide resolved
}

const action = await getAction()
let base = 'https://dweb.link'
Copy link
Member

@lidel lidel Feb 11, 2022

Choose a reason for hiding this comment

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

@hacdias I was thinking about simple, low-effort implementation that respects user choice made in ipfs-webui Settings:

  • every time you need to generate shareable link in ipfs-desktop, read the value from localStorage in ipfs-webui in renderer process.
  • not need for copy of the value does not be stored/updated in ipfs-desktop

@hacdias
Copy link
Member Author

hacdias commented Feb 17, 2022

🧊 needs IPFS cube as a visual hint to indicate where the question comes from

Done.

image

could we show the UR that triggered the dialog as part of the question

This is easy to do, but we have to make sure it doesn't overflow or wrap to the next line, otherwise some window text will be hidden. The maximum size would also vary with translations so I'm not sure what's the best way to proceed here.


I will defer the remaining updates once we have @autonome's and @SgtPooki's feedback regarding the gateway options.

@lidel lidel self-requested a review February 17, 2022 17:16
@SgtPooki
Copy link
Member

SgtPooki commented Mar 3, 2022

I agree 100% with all the callouts from lidel. A few additional comments:

If user selected "public" but their browser has redirect to local (Brave, Companion) that looks like a bug, because they wanted public link, and ended up on local
If user selected "local" but the node is down, then links either fail or we need to use public gateway anyway

I would reduce the number of options to only either: open in browser, open in ipfs desktop, and then let ipfs-companion/browser handle the rest, since they will override whichever decision is made in ipfs-desktop anyway. What do you think @lidel? And if we did do this, should the browser option always use local?

If a user is running ipfs-desktop, then they should have a local node running at the time ipfs-desktop opens the link in the browser, right?

@lidel
Copy link
Member

lidel commented Mar 4, 2022

I would reduce the number of options to only either: open in browser, open in ipfs desktop, and then let ipfs-companion/browser handle the rest, since they will override whichever decision is made in ipfs-desktop anyway. What do you think @lidel?

Yep, this sounds like the best way to do this.

And if we did do this, should the browser option always use local?
If a user is running ipfs-desktop, then they should have a local node running at the time ipfs-desktop opens the link in the browser, right?

Hm.. yes. If we have a generic "Open in browser" then yes, this makes sense and provides better experience for users with browser that does not understand IPFS, because links will open instantly from local node, instead of YMMV provided by a public gateway.

ipfs-desktop could make a quick test to confirm local gateway is still online, and use its address instead of public one.

ipfs-webui is already doing that type of check (it checks if local gateway port is functional, it also confirms if OS supports subdomains on localhost, and sets gateway links to the best option available, falling back to public gateway URL as the last resort)

To be specific, if we want to open from local node by default, we need to:

  • test if {cid}.ipfs.localhost:{port} works with some CID that does not require hitting dht (e.g. bafkqablimvwgy3yhello)
    • if subdomains are not available, fallback to IP: 127.0.0.1:{port}/ipfs/{cid} and check if it works
      • if that fails, use https://dweb.link/ipfs/{cid} (or other public gateway configured in webui)

@hacdias
Copy link
Member Author

hacdias commented Mar 11, 2022

I will work on those changes then.

hacdias and others added 12 commits March 17, 2022 13:18
License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>
Co-authored-by: Marcin Rataj <lidel@lidel.org>
Co-authored-by: Marcin Rataj <lidel@lidel.org>
Co-authored-by: Marcin Rataj <lidel@lidel.org>
Co-authored-by: Marcin Rataj <lidel@lidel.org>
License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>
@hacdias
Copy link
Member Author

hacdias commented Mar 17, 2022

Just updated the PR to match the conversation above.

image

Disclaimer: I tested this on macOS. It seems that the localhost domain works when using Chrome but fails when using fetch (also seems to not work on Safari). Thus, even though Chrome may be the default browser, it won't use the localhost version.

Copy link
Member

@SgtPooki SgtPooki left a comment

Choose a reason for hiding this comment

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

Thanks for the updates @hacdias . Many comments are questions because I'm newer to this repo, but the ctx refactor has helped me to gain a bit of understanding of the current problems we face with the ipfs-desktop, so I hope the non-question comments are helpful =)

assets/locales/en.json Show resolved Hide resolved
assets/locales/en.json Show resolved Hide resolved
assets/locales/en.json Outdated Show resolved Hide resolved
src/dialogs/prompt/index.js Outdated Show resolved Hide resolved
src/dialogs/prompt/styles.js Show resolved Hide resolved
src/dialogs/prompt/index.js Show resolved Hide resolved
src/i18n.js Outdated Show resolved Hide resolved
src/index.js Outdated Show resolved Hide resolved
src/protocol-handlers.js Outdated Show resolved Hide resolved
src/tray.js Outdated Show resolved Hide resolved
src/tray.js Outdated
Comment on lines 27 to 28
NAMESYS_PUBSUB_KEY,
ASK_OPENING_IPFS_URIS
Copy link
Member

Choose a reason for hiding this comment

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

@lidel @achingbrain This is why we need to use trailing commas. How can I go about updating the styling across our repos so that we can allow/require trailing commas in our code? These diffs don't need to be this noisy. git blaming is also a PITA when we try to find out who originally added NAMESYS_PUBSUB_KEY, or whatever the non-trailing-comma-having previous line ends up being in PRs.

@hacdias
Copy link
Member Author

hacdias commented May 10, 2022

@SgtPooki I think I addressed all of your comments!

@hacdias hacdias requested a review from SgtPooki May 10, 2022 12:35
src/dialogs/prompt/html.js Show resolved Hide resolved
src/protocol-handlers/index.js Outdated Show resolved Hide resolved
src/protocol-handlers/index.js Outdated Show resolved Hide resolved
src/protocol-handlers/index.js Outdated Show resolved Hide resolved
src/protocol-handlers/index.js Outdated Show resolved Hide resolved
src/protocol-handlers/urls.js Outdated Show resolved Hide resolved
const { status } = await fetch(
`${url}/ipfs/bafkqae2xmvwgg33nmuqhi3zajfiemuzahiwss`
)
return status === 200
Copy link
Member

Choose a reason for hiding this comment

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

do we need a status=200 or could we check for ok?

Copy link
Member Author

Choose a reason for hiding this comment

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

url = new URL(url)
url.hostname = `bafkqae2xmvwgg33nmuqhi3zajfiemuzahiwss.ipfs.${url.hostname}`
const { status } = await fetch(url.toString())
return status === 200
Copy link
Member

Choose a reason for hiding this comment

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

would using ok be sufficient or do we require an explicit 200?

Copy link
Member Author

Choose a reason for hiding this comment

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

Code borrowed from Web UI: https://github.com/ipfs/ipfs-webui/blob/4bf78a47fcb38872edbe55a5046ae3c7d3fe1a10/src/bundles/config.js#L113-L138

Not sure if we need explicit 200 or any OK suffices. /cc @lidel

Copy link
Member

Choose a reason for hiding this comment

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

@lidel pingity ping ping

const checkIfSubdomainGatewayUrlIsAccessible = async (url) => {
try {
url = new URL(url)
url.hostname = `bafkqae2xmvwgg33nmuqhi3zajfiemuzahiwss.ipfs.${url.hostname}`
Copy link
Member

Choose a reason for hiding this comment

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

What is the hardcoded CID in bafkqae2xmvwgg33nmuqhi3zajfiemuzahiwss.ipfs.${url.hostname}?

Should that be saved in consts.js?

Copy link
Member Author

Choose a reason for hiding this comment

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

Same as before: I did not write this code, but it seems that it is some safe CID (ipfs/ipfs-webui@ebda764) for "Welcome to IPFS :-)"

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 a CID which has Welcome to IPFS :-) string inlined inside identity Multihash.
Main reason for using this exotic multihash type is to avoid hitting DHT/datastore – gateway can respond immediatelly after decoding CID.

* @param {ParsedUrl} parsedUrl
* @returns
*/
async function getGatewayUrl (ctx, { protocol, hostname, path }) {
Copy link
Member

Choose a reason for hiding this comment

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

@lidel do we have an ipfs-utils or other library where we can put our higher level functions that are used across the stack? It could help prevent us from getting into a situation in the future where all of our libraries are using out of date low-level ipfs deps.

Copy link
Member

Choose a reason for hiding this comment

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

Afaik no.
There are things like https://github.com/ipfs/js-ipfs-utils (legacy, does not seem to be maintained) and https://github.com/ipfs/js-ipfs/tree/master/packages/ipfs-core-utils/src (part of js-ipfs), but they pull-in too many dependencies.

@hacdias
Copy link
Member Author

hacdias commented Jul 20, 2022

@SgtPooki solved the conflicts. It seems that the CI is taking way too long downloading Web UI for the tests. We may have to restart them later.

Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

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

@SgtPooki @hacdias I just realized this PR comes with an awful UX footgun 😿

If user tries to open ipns://en.wikipedia-on-ipfs.org/wiki/ and decides to do that in IPFS WebUI, it will fail because ipfs-webui is not optimized for showing huge HAMT-sharded UnixFS directories, and /ipns/en.wikipedia-on-ipfs.org/wiki/ is one (has ~20M items).

Due to this, I feel we need to mark this as blocked until we add a smart HAMT handling.

Upstream issues:

assets/locales/en.json Outdated Show resolved Hide resolved
@lidel lidel added the status/blocked Unable to be worked further until needs are met label Aug 1, 2022
Co-authored-by: Marcin Rataj <lidel@lidel.org>
@SgtPooki SgtPooki marked this pull request as draft September 12, 2022 17:02
@lidel
Copy link
Member

lidel commented Nov 6, 2023

This ended up no longer feasible, see #1646 (comment)

@lidel lidel closed this Nov 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status/blocked Unable to be worked further until needs are met
Projects
No open projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Improve onboarding via OS-level protocol handler
3 participants