Skip to content

Commit 8e0a9b1

Browse files
authored
Add back play button to visual panels (#195)
* Add back play button to visual panels * More tests for http and macros * complex macro and install httpmirror on every platform * Fix for fmt * Fixes for athena * Add go bin to path * Copy httpmirror on mac too
1 parent aba843b commit 8e0a9b1

File tree

13 files changed

+163
-73
lines changed

13 files changed

+163
-73
lines changed

desktop/panel/http.test.js

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,30 +32,36 @@ const baseline = JSON.parse(
3232

3333
const USERDATA_FILES = ['json', 'xlsx', 'csv', 'parquet', 'jsonl', 'cjson'];
3434
const PORT = '9799';
35+
const PORT2 = '9798';
3536

36-
let server;
37+
let server, server2;
3738
// Kill the existing server if it wasn't killed correctly already.
3839
beforeAll(async () => {
3940
// TODO: port this logic to other platforms...
40-
if (process.platform === 'linux') {
41-
try {
42-
cp.execSync(
43-
`bash -c "ps aux | grep 'http.server ${PORT}' | grep -v grep | awk '{print \\$2}' | xargs -I {} kill {}"`
44-
);
45-
} catch (e) {
46-
console.error(e);
41+
for (const port of [PORT, PORT2]) {
42+
if (process.platform === 'linux') {
43+
try {
44+
cp.execSync(
45+
`bash -c "ps aux | grep 'http.server ${port}' | grep -v grep | awk '{print \\$2}' | xargs -I {} kill {}"`
46+
);
47+
} catch (e) {
48+
console.error(e);
49+
}
4750
}
4851
}
4952

5053
// Start a new server for all tests
5154
server = spawn('python3', ['-m', 'http.server', PORT]);
55+
server2 = spawn('httpmirror', [PORT2]);
5256

53-
server.stdout.on('data', (data) => {
54-
console.log(data.toString());
55-
});
57+
[server, server2].forEach((server) => {
58+
server.stdout.on('data', (data) => {
59+
console.log(data.toString());
60+
});
5661

57-
server.stderr.on('data', (data) => {
58-
console.warn(data.toString());
62+
server.stderr.on('data', (data) => {
63+
console.warn(data.toString());
64+
});
5965
});
6066

6167
// Keep trying to connect to the server until it's ready
@@ -240,7 +246,7 @@ for (const subprocessName of RUNNERS) {
240246
});
241247

242248
describe('http with macro', () => {
243-
test('correct result', () => {
249+
test('macro as url', () => {
244250
const lp = new LiteralPanelInfo({
245251
contentTypeInfo: { type: 'text/plain' },
246252
content: '/testdata/allformats/unknown',
@@ -269,6 +275,40 @@ for (const subprocessName of RUNNERS) {
269275
{ evalPanels: true, subprocessName }
270276
);
271277
});
278+
279+
test('macro as body', () => {
280+
const lp = new LiteralPanelInfo({
281+
contentTypeInfo: { type: 'application/json' },
282+
content: '[{"name": "jim", "age": 12}]',
283+
name: 'Raw Data',
284+
});
285+
286+
const hp = new HTTPPanelInfo(
287+
'',
288+
new HTTPConnectorInfo('', 'http://localhost:9798')
289+
);
290+
hp.http.http.method = 'POST';
291+
hp.content = '{{ DM_getPanel("0") | json }}';
292+
hp.http.http.contentTypeInfo.type = 'text/plain';
293+
294+
const panels = [lp, hp];
295+
296+
return withSavedPanels(
297+
panels,
298+
(project) => {
299+
// Grab result
300+
const value = JSON.parse(
301+
fs
302+
.readFileSync(getProjectResultsFile(project.projectName) + hp.id)
303+
.toString()
304+
);
305+
expect([{ name: 'jim', age: 12 }]).toStrictEqual(
306+
JSON.parse(value.split('\r\n\r\n')[1])
307+
);
308+
},
309+
{ evalPanels: true, subprocessName }
310+
);
311+
});
272312
});
273313

274314
if (process.platform === 'linux') {
@@ -313,4 +353,5 @@ for (const subprocessName of RUNNERS) {
313353

314354
afterAll(() => {
315355
process.kill(server.pid);
356+
process.kill(server2.pid);
316357
});

runner/database_athena.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/multiprocessio/go-json"
99

1010
"github.com/aws/aws-sdk-go/aws"
11+
"github.com/aws/aws-sdk-go/aws/credentials"
1112
"github.com/aws/aws-sdk-go/aws/session"
1213
"github.com/aws/aws-sdk-go/service/athena"
1314
)
@@ -35,7 +36,14 @@ func mapAthenaType(value, t string) interface{} {
3536
}
3637

3738
func evalAthena(panel *PanelInfo, dbInfo DatabaseConnectorInfoDatabase, w io.Writer) error {
39+
secret, err := dbInfo.Password.decrypt()
40+
if err != nil {
41+
return err
42+
}
43+
3844
cfg := aws.NewConfig().WithRegion(dbInfo.Extra["aws_region"])
45+
cfg.Credentials = credentials.NewStaticCredentials(dbInfo.Username, secret, "")
46+
3947
sess := session.Must(session.NewSession(cfg))
4048

4149
svc := athena.New(sess, cfg)

runner/file.go

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,6 @@ func transformGeneric(in io.Reader, out io.Writer) error {
317317
return err
318318
}
319319

320-
var prev byte = ' '
321-
322320
for {
323321
b, err := r.ReadByte()
324322
if err == io.EOF {
@@ -329,19 +327,29 @@ func transformGeneric(in io.Reader, out io.Writer) error {
329327
return err
330328
}
331329

332-
if b == '"' && prev != '\\' {
333-
err = o.WriteByte('\\')
334-
if err != nil {
335-
return err
336-
}
330+
// Escape necessary characters
331+
switch b {
332+
case '\b':
333+
_, err = o.WriteString(`\b`)
334+
case '\f':
335+
_, err = o.WriteString(`\f`)
336+
case '\n':
337+
_, err = o.WriteString(`\n`)
338+
case '\r':
339+
_, err = o.WriteString(`\r`)
340+
case '\t':
341+
_, err = o.WriteString(`\t`)
342+
case '"':
343+
_, err = o.WriteString(`\"`)
344+
case '\\':
345+
_, err = o.WriteString(`\\`)
346+
default:
347+
err = o.WriteByte(b)
337348
}
338349

339-
err = o.WriteByte(b)
340350
if err != nil {
341351
return err
342352
}
343-
344-
prev = b
345353
}
346354

347355
err = o.WriteByte('"')

runner/file_test.go

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -192,26 +192,19 @@ func Test_transformORCFile(t *testing.T) {
192192
}
193193

194194
func Test_transformGeneric(t *testing.T) {
195-
tests := []struct {
196-
in string
197-
out interface{}
198-
}{
199-
{
200-
in: `abcdef`,
201-
out: `abcdef`,
202-
},
203-
{
204-
in: `ab""cdef`,
205-
out: `ab""cdef`,
206-
},
195+
tests := []string{
196+
`abcdef`,
197+
`ab""cdef`,
198+
`ab
199+
cdef`,
207200
}
208201

209202
for _, test := range tests {
210203
inTmp, err := ioutil.TempFile("", "")
211204
defer os.Remove(inTmp.Name())
212205
assert.Nil(t, err)
213206

214-
inTmp.WriteString(test.in)
207+
inTmp.WriteString(test)
215208

216209
outTmp, err := ioutil.TempFile("", "")
217210
defer os.Remove(outTmp.Name())
@@ -226,7 +219,7 @@ func Test_transformGeneric(t *testing.T) {
226219
err = json.Unmarshal(outTmpBs, &m)
227220
assert.Nil(t, err)
228221

229-
assert.Equal(t, test.out, m)
222+
assert.Equal(t, test, m)
230223
}
231224
}
232225

runner/http.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ func (ec EvalContext) evalHTTPPanel(project *ProjectState, pageIndex int, panel
201201
sendBody: panel.Content != "" &&
202202
(h.Method == http.MethodPut || h.Method == http.MethodPatch || h.Method == http.MethodPost),
203203
customCaCerts: customCaCerts,
204+
method: h.Method,
204205
})
205206
if err != nil {
206207
return err

scripts/ci/prepare_linux_integration_test_setup_only.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ set -ex
99
# Set up Julia, SSH, etc.
1010
sudo apt-get install -y jq julia openssh-server php
1111

12+
# Set up http helper
13+
go install github.com/multiprocessio/httpmirror@latest
14+
1215
# Set up coverage tools
1316
go install github.com/axw/gocov/[email protected]
1417
go install github.com/wadey/gocovmerge@b5bfa59

scripts/ci/prepare_macos.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@ brew uninstall [email protected]
77
brew install cmake jq go r julia node@16 npm
88
brew link --overwrite node@16
99
go install github.com/google/go-jsonnet/cmd/jsonnet@latest
10+
go install github.com/multiprocessio/httpmirror@latest
11+
cp ~/go/bin/httpmirror /usr/local/bin/httpmirror
1012
npm install --global yarn
1113
yarn

scripts/ci/prepare_windows.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH
44
scoop install nodejs@16 cmake python yarn zip jq curl go r julia
55
yarn
66
go install github.com/google/go-jsonnet/cmd/jsonnet@latest
7+
go install github.com/multiprocessio/httpmirror@latest
8+
Join-Path (Resolve-Path ~).Path "go\bin" >> $Env:GITHUB_PATH
79

810
New-Alias zip 7z

ui/Panel.tsx

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,11 @@ export function Panel({
314314
className={`panel ${fullScreen === panel.id ? 'panel--fullscreen' : ''} ${
315315
hidden ? 'panel--hidden' : ''
316316
} ${
317-
panelUIDetails.body === null && !results.exception ? 'panel--empty' : ''
317+
(panelUIDetails.body === null ||
318+
(panelUIDetails.hideBody && panelUIDetails.hideBody(panel))) &&
319+
!results.exception
320+
? 'panel--empty'
321+
: ''
318322
} ${results.loading ? 'panel--loading' : ''}`}
319323
tabIndex={1001}
320324
ref={panelRef}
@@ -431,27 +435,25 @@ export function Panel({
431435
'Run to apply changes'
432436
)}
433437
</span>
434-
{!VISUAL_PANELS.includes(panel.type) ? (
435-
<span
436-
title={
437-
results.loading
438-
? killable
439-
? 'Cancel'
440-
: 'Running'
441-
: 'Evaluate Panel (Ctrl-Enter)'
438+
<span
439+
title={
440+
results.loading
441+
? killable
442+
? 'Cancel'
443+
: 'Running'
444+
: 'Evaluate Panel (Ctrl-Enter)'
445+
}
446+
>
447+
<Button
448+
icon
449+
onClick={() =>
450+
killable ? killProcess() : reevalPanel(panel.id)
442451
}
452+
type="primary"
443453
>
444-
<Button
445-
icon
446-
onClick={() =>
447-
killable ? killProcess() : reevalPanel(panel.id)
448-
}
449-
type="primary"
450-
>
451-
{results.loading ? <IconPlayerPause /> : <IconPlayerPlay />}
452-
</Button>
453-
</span>
454-
) : null}
454+
{results.loading ? <IconPlayerPause /> : <IconPlayerPlay />}
455+
</Button>
456+
</span>
455457
<span title="Full screen mode">
456458
<Button
457459
icon
@@ -519,14 +521,17 @@ export function Panel({
519521
<ErrorBoundary className="panel-body">
520522
<div className="flex">
521523
<div className="panel-body">
522-
{panelUIDetails.body && (
523-
<panelUIDetails.body
524-
panel={panel}
525-
keyboardShortcuts={keyboardShortcuts}
526-
panels={panels}
527-
updatePanel={updatePanel}
528-
/>
529-
)}
524+
{panelUIDetails.body &&
525+
(panelUIDetails.hideBody
526+
? !panelUIDetails.hideBody(panel)
527+
: true) && (
528+
<panelUIDetails.body
529+
panel={panel}
530+
keyboardShortcuts={keyboardShortcuts}
531+
panels={panels}
532+
updatePanel={updatePanel}
533+
/>
534+
)}
530535
{results.exception instanceof PanelPlayWarning ? (
531536
<PanelPlayWarningWithLinks
532537
panels={panels}

ui/components/ContentTypePicker.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,19 @@ export function ContentTypePicker({
99
onChange,
1010
disableAutoDetect,
1111
inMemoryEval,
12+
label,
1213
}: {
1314
value: ContentTypeInfo;
1415
onChange: (v: ContentTypeInfo) => void;
1516
disableAutoDetect?: boolean;
1617
inMemoryEval: boolean;
18+
label?: string;
1719
}) {
1820
return (
1921
<React.Fragment>
2022
<div className="form-row">
2123
<Select
22-
label="Content Type"
24+
label={label || 'Content Type'}
2325
value={value.type}
2426
onChange={(type: string) => {
2527
if (type === 'null') {

0 commit comments

Comments
 (0)