Extract QueryInput to its own component.
Add larger modal text editor. Include JSON representation in JS filtering.
This commit is contained in:
parent
bd0967df0e
commit
368da3360a
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
export let confirm = 'Confirm'
|
||||
export let level = ''
|
||||
export let title
|
||||
export let onCancel = () => {}
|
||||
|
@ -15,8 +16,8 @@
|
|||
<slot></slot>
|
||||
</div>
|
||||
<div class="modal-button-row">
|
||||
<button on:click={onCancel}>Cancel</button>
|
||||
<button class={level} on:click={onConfirm}>Confirm</button>
|
||||
<button on:click={onCancel} style={onCancel ? '' : 'visibility: hidden;'}>Cancel</button>
|
||||
<button class={level} on:click={onConfirm}>{confirm}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -40,7 +41,7 @@
|
|||
/* Modal Content/Box */
|
||||
.modal-content {
|
||||
background-color: #fefefe;
|
||||
margin: 15% auto; /* 15% from the top and centered */
|
||||
margin: /*15%*/ auto; /* 15% from the top and centered */
|
||||
padding: 2em;
|
||||
border: 1px solid #888;
|
||||
border-radius: 10px;
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
<script>
|
||||
export let big
|
||||
export let jsFilter
|
||||
export let mutableObjects
|
||||
export let queryCode
|
||||
</script>
|
||||
|
||||
<div class="query-input-header">
|
||||
<div on:click={() => jsFilter = !jsFilter}>
|
||||
Use JavaScript to filter messages
|
||||
<input type=checkbox bind:checked={jsFilter}>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if jsFilter}
|
||||
<div class="query-input-display">
|
||||
<div title="If enabled, mutations made by the below code will be displayed in the result data.">
|
||||
Allow JavaScript to mutate objects
|
||||
<input type=checkbox bind:checked={mutableObjects}>
|
||||
</div>
|
||||
<textarea class={"query-input" + (big ? ' big' : '')} bind:value={queryCode}></textarea>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.query-input-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.query-input-display {
|
||||
margin-top: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.query-input {
|
||||
min-height: 5vw;
|
||||
resize: vertical;
|
||||
}
|
||||
.query-input.big {
|
||||
height: 60vh;
|
||||
width: 60vw;
|
||||
}
|
||||
|
||||
textarea {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
margin-left: 0;
|
||||
|
||||
background-color: #222222;
|
||||
color: #d0dde9;
|
||||
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
font-family: var(--font-mono);
|
||||
padding: 1em;
|
||||
overflow-x: auto;
|
||||
min-width: 20vw;
|
||||
}
|
||||
</style>
|
|
@ -39,6 +39,7 @@ export const testMode = true
|
|||
export const state = writable({
|
||||
items: [],
|
||||
itemCount: undefined,
|
||||
matchCount: undefined,
|
||||
error: 'Connecting to WebSocket...',
|
||||
})
|
||||
|
||||
|
@ -50,7 +51,7 @@ const updateClearError = updater => state.update(s => {
|
|||
let ws;
|
||||
let itemLimit = Infinity
|
||||
let disconnected = false
|
||||
let filterFunc = (_message, _value) => true
|
||||
let filterFunc = (_message, _value, _json) => true
|
||||
|
||||
let runTestQuery = true
|
||||
const testTimeout = 200
|
||||
|
@ -60,9 +61,13 @@ const testQuery = (mode) => {
|
|||
if (mode === queryMode.REAL_TIME) {
|
||||
const addItem = () => {
|
||||
const item = getRandomFromArray(mockItems)
|
||||
if (filterFunc(item, item.value)) {
|
||||
if (filterFunc(item, item.value, JSON.stringify(item))) {
|
||||
item.timestamp = new Date().getTime()
|
||||
state.update(s => ({ ...s, items: [item, ...s.items].slice(0, itemLimit), itemCount: (s.itemCount || 0) + 1 }))
|
||||
state.update(s => ({
|
||||
...s,
|
||||
items: [item, ...s.items].slice(0, itemLimit),
|
||||
itemCount: (s.itemCount || 0) + 1
|
||||
}))
|
||||
}
|
||||
if (runTestQuery) {
|
||||
setTimeout(addItem, testTimeout)
|
||||
|
@ -70,7 +75,11 @@ const testQuery = (mode) => {
|
|||
}
|
||||
setTimeout(addItem, testTimeout)
|
||||
} else {
|
||||
state.update(s => ({ ...s, items: mockItems.filter(item => filterFunc(item, item.value)), itemCount: (s.itemCount || 0) + 1 }))
|
||||
state.update(s => ({
|
||||
...s,
|
||||
items: mockItems.filter(item => filterFunc(item, item.value, JSON.stringify(item))),
|
||||
itemCount: (s.itemCount || 0) + 1
|
||||
}))
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Caught an error:', e.toString())
|
||||
|
@ -89,7 +98,7 @@ export const killQuery = async ({ }) => {
|
|||
// noinspection JSUnusedGlobalSymbols
|
||||
export const query = async ({ cluster, topic, mode, jsFilter, queryCode, maxItems, mutableObjects }) => {
|
||||
if (jsFilter) {
|
||||
filterFunc = new Function('message', 'value', queryCode)
|
||||
filterFunc = new Function('message', 'value', 'json', queryCode)
|
||||
} else {
|
||||
filterFunc = () => true
|
||||
}
|
||||
|
@ -153,7 +162,7 @@ export const connect = () => {
|
|||
}))
|
||||
break;
|
||||
case 'message':
|
||||
if (filterFunc(data.message)) {
|
||||
if (filterFunc(data.message, data.message.value, message.data)) {
|
||||
updateClearError(s => ({
|
||||
...s,
|
||||
items: console.log('new item', data.message) || [data.message, ...s.items].slice(0, itemLimit),
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
import { JsonView } from '@zerodevx/svelte-json-view'
|
||||
import QueryInput from '$lib/QueryInput.svelte'
|
||||
import { state, connect, query, killQuery } from '$lib/state'
|
||||
import { queryMode } from "../lib/constants.js"
|
||||
import { apiFetch } from "../utils.js"
|
||||
import Modal from "../lib/Modal.svelte";
|
||||
|
||||
let showQueryModal = false
|
||||
|
||||
let expandAll = true
|
||||
let showMetadata = true
|
||||
|
@ -16,8 +20,10 @@
|
|||
maxItems: 20,
|
||||
mutableObjects: false,
|
||||
queryCode:
|
||||
`// The message object contains all metadata
|
||||
`// \`message\` contains all metadata
|
||||
// \`value\` is shorthand for message.value
|
||||
// it contains the actual produced data
|
||||
// \`json\` is a JSON representation of \`message\`
|
||||
|
||||
return message.value.eventType === "Television";`
|
||||
}
|
||||
|
@ -123,14 +129,24 @@ return message.value.eventType === "Television";`
|
|||
<br/>
|
||||
|
||||
<div class="settings-option">
|
||||
<div class="query-input-header"><div on:click={() => querySettings.jsFilter = !querySettings.jsFilter}>Use JavaScript to filter messages</div> <input type=checkbox bind:checked={querySettings.jsFilter}></div>
|
||||
<QueryInput
|
||||
bind:jsFilter={querySettings.jsFilter}
|
||||
bind:mutableObjects={querySettings.mutableObjects}
|
||||
bind:queryCode={querySettings.queryCode} />
|
||||
{#if querySettings.jsFilter}
|
||||
<div class="query-input-display">
|
||||
<div title="If enabled, mutations made by the below code will be displayed in the result data.">
|
||||
Allow JavaScript to mutate objects <input type=checkbox bind:checked={querySettings.mutableObjects}>
|
||||
</div>
|
||||
<textarea class="query-input" bind:value={querySettings.queryCode}></textarea>
|
||||
</div>
|
||||
<button class="query-input-button" on:click={() => showQueryModal = true}>Open Large Editor</button>
|
||||
{/if}
|
||||
{#if showQueryModal}
|
||||
<Modal onClickOut={() => showQueryModal = false}
|
||||
onCancel={null}
|
||||
onConfirm={() => showQueryModal = false}
|
||||
confirm="Close"
|
||||
title={'JS Filter'}>
|
||||
<QueryInput big
|
||||
bind:jsFilter={querySettings.jsFilter}
|
||||
bind:mutableObjects={querySettings.mutableObjects}
|
||||
bind:queryCode={querySettings.queryCode} />
|
||||
</Modal>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
@ -167,21 +183,25 @@ return message.value.eventType === "Television";`
|
|||
|
||||
<div class="data-view-container">
|
||||
<div class="data-view-bar">
|
||||
<div>
|
||||
<div class="border-between">
|
||||
<button class={expandAll ? 'selected' : ''} on:click={() => expandAll = !expandAll}>
|
||||
Expand All Objects
|
||||
</button>
|
||||
<button class={showMetadata ? 'selected' : ''} on:click={() => showMetadata = !showMetadata}>
|
||||
Show Metadata
|
||||
</button>
|
||||
<button on:click={fontUp}>+</button>
|
||||
<button on:click={fontDown}>-</button>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center">
|
||||
{#if $state.itemCount >= 0}
|
||||
<div class="data-view-results">
|
||||
{$state.itemCount} Messages
|
||||
</div>
|
||||
{/if}
|
||||
<div class="border-between">
|
||||
<button on:click={fontDown} style="border-color: #aaa;">-</button>
|
||||
<button on:click={fontUp}>+</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if $state.items?.length > 0}
|
||||
<div class="data-view" style={`font-size: ${fontSizes[dataViewFontSize]}%`}>
|
||||
|
@ -212,10 +232,21 @@ return message.value.eventType === "Television";`
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.data-view-bar button {
|
||||
.border-between {
|
||||
border-width: 1px;
|
||||
border-style: none;
|
||||
display: flex;
|
||||
}
|
||||
.border-between button:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
.data-view-bar button {
|
||||
border-color: white;
|
||||
border-style: none;
|
||||
border-right: solid;
|
||||
border-width: 1px;
|
||||
border-radius: 0;
|
||||
margin-right: 1px;
|
||||
margin: 0;
|
||||
}
|
||||
button.selected {
|
||||
background-color: #4732a5;
|
||||
|
@ -243,20 +274,14 @@ return message.value.eventType === "Television";`
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
margin-left: 0;
|
||||
|
||||
background-color: #222222;
|
||||
.query-input-button {
|
||||
border-style: none;
|
||||
border-radius: 0;
|
||||
background-color: #313131;
|
||||
color: #d0dde9;
|
||||
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
font-family: var(--font-mono);
|
||||
padding: 1em;
|
||||
overflow-x: auto;
|
||||
min-width: 20vw;
|
||||
}
|
||||
.query-input-button:hover {
|
||||
background-color: #575757;
|
||||
}
|
||||
|
||||
.query-settings {
|
||||
|
@ -269,21 +294,6 @@ return message.value.eventType === "Television";`
|
|||
height: 83vh;
|
||||
}
|
||||
|
||||
.query-input-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.query-input-display {
|
||||
margin-top: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.query-input {
|
||||
min-height: 4vw;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.query-type {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
Loading…
Reference in New Issue