chore: use api client from upend.js in webui
parent
69d1059739
commit
f9cfca8fcf
|
@ -27,7 +27,7 @@ export class UpEndApi {
|
|||
this.instanceUrl = apiUrl.replace(/\/+$/g, "");
|
||||
}
|
||||
|
||||
private get apiUrl() {
|
||||
public get apiUrl() {
|
||||
return this.instanceUrl + "/api";
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { useNavigate } from "svelte-navigator";
|
||||
import { uploadFile } from "../lib/api";
|
||||
import Icon from "./utils/Icon.svelte";
|
||||
import IconButton from "./utils/IconButton.svelte";
|
||||
import api from "../lib/api";
|
||||
const navigate = useNavigate();
|
||||
|
||||
let files: File[] = [];
|
||||
|
@ -39,7 +39,7 @@
|
|||
|
||||
try {
|
||||
const addresses = await Promise.all(
|
||||
files.map(async (file) => uploadFile(file))
|
||||
files.map(async (file) => api.uploadFile(file))
|
||||
);
|
||||
|
||||
navigate(`/browse/${addresses.join(",")}`);
|
||||
|
|
|
@ -15,16 +15,11 @@
|
|||
import type { BrowseContext } from "../util/browse";
|
||||
import { Link, useParams } from "svelte-navigator";
|
||||
import { GROUP_TYPE_ADDR } from "upend/constants";
|
||||
import {
|
||||
deleteEntry,
|
||||
putEntityAttribute,
|
||||
putEntry,
|
||||
queryOnce,
|
||||
} from "../lib/api";
|
||||
import Icon from "./utils/Icon.svelte";
|
||||
import BlobViewer from "./display/BlobViewer.svelte";
|
||||
import { i18n } from "../i18n";
|
||||
import EntryList from "./widgets/EntryList.svelte";
|
||||
import api from "../lib/api";
|
||||
const dispatch = createEventDispatcher();
|
||||
const params = useParams();
|
||||
|
||||
|
@ -138,9 +133,9 @@
|
|||
let attributesUsed: UpEntry[] = [];
|
||||
$: {
|
||||
if ($entityInfo?.t === "Attribute") {
|
||||
queryOnce(`(matches ? "${$entityInfo.c}" ?)`).then(
|
||||
(result) => (attributesUsed = result.entries)
|
||||
);
|
||||
api
|
||||
.query(`(matches ? "${$entityInfo.c}" ?)`)
|
||||
.then((result) => (attributesUsed = result.entries));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,17 +143,17 @@
|
|||
const change = ev.detail;
|
||||
switch (change.type) {
|
||||
case "create":
|
||||
await putEntry({
|
||||
await api.putEntry({
|
||||
entity: address,
|
||||
attribute: change.attribute,
|
||||
value: change.value,
|
||||
});
|
||||
break;
|
||||
case "delete":
|
||||
await deleteEntry(change.address);
|
||||
await api.deleteEntry(change.address);
|
||||
break;
|
||||
case "update":
|
||||
await putEntityAttribute(address, change.attribute, change.value);
|
||||
await api.putEntityAttribute(address, change.attribute, change.value);
|
||||
break;
|
||||
default:
|
||||
console.error("Unimplemented AttributeChange", change);
|
||||
|
@ -178,7 +173,7 @@
|
|||
if (!groupToAdd) {
|
||||
return;
|
||||
}
|
||||
await putEntry([
|
||||
await api.putEntry([
|
||||
{
|
||||
entity: String(groupToAdd.c),
|
||||
attribute: "HAS",
|
||||
|
@ -201,19 +196,19 @@
|
|||
}
|
||||
|
||||
async function removeGroup(groupAddress: string) {
|
||||
await deleteEntry(groupAddress);
|
||||
await api.deleteEntry(groupAddress);
|
||||
revalidate();
|
||||
}
|
||||
|
||||
async function deleteObject() {
|
||||
if (confirm(`${$i18n.t("Really delete")} "${identities.join(" | ")}"?`)) {
|
||||
await deleteEntry(address);
|
||||
await api.deleteEntry(address);
|
||||
dispatch("close");
|
||||
}
|
||||
}
|
||||
|
||||
async function onAttributeWidgetSwitch(ev: CustomEvent<string>) {
|
||||
await putEntityAttribute(address, "LAST_ATTRIBUTE_WIDGET", {
|
||||
await api.putEntityAttribute(address, "LAST_ATTRIBUTE_WIDGET", {
|
||||
t: "String",
|
||||
c: ev.detail,
|
||||
});
|
||||
|
@ -221,12 +216,12 @@
|
|||
|
||||
$: entity.subscribe(async (object) => {
|
||||
if (object && object.listing.entries.length) {
|
||||
await putEntityAttribute(object.address, "LAST_VISITED", {
|
||||
await api.putEntityAttribute(object.address, "LAST_VISITED", {
|
||||
t: "Number",
|
||||
c: new Date().getTime() / 1000,
|
||||
});
|
||||
|
||||
await putEntityAttribute(object.address, "NUM_VISITED", {
|
||||
await api.putEntityAttribute(object.address, "NUM_VISITED", {
|
||||
t: "Number",
|
||||
c: (parseInt(String(object.get("NUM_VISITED"))) || 0) + 1,
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import ModelViewer from "./blobs/ModelViewer.svelte";
|
||||
import VideoViewer from "./blobs/VideoViewer.svelte";
|
||||
import HashBadge from "./HashBadge.svelte";
|
||||
import { API_URL } from "../../lib/api";
|
||||
import api from "../../lib/api";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { getTypes } from "../../util/mediatypes";
|
||||
import { formatDuration } from "../../util/fragments/time";
|
||||
|
@ -89,7 +89,7 @@
|
|||
{:else if types.model}
|
||||
<ModelViewer
|
||||
lookonly
|
||||
src="{API_URL}/raw/{address}"
|
||||
src="{api.apiUrl}/raw/{address}"
|
||||
on:loaded={() => (loaded = address)}
|
||||
/>
|
||||
{:else if types.web}
|
||||
|
@ -108,7 +108,7 @@
|
|||
{:else if types.audio}
|
||||
<div class="audiopreview image">
|
||||
<img
|
||||
src="{API_URL}/thumb/{address}?mime=audio"
|
||||
src="{api.apiUrl}/thumb/{address}?mime=audio"
|
||||
alt="Thumbnail for {address}..."
|
||||
loading="lazy"
|
||||
on:load={() => (loaded = address)}
|
||||
|
@ -129,7 +129,7 @@
|
|||
{:else}
|
||||
<div class="image" class:loaded={loaded == address || !handled}>
|
||||
<img
|
||||
src="{API_URL}/{types.mimeType?.includes('svg+xml')
|
||||
src="{api.apiUrl}/{types.mimeType?.includes('svg+xml')
|
||||
? 'raw'
|
||||
: 'thumb'}/{address}?size=512&quality=75"
|
||||
alt="Thumbnail for {address}..."
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import TextViewer from "./blobs/TextViewer.svelte";
|
||||
import VideoViewer from "./blobs/VideoViewer.svelte";
|
||||
import UpLink from "./UpLink.svelte";
|
||||
import { API_URL } from "../../lib/api";
|
||||
import api from "../../lib/api";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { getTypes } from "../../util/mediatypes";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
@ -56,12 +56,12 @@
|
|||
{/if}
|
||||
{#if types.pdf}
|
||||
<iframe
|
||||
src="{API_URL}/raw/{address}?inline"
|
||||
src="{api.apiUrl}/raw/{address}?inline"
|
||||
title="PDF document of {address}"
|
||||
/>
|
||||
{/if}
|
||||
{#if types.model}
|
||||
<ModelViewer src="{API_URL}/raw/{address}" />
|
||||
<ModelViewer src="{api.apiUrl}/raw/{address}" />
|
||||
{/if}
|
||||
{#if types.web}
|
||||
{#if imageLoaded != address}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { getAddress } from "../../lib/api";
|
||||
import { getContext } from "svelte";
|
||||
import { useNavigate, useLocation } from "svelte-navigator";
|
||||
import { readable } from "svelte/store";
|
||||
import type { Address, VALUE_TYPE } from "upend/types";
|
||||
import type { BrowseContext } from "../../util/browse";
|
||||
import api from "../../lib/api";
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
|||
if (to.entity) {
|
||||
targetHref = to.entity;
|
||||
} else if (to.attribute) {
|
||||
getAddress({ attribute: to.attribute }).then((address) => {
|
||||
api.getAddress({ attribute: to.attribute }).then((address) => {
|
||||
targetHref = address;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
import HashBadge from "./HashBadge.svelte";
|
||||
import Ellipsis from "../utils/Ellipsis.svelte";
|
||||
import UpLink from "./UpLink.svelte";
|
||||
import { API_URL, nativeOpen as nativeOpenApi } from "../../lib/api";
|
||||
import { readable, type Readable } from "svelte/store";
|
||||
import { notify, UpNotification } from "../../notifications";
|
||||
import IconButton from "../utils/IconButton.svelte";
|
||||
|
@ -13,7 +12,8 @@
|
|||
import type { UpObject } from "upend";
|
||||
import { i18n } from "../../i18n";
|
||||
import type { EntityInfo } from "upend/types";
|
||||
import { useEntity } from "src/lib/entity";
|
||||
import { useEntity } from "../../lib/entity";
|
||||
import api from "../../lib/api";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let address: string;
|
||||
|
@ -62,7 +62,8 @@
|
|||
} in a default native application...`
|
||||
)
|
||||
);
|
||||
nativeOpenApi(address)
|
||||
api
|
||||
.nativeOpen(address)
|
||||
.then(async (response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`${response.statusText} - ${await response.text()}`);
|
||||
|
@ -105,7 +106,7 @@
|
|||
<div class="separator" />
|
||||
<div class="label" class:resolving title={displayLabel}>
|
||||
{#if banner && isFile}
|
||||
<a href="{API_URL}/raw/{address}" download={inferredIds[0]}>
|
||||
<a href="{api.apiUrl}/raw/{address}" download={inferredIds[0]}>
|
||||
<Ellipsis value={displayLabel} />
|
||||
</a>
|
||||
{:else if link}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts">
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import HashBadge from "./HashBadge.svelte";
|
||||
import UpLink from "./UpLink.svelte";
|
||||
import BlobPreview from "./BlobPreview.svelte";
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { debounce, throttle } from "lodash";
|
||||
import { onMount } from "svelte";
|
||||
import type { IEntry, IValue } from "upend/types";
|
||||
import type { IValue } from "upend/types";
|
||||
import type WaveSurfer from "wavesurfer.js";
|
||||
import type { Region, RegionParams } from "wavesurfer.js/src/plugin/regions";
|
||||
import {
|
||||
API_URL,
|
||||
deleteEntry,
|
||||
fetchEntity,
|
||||
putEntityAttribute,
|
||||
putEntry,
|
||||
} from "../../../lib/api";
|
||||
import api from "../../../lib/api";
|
||||
import { TimeFragment } from "../../../util/fragments/time";
|
||||
import Icon from "../../utils/Icon.svelte";
|
||||
import Selector from "../../utils/Selector.svelte";
|
||||
|
@ -42,11 +36,11 @@
|
|||
let currentAnnotation: UpRegion | undefined;
|
||||
|
||||
async function loadAnnotations() {
|
||||
const entity = await fetchEntity(address);
|
||||
const entity = await api.fetchEntity(address);
|
||||
entity.backlinks
|
||||
.filter((e) => e.attribute == "ANNOTATES")
|
||||
.forEach(async (e) => {
|
||||
const annotation = await fetchEntity(e.entity);
|
||||
const annotation = await api.fetchEntity(e.entity);
|
||||
if (annotation.get("W3C_FRAGMENT_SELECTOR")) {
|
||||
const fragment = TimeFragment.parse(
|
||||
String(annotation.get("W3C_FRAGMENT_SELECTOR"))
|
||||
|
@ -83,7 +77,7 @@
|
|||
|
||||
// Newly created
|
||||
if (!entity) {
|
||||
let [_, newEntity] = await putEntry({
|
||||
let [_, newEntity] = await api.putEntry({
|
||||
entity: {
|
||||
t: "Uuid",
|
||||
},
|
||||
|
@ -98,30 +92,30 @@
|
|||
} as any); // incorrect types, `update()` does take `attributes`
|
||||
}
|
||||
|
||||
await putEntityAttribute(entity, "LBL", {
|
||||
await api.putEntityAttribute(entity, "LBL", {
|
||||
t: "String",
|
||||
c: region.attributes["label"],
|
||||
});
|
||||
|
||||
await putEntityAttribute(entity, "ANNOTATES", {
|
||||
await api.putEntityAttribute(entity, "ANNOTATES", {
|
||||
t: "Address",
|
||||
c: address,
|
||||
});
|
||||
|
||||
await putEntityAttribute(entity, "W3C_FRAGMENT_SELECTOR", {
|
||||
await api.putEntityAttribute(entity, "W3C_FRAGMENT_SELECTOR", {
|
||||
t: "String",
|
||||
c: new TimeFragment(region.start, region.end).toString(),
|
||||
});
|
||||
|
||||
if (region.color !== DEFAULT_ANNOTATION_COLOR) {
|
||||
await putEntityAttribute(entity, "COLOR", {
|
||||
await api.putEntityAttribute(entity, "COLOR", {
|
||||
t: "String",
|
||||
c: region.color,
|
||||
});
|
||||
}
|
||||
|
||||
if (Object.values(region.data).length) {
|
||||
await putEntityAttribute(entity, "NOTE", region.data as IValue);
|
||||
await api.putEntityAttribute(entity, "NOTE", region.data as IValue);
|
||||
}
|
||||
|
||||
region.update({
|
||||
|
@ -134,7 +128,7 @@
|
|||
|
||||
async function deleteAnnotation(region: Region) {
|
||||
if (region.attributes["upend-address"]) {
|
||||
await deleteEntry(region.attributes["upend-address"]);
|
||||
await api.deleteEntry(region.attributes["upend-address"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,13 +232,13 @@
|
|||
|
||||
try {
|
||||
const peaksReq = await fetch(
|
||||
`${API_URL}/thumb/${address}?mime=audio&type=json`
|
||||
`${api.apiUrl}/thumb/${address}?mime=audio&type=json`
|
||||
);
|
||||
const peaks = await peaksReq.json();
|
||||
wavesurfer.load(`${API_URL}/raw/${address}`, peaks.data);
|
||||
wavesurfer.load(`${api.apiUrl}/raw/${address}`, peaks.data);
|
||||
} catch (e) {
|
||||
console.warn(`Failed to load peaks: ${e}`);
|
||||
const entity = await fetchEntity(address);
|
||||
const entity = await api.fetchEntity(address);
|
||||
if (
|
||||
(parseInt(String(entity.get("FILE_SIZE"))) || 0) < 20_000_000 ||
|
||||
confirm(
|
||||
|
@ -257,7 +251,7 @@
|
|||
`Failed to load peaks, falling back to client-side render...`
|
||||
);
|
||||
|
||||
wavesurfer.load(`${API_URL}/raw/${address}`);
|
||||
wavesurfer.load(`${api.apiUrl}/raw/${address}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
export let address: string;
|
||||
export let detail: boolean;
|
||||
import { xywh } from "../../../util/fragments/xywh";
|
||||
import { API_URL } from "../../../lib/api";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import api from "../../../lib/api";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
const { entity } = useEntity(address);
|
||||
|
@ -30,7 +30,7 @@
|
|||
<img
|
||||
class="preview-image"
|
||||
class:imageLoaded
|
||||
src="{API_URL}/{detail ? 'raw' : 'thumb'}/{objectAddress}#{$entity?.get(
|
||||
src="{api.apiUrl}/{detail ? 'raw' : 'thumb'}/{objectAddress}#{$entity?.get(
|
||||
'W3C_FRAGMENT_SELECTOR'
|
||||
)}"
|
||||
use:xywh
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
<script lang="ts">
|
||||
import type { IEntry } from "upend/types";
|
||||
|
||||
import {
|
||||
API_URL,
|
||||
deleteEntry,
|
||||
fetchEntity,
|
||||
putEntry,
|
||||
} from "../../../lib/api";
|
||||
import api from "../../../lib/api";
|
||||
import { useEntity } from "../../../lib/entity";
|
||||
import IconButton from "../../utils/IconButton.svelte";
|
||||
import Spinner from "../../utils/Spinner.svelte";
|
||||
|
@ -59,7 +54,7 @@
|
|||
$entity?.backlinks
|
||||
.filter((e) => e.attribute == "ANNOTATES")
|
||||
.forEach(async (e) => {
|
||||
const annotation = await fetchEntity(e.entity);
|
||||
const annotation = await api.fetchEntity(e.entity);
|
||||
if (annotation.get("W3C_FRAGMENT_SELECTOR")) {
|
||||
anno.addAnnotation({
|
||||
type: "Annotation",
|
||||
|
@ -111,7 +106,7 @@
|
|||
});
|
||||
|
||||
anno.on("createAnnotation", async (annotation) => {
|
||||
const [_, uuid] = await putEntry({
|
||||
const [_, uuid] = await api.putEntry({
|
||||
entity: {
|
||||
t: "Uuid",
|
||||
},
|
||||
|
@ -119,7 +114,7 @@
|
|||
|
||||
annotation.id = uuid;
|
||||
|
||||
await putEntry([
|
||||
await api.putEntry([
|
||||
{
|
||||
entity: uuid,
|
||||
attribute: "ANNOTATES",
|
||||
|
@ -149,13 +144,13 @@
|
|||
]);
|
||||
});
|
||||
anno.on("updateAnnotation", async (annotation) => {
|
||||
const annotationObject = await fetchEntity(annotation.id);
|
||||
const annotationObject = await api.fetchEntity(annotation.id);
|
||||
await Promise.all(
|
||||
annotationObject.attr["LBL"]
|
||||
.concat(annotationObject.attr["W3C_FRAGMENT_SELECTOR"])
|
||||
.map(async (e) => deleteEntry(e.address))
|
||||
.map(async (e) => api.deleteEntry(e.address))
|
||||
);
|
||||
await putEntry([
|
||||
await api.putEntry([
|
||||
{
|
||||
entity: annotation.id,
|
||||
attribute: "W3C_FRAGMENT_SELECTOR",
|
||||
|
@ -177,7 +172,7 @@
|
|||
]);
|
||||
});
|
||||
anno.on("deleteAnnotation", async (annotation) => {
|
||||
await deleteEntry(annotation.id);
|
||||
await api.deleteEntry(annotation.id);
|
||||
});
|
||||
|
||||
imageLoaded = true;
|
||||
|
@ -233,7 +228,7 @@
|
|||
>
|
||||
<img
|
||||
class="preview-image"
|
||||
src="{API_URL}/{detail || svg ? 'raw' : 'thumb'}/{address}"
|
||||
src="{api.apiUrl}/{detail || svg ? 'raw' : 'thumb'}/{address}"
|
||||
alt={address}
|
||||
on:load={loaded}
|
||||
bind:this={imageEl}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { getRaw } from "../../../lib/api";
|
||||
import api from "../../../lib/api";
|
||||
import IconButton from "../../utils/IconButton.svelte";
|
||||
import Spinner from "../../utils/Spinner.svelte";
|
||||
export let address: string;
|
||||
|
@ -7,7 +7,7 @@
|
|||
let mode: "preview" | "full" | "markdown" = "preview";
|
||||
|
||||
$: textContent = (async () => {
|
||||
const response = await getRaw(address, mode == "preview");
|
||||
const response = await api.getRaw(address, mode == "preview");
|
||||
const text = await response.text();
|
||||
if (mode === "markdown") {
|
||||
const { marked } = await import("marked");
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
import { throttle } from "lodash";
|
||||
import Spinner from "../../utils/Spinner.svelte";
|
||||
import Icon from "../../utils/Icon.svelte";
|
||||
import { API_URL } from "../../../lib/api";
|
||||
import { useEntity } from "../../../lib/entity";
|
||||
import { i18n } from "../../../i18n";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import api from "../../../lib/api";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let address: string;
|
||||
|
@ -89,7 +89,7 @@
|
|||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<img
|
||||
class="thumb"
|
||||
src="{API_URL}/thumb/{address}?mime=video"
|
||||
src="{api.apiUrl}/thumb/{address}?mime=video"
|
||||
alt="Preview for {address}"
|
||||
loading="lazy"
|
||||
on:load={() => (state = State.PREVIEW)}
|
||||
|
@ -100,8 +100,8 @@
|
|||
<!-- svelte-ignore a11y-media-has-caption -->
|
||||
<video
|
||||
preload={detail ? "auto" : "metadata"}
|
||||
src="{API_URL}/raw/{address}"
|
||||
poster="{API_URL}/thumb/{address}?mime=video"
|
||||
src="{api.apiUrl}/raw/{address}"
|
||||
poster="{api.apiUrl}/thumb/{address}?mime=video"
|
||||
on:mousemove={updatePreviewPosition}
|
||||
on:mouseleave={resetPreview}
|
||||
on:click|preventDefault={startPlaying}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
import Jobs from "./Jobs.svelte";
|
||||
import Notifications from "./Notifications.svelte";
|
||||
import { i18n } from "../../i18n";
|
||||
import { get_root_for_style } from "svelte/internal";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let rootEl: HTMLElement;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<script lang="ts">
|
||||
import { Link, useLocation, useNavigate } from "svelte-navigator";
|
||||
import { useMatch } from "svelte-navigator";
|
||||
import { refreshVault } from "../../lib/api";
|
||||
import { addEmitter } from "../AddModal.svelte";
|
||||
import Icon from "../utils/Icon.svelte";
|
||||
import Input from "../utils/Input.svelte";
|
||||
import { jobsEmitter } from "./Jobs.svelte";
|
||||
import api from "../../lib/api";
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
|||
}
|
||||
|
||||
async function rescan() {
|
||||
await refreshVault();
|
||||
await api.refreshVault();
|
||||
jobsEmitter.emit("reload");
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
import type { IJob } from "upend/types";
|
||||
import { fade } from "svelte/transition";
|
||||
import ProgessBar from "../utils/ProgessBar.svelte";
|
||||
import { fetchJobs } from "../../lib/api";
|
||||
import api from "../../lib/api";
|
||||
|
||||
interface JobWithId extends IJob {
|
||||
id: string;
|
||||
|
@ -26,7 +26,7 @@
|
|||
let timeout: NodeJS.Timeout;
|
||||
async function updateJobs() {
|
||||
clearTimeout(timeout);
|
||||
jobs = await fetchJobs();
|
||||
jobs = await api.fetchJobs();
|
||||
|
||||
activeJobs = Object.entries(jobs)
|
||||
.filter(([_, job]) => job.state == "InProgress")
|
||||
|
|
|
@ -3,17 +3,13 @@
|
|||
import { createEventDispatcher } from "svelte";
|
||||
import type { UpListing } from "upend";
|
||||
import type { IValue, VALUE_TYPE } from "upend/types";
|
||||
import {
|
||||
fetchAllAttributes,
|
||||
putEntityAttribute,
|
||||
putEntry,
|
||||
} from "../../lib/api";
|
||||
import { baseSearchOnce, createLabelled } from "../../util/search";
|
||||
import UpObject from "../display/UpObject.svelte";
|
||||
import IconButton from "./IconButton.svelte";
|
||||
import Input from "./Input.svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
import { matchSorter } from "match-sorter";
|
||||
import api from "../../lib/api";
|
||||
|
||||
const MAX_OPTIONS = 25;
|
||||
|
||||
|
@ -60,7 +56,7 @@
|
|||
const updateOptions = debounce(async (query: string, doSearch: boolean) => {
|
||||
switch (type) {
|
||||
case "attribute": {
|
||||
const allAttributes = await fetchAllAttributes();
|
||||
const allAttributes = await api.fetchAllAttributes();
|
||||
const attributes = attributeOptions
|
||||
? allAttributes.filter((attr) => attributeOptions.includes(attr.name))
|
||||
: allAttributes;
|
||||
|
@ -197,11 +193,11 @@
|
|||
case "attribute":
|
||||
if (option.labelToCreate) {
|
||||
// First, "create" attribute, getting its address.
|
||||
const [_, address] = await putEntry({
|
||||
const [_, address] = await api.putEntry({
|
||||
entity: { t: "Attribute", c: option.attribute.name },
|
||||
});
|
||||
// Second, label it.
|
||||
await putEntityAttribute(address, "LBL", {
|
||||
await api.putEntityAttribute(address, "LBL", {
|
||||
t: "String",
|
||||
c: option.labelToCreate,
|
||||
});
|
||||
|
|
|
@ -1,150 +1,3 @@
|
|||
import LRU from "lru-cache";
|
||||
import { UpListing, UpObject } from "upend";
|
||||
import type {
|
||||
Address,
|
||||
IJob,
|
||||
PutInput,
|
||||
IValue,
|
||||
ListingResult,
|
||||
PutResult,
|
||||
VaultInfo,
|
||||
StoreInfo,
|
||||
AttributeListingResult,
|
||||
EntityListing,
|
||||
} from "upend/types";
|
||||
import { UpEndApi } from "upend/api";
|
||||
|
||||
export const API_URL = "api";
|
||||
|
||||
export async function fetchEntity(address: string): Promise<UpObject> {
|
||||
const entityFetch = await fetch(`${API_URL}/obj/${address}`);
|
||||
const entityResult = (await entityFetch.json()) as EntityListing;
|
||||
const entityListing = new UpListing(entityResult.entries);
|
||||
return entityListing.getObject(address);
|
||||
}
|
||||
|
||||
export async function fetchEntry(address: string) {
|
||||
const response = await fetch(`${API_URL}/raw/${address}`);
|
||||
const data = await response.json();
|
||||
const listing = new UpListing({ address: data });
|
||||
return listing.entries[0];
|
||||
}
|
||||
|
||||
const queryOnceLRU = new LRU<string, UpListing>(128);
|
||||
const inFlightRequests: { [key: string]: Promise<UpListing> } = {};
|
||||
|
||||
export async function queryOnce(query: string): Promise<UpListing> {
|
||||
const cacheResult = queryOnceLRU.get(query);
|
||||
if (!cacheResult) {
|
||||
if (!inFlightRequests[query]) {
|
||||
console.debug(`Querying: ${query}`);
|
||||
inFlightRequests[query] = new Promise((resolve, reject) => {
|
||||
fetch(`${API_URL}/query`, {
|
||||
method: "POST",
|
||||
body: query,
|
||||
keepalive: true,
|
||||
})
|
||||
.then(async (response) => {
|
||||
inFlightRequests[query] = null;
|
||||
resolve(new UpListing(await response.json()));
|
||||
})
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
} else {
|
||||
console.debug(`Chaining request for ${query}...`);
|
||||
}
|
||||
return await inFlightRequests[query];
|
||||
} else {
|
||||
console.debug(`Returning cached: ${query}`);
|
||||
return cacheResult;
|
||||
}
|
||||
}
|
||||
|
||||
export async function putEntry(input: PutInput): Promise<PutResult> {
|
||||
const response = await fetch(`${API_URL}/obj`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function putEntityAttribute(
|
||||
entity: Address,
|
||||
attribute: string,
|
||||
value: IValue
|
||||
): Promise<Address> {
|
||||
const response = await fetch(`${API_URL}/obj/${entity}/${attribute}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(value),
|
||||
});
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function uploadFile(file: File): Promise<PutResult> {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
|
||||
const response = await fetch(`${API_URL}/blob`, {
|
||||
method: "PUT",
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw Error(await response.text());
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function deleteEntry(address: Address): Promise<void> {
|
||||
await fetch(`${API_URL}/obj/${address}`, { method: "DELETE" });
|
||||
}
|
||||
|
||||
export async function getRaw(address: Address, preview = false) {
|
||||
return await fetch(`${API_URL}/${preview ? "thumb" : "raw"}/${address}`);
|
||||
}
|
||||
|
||||
export async function refreshVault() {
|
||||
return await fetch(`${API_URL}/refresh`, { method: "POST" });
|
||||
}
|
||||
|
||||
export async function nativeOpen(address: Address) {
|
||||
return fetch(`${API_URL}/raw/${address}?native=1`);
|
||||
}
|
||||
|
||||
export async function fetchRoots(): Promise<ListingResult> {
|
||||
const response = await fetch(`${API_URL}/hier_roots`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function fetchJobs(): Promise<IJob[]> {
|
||||
const response = await fetch(`${API_URL}/jobs`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function fetchAllAttributes(): Promise<AttributeListingResult> {
|
||||
const response = await fetch(`${API_URL}/all/attributes`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function fetchInfo(): Promise<VaultInfo> {
|
||||
const response = await fetch(`${API_URL}/info`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function fetchStoreInfo(): Promise<{ [key: string]: StoreInfo }> {
|
||||
const response = await fetch(`${API_URL}/store`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function getAddress(input: {
|
||||
attribute: string;
|
||||
}): Promise<string> {
|
||||
const response = await fetch(
|
||||
`${API_URL}/address?attribute=${input.attribute}`
|
||||
);
|
||||
return await response.json();
|
||||
}
|
||||
export default new UpEndApi("/");
|
|
@ -3,11 +3,11 @@ import { derived, type Readable } from "svelte/store";
|
|||
import { UpListing, UpObject } from "upend";
|
||||
import type { ListingResult, EntityListing, EntityInfo } from "upend/types";
|
||||
import { useSWR } from "../util/fetch";
|
||||
import { API_URL } from "./api";
|
||||
import api from "./api";
|
||||
|
||||
export function useEntity(address: string) {
|
||||
const { data, error, revalidate } = useSWR<EntityListing, unknown>(
|
||||
`${API_URL}/obj/${address}`
|
||||
`${api.apiUrl}/obj/${address}`
|
||||
);
|
||||
|
||||
const entity: Readable<UpObject | undefined> = derived(data, ($listing) => {
|
||||
|
@ -37,7 +37,7 @@ export function useEntity(address: string) {
|
|||
export function query(query: string) {
|
||||
console.debug(`Querying: ${query}`);
|
||||
const { data, error, revalidate } = useSWR<ListingResult, unknown>(
|
||||
`${API_URL}/query`,
|
||||
`${api.apiUrl}/query`,
|
||||
{ method: "POST", body: query }
|
||||
);
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import api from "../lib/api";
|
||||
import { readable, type Readable } from "svelte/store";
|
||||
import type { VaultInfo } from "upend/types";
|
||||
import { fetchInfo } from "../lib/api";
|
||||
|
||||
export const vaultInfo: Readable<VaultInfo> = readable(undefined, (set) => {
|
||||
fetchInfo().then(async (info) => {
|
||||
api.fetchInfo().then(async (info) => {
|
||||
set(info);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import api from "../lib/api";
|
||||
import { i18n } from "../i18n";
|
||||
import { derived, readable, type Readable } from "svelte/store";
|
||||
import { fetchAllAttributes } from "../lib/api";
|
||||
|
||||
const databaseAttributeLabels: Readable<{ [key: string]: string }> = readable(
|
||||
{},
|
||||
(set) => {
|
||||
const result = {};
|
||||
fetchAllAttributes().then((attributes) => {
|
||||
api.fetchAllAttributes().then((attributes) => {
|
||||
attributes.forEach((attribute) => {
|
||||
if (attribute.labels.length) {
|
||||
result[attribute.name] = attribute.labels.sort()[0];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { PutInput } from "upend/types";
|
||||
import { putEntry, queryOnce } from "../lib/api";
|
||||
import { query as queryFn } from "../lib/entity";
|
||||
import api from "../lib/api";
|
||||
|
||||
export function baseSearch(query: string) {
|
||||
return queryFn(
|
||||
|
@ -9,7 +9,7 @@ export function baseSearch(query: string) {
|
|||
}
|
||||
|
||||
export function baseSearchOnce(query: string) {
|
||||
return queryOnce(
|
||||
return api.query(
|
||||
`(or (matches (contains "${query}") ? ?) (matches ? (contains "${query}") ?) (matches ? ? (contains "${query}")))`
|
||||
);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ export async function createLabelled(label: string) {
|
|||
}
|
||||
|
||||
try {
|
||||
const [_, entry] = await putEntry(body);
|
||||
const [_, entry] = await api.putEntry(body);
|
||||
return entry;
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to create object: ${error}`);
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
import AttributeView from "../components/AttributeView.svelte";
|
||||
import UpObjectCard from "../components/display/UpObjectCard.svelte";
|
||||
import Spinner from "../components/utils/Spinner.svelte";
|
||||
import { fetchRoots } from "../lib/api";
|
||||
import api from "../lib/api";
|
||||
import { query } from "../lib/entity";
|
||||
import { vaultInfo } from "../util/info";
|
||||
import { updateTitle } from "../util/title";
|
||||
import { i18n } from "../i18n";
|
||||
|
||||
const roots = (async () => {
|
||||
const data = await fetchRoots();
|
||||
const data = await api.fetchRoots();
|
||||
const listing = new UpListing(data);
|
||||
return Object.values(listing.objects)
|
||||
.filter((obj) => Boolean(obj.attr["LBL"]))
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
import { updateTitle } from "../util/title";
|
||||
import { query as queryFn } from "../lib/entity";
|
||||
import AttributeView from "../components/AttributeView.svelte";
|
||||
import { queryOnce } from "../lib/api";
|
||||
import api from "../lib/api";
|
||||
import Gallery from "../components/widgets/Gallery.svelte";
|
||||
import type { Widget } from "src/lib/types";
|
||||
import { matchSorter } from "match-sorter";
|
||||
|
@ -44,7 +44,7 @@
|
|||
let exactHits: string[] = [];
|
||||
$: {
|
||||
const addressesString = objects.map((e) => `@${e.entity}`).join(" ");
|
||||
queryOnce(`(matches (in ${addressesString}) "LBL" ? )`).then(
|
||||
api.query(`(matches (in ${addressesString}) "LBL" ? )`).then(
|
||||
(labelListing) => {
|
||||
exactHits = labelListing.entries
|
||||
.filter(
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
import UpObject from "../components/display/UpObject.svelte";
|
||||
import Icon from "../components/utils/Icon.svelte";
|
||||
import Spinner from "../components/utils/Spinner.svelte";
|
||||
import { fetchStoreInfo } from "../lib/api";
|
||||
import api from "../lib/api";
|
||||
|
||||
const stores = fetchStoreInfo();
|
||||
const stores = api.fetchStoreInfo();
|
||||
</script>
|
||||
|
||||
<div class="store">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import UpObject from "../components/display/UpObject.svelte";
|
||||
import { putEntityAttribute, putEntry, queryOnce } from "../lib/api";
|
||||
import api from "../lib/api";
|
||||
import Selector from "../components/utils/Selector.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import type { ZoomTransform } from "d3";
|
||||
|
@ -37,7 +37,7 @@
|
|||
let points: IPoint[] = [];
|
||||
async function loadPoints() {
|
||||
points = [];
|
||||
const result = await queryOnce(`(matches ? (in "${x}" "${y}") ?)`);
|
||||
const result = await api.query(`(matches ? (in "${x}" "${y}") ?)`);
|
||||
|
||||
points = Object.entries(result.objects)
|
||||
.map(([address, obj]) => {
|
||||
|
@ -148,7 +148,7 @@
|
|||
[x, xValue],
|
||||
[y, yValue],
|
||||
].map(([axis, value]: [string, number]) =>
|
||||
putEntityAttribute(ev.detail.c as string, axis, {
|
||||
api.putEntityAttribute(ev.detail.c as string, axis, {
|
||||
t: "Number",
|
||||
c: value,
|
||||
})
|
||||
|
|
|
@ -12567,10 +12567,10 @@ __metadata:
|
|||
|
||||
"upend@file:../tools/upend_js::locator=upend-kestrel%40workspace%3A.":
|
||||
version: 0.0.1
|
||||
resolution: "upend@file:../tools/upend_js#../tools/upend_js::hash=20d186&locator=upend-kestrel%40workspace%3A."
|
||||
resolution: "upend@file:../tools/upend_js#../tools/upend_js::hash=d49cb4&locator=upend-kestrel%40workspace%3A."
|
||||
dependencies:
|
||||
lru-cache: ^7.0.0
|
||||
checksum: 0ea49df94876cfe7ffacf3c3c7342d71fdbdcc0326d6aa4c4ce7d1b8a6a14648357e3cf15adeb1c6ad8b5e65c7dce76c312296e16763dd79fc50c2a11907eae6
|
||||
checksum: f05d8b055ca0c72e357218b5bf71ecd0ab59a56b01cf3b4dfde7f58f80dedbc6337b67c7b2d8fd24b43dd1bf7f54793fe3e9bf8da48f13d23a88a031f9a17f40
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
Loading…
Reference in New Issue