Skip to content
This repository has been archived by the owner on Aug 1, 2022. It is now read-only.

Commit

Permalink
feat(ui): wire up settings endpoints (#390)
Browse files Browse the repository at this point in the history
Closes #385

***

* feat: wire up settings endpoints
* Make theme depend on settings
* Improve theme handling
* Add settings test spec
* Adjust to new cypress command
  • Loading branch information
xla committed May 15, 2020
1 parent 5999e00 commit d84f604
Show file tree
Hide file tree
Showing 17 changed files with 203 additions and 75 deletions.
2 changes: 0 additions & 2 deletions cypress/integration/identity_creation.spec.js
Expand Up @@ -36,8 +36,6 @@ context("identity creation", () => {

// Land on profile screen
cy.get('[data-cy="go-to-profile-button"]').click();
// TODO(rudolfs): change this to the actual handle that we
// just created once the backend is wired up
cy.get('[data-cy="profile-avatar"]').contains("rafalca");
});

Expand Down
39 changes: 39 additions & 0 deletions cypress/integration/settings_specs.js
@@ -0,0 +1,39 @@
context("settings", () => {
beforeEach(() => {
cy.nukeCache();
cy.nukeSessionState();
cy.createIdentity();

cy.visit("public/index.html");
cy.pick("sidebar", "settings").click();
});

context("theme", () => {
it("is set to the default", () => {
cy.get("[data-theme='light']").should("exist");
});

it("can be switched to dark", () => {
cy.get("button[value='dark']").click();
cy.get("[data-theme='dark']").should("exist");
});
});

context("session", () => {
it("state can be cleared", () => {
cy.pick("clear-session-button").click();
cy.pick("get-started-button").should("exist");
});

it("cache can be cleared", () => {
// Prepare transaction center.
cy.registerUser();
cy.get("body").type("{shift}T");
cy.pick("transaction-center").should("exist");

// Clear cache.
cy.pick("clear-cache-button").click();
cy.pick("transaction-center").should("not.exist");
});
});
});
5 changes: 5 additions & 0 deletions cypress/support/commands.js
@@ -1,3 +1,8 @@
Cypress.Commands.add("nukeCache", () => {
console.log("Nuking Cache");
fetch("http://localhost:8080/v1/session/cache", { method: "DELETE" });
});

Cypress.Commands.add("nukeCocoState", () => {
console.log("Nuking CoCo state");
fetch("http://localhost:8080/v1/control/nuke/coco");
Expand Down
2 changes: 1 addition & 1 deletion proxy/src/session.rs
Expand Up @@ -169,7 +169,7 @@ pub mod settings {

/// Known networks the application can connect to.
#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "lowercase")]
pub enum Network {
/// In-memory registry, which only lives as long as the app does.
Emulator,
Expand Down
2 changes: 1 addition & 1 deletion public/colors.css
Expand Up @@ -37,7 +37,7 @@
--color-foreground-level-6: #546474;
}

[data-theme="darkMode"] {
[data-theme="dark"] {
--color-primary: #ff55ff;
--color-primary-level-1: #382847;
--color-primary-level-2: #62326d;
Expand Down
6 changes: 3 additions & 3 deletions tokens/colors.js
@@ -1,8 +1,8 @@
export const colorConfig = {
defaultTheme: "lightMode",
defaultTheme: "light",
themes: [
{
name: "lightMode",
name: "light",
colors: [
{ name: "primary", hex: "#ff55ff" },
{ name: "primary-level-1", hex: "#ffd4ff" },
Expand Down Expand Up @@ -39,7 +39,7 @@ export const colorConfig = {
],
},
{
name: "darkMode",
name: "dark",
colors: [
{ name: "primary", hex: "#ff55ff" },
{ name: "primary-level-1", hex: "#382847" },
Expand Down
4 changes: 3 additions & 1 deletion ui/App.svelte
Expand Up @@ -9,6 +9,7 @@
import { NotificationFaucet, Remote } from "./DesignSystem/Component";
import Hotkeys from "./Hotkeys.svelte";
import Theme from "./Theme.svelte";
import Blank from "./Screen/Blank.svelte";
import IdentityCreation from "./Screen/IdentityCreation.svelte";
Expand Down Expand Up @@ -73,6 +74,7 @@

<Hotkeys />
<NotificationFaucet style="margin-top: calc(var(--topbar-height) + 11px)" />
<Remote {store} context="session">
<Theme />
<Remote {store} let:data={session} context="session">
<Router {routes} />
</Remote>
2 changes: 1 addition & 1 deletion ui/DesignSystem/Component/SegmentedControl.svelte
Expand Up @@ -8,7 +8,7 @@
export let options = null;
const onClick = (option) => {
dispatch("select", option);
dispatch("select", option.value);
currentlyActive = option.value;
};
Expand Down
6 changes: 5 additions & 1 deletion ui/DesignSystem/Component/Transaction/Accordion.svelte
Expand Up @@ -125,7 +125,11 @@
}
</style>

<div class="pipeline" class:negative={iconState === 'negative'} {style}>
<div
data-cy="transaction-center"
class="pipeline"
class:negative={iconState === 'negative'}
{style}>
<div class="cards" class:hidden>
{#each transactions as transaction}
<div
Expand Down
11 changes: 6 additions & 5 deletions ui/Hotkeys.svelte
Expand Up @@ -2,7 +2,7 @@
import { location, pop, push } from "svelte-spa-router";
import * as path from "./src/path.ts";
import * as theme from "./src/theme.ts";
import * as transaction from "./src/transaction.ts";
const toggle = (destination) => {
if (path.active(destination, $location)) {
Expand All @@ -16,14 +16,15 @@
return false;
}
if (event.shiftKey && event.code === "KeyC") {
theme.next();
}
if (event.shiftKey && event.code === "KeyD") {
toggle(path.designSystemGuide());
}
// TODO(xla): Remove once we have tx polling.
if (event.shiftKey && event.code === "KeyT") {
transaction.fetchList();
}
if (event.shiftKey && event.code === "Slash") {
toggle(path.help());
}
Expand Down
60 changes: 30 additions & 30 deletions ui/Screen/Settings.svelte
@@ -1,31 +1,21 @@
<script>
import {
clear,
clearCache,
settings,
updateAppearance,
updateRegistry,
} from "../src/session.ts";
import { networkOptions, themeOptions } from "../src/settings.ts";
import { Title, Text, Button } from "../DesignSystem/Primitive";
import { SidebarLayout, SegmentedControl } from "../DesignSystem/Component";
const themeOptions = [
{
title: "Light",
value: 0,
},
{
title: "Dark",
value: 1,
},
];
const networkOptions = [
{
title: "Emulator",
value: 0,
},
{
title: "FFnet",
value: 1,
},
{
title: "Testnet",
value: 2,
},
];
const updateNetwork = (event) =>
updateRegistry({ ...$settings.registry, network: event.detail });
const updateTheme = (event) =>
updateAppearance({ ...$settings.appearance, theme: event.detail });
</script>

<style>
Expand Down Expand Up @@ -83,9 +73,9 @@
</div>
<div class="action">
<SegmentedControl
active={0}
active={$settings.appearance.theme}
options={themeOptions}
on:select={() => console.log('event(select)')} />
on:select={updateTheme} />
</div>
</div>
</section>
Expand All @@ -100,9 +90,9 @@
</div>
<div class="action">
<SegmentedControl
active={0}
active={$settings.registry.network}
options={networkOptions}
on:select={() => console.log('event(select)')} />
on:select={updateNetwork} />
</div>
</div>
</section>
Expand All @@ -119,7 +109,12 @@
</Text>
</div>
<div class="action">
<Button variant="outline">Clear cache</Button>
<Button
dataCy="clear-cache-button"
variant="outline"
on:click={clearCache}>
Clear cache
</Button>
</div>
</div>
<div class="section-item">
Expand All @@ -131,7 +126,12 @@
</Text>
</div>
<div class="action">
<Button variant="outline">Clear session</Button>
<Button
dataCy="clear-session-button"
variant="outline"
on:click={clear}>
Clear session
</Button>
</div>
</div>
</section>
Expand Down
9 changes: 9 additions & 0 deletions ui/Theme.svelte
@@ -0,0 +1,9 @@
<script>
import { settings } from "./src/session.ts";
import { Theme } from "./src/settings.ts";
$: {
const theme = $settings ? $settings.appearance.theme : Theme.Light;
document.documentElement.setAttribute("data-theme", theme);
}
</script>
34 changes: 25 additions & 9 deletions ui/src/api.ts
Expand Up @@ -26,29 +26,45 @@ const request = (endpoint: string, init?: Init): Request => {
});
}

async function http<T>(req: RequestInfo): Promise<T> {
const http = async <T>(req: RequestInfo): Promise<T> => {
const res = await fetch(req);
const body = await res.json();

// For non-success status codes we throw the body as it carries the error type.
if (!res.ok) {
throw body;
}

return body;
}

export async function del(endpoint: string, options?: Options): Promise<void> {
return http<void>(request(endpoint, { method: "DELETE", ...options }));
}
const noContent = async (req: RequestInfo): Promise<null> => {
const res = await fetch(req);

export async function get<T>(endpoint: string, options?: Options): Promise<T> {
return http<T>(request(endpoint, { method: "GET", ...options }));
if (res.status !== 204) {
const body = await res.json();
throw body;
}

return null;
}

export async function post<I, D>(endpoint: string, body: I, options?: Options): Promise<D> {
return http<D>(request(endpoint, {
export const del = async (endpoint: string, options?: Options): Promise<null> =>
noContent(request(endpoint, { method: "DELETE", ...options }));

export const get = async <T>(endpoint: string, options?: Options): Promise<T> =>
http<T>(request(endpoint, { method: "GET", ...options }));

export const post = async <I, D>(endpoint: string, body: I, options?: Options): Promise<D> =>
http<D>(request(endpoint, {
method: "POST",
body: JSON.stringify(body),
...options,
}));

export const set = async <T>(endpoint: string, body: T, options?: Options): Promise<null> =>
noContent(request(endpoint, {
method: "POST",
body: JSON.stringify(body),
...options,
}));
}

0 comments on commit d84f604

Please sign in to comment.