Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | 36x 36x 36x 36x 36x 36x 15x 15x 15x 66x 12x 12x 54x 36x 3x 3x 3x 36x 66x 66x 45x 66x 36x 3x 3x 3x 66x 66x 36x | /*
* Copyright 2021 Harness Inc. All rights reserved.
* Use of this source code is governed by the PolyForm Shield 1.0.0 license
* that can be found in the licenses directory at the root of this repository, also available at
* https://polyformproject.org/wp-content/uploads/2020/06/PolyForm-Shield-1.0.0.txt.
*/
import React from 'react'
import classnames from 'classnames'
import { Container } from '@wings-software/uicore'
import isUndefined from 'lodash/isUndefined'
import css from './JsonSelector.module.scss'
export interface JsonSelectorProps {
json: Record<string, any>
className?: string
onPathSelect?: (path: string) => void
}
const MAX_NESTING_LEVEL = 100
function visit(json: Record<string, any>, rows: Array<any>, path: Array<string> = []) {
Iif (path.length === MAX_NESTING_LEVEL) {
// This is the simple guard since the algorithm currently doesn't check
// for backward references - it expects "config" json.
throw new Error('max nesting level was reached.')
}
Eif (json) {
for (const entry of Object.entries(json)) {
if (typeof entry[1] === 'object' && entry[1] !== null) {
rows.push({
key: entry[0],
path
})
visit(entry[1], rows, [...path, entry[0]])
// TODO - When exactly we need to have empty rows?
// rows.push(null);
} else {
rows.push({
key: entry[0],
value: entry[1],
path
})
}
}
}
}
const calculateRows = (json: any) => {
const rows: Array<any> = []
// TODO - memoize ??
visit(json, rows)
return rows
}
const ident = (nestingLevel: number): string => {
let ret = ''
while (nestingLevel-- > 0) {
ret += '\u00A0\u00A0\u00A0\u00A0'
}
return ret
}
const JsonSelector: React.FC<JsonSelectorProps> = ({ json, className, onPathSelect }) => {
const rows: Array<any> = calculateRows(json)
const onSelect = (row: any) => {
if (onPathSelect) {
const path = [...row.path, row.key]
onPathSelect(path.join('.'))
}
}
return (
<Container className={classnames(css.jsonSelector, className)}>
<div className={css.lineNumbersCol}>
{rows.map((_, index) => (
<div key={index} className={css.lineNumber}>
{index + 1}
</div>
))}
</div>
<div className={css.panel}>
<div className={css.contentWrap}>
{rows.map((row, index) => (
<div key={index} className={css.editorRow}>
{!!row && (
<React.Fragment>
<span>{ident(row.path.length)}</span>
{isUndefined(row.value) && <span>{row.key}</span>}
{!isUndefined(row.value) && (
<span>
<span onClick={() => onSelect(row)} className={css.selectableKey}>
{row.key}
</span>
: {row.value}
</span>
)}
</React.Fragment>
)}
</div>
))}
</div>
</div>
</Container>
)
}
export default JsonSelector
|