Skip to content

Commit

Permalink
feat: implement a configuration dropdown to select a query language
Browse files Browse the repository at this point in the history
  • Loading branch information
josdejong committed Nov 17, 2021
1 parent 54c6586 commit 871ac5c
Show file tree
Hide file tree
Showing 7 changed files with 250 additions and 77 deletions.
15 changes: 11 additions & 4 deletions src/lib/components/JSONEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import AbsolutePopup from './modals/popup/AbsolutePopup.svelte'
import CodeMode from './modes/codemode/CodeMode.svelte'
import TreeMode from './modes/treemode/TreeMode.svelte'
import { lodashQueryLanguage } from '$lib/plugins/query/lodashQueryLanguage'
// TODO: document how to enable debugging in the readme: localStorage.debug="jsoneditor:*", then reload
const debug = createDebug('jsoneditor:Main')
Expand Down Expand Up @@ -39,7 +38,9 @@
export let queryLanguageId
/** @type {(queryLanguageId: string) => void} */
export let onChangeQueryLanguage
export let onChangeQueryLanguage = () => {
// no op by default
}
/** @type {((content: Content, previousContent: Content, patchResult: JSONPatchResult | null) => void) | null} */
export let onChange = null
Expand Down Expand Up @@ -276,6 +277,12 @@
return onRenderMenu(mode, updatedItems) || updatedItems
}
function handleChangeQueryLanguage(newQueryLanguageId) {
debug('handleChangeQueryLanguage', newQueryLanguageId)
queryLanguageId = newQueryLanguageId
onChangeQueryLanguage(newQueryLanguageId)
}
</script>

<Modal>
Expand All @@ -293,7 +300,7 @@
{validator}
{queryLanguages}
{queryLanguageId}
{onChangeQueryLanguage}
onChangeQueryLanguage={handleChangeQueryLanguage}
onChange={handleChangeText}
onSwitchToTreeMode={handleSwitchToTreeMode}
{onError}
Expand All @@ -313,7 +320,7 @@
{validator}
{queryLanguages}
{queryLanguageId}
{onChangeQueryLanguage}
onChangeQueryLanguage={handleChangeQueryLanguage}
{onError}
onChange={handleChange}
onRequestRepair={handleRequestRepair}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
@import '../../../styles';

.jse-select-query-language {
position: relative;
width: 32px;

.jse-select-query-language-container {
position: absolute;
top: 0;
right: 0;
display: flex;
flex-direction: column;
box-shadow: $box-shadow;

.jse-query-language {
@include jsoneditor-button;

text-align: left;
padding: $padding 2 * $padding;
white-space: nowrap;
color: white;
background: $dark-gray;

$gray-highlight: lighten($dark-gray, 5%);

&:hover {
background: $gray-highlight;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<script>
import Icon from 'svelte-awesome'
import { faCheckSquare, faSquare } from '@fortawesome/free-regular-svg-icons'
/** @type {QueryLanguage[]} */
export let queryLanguages
/** @type {string} */
export let queryLanguageId
/** @type {(queryLanguageId: string) => void} */
export let onChangeQueryLanguage
function handleChangeQueryLanguage(newQueryLanguageId) {
queryLanguageId = newQueryLanguageId
onChangeQueryLanguage(newQueryLanguageId)
}
</script>

<div class="jse-select-query-language">
<div class="jse-select-query-language-container">
{#each queryLanguages as queryLanguage}
<button
on:click={() => handleChangeQueryLanguage(queryLanguage.id)}
class="jse-query-language"
class:selected={queryLanguage.id === queryLanguageId}
title={`Select ${queryLanguage.name} as query language`}
>
{#if queryLanguage.id === queryLanguageId}
<Icon data={faCheckSquare} />
{:else}
<Icon data={faSquare} />
{/if}
{queryLanguage.name}
</button>
{/each}
</div>
</div>

<style src="./SelectQueryLanguage.scss"></style>
1 change: 1 addition & 0 deletions src/lib/components/modals/Header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
vertical-align: middle;
}

button.config,
button.close {
border: none;
background: transparent;
Expand Down
144 changes: 81 additions & 63 deletions src/lib/components/modals/TransformModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
import { compileJSONPointer, getIn } from 'immutable-json-patch'
import { stringifyPath } from '../../utils/pathUtils.js'
import { truncate } from '../../utils/stringUtils.js'
import Header from './Header.svelte'
import { transformModalState } from './transformModalState.js'
import TransformWizard from './TransformWizard.svelte'
import TransformModalHeader from '$lib/components/modals/TransformModalHeader.svelte'
import AbsolutePopup from '$lib/components/modals/popup/AbsolutePopup.svelte'
import createDebug from 'debug'
const debug = createDebug('jsoneditor:TransformModal')
export let id = 'transform-modal-' + uniqueId()
export let json
Expand All @@ -25,25 +29,25 @@
export let queryLanguageId
/** @type {(queryLanguageId: string) => void} */
export let onChangeQueryLanguage // TODO: implement a dropdown to change the selected query language
export let onChangeQueryLanguage
export let onTransform
export let indentation = 2
$: selectedJson = getIn(json, selectedPath)
function getSelectedQueryLanguage() {
// TODO: log a console warning when the queryLanguage is not found
return queryLanguages.find((item) => item.id === queryLanguageId) || queryLanguages[0]
}
$: selectedQueryLanguage =
queryLanguages.find((item) => item.id === queryLanguageId) || queryLanguages[0]
const { close } = getContext('simple-modal')
const stateId = `${id}:${compileJSONPointer(selectedPath)}`
const state = transformModalState[stateId] || {}
let query = state.query || getSelectedQueryLanguage().createQuery(json, {})
let query
$: query = state.query || selectedQueryLanguage.createQuery(json, {}) // FIXME: should apply wizard
let previewHasError = false
let preview = ''
Expand All @@ -64,7 +68,8 @@
function previewTransform(json, query) {
try {
const jsonTransformed = getSelectedQueryLanguage().executeQuery(json, query)
debug('previewTransform', { query, selectedQueryLanguage })
const jsonTransformed = selectedQueryLanguage.executeQuery(json, query)
preview = truncate(JSON.stringify(jsonTransformed, null, indentation), MAX_PREVIEW_CHARACTERS)
previewHasError = false
Expand All @@ -82,7 +87,8 @@
function handleTransform() {
try {
const jsonTransformed = getSelectedQueryLanguage().executeQuery(selectedJson, query)
debug('handleTransform', { query })
const jsonTransformed = selectedQueryLanguage.executeQuery(selectedJson, query)
onTransform([
{
Expand Down Expand Up @@ -124,66 +130,78 @@
function focus(element) {
element.focus()
}
function handleChangeQueryLanguage(newQueryLanguageId) {
debug('handleChangeQueryLanguage', newQueryLanguageId)
queryLanguageId = newQueryLanguageId
onChangeQueryLanguage(newQueryLanguageId)
}
</script>

<div class="jsoneditor-modal transform">
<Header title="Transform" />
<div class="contents">
<div class="description">
{@html getSelectedQueryLanguage().description}
</div>

<div class="label">Path</div>
<input
class="path"
type="text"
readonly
title="Selected path"
value={!isEmpty(selectedPath) ? stringifyPath(selectedPath) : '(whole document)'}
<AbsolutePopup>
<TransformModalHeader
{queryLanguages}
{queryLanguageId}
onChangeQueryLanguage={handleChangeQueryLanguage}
/>

<div class="label">
<button type="button" on:click={toggleShowWizard}>
<Icon data={showWizard ? faCaretDown : faCaretRight} />
Wizard
</button>
</div>
{#if showWizard}
{#if Array.isArray(selectedJson)}
<TransformWizard
bind:filterPath
bind:filterRelation
bind:filterValue
bind:sortPath
bind:sortDirection
bind:projectionPaths
json={selectedJson}
onQuery={updateQuery}
createQuery={getSelectedQueryLanguage().createQuery}
/>
{:else}
(Only available for arrays, not for objects)
<div class="contents">
<div class="description">
{@html selectedQueryLanguage.description}
</div>

<div class="label">Path</div>
<input
class="path"
type="text"
readonly
title="Selected path"
value={!isEmpty(selectedPath) ? stringifyPath(selectedPath) : '(whole document)'}
/>

<div class="label">
<button type="button" on:click={toggleShowWizard}>
<Icon data={showWizard ? faCaretDown : faCaretRight} />
Wizard
</button>
</div>
{#if showWizard}
{#if Array.isArray(selectedJson)}
<TransformWizard
bind:filterPath
bind:filterRelation
bind:filterValue
bind:sortPath
bind:sortDirection
bind:projectionPaths
json={selectedJson}
onQuery={updateQuery}
createQuery={selectedQueryLanguage.createQuery}
/>
{:else}
(Only available for arrays, not for objects)
{/if}
{/if}
{/if}

<div class="label">Query</div>
<textarea class="query" spellcheck="false" bind:value={query} />

<div class="label">Preview</div>
<textarea class="preview" class:error={previewHasError} bind:value={preview} readonly />

<div class="actions">
<button
type="button"
class="primary"
on:click={handleTransform}
use:focus
disabled={previewHasError}
>
Transform
</button>

<div class="label">Query</div>
<textarea class="query" spellcheck="false" bind:value={query} />

<div class="label">Preview</div>
<textarea class="preview" class:error={previewHasError} bind:value={preview} readonly />

<div class="actions">
<button
type="button"
class="primary"
on:click={handleTransform}
use:focus
disabled={previewHasError}
>
Transform
</button>
</div>
</div>
</div>
</AbsolutePopup>
</div>

<style src="./TransformModal.scss"></style>
61 changes: 61 additions & 0 deletions src/lib/components/modals/TransformModalHeader.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<svelte:options immutable={true} />

<script>
import { getContext } from 'svelte'
import Icon from 'svelte-awesome'
import { faCog, faTimes } from '@fortawesome/free-solid-svg-icons'
import SelectQueryLanguage from '$lib/components/controls/selectQueryLanguage/SelectQueryLanguage.svelte'
/** @type {QueryLanguage[]} */
export let queryLanguages
/** @type {string} */
export let queryLanguageId
/** @type {(queryLanguageId: string) => void} */
export let onChangeQueryLanguage
let refConfigButton
const { close } = getContext('simple-modal')
const { openAbsolutePopup, closeAbsolutePopup } = getContext('absolute-popup')
function openConfig() {
const props = {
queryLanguages,
queryLanguageId,
onChangeQueryLanguage: (selectedQueryLanguage) => {
closeAbsolutePopup()
onChangeQueryLanguage(selectedQueryLanguage)
}
}
openAbsolutePopup(SelectQueryLanguage, props, {
position: 'bottom',
offsetTop: -2,
offsetLeft: 0,
anchor: refConfigButton,
closeOnOuterClick: true
})
}
</script>

<div class="header">
<div class="title">Transform</div>
{#if queryLanguages.length > 1}
<button
bind:this={refConfigButton}
type="button"
class="config"
on:click={openConfig}
title="Select a query language"
>
<Icon data={faCog} />
</button>
{/if}
<button type="button" class="close" on:click={close}>
<Icon data={faTimes} />
</button>
</div>

<style src="./Header.scss"></style>
Loading

0 comments on commit 871ac5c

Please sign in to comment.