2023-05-20 18:17:13 +02:00
|
|
|
<script lang="ts">
|
|
|
|
import browser from "webextension-polyfill";
|
2023-05-21 21:37:29 +02:00
|
|
|
import { UpEndApi } from "upend/api";
|
2023-05-20 18:17:13 +02:00
|
|
|
import { cleanInstanceUrl, instanceUrlStore } from "./common";
|
|
|
|
import { onMount } from "svelte";
|
|
|
|
import "./main.scss";
|
|
|
|
|
2023-05-21 21:37:29 +02:00
|
|
|
const api = new UpEndApi("http://localhost:8093");
|
|
|
|
|
2023-05-20 18:17:13 +02:00
|
|
|
let opening = false;
|
|
|
|
let openError: string | undefined;
|
|
|
|
|
|
|
|
let instanceUrl: string;
|
|
|
|
$: instanceUrl = $instanceUrlStore;
|
|
|
|
let instanceUrlModified = false;
|
|
|
|
$: instanceUrlModified = $instanceUrlStore !== instanceUrl;
|
|
|
|
|
|
|
|
let instanceVersion: string;
|
|
|
|
let instanceVersionError: string;
|
|
|
|
$: Boolean($instanceUrlStore) && updateVersion();
|
|
|
|
|
|
|
|
async function updateVersion() {
|
|
|
|
instanceVersion = undefined;
|
|
|
|
instanceVersionError = undefined;
|
|
|
|
|
|
|
|
try {
|
2023-05-21 21:37:29 +02:00
|
|
|
const vaultInfo = await api.fetchInfo();
|
2023-05-20 18:17:13 +02:00
|
|
|
instanceVersion = vaultInfo.version;
|
|
|
|
} catch (err: unknown) {
|
|
|
|
instanceVersionError = processError(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-27 14:01:04 +02:00
|
|
|
async function getCurrentUrl() {
|
2023-05-20 18:17:13 +02:00
|
|
|
const currentTab = (
|
|
|
|
await browser.tabs.query({
|
|
|
|
active: true,
|
|
|
|
currentWindow: true,
|
|
|
|
})
|
|
|
|
)[0];
|
2023-05-27 14:01:04 +02:00
|
|
|
return currentTab.url;
|
|
|
|
}
|
|
|
|
|
|
|
|
let currentUrl: string | undefined;
|
|
|
|
let contentType: string | undefined;
|
|
|
|
onMount(async () => {
|
|
|
|
currentUrl = await getCurrentUrl();
|
2023-05-20 18:17:13 +02:00
|
|
|
|
2023-05-27 14:01:04 +02:00
|
|
|
browser.tabs.onUpdated.addListener(async () => {
|
|
|
|
if (currentUrl !== (await getCurrentUrl())) {
|
|
|
|
window.close();
|
|
|
|
}
|
|
|
|
});
|
2023-05-20 18:17:13 +02:00
|
|
|
|
2023-05-27 14:01:04 +02:00
|
|
|
contentType = (await browser.tabs.executeScript(undefined, {
|
2023-05-20 18:17:13 +02:00
|
|
|
code: "document.contentType",
|
|
|
|
})) as unknown as string | undefined;
|
|
|
|
});
|
|
|
|
|
|
|
|
function visit(address: string) {
|
|
|
|
browser.tabs.create({ url: `${$cleanInstanceUrl}/#/browse/${address}` });
|
|
|
|
window.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
async function openAsUrl() {
|
2023-05-21 21:37:29 +02:00
|
|
|
open({ url: currentUrl });
|
2023-05-20 18:17:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
async function openContent() {
|
2023-05-21 21:37:29 +02:00
|
|
|
open({ urlContent: currentUrl });
|
2023-05-20 22:33:22 +02:00
|
|
|
}
|
|
|
|
|
2023-05-27 14:01:04 +02:00
|
|
|
async function open(input: { url: string } | { urlContent: string }) {
|
2023-05-20 18:17:13 +02:00
|
|
|
opening = true;
|
|
|
|
try {
|
2023-05-21 21:37:29 +02:00
|
|
|
const address = await api.getAddress(input);
|
2023-05-20 22:33:22 +02:00
|
|
|
|
|
|
|
// const obj = (await (
|
|
|
|
// await fetch(`${$cleanInstanceUrl}/api/obj/${address}`)
|
|
|
|
// ).json()) as EntityListing;
|
|
|
|
|
2023-05-20 18:17:13 +02:00
|
|
|
visit(address);
|
|
|
|
} catch (err) {
|
|
|
|
openError = processError(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let primaryAction: [string, () => void] | undefined;
|
|
|
|
$: primaryAction =
|
|
|
|
contentType &&
|
|
|
|
(contentType == "text/html"
|
|
|
|
? ["Open as URL", openAsUrl]
|
|
|
|
: ["Open Content", openContent]);
|
|
|
|
|
|
|
|
$: primaryActionLabel = primaryAction ? primaryAction[0] : "...";
|
|
|
|
function performPrimaryAction() {
|
|
|
|
primaryAction[1]();
|
|
|
|
}
|
|
|
|
|
|
|
|
function processError(err: unknown): string {
|
|
|
|
if (err instanceof Error) {
|
|
|
|
if (err.message.includes("NetworkError")) {
|
|
|
|
return "Network Error. Is UpEnd running?";
|
|
|
|
} else {
|
|
|
|
return err.message;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return String(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<main>
|
|
|
|
<div class="primary-controls">
|
|
|
|
<button
|
|
|
|
class="button"
|
2023-05-21 21:46:33 +02:00
|
|
|
disabled={!primaryAction}
|
2023-05-20 18:17:13 +02:00
|
|
|
on:click={performPrimaryAction}
|
|
|
|
>
|
|
|
|
{primaryActionLabel}
|
|
|
|
</button>
|
|
|
|
<div class="label">Content type: {contentType || "???"}</div>
|
|
|
|
</div>
|
|
|
|
<div class="controls row">
|
|
|
|
<button class="button" on:click={openAsUrl}>Open as URL</button>
|
|
|
|
<button class="button" on:click={openContent}>Open Content</button>
|
|
|
|
</div>
|
|
|
|
{#if opening && !openError}
|
|
|
|
<div class="status-label">Opening, please wait...</div>
|
|
|
|
{/if}
|
|
|
|
{#if openError}
|
|
|
|
<div class="status-label error">{openError}</div>
|
|
|
|
{/if}
|
|
|
|
<hr />
|
|
|
|
<div class="row">
|
|
|
|
<label>
|
|
|
|
Instance URL
|
|
|
|
<input
|
|
|
|
class="instance-input"
|
|
|
|
type="url"
|
|
|
|
bind:value={instanceUrl}
|
|
|
|
class:modified={instanceUrlModified}
|
|
|
|
/>
|
|
|
|
</label>
|
|
|
|
<button class="button" on:click={() => ($instanceUrlStore = instanceUrl)}>
|
|
|
|
Save
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<div class="version">
|
|
|
|
Status: {#if !instanceVersionError}
|
|
|
|
{`OK, v.${instanceVersion}` || "???"}
|
|
|
|
{:else}
|
|
|
|
<div class="error">{instanceVersionError}</div>
|
|
|
|
{/if}
|
|
|
|
</div>
|
|
|
|
</main>
|
|
|
|
|
|
|
|
<style lang="scss">
|
|
|
|
@use "../../webui/src/styles/colors";
|
|
|
|
|
|
|
|
main {
|
|
|
|
padding: 1em;
|
|
|
|
}
|
|
|
|
|
|
|
|
input {
|
|
|
|
background: var(--background);
|
|
|
|
color: var(--foreground);
|
|
|
|
border: 1px solid var(--foreground);
|
|
|
|
border-radius: 2px;
|
|
|
|
}
|
|
|
|
|
|
|
|
input[type="url"] {
|
|
|
|
font-family: var(--monospace-font);
|
|
|
|
|
|
|
|
&:focus-visible {
|
|
|
|
outline: 1px solid var(--primary-lighter);
|
|
|
|
}
|
|
|
|
|
|
|
|
&:invalid {
|
|
|
|
color: colors.$red;
|
|
|
|
outline: 2px solid colors.$red;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.instance-input.modified {
|
|
|
|
color: colors.$yellow;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr {
|
|
|
|
margin: 1rem 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.controls {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-evenly;
|
|
|
|
}
|
|
|
|
|
|
|
|
.primary-controls {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
align-items: center;
|
|
|
|
gap: 0.25rem;
|
|
|
|
|
|
|
|
margin-bottom: 1rem;
|
|
|
|
.button {
|
|
|
|
font-size: 1.5rem;
|
|
|
|
}
|
|
|
|
.label {
|
|
|
|
font-size: 0.75rem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.row {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
gap: 1rem;
|
|
|
|
}
|
|
|
|
|
|
|
|
.status-label {
|
|
|
|
margin-top: 1rem;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
.error {
|
|
|
|
color: colors.$red;
|
|
|
|
}
|
|
|
|
|
|
|
|
.version .error {
|
|
|
|
display: inline;
|
|
|
|
}
|
|
|
|
</style>
|