WebID UI#16
Conversation
| import type { DatasetCore, Quad, Term } from "@rdfjs/types" | ||
|
|
||
| // TODO: Eliminate once N3 stops trying to nodejs the browser | ||
| export class SimpleDataset implements DatasetCore { |
There was a problem hiding this comment.
I'm not sure what the proper way to do this is.
I find N3 unusable in a modern module way. Maybe I just don't know how to configure package dependencies and/or import maps and/or unpackagers.
Specifically N3 seems to be pulling in readable-stream which is Node only, so here's this minimal implementation instead of N3.Store.
| </dialog> | ||
| ` | ||
|
|
||
| export class WebIdPicker extends HTMLElement { |
There was a problem hiding this comment.
A very simple custom element that is quite similar to the existing IdP picker.
It's a modal that asks for a WebID URI, with an optional datalist for soft select functionality, as well as slots for text customization and cancel support.
I'll add CSS parts later.
| this.#input.addEventListener("change", () => { | ||
| if (this.#input.value.includes(searchString)) { | ||
| const start = this.#input.value.indexOf(searchString) | ||
| this.#input.setSelectionRange(start, start + searchString.length, "forward") | ||
| } | ||
| }) |
There was a problem hiding this comment.
If the options include the string "YOUR_USERNAME" in the WebID URI template then it will be selected for the user to type over.
| "dpop": "https://cdn.jsdelivr.net/npm/dpop@2.1.1/+esm" | ||
| "dpop": "https://cdn.jsdelivr.net/npm/dpop@2.1.1/+esm", | ||
| "n3": "https://esm.sh/n3@2.0.3", | ||
| "@rdfjs/wrapper": "https://cdn.jsdelivr.net/npm/@rdfjs/wrapper@0.34.0/+esm" |
There was a problem hiding this comment.
As before, this is for the demo only. Just so I don't have to worry about transpilation and bundling at the moment.
| /* Reactive fetch infrastructure */ | ||
| const ui = document.querySelector("authorization-code-flow") | ||
| const issuerUi = document.querySelector("idp-picker") | ||
| const callbackUri = new URL("/callback.html", location.href).toString() | ||
|
|
||
| const dPoPTokenProvider = new DPoPTokenProvider(callbackUri, ui.getCode.bind(ui), issuerUi.getIssuer.bind(issuerUi)) | ||
|
|
||
| const fetch = new ReactiveFetchManager([dPoPTokenProvider]).fetch | ||
|
|
There was a problem hiding this comment.
Substantial change here is that in the demo, global fetch is no longer patched. Because now we're using it to get WebIDs too.
Fun fact: Some Solid servers return 401 for a bogus WebID (e.g. https://YOUR_USERNAME.solidcommunity.net/profile/card#me).
| <webid-picker slot="webid-picker"> | ||
| <option value="https://YOUR_USERNAME.solidcommunity.net/profile/card#me"></option> | ||
| <option value="https://id.inrupt.com/YOUR_USERNAME"></option> | ||
| <option value="https://YOUR_USERNAME.datapod.igrant.io/profile/card#me"></option> | ||
| <option value="https://YOUR_USERNAME.solidweb.app/profile/card.jsonld#me"></option> | ||
| <option value="https://teamid.live/YOUR_USERNAME/profile/card#me"></option> | ||
| <option value="https://YOUR_USERNAME.solidweb.org/profile/card#me"></option> | ||
| </webid-picker> |
There was a problem hiding this comment.
Interesting pattern of composing custom elements:
The new <webid-picker/> is a standalone web component.
But it also integrates this way with the existing <idp-picker/>.
Advantage over programmatic construction is customizability and stylability.
| <button type="button" id="webid" hidden disabled accesskey="w"> | ||
| <slot name="webid-button">Use <u>W</u>ebID</slot> | ||
| </button> |
There was a problem hiding this comment.
New button on existing UI that allows invoking the new element to get WebID from there.
| shadow.querySelector("datalist")!.appendChild(option.cloneNode()) | ||
| } | ||
|
|
||
| this.#webIdButton.disabled = this.#webIdButton.hidden = this.#webIdPicker === null |
There was a problem hiding this comment.
IdP selecto works as before if there's no WebID picker child. But if there is then it can be invoked here.
| async #useWebId() { | ||
| this.#webIdButton.disabled = true | ||
| try { | ||
| const webid = await this.#webIdPicker!.getWebId(this.#request!) | ||
| const issuer = await issuerFromWebId(webid, this.#request!.signal) | ||
| this.#input.value = issuer.href | ||
| } finally { | ||
| this.#webIdButton.disabled = false | ||
| this.#input.focus() | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
React to click of new button. Get URI, load, parse, extract issuer and populate our own input.
| } | ||
| } | ||
|
|
||
| async function issuerFromWebId(webId: URL, signal: AbortSignal): Promise<URL> { |
There was a problem hiding this comment.
Very simple and intentionally paranoid method to load and parse WebID and extract issuer.
Adds a new custom element for getting a WebID URI from the user via a modal dialog.
Integrates same into existing custom element that gets an authorization server URI from the user.
(But new element can be used on its own as well.)
Supports the well-known Solid app UX pattern of getting IdP from profile.
New button Use WebID to get authorization server URI from WebID profile:

New custom element toi get a WebID URI from user:
