Skip to content

Commit e53efc0

Browse files
Adam Erbsvc-squareup-copybara
authored andcommitted
1) Add help dialog. 2) Trigger auto-completion dropdown whenever
completions available GitOrigin-RevId: 6cc63410235eec1d8bc40c00f4a84b1a1a131b88
1 parent 7a623d7 commit e53efc0

File tree

7 files changed

+142
-11
lines changed

7 files changed

+142
-11
lines changed

misk-admin/web-actions/src/index.tsx

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useState, useRef, useCallback } from 'react';
1+
import React, { useEffect, useState, useRef } from 'react';
22

33
import { createRoot } from 'react-dom/client';
44
import RequestEditor from '@web-actions/ui/RequestEditor';
@@ -11,7 +11,9 @@ import {
1111
Heading,
1212
Input,
1313
IconButton,
14+
Button,
1415
} from '@chakra-ui/react';
16+
import HelpPanel from '@web-actions/ui/HelpPanel';
1517
import ReadOnlyEditor from '@web-actions/ui/ReadOnlyViewer';
1618
import 'ace-builds';
1719
import 'ace-builds/webpack-resolver';
@@ -34,6 +36,7 @@ function App() {
3436
callables: [],
3537
});
3638
const [loading, setLoading] = useState<boolean>(true);
39+
const [isHelpOpen, setIsHelpOpen] = useState<boolean>(false);
3740
const endPointSelectorRef = useRef<EndpointSelector>();
3841
const requestEditorRef = useRef<RequestEditor>();
3942

@@ -60,16 +63,26 @@ function App() {
6063
useEffect(() => {
6164
const handleKeyPress = (event: KeyboardEvent) => {
6265
const isShortcutKey = event.ctrlKey || event.metaKey;
66+
67+
if (isShortcutKey && event.key === '/') {
68+
event.preventDefault();
69+
event.stopPropagation();
70+
setIsHelpOpen((prev) => !prev);
71+
return;
72+
}
73+
6374
if (isShortcutKey && event.key === 'k') {
6475
event.preventDefault();
6576
endPointSelectorRef.current?.focusSelect();
6677
} else if (isShortcutKey && event.key === 'Enter') {
6778
requestEditorRef.current?.submitRequest();
6879
}
6980
};
70-
document.addEventListener('keydown', handleKeyPress);
81+
82+
document.addEventListener('keydown', handleKeyPress, true);
83+
7184
return () => {
72-
document.removeEventListener('keydown', handleKeyPress);
85+
document.removeEventListener('keydown', handleKeyPress, true);
7386
};
7487
}, []);
7588

@@ -106,13 +119,23 @@ function App() {
106119
bg="gray.600"
107120
alignItems="start"
108121
>
109-
<EndpointSelector
110-
ref={endPointSelectorRef as any}
111-
onDismiss={() => {
112-
requestEditorRef?.current?.focusEditor();
113-
}}
114-
endpointSelectionCallbacks={endpointSelectionCallbacks}
115-
/>
122+
<HStack width="100%" justifyContent="space-between">
123+
<EndpointSelector
124+
ref={endPointSelectorRef as any}
125+
onDismiss={() => {
126+
requestEditorRef?.current?.focusEditor();
127+
}}
128+
endpointSelectionCallbacks={endpointSelectionCallbacks}
129+
/>
130+
<Button
131+
colorScheme="blue"
132+
size="sm"
133+
onClick={() => setIsHelpOpen(true)}
134+
>
135+
Help (⌘/)
136+
</Button>
137+
</HStack>
138+
<HelpPanel isOpen={isHelpOpen} onClose={() => setIsHelpOpen(false)} />
116139
<HStack spacing={2} flexGrow={1} width="100%">
117140
<VStack height="100%" flexGrow={1} alignItems="start">
118141
<Heading color="white" size="sm" fontWeight="semibold">

misk-admin/web-actions/src/web-actions/completion/CompletionProvider.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ export default class CompletionProvider {
7777
currIndex - completion.cursorOffset - 1,
7878
);
7979
editor.moveCursorTo(moveCursorTo.row, moveCursorTo.column);
80+
if (type.isObject()) {
81+
editor.triggerCompletionDialog();
82+
}
8083
},
8184
prefix,
8285
};

misk-admin/web-actions/src/web-actions/completion/Editor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ export default interface Editor {
66
delete(row: number, column: number): void;
77
indexToPosition(index: number): Position;
88
positionToIndex(position: Position): number;
9+
triggerCompletionDialog(): void;
910
}

misk-admin/web-actions/src/web-actions/completion/__test__/FakeEditor.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export default class FakeEditor implements Editor {
2222
cursor: PositionWithIndex = { row: 0, column: 0, index: 0 };
2323
completions?: CompletionProvider;
2424

25+
triggerCompletionDialog() {}
26+
2527
moveCursorTo(row: number, column: number) {
2628
let index = 0;
2729
for (let i = 0; i < row; i++) {

misk-admin/web-actions/src/web-actions/ui/AceEditor.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,17 @@ import Editor from '@web-actions/completion/Editor';
22
import { Ace, Range } from 'ace-builds';
33
import Position from '@web-actions/completion/Position';
44

5+
export function triggerCompletionDialog(editor: Ace.Editor | null | undefined) {
6+
if (!editor) {
7+
return;
8+
}
9+
setTimeout(() => {
10+
editor.commands?.byName?.startAutocomplete?.exec(editor);
11+
}, 100);
12+
}
13+
514
export default class AceEditor implements Editor {
6-
private editor: Ace.Editor;
15+
private readonly editor: Ace.Editor;
716

817
constructor(editor: Ace.Editor) {
918
this.editor = editor;
@@ -28,6 +37,10 @@ export default class AceEditor implements Editor {
2837
delete(row: number, column: number): void {
2938
this.editor.session.remove(charRange(row, column));
3039
}
40+
41+
triggerCompletionDialog() {
42+
triggerCompletionDialog(this.editor);
43+
}
3144
}
3245

3346
function charRange(row: number, column: number): Ace.Range {
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import React from 'react';
2+
import {
3+
Modal,
4+
ModalOverlay,
5+
ModalContent,
6+
ModalHeader,
7+
ModalBody,
8+
ModalCloseButton,
9+
Heading,
10+
Text,
11+
UnorderedList,
12+
OrderedList,
13+
ListItem,
14+
Code,
15+
VStack,
16+
useColorModeValue,
17+
} from '@chakra-ui/react';
18+
19+
interface HelpPanelProps {
20+
isOpen: boolean;
21+
onClose: () => void;
22+
}
23+
24+
export default function HelpPanel({
25+
isOpen,
26+
onClose,
27+
}: HelpPanelProps): JSX.Element {
28+
const bgColor = useColorModeValue('white', 'gray.800');
29+
30+
return (
31+
<Modal isOpen={isOpen} onClose={onClose} size="xl" scrollBehavior="inside">
32+
<ModalOverlay backdropFilter="blur(2px)" />
33+
<ModalContent bg={bgColor} maxW="600px">
34+
<ModalHeader>Web Actions Help</ModalHeader>
35+
<ModalCloseButton />
36+
37+
<ModalBody pb={6}>
38+
<VStack align="stretch" spacing={6}>
39+
<section>
40+
<Heading as="h3" size="md" mb={2}>
41+
Overview
42+
</Heading>
43+
<Text>
44+
Web Actions allows you edit and submit requests to Misk Action
45+
endpoints.
46+
</Text>
47+
</section>
48+
49+
<section>
50+
<Heading as="h3" size="md" mb={2}>
51+
Usage
52+
</Heading>
53+
<OrderedList spacing={1} pl={4}>
54+
<ListItem>Trigger the action selector with ⌘K</ListItem>
55+
<ListItem>Type to filter options, and select with ⏎</ListItem>
56+
<ListItem>
57+
Use the Request Editor to modify request. ⌃Space triggers
58+
auto-completions.
59+
</ListItem>
60+
<ListItem>Submit request with ⌘⏎</ListItem>
61+
<ListItem>Repeat</ListItem>
62+
</OrderedList>
63+
</section>
64+
65+
<section>
66+
<Heading as="h3" size="md" mb={2}>
67+
Keyboard Shortcuts
68+
</Heading>
69+
<UnorderedList spacing={1} pl={4}>
70+
<ListItem>⌘K - Open web action selector</ListItem>
71+
<ListItem>⌘⏎ - Submit request</ListItem>
72+
<ListItem>
73+
⌃Space - Trigger auto-completion in request editor
74+
</ListItem>
75+
<ListItem>⌘/ - Toggle help panel</ListItem>
76+
<ListItem>
77+
Esc - Dismiss action selector / completion dialogs
78+
</ListItem>
79+
</UnorderedList>
80+
</section>
81+
</VStack>
82+
</ModalBody>
83+
</ModalContent>
84+
</Modal>
85+
);
86+
}

misk-admin/web-actions/src/web-actions/ui/RequestEditor.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CopyIcon } from '@chakra-ui/icons';
88
import { CommandParser } from '@web-actions/parsing/CommandParser';
99
import { MiskWebActionDefinition } from '@web-actions/api/responseTypes';
1010
import { EndpointSelectionCallbacks } from '@web-actions/ui/EndpointSelection';
11+
import { triggerCompletionDialog } from '@web-actions/ui/AceEditor';
1112

1213
interface State {
1314
loading: boolean;
@@ -81,6 +82,8 @@ export default class RequestEditor extends React.Component<Props, State> {
8182
this.editor?.setValue('{\n \n}', -1);
8283
this.editor?.moveCursorTo(1, 2);
8384
this.editor?.focus();
85+
86+
triggerCompletionDialog(this.editor);
8487
}
8588
}
8689

0 commit comments

Comments
 (0)