Skip to content

Commit 192d701

Browse files
authored
All panels autocomplete (#250)
1 parent 1f3a63a commit 192d701

File tree

4 files changed

+51
-45
lines changed

4 files changed

+51
-45
lines changed

ui/Updates.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ import * as React from 'react';
22
import { SITE_ROOT, VERSION } from '../shared/constants';
33
import { request } from '../shared/http';
44
import log from '../shared/log';
5+
import { newId } from '../shared/object';
56
import { ContentTypeInfo } from '../shared/state';
67
import { SettingsContext } from './Settings';
78

9+
const s = newId();
10+
811
export function Updates() {
912
const { state: settings } = React.useContext(SettingsContext);
1013
const [updates, setUpdates] = React.useState(null);
@@ -15,7 +18,7 @@ export function Updates() {
1518
const updates = await request(
1619
window.fetch,
1720
'GET',
18-
`${SITE_ROOT}/api/updates?version=${VERSION}&i=${settings.id}`,
21+
`${SITE_ROOT}/api/updates?version=${VERSION}&i=${settings.id}&s=${s}`,
1922
new ContentTypeInfo(),
2023
[],
2124
'',

ui/components/CodeEditor.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ export function skipWhitespaceForward(it: Ace.TokenIterator) {
4444
}
4545
}
4646

47+
const AUTOCOMPLETE_MAP: Record<
48+
string,
49+
(
50+
tokenIteratorFactory: () => Ace.TokenIterator,
51+
prefix: string
52+
) => Array<Ace.Completion>
53+
> = {};
54+
4755
export function CodeEditor({
4856
value,
4957
onChange,
@@ -78,6 +86,10 @@ export function CodeEditor({
7886
state: { theme, autocompleteDisabled },
7987
} = React.useContext(SettingsContext);
8088

89+
if (autocomplete) {
90+
AUTOCOMPLETE_MAP[id] = autocomplete;
91+
}
92+
8193
const [editorRef, setEditorRef] = React.useState<AceEditor>(null);
8294
const debounced = useDebouncedCallback(onChange, INPUT_SYNC_PERIOD);
8395
// Flush on unmount
@@ -136,15 +148,10 @@ export function CodeEditor({
136148
prefix: string,
137149
callback: Ace.CompleterCallback
138150
) => {
139-
// This gets registered globally which is kind of weird. //
140-
// So it needs to check again that the currently editing editor
141-
// is the one attached to this callback.
142-
if (!autocomplete || (editorRef.editor as unknown) !== editor) {
143-
return callback(null, []);
144-
}
145-
151+
// This gets set/called in a global context so we need to figure out which panel is actually calling it.
146152
try {
147153
const factory = () => new TokenIterator(session, pos.row, pos.column);
154+
const autocomplete = AUTOCOMPLETE_MAP[(editor as any).container.id];
148155
return callback(null, autocomplete(factory, prefix));
149156
} catch (e) {
150157
log.error(e);

ui/panels/DatabasePanel.tsx

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Ace } from 'ace-builds';
21
import * as React from 'react';
32
import { DOCS_ROOT } from '../../shared/constants';
43
import { NoConnectorError } from '../../shared/errors';
@@ -7,7 +6,6 @@ import {
76
ConnectorInfo,
87
DatabaseConnectorInfo,
98
DatabasePanelInfo,
10-
PanelInfo,
119
TimeSeriesRange as TimeSeriesRangeT,
1210
} from '../../shared/state';
1311
import { panelRPC } from '../asyncRPC';
@@ -20,12 +18,7 @@ import { TimeSeriesRange } from '../components/TimeSeriesRange';
2018
import { Toggle } from '../components/Toggle';
2119
import { VENDORS } from '../connectors';
2220
import { ProjectContext } from '../state';
23-
import {
24-
builtinCompletions,
25-
dotAccessPanelShapeCompletions,
26-
panelNameCompletions,
27-
stringPanelShapeCompletions,
28-
} from './ProgramPanel';
21+
import { BUILTINS, makeAutocomplete } from './ProgramPanel';
2922
import { PanelBodyProps, PanelDetailsProps, PanelUIDetails } from './types';
3023

3124
export async function evalDatabasePanel(
@@ -270,9 +263,20 @@ export function DatabasePanelBody({
270263
panels,
271264
keyboardShortcuts,
272265
}: PanelBodyProps<DatabasePanelInfo>) {
266+
const { connectors } = React.useContext(ProjectContext).state;
267+
const connector = connectors.find(
268+
(c) => c.id === panel.database.connectorId
269+
) as DatabaseConnectorInfo;
270+
271+
const vendor = VENDORS[connector?.database.type]?.id;
272+
273273
return (
274274
<CodeEditor
275-
autocomplete={makeAutocomplete(panels.filter((p) => p.id !== panel.id))}
275+
autocomplete={makeAutocomplete(
276+
panels.filter((p) => p.id !== panel.id),
277+
vendor === 'sqlite' ? BUILTINS.sql : [],
278+
'sql'
279+
)}
276280
id={'editor-' + panel.id}
277281
onKeyDown={keyboardShortcuts}
278282
value={panel.content}
@@ -286,21 +290,6 @@ export function DatabasePanelBody({
286290
);
287291
}
288292

289-
export function makeAutocomplete(panels: Array<PanelInfo>) {
290-
return (tokenIteratorFactory: () => Ace.TokenIterator, prefix: string) => {
291-
return [
292-
...builtinCompletions(tokenIteratorFactory).filter(
293-
(c) => !c.value.startsWith('DM_setPanel')
294-
),
295-
...panelNameCompletions(tokenIteratorFactory, panels),
296-
...dotAccessPanelShapeCompletions(tokenIteratorFactory, panels),
297-
...stringPanelShapeCompletions(tokenIteratorFactory, panels),
298-
]
299-
.flat()
300-
.filter((c) => c && c.value.startsWith(prefix));
301-
};
302-
}
303-
304293
export function DatabaseInfo({ panel }: { panel: DatabasePanelInfo }) {
305294
const { connectors } = React.useContext(ProjectContext).state;
306295
const connector = connectors.find(

ui/panels/ProgramPanel.tsx

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export function ProgramPanelDetails({
110110
);
111111
}
112112

113-
const builtins: Record<
113+
export const BUILTINS: Record<
114114
ProgramPanelInfo['program']['type'],
115115
Array<{ value: string; meta: string; score: number }>
116116
> = {
@@ -636,7 +636,8 @@ const builtins: Record<
636636

637637
export function builtinCompletions(
638638
tokenIteratorFactory: () => Ace.TokenIterator,
639-
builtins: Array<{ value: string; score: number; meta: string }> = []
639+
builtins: Array<{ value: string; meta: string; score: number }>,
640+
language: ProgramPanelInfo['program']['type']
640641
) {
641642
const ti = tokenIteratorFactory();
642643
const token = ti.getCurrentToken();
@@ -649,14 +650,18 @@ export function builtinCompletions(
649650
...builtins,
650651
{
651652
value: 'DM_getPanel("panelName")',
652-
meta: 'DataStation Panels',
653-
score: 1000,
654-
},
655-
{
656-
value: 'DM_setPanel(result)',
657-
meta: 'DataStation Panels',
658-
score: 1000,
659-
},
653+
meta: 'Fetch results of this DataStation panel',
654+
score: 1000,
655+
},
656+
...(language === 'sql'
657+
? []
658+
: [
659+
{
660+
value: 'DM_setPanel(result)',
661+
meta: 'Set results of this DataStation panel',
662+
score: 1000,
663+
},
664+
]),
660665
];
661666
}
662667

@@ -753,11 +758,12 @@ export function stringPanelShapeCompletions(
753758

754759
export function makeAutocomplete(
755760
panels: Array<PanelInfo>,
756-
builtins: Array<{ value: string; score: number; meta: string }> = []
761+
builtins: Array<{ value: string; meta: string; score: number }>,
762+
language: ProgramPanelInfo['program']['type']
757763
) {
758764
return (tokenIteratorFactory: () => Ace.TokenIterator, prefix: string) => {
759765
return [
760-
...builtinCompletions(tokenIteratorFactory, builtins),
766+
...builtinCompletions(tokenIteratorFactory, builtins, language),
761767
...panelNameCompletions(tokenIteratorFactory, panels),
762768
...dotAccessPanelShapeCompletions(tokenIteratorFactory, panels),
763769
...stringPanelShapeCompletions(tokenIteratorFactory, panels),
@@ -779,7 +785,8 @@ export function ProgramPanelBody({
779785
<CodeEditor
780786
autocomplete={makeAutocomplete(
781787
panels.filter((p) => p.id !== panel.id),
782-
builtins[language] || []
788+
BUILTINS[language] || [],
789+
language
783790
)}
784791
id={'editor-' + panel.id}
785792
onKeyDown={keyboardShortcuts}

0 commit comments

Comments
 (0)