-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
684 additions
and
332 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,46 @@ | ||
<script lang="ts"> | ||
import { Router, Route } from "svelte-routing"; | ||
import { onMount } from "svelte"; | ||
import { invoke } from "@tauri-apps/api/core"; | ||
import * as router from "@app/lib/router"; | ||
import { theme } from "@app/components/ThemeSwitch.svelte"; | ||
import { unreachable } from "@app/lib/utils"; | ||
import DesignSystem from "@app/views/DesignSystem.svelte"; | ||
import Repos from "@app/views/Repos.svelte"; | ||
import Startup from "@app/views/Startup.svelte"; | ||
import Home from "@app/views/Home.svelte"; | ||
import AuthenticationError from "@app/views/AuthenticationError.svelte"; | ||
const activeRouteStore = router.activeRouteStore; | ||
void router.loadFromLocation(); | ||
onMount(async () => { | ||
try { | ||
await invoke("authenticate"); | ||
void router.push({ resource: "home" }); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
} catch (e: any) { | ||
void router.push({ | ||
resource: "authenticationError", | ||
params: { | ||
error: e.err, | ||
hint: e.hint, | ||
}, | ||
}); | ||
} | ||
}); | ||
$: document.documentElement.setAttribute("data-theme", $theme); | ||
</script> | ||
|
||
<Router> | ||
<Route path="/" component={Startup} /> | ||
<Route path="/repos" component={Repos} /> | ||
<Route path="/design-system" component={DesignSystem} /> | ||
</Router> | ||
{#if $activeRouteStore.resource === "booting"} | ||
<!-- Don't show anything --> | ||
{:else if $activeRouteStore.resource === "home"} | ||
<Home /> | ||
{:else if $activeRouteStore.resource === "authenticationError"} | ||
<AuthenticationError {...$activeRouteStore.params} /> | ||
{:else if $activeRouteStore.resource === "designSystem"} | ||
<DesignSystem /> | ||
{:else} | ||
{unreachable($activeRouteStore)} | ||
{/if} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<script lang="ts" strictEvents> | ||
import type { Route } from "@app/lib/router/definitions"; | ||
import { createEventDispatcher } from "svelte"; | ||
import { push, routeToPath } from "@app/lib/router"; | ||
export let route: Route; | ||
export let disabled: boolean = false; | ||
const dispatch = createEventDispatcher<{ | ||
afterNavigate: null; | ||
}>(); | ||
function navigateToRoute(event: MouseEvent): void { | ||
event.preventDefault(); | ||
if (disabled) { | ||
return; | ||
} | ||
void push(route); | ||
dispatch("afterNavigate"); | ||
} | ||
</script> | ||
|
||
<style> | ||
a { | ||
color: var(--color-fill-secondary); | ||
text-decoration: none; | ||
} | ||
a:hover { | ||
text-decoration: underline; | ||
text-decoration-thickness: 1px; | ||
text-underline-offset: 2px; | ||
} | ||
</style> | ||
|
||
<a on:click={navigateToRoute} href={routeToPath(route)}> | ||
<slot /> | ||
</a> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// Copyright © 2021 The Radicle Upstream Contributors | ||
// | ||
// This file is part of radicle-upstream, distributed under the GPLv3 | ||
// with Radicle Linking Exception. For full terms see the included | ||
// LICENSE file. | ||
|
||
//@ts-expect-error the typescript bindings are out of date. | ||
import * as Bacon from "baconjs"; | ||
|
||
// A task executor that runs only one task concurrently. If a new task | ||
// is run, any previously running task is aborted and the promise | ||
// returned from `run()` will return undefined. | ||
// | ||
// import * as mutexExecutor from "ui/src/mutexExecutor" | ||
// const executor = mutexExecutor.create() | ||
// const first = await executor.run(async () => { | ||
// await sleep(1000) | ||
// return "first" | ||
// }) | ||
// const second = await executor.run(async () => "second") | ||
// | ||
// In the example above the promise `first` will resolve to `undefined` | ||
// while the promise `second` will resolve to "second". | ||
// | ||
// If the first tasks throws after the second task has run the | ||
// behavior is the same. | ||
// | ||
// const first = await executor.run(async () => { | ||
// await sleep(1000) | ||
// throw new Error() | ||
// }) | ||
// | ||
// The task call back receives an AbortSignal as a parameter. The abort | ||
// event is emitted when another task is run. | ||
export function create(): MutexExecutor { | ||
return new MutexExecutor(); | ||
} | ||
|
||
// A worker that asynchronously process one item at a time and provides | ||
// the result as an event stream. | ||
// | ||
// import * as mutexExecutor from "ui/src/mutexExecutor" | ||
// const worker = mutexExecutor.createWorker(async (value) => { | ||
// await sleep(1000) | ||
// return value | ||
// }) | ||
// | ||
// const firstPromise = worker.output.firstToPromise() | ||
// worker.push("first) | ||
// assert.equal(await firstPromise, "first") | ||
// | ||
// When an item is submitted to the worker while the previous items is | ||
// still being processed, the result of the first item will not be | ||
// emitted to `worker.output`. Instead, only the last item will be | ||
// emitted. | ||
export function createWorker<In, Out>( | ||
fn: (x: In, abortSignal: AbortSignal) => Promise<Out>, | ||
): MutexWorker<In, Out> { | ||
return new MutexWorker(fn); | ||
} | ||
|
||
class MutexExecutor { | ||
private runningTaskId = 0; | ||
private abortController: AbortController | null = null; | ||
|
||
public async run<T>( | ||
f: (abortSignal: AbortSignal) => Promise<T>, | ||
): Promise<T | undefined> { | ||
this.runningTaskId += 1; | ||
const taskId = this.runningTaskId; | ||
|
||
if (this.abortController) { | ||
this.abortController.abort(); | ||
} | ||
this.abortController = new AbortController(); | ||
return f(this.abortController.signal).then( | ||
data => { | ||
if (this.runningTaskId === taskId) { | ||
return data; | ||
} else { | ||
return undefined; | ||
} | ||
}, | ||
err => { | ||
if (this.runningTaskId === taskId) { | ||
throw err; | ||
} else { | ||
return undefined; | ||
} | ||
}, | ||
); | ||
} | ||
} | ||
|
||
class MutexWorker<In, Out> { | ||
private outputBus = new Bacon.Bus<Out>(); | ||
private executor = new MutexExecutor(); | ||
|
||
public output: Bacon.EventStream<Out>; | ||
|
||
public constructor( | ||
private fn: (x: In, abortSignal: AbortSignal) => Promise<Out>, | ||
) { | ||
this.output = this.outputBus.toEventStream(); | ||
} | ||
|
||
public async submit(x: In): Promise<void> { | ||
const output = await this.executor.run(abort => this.fn(x, abort)); | ||
if (output !== undefined) { | ||
this.outputBus.push(output); | ||
} | ||
} | ||
} |
Oops, something went wrong.