Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): enable streaming updated via graphql subscriptions/websockets #18

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@urql/core": "^4.1.1",
"@urql/svelte": "^4.0.4",
"fuse.js": "^7.0.0",
"graphql-ws": "^5.16.0",
"underscore": "^1.13.6"
}
}
2 changes: 1 addition & 1 deletion frontend/package.json.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
d2d982bc8b0a5ab3099ac8adbdf56b66
15620fe1e6786ed80d4dff1a5fa96dc3
23 changes: 20 additions & 3 deletions frontend/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
<script lang="ts">
import SearchBar from "./SearchBar.svelte";
import Legend from "./Legend.svelte";
import {Client, cacheExchange, fetchExchange, setContextClient} from '@urql/svelte';
import {Client, cacheExchange, fetchExchange, setContextClient, subscriptionExchange} from '@urql/svelte';
import JsonTable from "./JsonTable.svelte";
import { createClient as createWSClient } from 'graphql-ws';

window.addEventListener("keydown", function(e) {
if(["Space","ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].indexOf(e.code) > -1) {
e.preventDefault();
}
}, false);

const graphqlUri = "localhost:8080/graphql"
const wsClient = createWSClient({
url: 'ws://' + graphqlUri,
});

const client = new Client({
// TODO: https
url: 'http://localhost:8080/graphql',
exchanges: [cacheExchange, fetchExchange],
url: 'http://' + graphqlUri,
exchanges: [cacheExchange, fetchExchange,
subscriptionExchange({
forwardSubscription(request) {
const input = { ...request, query: request.query || '' };
return {
subscribe(sink) {
const unsubscribe = wsClient.subscribe(input, sink);
return { unsubscribe };
},
};
},
}),],
maskTypename: true, // suppresses __typename field from graphql response
});
setContextClient(client);
Expand Down
72 changes: 72 additions & 0 deletions frontend/src/ContextData.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<script lang="ts">
import {transform, rowCount} from "./utils";
import { onDestroy } from 'svelte';
export let store
import {type Writable, writable} from "svelte/store";
// const items = writable([]);
export const items: Writable<Array<any>> = writable([])


$: if ($store.data) {
let [[_, obj]] = Object.entries($store.data)
items.update( arr => {
arr.push(transform(obj))
return arr
} )
}

items.subscribe( i => {
rowCount.update(n => n + $items.length)
})

onDestroy(() => {
rowCount.update(n => n - $items.length);
});


</script>

{#if $items.length > 0 }
{#each $items as item}
<tr>
<td>
<slot name="cluster-context"/>
</td>
{#each Object.values(item) as cell }
<td>{cell}</td>
{/each}
</tr>
{/each}
{/if}

<style>
table {
width: 100%;
}

td {
padding: 4px;
text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100px;
}

th {
padding: 6px;
text-align: left;
color: #1988d9;
font-weight: normal;

/* required for sticky header */
background-color: rgba(31, 31, 31, 1);
position: sticky;
top: 2px;
}

:global(.highlight) {
background-color: rgba(60, 115, 176, 0.2)
}
</style>

58 changes: 25 additions & 33 deletions frontend/src/JsonTable.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
<script lang="ts">
import {searchTerm, filterTerm, tableDataStore, filter} from "./jsonTable"
import ContextData from "./ContextData.svelte";
import {activeContextStore} from "./activeContextStore";
import {transform} from "./utils"
import {rowCount} from "./utils";

let activeRowIndex = 0, filteredData, displayedData
$: data = Array.from($tableDataStore.values()).flatMap(arr => arr)
$: displayedData = filteredData ? filteredData : data
let activeRowIndex = 0, filteredData, randomStore
let stores = []
$: stores = Array.from($activeContextStore.values()).length > 0 ? Array.from($activeContextStore.values()) : []
$: randomStore = stores.length > 0 ? stores[0].subscriptionStore : null

function handleKeyDown(event: CustomEvent | KeyboardEvent) {
let element = document.getElementById('highlight')
Expand All @@ -14,12 +19,12 @@
if (event.key === 'ArrowUp' || event.key === 'Up') {
activeRowIndex = Math.max(0, activeRowIndex - 1);
} else if (event.key === 'ArrowDown' || event.key === 'Down') {
activeRowIndex = Math.min(data.length - 1, activeRowIndex + 1);
activeRowIndex = Math.min($rowCount - 1, activeRowIndex + 1);
}
}

filterTerm.subscribe( term => {
if (term == "" || term == null){
filterTerm.subscribe(term => {
if (term == "" || term == null) {
filteredData = null
return
}
Expand All @@ -29,44 +34,31 @@
window.addEventListener("keydown", function (e) {
handleKeyDown(e)
});

</script>

{#if (!displayedData)}
Dataset does not exist
{:else if displayedData.length === 0}
Dataset is empty
{:else if displayedData.length > 0}
{#if randomStore && $randomStore.data && stores.length > 0}
{@const [[_, obj]] = Object.entries($randomStore.data)}

<fieldset>
<legend>{$searchTerm.charAt(0).toUpperCase() + $searchTerm.slice(1) + "s" + "(" + displayedData.length + ")"} </legend>
<legend>{$searchTerm.charAt(0).toUpperCase() + $searchTerm.slice(1) + "s" + "(" + $rowCount + ")"} </legend>
<div class="scrollable-content">
<table>
<!-- HEADER ROW -->
<thead>
<tr>
{#each Object.keys(displayedData[0]) as header}
<th columnId={header}>
{header}
</th>
<th>Context</th>
{#each Object.keys(transform(obj)) as key}
<th>
{key}
</th>
{/each}
</tr>
</thead>
<!-- DATA ROWS -->

<tbody>
{#each Object.entries(displayedData) as [id, obj] }
{#if id == activeRowIndex}
<tr id="highlight">
{#each Object.values(obj) as val }
<td class="highlight">{val}</td>
{/each}
</tr>
{:else }
<tr>
{#each Object.values(obj) as val }
<td>{val}</td>
{/each}
</tr>
{/if}
{#each stores as store}
<ContextData store={store.subscriptionStore}>
<td slot="cluster-context">{store.contextName}</td>
</ContextData>
{/each}
</tbody>
</table>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/Legend.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@

// update active contexts
if (toggle) {
console.log("INFO: adding context store:", name)
addContextStore.set(name)
} else {
console.log("INFO: removing context store: ", name)
removeContextStore.set(name)
}
}
Expand Down
Loading
Loading