Skip to content

Commit

Permalink
Use anchor picker in authenticate (#1024)
Browse files Browse the repository at this point in the history
* Use anchor picker in authenticate

This integrates the anchor picker component in the authenticate
flow/prompt.

The component supports selecting from multiple anchors, but for
simplicity we only support a single anchor for now (to avoid messing
with the local storage schema just yet).

* Cleanup
  • Loading branch information
nmattia authored Nov 17, 2022
1 parent 4c8ae86 commit 73002c2
Show file tree
Hide file tree
Showing 25 changed files with 77 additions and 84 deletions.
Binary file modified screenshots/desktop/about.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/desktop/authenticate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/desktop/authenticateAlternative.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/desktop/compatibilityNotice.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/desktop/deviceRegistrationDisabledInfo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/desktop/faq.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/desktop/renderPollForTentativeDevicePage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/desktop/welcomeReturn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/mobile/about.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/mobile/authenticate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/mobile/authenticateAlternative.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/mobile/compatibilityNotice.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/mobile/deviceRegistrationDisabledInfo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/mobile/faq.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/mobile/renderPollForTentativeDevicePage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/mobile/welcomeReturn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 11 additions & 1 deletion src/frontend/src/components/anchorPicker.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { mkAnchorPicker } from "./anchorPicker";
import { render } from "lit-html";

const commonProps = {
button: "go",
recoverAnchor: () => {},
register: () => {},
addDevice: () => {},
};

test("first anchor is focused", async () => {
const picker = mkAnchorPicker({
savedAnchors: [BigInt(10000), BigInt(9990042)],
pick: () => {},
...commonProps,
});
render(picker.template, document.body);
// Tick once, otherwise element isn't focused yet
Expand All @@ -20,6 +28,7 @@ test("pick saved anchor", async () => {
pick: (anchor) => {
picked = anchor;
},
...commonProps,
});
render(picker.template, document.body);
// Tick once, otherwise element isn't focused yet
Expand All @@ -38,12 +47,13 @@ test("pick custom anchor", async () => {
pick: (anchor) => {
picked = anchor;
},
...commonProps,
});
render(picker.template, document.body);
// Tick once, otherwise element isn't focused yet
await tick();
const elem = document.querySelector(
'[data-role="use-another-anchor"]'
'[data-role="more-options"]'
) as HTMLElement;
elem.click();
await tick();
Expand Down
56 changes: 40 additions & 16 deletions src/frontend/src/components/anchorPicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ import { until } from "lit-html/directives/until.js";
type PickerProps = {
savedAnchors: bigint[];
pick: PickCB;
button: string;
} & Links;

type Links = {
recoverAnchor: () => void;
register: () => void;
addDevice: () => void;
};

type PickCB = (userNumber: bigint) => void;
Expand All @@ -28,7 +35,7 @@ export const mkAnchorPicker = (

// The list elements, including the anchor creation menu
function elements(props: PickerProps): TemplateResult[] {
const otherAnchorMenuTpl = otherAnchorMenu({ pick: props.pick });
const otherAnchorMenuTpl = otherAnchorMenu(props);
const savedAnchorsTpl = props.savedAnchors.map((anchor, i) =>
anchorItem({ anchor, pick: props.pick, focus: i == 0 })
);
Expand All @@ -52,9 +59,9 @@ function elements(props: PickerProps): TemplateResult[] {
@focus="${() => {
otherAnchorOpen?.();
}}"
data-role="use-another-anchor"
data-role="more-options"
>
Use another anchor<i class="c-list__icon"></i>
More options<i class="c-list__icon"></i>
</button>
`;

Expand All @@ -64,7 +71,7 @@ function elements(props: PickerProps): TemplateResult[] {
// replace the "use another anchor" button with actual menu when ready (clicked)
new Promise<void>((resolve) => {
otherAnchorOpen = resolve;
}).then(() => Promise.resolve(otherAnchorMenu({ pick: props.pick }))),
}).then(() => Promise.resolve(otherAnchorMenu(props))),
otherAnchorOffer
)}
</li>`);
Expand Down Expand Up @@ -105,7 +112,7 @@ const anchorItem = (props: {
</li>
`;

function otherAnchorMenu(props: { pick: PickCB }): TemplateResult {
function otherAnchorMenu(props: PickerProps): TemplateResult {
const anchorInput = mkAnchorInput({ onSubmit: props.pick });

return html`
Expand All @@ -115,22 +122,39 @@ function otherAnchorMenu(props: { pick: PickCB }): TemplateResult {
${anchorInput.template}
<button
class="c-button"
id="authorizeButton"
data-role="anchor-create"
@click="${anchorInput.submit}"
>
Oh ouiiii
${props.button}
</button>
<p class="l-stack">
An <b class="t-strong">Identity Anchor</b> is a
<b class="t-strong">unique ID</b> that is used to authenticate yourself.
You will be able to use it to <b class="t-strong">log in</b> to all
kinds of apps.
<p class="l-stack t-centered">
An <b class="t-strong">Anchor</b> is used to authenticate yourself when
using dapps on the Internet Computer.
</p>
<div class="l-stack">
<button class="c-button c-button--secondary">
Create a new anchor
</button>
</div>
${mkLinks(props)}
</div>
`;
}

const mkLinks = ({ recoverAnchor, register, addDevice }: Links) => html`
<div class="l-stack">
<ul class="c-list--flex">
<li>
<a @click=${() => register()} id="registerButton" class="t-link"
>Create Anchor</a
>
</li>
<li>
<a @click="${() => recoverAnchor()}" id="recoverButton" class="t-link"
>Lost Access?</a
>
</li>
<li>
<a @click="${() => addDevice()}" id="addNewDeviceButton" class="t-link"
>Add a device</a
>
</li>
</ul>
</div>
`;
57 changes: 9 additions & 48 deletions src/frontend/src/components/authenticateBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { icLogo, caretDownIcon } from "./icons";
import { footer } from "./footer";
import { withLoader } from "./loader";
import { addRemoteDevice } from "../flows/addDevice/welcomeView";
import { mkAnchorInput } from "./anchorInput";
import { mkAnchorPicker } from "./anchorPicker";
import { getUserNumber, setUserNumber } from "../utils/userNumber";
import { unreachable } from "../utils/utils";
import { Connection } from "../utils/iiConnection";
Expand Down Expand Up @@ -102,33 +102,24 @@ const pageContent = ({
register,
userNumber,
}: PageProps): TemplateResult => {
const anchorInput = mkAnchorInput({
userNumber,
onSubmit: onContinue,
const anchorInput = mkAnchorPicker({
savedAnchors: userNumber !== undefined ? [userNumber] : [],
pick: onContinue,
button: templates.button,
addDevice,
recoverAnchor,
register,
});

return html` <div class="l-container c-card c-card--highlight">
<!-- The title is hidden but used for accessibility -->
<h1 class="is-hidden">Internet Identity</h1>
<h1 data-page="authenticate" class="is-hidden">Internet Identity</h1>
<div class="c-logo">${icLogo}</div>
<div class="l-stack t-centered">
${templates.message} ${templates.chasm ? mkChasm(templates.chasm) : ""}
</div>
${anchorInput.template}
<button
@click="${anchorInput.submit}"
id="authorizeButton"
class="c-button"
>
${templates.button}
</button>
${mkLinks({
register,
recoverAnchor: () => recoverAnchor(anchorInput.readUserNumber()),
addDevice,
})}
</div>
${footer}`;
};
Expand Down Expand Up @@ -192,33 +183,3 @@ const mkChasm = ({ info, message }: ChasmOpts): TemplateResult => {
</p>
`;
};

const mkLinks = ({
recoverAnchor,
register,
addDevice,
}: {
recoverAnchor: () => void;
register: () => void;
addDevice: () => void;
}) => html`
<div class="l-stack">
<ul class="c-list--flex">
<li>
<a @click=${register} id="registerButton" class="t-link"
>Create Anchor</a
>
</li>
<li>
<a @click="${recoverAnchor}" id="recoverButton" class="t-link"
>Lost Access?</a
>
</li>
<li>
<a @click="${addDevice}" id="addNewDeviceButton" class="t-link"
>Add a device</a
>
</li>
</ul>
</div>
`;
5 changes: 5 additions & 0 deletions src/frontend/src/showcase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ const components = (): TemplateResult => {
withRef(showSelected, (div) => {
div.innerText = anchor.toString();
}),
button: "Let's go",

addDevice: () => console.log("Add device requested"),
recoverAnchor: console.log,
register: () => console.log("Register requested"),
}).template;

const chan = new Chan<TemplateResult>();
Expand Down
5 changes: 0 additions & 5 deletions src/frontend/src/styles/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -916,10 +916,6 @@ a:hover,
margin: 0.5rem;
}

.c-list li + li {
margin-top: var(--vs-stack);
}

.c-list--bulleted {
list-style-type: disc;
}
Expand All @@ -944,7 +940,6 @@ a:hover,

.c-list--anchors {
--border-radius: 8px;
width: 40rem;
}

.c-list__item--icon {
Expand Down
3 changes: 1 addition & 2 deletions src/frontend/src/test-e2e/alternativeOrigin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,7 @@ test("Should fetch /.well-known/ii-alternative-origins using the non-raw url", a
// This works anyway --> fetched using non-raw
const authenticateView = new AuthenticateView(browser);
await authenticateView.waitForDisplay();
await authenticateView.expectPrefilledAnchorToBe(userNumber);
await authenticateView.authenticate();
await authenticateView.pickAnchor(userNumber);
await waitToClose(browser);

expect(await niceDemoAppView.getPrincipal()).not.toBe("2vxsx-fae");
Expand Down
6 changes: 2 additions & 4 deletions src/frontend/src/test-e2e/misc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,7 @@ test("Should issue the same principal to nice url and canonical url", async () =
);
let authenticateView = new AuthenticateView(browser);
await authenticateView.waitForDisplay();
await authenticateView.expectPrefilledAnchorToBe(userNumber);
await authenticateView.authenticate();
await authenticateView.pickAnchor(userNumber);
await waitToClose(browser);

const principal1 = await canonicalDemoAppView.getPrincipal();
Expand All @@ -150,8 +149,7 @@ test("Should issue the same principal to nice url and canonical url", async () =
);
authenticateView = new AuthenticateView(browser);
await authenticateView.waitForDisplay();
await authenticateView.expectPrefilledAnchorToBe(userNumber);
await authenticateView.authenticate();
await authenticateView.pickAnchor(userNumber);
await waitToClose(browser);

const principal2 = await niceDemoAppView.getPrincipal();
Expand Down
3 changes: 1 addition & 2 deletions src/frontend/src/test-e2e/register.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,7 @@ test("Register first then log into client application", async () => {

const authenticateView = new AuthenticateView(browser);
await authenticateView.waitForDisplay();
await authenticateView.expectPrefilledAnchorToBe(userNumber);
await authenticateView.authenticate();
await authenticateView.pickAnchor(userNumber);
const recoveryMethodSelectorView = new RecoveryMethodSelectorView(browser);
await recoveryMethodSelectorView.waitForDisplay();
await recoveryMethodSelectorView.skipRecovery();
Expand Down
14 changes: 8 additions & 6 deletions src/frontend/src/test-e2e/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,14 +321,12 @@ export class VerifyRemoteDeviceView extends View {
export class AuthenticateView extends View {
async waitForDisplay(): Promise<void> {
await this.browser
.$("#authorizeButton")
.waitForDisplayed({ timeout: 5_000 });
.$('[data-page="authenticate"]')
.waitForExist({ timeout: 5_000 });
}

async expectPrefilledAnchorToBe(anchor: string): Promise<void> {
expect(await this.browser.$('[data-role="anchor-input"]').getValue()).toBe(
anchor
);
async pickAnchor(anchor: string): Promise<void> {
await this.browser.$(`[data-anchor-id="${anchor}"]`).click();
}

async expectAnchorInputField(): Promise<void> {
Expand All @@ -338,6 +336,10 @@ export class AuthenticateView extends View {
}

async authenticate(): Promise<void> {
const moreOptions = await this.browser.$('[data-role="more-options"]');
if (await moreOptions.isExisting()) {
await moreOptions.click();
}
await this.browser.$("#authorizeButton").click();
}

Expand Down

0 comments on commit 73002c2

Please sign in to comment.