Collapsible query settings and better mobile support.

Also use a larger list of test clusters, for testing.
This commit is contained in:
Sage Vaillancourt 2022-09-06 16:48:25 -04:00
parent 4e75739b1d
commit 81e18d4e60
4 changed files with 162 additions and 148 deletions

View File

@ -38,6 +38,11 @@ select, input {
padding: 0.3em; padding: 0.3em;
background-color: white; background-color: white;
border-radius: 4px; border-radius: 4px;
max-width: 90%;
}
main {
height: calc(100% - 4em);
} }
select option { select option {
@ -230,13 +235,12 @@ button {
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
border-color: #95c1d3; border-color: #95c1d3;
flex-grow: 2; flex-grow: 1;
padding: 1em; padding: 1em;
background-color: #e2eaff; background-color: #e2eaff;
height: 84vh;
max-width: 65vw;
min-width: 65vw; min-width: 65vw;
overflow-y: scroll; overflow-y: scroll;
margin-bottom: 1em;
} }
.settings-option { .settings-option {
@ -254,8 +258,57 @@ button:focus:not(:focus-visible) {
outline: none; outline: none;
} }
.query-settings-hider {
color: rgba(0,0,0, 0.5)
}
.query-settings-shower {
color: rgba(0,0,0, 0.5)
}
.query-settings-hider:before {
content: "«";
}
.query-settings-shower:before {
content: "»";
}
section {
display: flex;
flex-direction: row;
flex: 1;
justify-content: space-between;
overflow: hidden;
}
.query-settings {
margin-right: 1rem;
display: flex;
flex-direction: column;
padding: 1em;
}
@media (min-width: 720px) { @media (min-width: 720px) {
h1 { h1 {
font-size: 2.4rem; font-size: 2.4rem;
} }
.query-settings {
overflow: scroll;
}
}
@media (max-width: 719px) {
section {
flex-direction: column;
overflow: scroll;
}
.query-settings {
flex-grow: 1;
overflow: visible;
}
.query-settings-hider:before {
content: '▲';
}
.query-settings-shower:before {
content: '▼';
}
} }

View File

@ -16,6 +16,7 @@
} from './+page.js'; } from './+page.js';
export let errors, data export let errors, data
let showQuerySettings = true
let showQueryModal = false let showQueryModal = false
let queryRunning = '' let queryRunning = ''
@ -90,120 +91,99 @@
</svelte:head> </svelte:head>
<section> <section>
<div class="query-settings"> {#if showQuerySettings}
<!-- <div class="query-settings">
<Header /> <!--
<NavBar /> <Header />
--> <NavBar />
<h1>Topic Search</h1> -->
<div class="state-error"> <h1>Topic Search</h1>
{#if $state.error} <div class="state-error">
<span transition:fade={{duration: 100}}>{$state.error}</span> {#if $state.error}
{#if $state.errorDetails} <span transition:fade={{duration: 100}}>{$state.error}</span>
<div class="state-error-details">{$state.errorDetails}</div> {#if $state.errorDetails}
<div class="state-error-details">{$state.errorDetails}</div>
{/if}
{:else}
&nbsp;
{/if} {/if}
{:else} </div>
&nbsp;
{/if}
</div>
<div class="settings-option"> <div class="settings-option">
<h3>Cluster</h3> <h3>Cluster</h3>
<select disabled={clusterNames.length === 0} bind:value={querySettings.cluster} name="cluster" id="cluster" on:change={updateTopics}> <select disabled={clusterNames.length === 0} bind:value={querySettings.cluster} name="cluster" id="cluster" on:change={updateTopics}>
{#each clusterNames as clusterName} {#each clusterNames as clusterName}
<option value={clusterName}>{clusterName}</option> <option value={clusterName}>{clusterName}</option>
{/each} {/each}
</select> </select>
</div> </div>
<div class="settings-option"> <div class="settings-option">
<h3>Topic</h3> <h3>Topic</h3>
<select disabled={topics.length === 0} bind:value={querySettings.topic} name="topic" id="topic"> <select disabled={topics.length === 0} bind:value={querySettings.topic} name="topic" id="topic">
{#each topics as topic} {#each topics as topic}
<option value={topic}>{topic}</option> <option value={topic}>{topic}</option>
{/each} {/each}
</select> </select>
</div> </div>
<div class="settings-option"> <div class="settings-option">
<label> <label>
Maximum Results Maximum Results
<input type=number bind:value={querySettings.maxItems} min=0 max=10000> <input type=number bind:value={querySettings.maxItems} min=0 max=10000>
</label>
</div>
<br/>
<div class="settings-option">
<QueryInput
bind:jsFilter={querySettings.jsFilter}
bind:mutableObjects={querySettings.mutableObjects}
bind:queryCode={querySettings.queryCode} />
{#if querySettings.jsFilter}
<button class="query-input-button" on:click={() => showQueryModal = true}>Open Editor Window</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>
<!-- Previous 'Start' style
<div class="settings-option query-type">
<span>Query Type:</span>
<span>
<label title="Consume and display new events as they are produced.">
<input type=radio bind:group={querySettings.mode} name="mode" value={queryMode.REAL_TIME}>
Real Time
</label> </label>
</div>
<br/>
<label title="Query all messages that currently exist, then stop."> <div class="settings-option">
<input type=radio bind:group={querySettings.mode} name="mode" value={queryMode.ONE_SHOT}> <QueryInput
One Shot bind:jsFilter={querySettings.jsFilter}
</label> bind:mutableObjects={querySettings.mutableObjects}
</span> bind:queryCode={querySettings.queryCode} />
</div> {#if querySettings.jsFilter}
<button class="query-input-button" on:click={() => showQueryModal = true}>Open Editor Window</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>
<div class="query-button"> <div class="query-button">
{#if queryRunning} {#if queryRunning && $state.queryState !== queryState.DONE}
<button class="danger" on:click={() => queryRunning = stopQuery(querySettings)}>Stop Query</button> <div transition:slide|local class="stop-button">
{:else} <button class="danger" on:click={() => queryRunning = stopQuery(querySettings)}>
<button class="colored" on:click={() => queryRunning = startQuery(querySettings)}>Start Query</button> {queryRunning === queryMode.REAL_TIME ? 'End Real Time' : 'Cancel One-Shot'} Query
{/if} </button>
</div>
{:else}
<div transition:slide|local class="start-buttons colored">
<button class="colored" on:click={() => queryRunning = startQuery({...querySettings, mode: queryMode.ONE_SHOT})}>
Start One-Shot
</button>
<div class="separator"></div>
<button class="colored" on:click={() => queryRunning = startQuery({...querySettings, mode: queryMode.REAL_TIME})}>
Start Real-Time
</button>
</div>
{/if}
</div>
</div> </div>
--> {/if}
<div class="query-button">
{#if queryRunning && $state.queryState !== queryState.DONE}
<div transition:slide|local class="stop-button">
<button class="danger" on:click={() => queryRunning = stopQuery(querySettings)}>
{queryRunning === queryMode.REAL_TIME ? 'End Real Time' : 'Cancel One-Shot'} Query
</button>
</div>
{:else}
<div transition:slide|local class="start-buttons colored">
<button class="colored" on:click={() => queryRunning = startQuery({...querySettings, mode: queryMode.ONE_SHOT})}>
Start One-Shot
</button>
<div class="separator"></div>
<button class="colored" on:click={() => queryRunning = startQuery({...querySettings, mode: queryMode.REAL_TIME})}>
Start Real-Time
</button>
</div>
{/if}
</div>
</div>
<div class="data-view-container"> <div class="data-view-container">
<div class="data-view-bar"> <div class="data-view-bar">
<div class="border-between"> <div class="border-between">
<button class={showQuerySettings ? "query-settings-hider" : "query-settings-shower"}
on:click={() => showQuerySettings = !showQuerySettings}></button>
<button class={jsonDisplay.expandAll ? 'selected' : ''} <button class={jsonDisplay.expandAll ? 'selected' : ''}
on:click={() => jsonDisplay.expandAll = !jsonDisplay.expandAll}> on:click={() => jsonDisplay.expandAll = !jsonDisplay.expandAll}>
Expand All Objects Expand All Objects
@ -252,6 +232,7 @@
.data-view-container { .data-view-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-grow: 1;
} }
.data-view-bar { .data-view-bar {
background-color: #d7dbf3; background-color: #d7dbf3;
@ -299,14 +280,6 @@
margin-right: 1em; margin-right: 1em;
} }
section {
display: flex;
flex-direction: row;
flex: 1;
justify-content: space-between;
overflow: hidden;
}
h1 { h1 {
width: 100%; width: 100%;
} }
@ -321,16 +294,6 @@
background-color: #575757; background-color: #575757;
} }
.query-settings {
margin-right: 1rem;
flex-grow: 1;
display: flex;
flex-direction: column;
overflow: auto;
padding: 1em;
height: 84.5vh;
}
.query-type { .query-type {
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -159,6 +159,9 @@
</section> </section>
<style> <style>
.data-view {
min-height: 40%;
}
.cluster-listing { .cluster-listing {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -183,13 +186,6 @@
} }
section {
display: flex;
flex-direction: row;
flex: 1;
justify-content: space-between;
}
h1 { h1 {
width: 100%; width: 100%;
} }
@ -210,14 +206,6 @@
min-width: 20vw; min-width: 20vw;
} }
.query-settings {
margin-right: 1rem;
padding: 1em;
overflow: auto;
display: flex;
flex-direction: column;
}
.settings-sub-option { .settings-sub-option {
margin-top: 0.2em; margin-top: 0.2em;
display: flex; display: flex;

View File

@ -29,18 +29,28 @@ const jsonRequest = type => async (path, object) => fetch(backendUrl + path, {
export const postJson = (path, object) => jsonRequest('POST')(path, object) export const postJson = (path, object) => jsonRequest('POST')(path, object)
export const putJson = (path, object) => jsonRequest('PUT')(path, object) export const putJson = (path, object) => jsonRequest('PUT')(path, object)
const mockCluster = {
clientId: 'TestClient',
brokers: ['testbroker.com:5000'],
ssl: true,
sasl: {
mechanism: 'SCRAM-SHA-512',
username: 'testuser',
password: 'XXXXXXXXXXXXXXXXXXXXXX'
}
}
const mockApi = { const mockApi = {
'/clusters': { '/clusters': {
'TestCluster': { 'TestCluster1': mockCluster,
clientId: 'TestClient', 'TestCluster2': mockCluster,
brokers: ['testbroker.com:5000'], 'TestCluster3': mockCluster,
ssl: true, 'TestCluster4': mockCluster,
sasl: { 'TestCluster5': mockCluster,
mechanism: 'SCRAM-SHA-512', 'TestCluster6': mockCluster,
username: 'testuser', 'TestCluster7': mockCluster,
password: 'XXXXXXXXXXXXXXXXXXXXXX' 'TestCluster8': mockCluster,
} 'TestCluster9': mockCluster,
} 'TestCluster10': mockCluster,
}, },
'/topics/TestCluster': ['NewReleases'] '/topics/TestCluster': ['NewReleases']
} }