Skip to content

Commit

Permalink
Tabulator, Admin: UI for modifying tabulator configs (#4135)
Browse files Browse the repository at this point in the history
Co-authored-by: Alexei Mochalov <[email protected]>
  • Loading branch information
fiskus and nl0 authored Oct 4, 2024
1 parent 3c304c6 commit 823aaa6
Show file tree
Hide file tree
Showing 30 changed files with 2,355 additions and 642 deletions.
1 change: 1 addition & 0 deletions catalog/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ where verb is one of

## Changes

- [Added] Admin: UI for configuring longitudinal queries (Tabulator) ([#4135](https://github.com/quiltdata/quilt/pull/4135))
- [Changed] Admin: Move bucket settings to a separate page ([#4122](https://github.com/quiltdata/quilt/pull/4122))
- [Changed] Athena: always show catalog name, simplify setting execution context ([#4123](https://github.com/quiltdata/quilt/pull/4123))
- [Added] Support `ui.actions.downloadObject` and `ui.actions.downloadPackage` options for configuring visibility of download buttons under "Bucket" and "Packages" respectively ([#4111](https://github.com/quiltdata/quilt/pull/4111))
Expand Down
17 changes: 15 additions & 2 deletions catalog/app/components/FileEditor/FileEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ import { EditorInputType } from './types'
export { detect, isSupportedFileType } from './loader'

interface EditorProps extends EditorState {
className: string
editing: EditorInputType
empty?: boolean
handle: Model.S3.S3ObjectLocation
}

function EditorSuspended({
className,
saving,
empty,
error,
Expand All @@ -37,14 +39,22 @@ function EditorSuspended({
if (empty)
return editing.brace === '__quiltConfig' ? (
<QuiltConfigEditor
className={className}
handle={handle}
disabled={disabled}
error={error}
onChange={onChange}
initialValue=""
/>
) : (
<TextEditor error={error} type={editing} value="" onChange={onChange} />
<TextEditor
autoFocus
className={className}
error={error}
initialValue=""
onChange={onChange}
type={editing}
/>
)
return data.case({
_: () => <Skeleton />,
Expand All @@ -61,6 +71,7 @@ function EditorSuspended({
if (editing.brace === '__quiltConfig') {
return (
<QuiltConfigEditor
className={className}
handle={handle}
disabled={disabled}
error={error}
Expand All @@ -71,11 +82,13 @@ function EditorSuspended({
}
return (
<TextEditor
autoFocus
className={className}
disabled={disabled}
error={error}
onChange={onChange}
type={editing}
value={value}
initialValue={value}
/>
)
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ErrorObject } from 'ajv'
import cx from 'classnames'
import * as React from 'react'
import * as M from '@material-ui/core'

Expand All @@ -22,6 +23,7 @@ const useStyles = M.makeStyles((t) => ({
}))

export interface QuiltConfigEditorProps {
className?: string
disabled?: boolean
error: Error | null
initialValue?: string
Expand All @@ -34,6 +36,7 @@ interface QuiltConfigEditorEssentialProps {
}

export default function QuiltConfigEditorSuspended({
className,
disabled,
error,
header,
Expand All @@ -56,7 +59,7 @@ export default function QuiltConfigEditorSuspended({
[onChange, validate],
)
return (
<div className={classes.root}>
<div className={cx(classes.root, className)}>
{!!header && <div className={classes.header}>{header}</div>}
<JsonEditor
disabled={disabled}
Expand Down
11 changes: 8 additions & 3 deletions catalog/app/components/FileEditor/Skeleton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Skel from 'components/Skeleton'
const useSkeletonStyles = M.makeStyles((t) => ({
root: {
display: 'flex',
height: t.spacing(30),
height: ({ height }: { height: number }) => t.spacing(height),
width: '100%',
},
lineNumbers: {
Expand All @@ -16,6 +16,7 @@ const useSkeletonStyles = M.makeStyles((t) => ({
content: {
flexGrow: 1,
marginLeft: t.spacing(2),
overflow: 'hidden',
},
line: {
height: t.spacing(2),
Expand All @@ -25,8 +26,12 @@ const useSkeletonStyles = M.makeStyles((t) => ({

const fakeLines = [80, 50, 100, 60, 30, 80, 50, 100, 60, 30, 20, 70]

export default function Skeleton() {
const classes = useSkeletonStyles()
interface SkeletonProps {
height?: number
}

export default function Skeleton({ height = 30 }: SkeletonProps) {
const classes = useSkeletonStyles({ height })
return (
<div className={classes.root}>
<Skel className={classes.lineNumbers} height="100%" />
Expand Down
61 changes: 45 additions & 16 deletions catalog/app/components/FileEditor/TextEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as brace from 'brace'
import cx from 'classnames'
import * as React from 'react'
import * as M from '@material-ui/core'
import * as Lab from '@material-ui/lab'

import Lock from 'components/Lock'

Expand All @@ -11,33 +11,50 @@ import 'brace/theme/eclipse'

const useEditorTextStyles = M.makeStyles((t) => ({
root: {
border: `1px solid ${t.palette.divider}`,
width: '100%',
display: 'flex',
flexDirection: 'column',
position: 'relative',
width: '100%',
},
editor: {
height: t.spacing(50),
border: `1px solid ${t.palette.divider}`,
flexGrow: 1,
resize: 'vertical',
},
error: {
marginTop: t.spacing(1),
'& $editor': {
borderColor: t.palette.error.main,
},
'& $helperText': {
color: t.palette.error.main,
},
},
helperText: {
marginTop: t.spacing(0.5),
whiteSpace: 'pre-wrap', // TODO: use JsonValidationErrors
},
}))

interface TextEditorProps {
autoFocus?: boolean
className: string
disabled?: boolean
error: Error | null
leadingChange?: boolean
onChange: (value: string) => void
type: EditorInputType
value?: string
error: Error | null
initialValue?: string
}

export default function TextEditor({
error,
className,
autoFocus,
disabled,
type,
value = '',
error,
leadingChange = true,
onChange,
type,
initialValue = '',
}: TextEditorProps) {
const classes = useEditorTextStyles()
const ref = React.useRef<HTMLDivElement | null>(null)
Expand All @@ -53,23 +70,35 @@ export default function TextEditor({

editor.getSession().setMode(`ace/mode/${type.brace}`)
editor.setTheme('ace/theme/eclipse')
editor.setValue(value, -1)
onChange(editor.getValue()) // initially fill the value

editor.$blockScrolling = Infinity
editor.setValue(initialValue, -1)
if (leadingChange) {
// Initially fill the value in the parent component.
// TODO: Re-design fetching data, so leading onChange won't be necessary
// probably, by putting data fetch into FileEditor/State
onChange(editor.getValue())
}
editor.on('change', () => onChange(editor.getValue()))

if (autoFocus) {
editor.focus()
wrapper.scrollIntoView()
}

return () => {
resizeObserver.unobserve(wrapper)
editor.destroy()
}
}, [onChange, ref, type.brace, value])
}, [autoFocus, leadingChange, onChange, ref, type.brace, initialValue])

return (
<div className={classes.root}>
<div className={cx(classes.root, className, { [classes.error]: !!error })}>
<div className={classes.editor} ref={ref} />
{error && (
<Lab.Alert severity="error" className={classes.error} variant="outlined">
<M.Typography className={classes.helperText} variant="body2">
{error.message}
</Lab.Alert>
</M.Typography>
)}
{disabled && <Lock />}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface SingleErrorProps {
error: Err
}

// TODO: use more humble layout similar to TextField#helperText
function SingleError({ className, error }: SingleErrorProps) {
const classes = useSingleErrorStyles()

Expand Down
Loading

0 comments on commit 823aaa6

Please sign in to comment.