diff --git a/package-lock.json b/package-lock.json index 74314ac..49016f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "dependencies": { "@fontsource/fira-mono": "^4.5.0", + "@zerodevx/svelte-json-view": "^0.2.1", "cookie": "^0.4.1", "highlight.js": "^11.6.0", "svelte-highlight": "^6.2.1" @@ -17,8 +18,7 @@ "@sveltejs/adapter-auto": "next", "@sveltejs/kit": "next", "@types/cookie": "^0.5.1", - "@zerodevx/svelte-json-view": "^0.2.1", - "eslint": "^8.16.0", + "eslint": "^8.22.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^4.0.0", "prettier": "^2.6.2", @@ -395,8 +395,7 @@ "node_modules/@zerodevx/svelte-json-view": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@zerodevx/svelte-json-view/-/svelte-json-view-0.2.1.tgz", - "integrity": "sha512-yaLojLYTi08vccUKRg/XSRCCPoyzCZqrG+W8mVhJEGiOfFKAmWqNH6b+/il1gG3V1UaEe7amj2mzmo1mo4q1iA==", - "dev": true + "integrity": "sha512-yaLojLYTi08vccUKRg/XSRCCPoyzCZqrG+W8mVhJEGiOfFKAmWqNH6b+/il1gG3V1UaEe7amj2mzmo1mo4q1iA==" }, "node_modules/abbrev": { "version": "1.1.1", @@ -3515,8 +3514,7 @@ "@zerodevx/svelte-json-view": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@zerodevx/svelte-json-view/-/svelte-json-view-0.2.1.tgz", - "integrity": "sha512-yaLojLYTi08vccUKRg/XSRCCPoyzCZqrG+W8mVhJEGiOfFKAmWqNH6b+/il1gG3V1UaEe7amj2mzmo1mo4q1iA==", - "dev": true + "integrity": "sha512-yaLojLYTi08vccUKRg/XSRCCPoyzCZqrG+W8mVhJEGiOfFKAmWqNH6b+/il1gG3V1UaEe7amj2mzmo1mo4q1iA==" }, "abbrev": { "version": "1.1.1", diff --git a/package.json b/package.json index f06807c..a49c17e 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "my-app", + "name": "kafka-dance-frontend", "version": "0.0.1", "scripts": { "dev": "vite dev", @@ -15,7 +15,7 @@ "@sveltejs/adapter-auto": "next", "@sveltejs/kit": "next", "@types/cookie": "^0.5.1", - "eslint": "^8.16.0", + "eslint": "^8.22.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^4.0.0", "prettier": "^2.6.2", diff --git a/src/app.css b/src/app.css index e0c17f0..a4cb029 100644 --- a/src/app.css +++ b/src/app.css @@ -144,7 +144,8 @@ button { padding: 1em; background-color: #e2eaff; height: 86vh; - max-width: 70vw; + max-width: 65vw; + min-width: 65vw; overflow-y: scroll; } diff --git a/src/lib/constants.js b/src/lib/constants.js index 55854c7..cd1f009 100644 --- a/src/lib/constants.js +++ b/src/lib/constants.js @@ -5,4 +5,6 @@ export const queryMode = { export const backendAddressAndPort = 'localhost:3000' -export const backendUrl = `http://${backendAddressAndPort}` \ No newline at end of file +export const backendUrl = `http://${backendAddressAndPort}` + +export const saslAuthMethods = ['PLAIN', 'SCRAM-SHA-256', 'SCRAM-SHA-512', 'AWS'] \ No newline at end of file diff --git a/src/lib/header/Header.svelte b/src/lib/header/Header.svelte index aced15c..ee57d05 100644 --- a/src/lib/header/Header.svelte +++ b/src/lib/header/Header.svelte @@ -1,6 +1,7 @@
@@ -13,7 +14,16 @@
- + {#if testMode} +
TEST MODE ENABLED
+ {/if} +
@@ -28,6 +38,7 @@ font-size: 18px; color: black; height: 3em; + padding: 1em; } .corner a { diff --git a/src/lib/state.js b/src/lib/state.js index 676a4ae..6c01296 100644 --- a/src/lib/state.js +++ b/src/lib/state.js @@ -17,15 +17,15 @@ const mockItems = [ { "eventType": "Movie", "broughtToYouBy": "20th Century Fox", - "title": "Star Wars 2" + "title": "Star Wars 2: The Star Warsening, brought to you by the Big Stink Corporation, a division of PepsiCo and somehow also Disney." }, ].map(o => ({ value: o, timestamp: new Date().getTime() })) -const testMode = false +export const testMode = true export const state = writable({ items: [], itemCount: undefined, - error: null, + error: 'Connecting to WebSocket...', }) const updateClearError = updater => state.update(s => { s.error = null @@ -38,6 +38,7 @@ let disconnected = false const getRandomFromArray = array => array[Math.floor(Math.random() * array.length)] +const testTimeout = 200 const testQuery = (mode, jsFilter, queryCode) => { try { const f = new Function('message', 'value', queryCode) @@ -46,16 +47,17 @@ const testQuery = (mode, jsFilter, queryCode) => { const item = getRandomFromArray(mockItems) if (!jsFilter || f(item, item.value)) { item.timestamp = new Date().getTime() - updateClearError(s => ({ ...s, items: [item, ...s.items].slice(0, itemLimit), itemCount: 0 })) + state.update(s => ({ ...s, items: [item, ...s.items].slice(0, itemLimit), itemCount: 0 })) } - setTimeout(addItem, 2000) + setTimeout(addItem, testTimeout) } - setTimeout(addItem, 2000) + setTimeout(addItem, testTimeout) } else { - updateClearError(s => ({ ...s, items: mockItems.filter(item => !jsFilter || f(item, item.value)), itemCount: 0 })) + state.update(s => ({ ...s, items: mockItems.filter(item => !jsFilter || f(item, item.value)), itemCount: 0 })) } } catch (e) { - updateClearError(s => ({ ...s, error: e.toString() })) + console.log('Caught an error:', e.toString()) + state.update(s => ({ ...s, error: e.toString() })) } } @@ -83,16 +85,16 @@ export const query = async ({ cluster, topic, mode, jsFilter, queryCode, maxItem } export const connect = () => { - ws = new WebSocket(`ws://${backendAddressAndPort}`) + try { + ws = new WebSocket(`ws://${backendAddressAndPort}`) + } catch (e) { + console.error(e.toString()) + } if (!ws) { updateClearError(s => ({ ...s, error: 'Unable to connect to websocket.' })) return } - ws.addEventListener('close', () => { - disconnected = true - }) - ws.addEventListener('open', () => { console.log('WebSocket opened') }) @@ -101,7 +103,6 @@ export const connect = () => { let data; try { data = JSON.parse(message.data) - console.log('WebSocket message received', data) switch (data?.type.toLowerCase()) { case 'complete': updateClearError(s => ({ @@ -128,6 +129,15 @@ export const connect = () => { }) ws.addEventListener('close', () => { - console.log('WebSocket closed') + disconnected = true + state.update(s => ({ ...s, error: 'WebSocket connection closed.' })) }) + + ws.addEventListener('error', () => { + state.update(s => ({ ...s, error: 'WebSocket connection error.' })) + }) + + if (ws.readyState === ws.CLOSED || ws.readyState === ws.CLOSING) { + state.update(s => ({ ...s, error: 'WebSocket connection closed.' })) + } } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index bbc1a94..e901c83 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -2,7 +2,8 @@ import { onMount } from 'svelte' import { JsonView } from '@zerodevx/svelte-json-view' import { state, connect, query } from '$lib/state'; - import { queryMode, backendUrl } from "../lib/constants.js"; + import { queryMode } from "../lib/constants.js"; + import { apiFetch } from "../utils.js"; let expandAll = true let showMetadata = true @@ -24,28 +25,22 @@ return message.value.eventType === "Television";` let topics = [] let clusters = [] const updateTopics = async () => { - topics = [] - try { - const response = await fetch(`${backendUrl}/topics/${querySettings.cluster}`) - topics = await response.json() - topics.sort() - console.log('topics', topics) - querySettings.topic = topics[0] - } catch (e) { - console.log('fetch error:', e.toString()) - } + topics = await apiFetch(`/topics/${querySettings.cluster}`) + topics ??= [] + topics.sort() + console.log('topics', topics) + querySettings.topic = topics[0] } onMount(async () => { connect(); - const response = await fetch(`${backendUrl}/clusters`) - clusters = Object.keys(await response.json()) + clusters = Object.keys((await apiFetch('/clusters')) || {}) querySettings.cluster = clusters[0] await updateTopics() }) - {querySettings.topic} - Kafka Dance + {querySettings.topic ? `${querySettings.topic} - ` : ''}Kafka Dance diff --git a/src/routes/settings/+page.svelte b/src/routes/settings/+page.svelte index 3774399..4282d21 100644 --- a/src/routes/settings/+page.svelte +++ b/src/routes/settings/+page.svelte @@ -1,6 +1,7 @@