Skip to content

Commit 498124b

Browse files
authored
fix: Merge pull request #167 from UniversalDataTool/feat/keyboard-shortcut-manager
Shortcut Manager
2 parents e4103c7 + 6a7d874 commit 498124b

File tree

26 files changed

+529
-179
lines changed

26 files changed

+529
-179
lines changed

.github/workflows/test.yml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@ jobs:
1616
run: npx prettier --check "src/**/*.js"
1717
- name: Run Lint Test
1818
run: |
19-
rm package.json
20-
rm package-lock.json
21-
npm init -y
22-
npm install react-scripts
23-
echo '{"extends": "react-app"}' > .eslintrc
24-
npx eslint src
19+
# TODO this takes 1-2 mins to install, run eslint w/o installing
20+
# everything
21+
npm install
22+
npm run test:lint
2523
cypress-run:
2624
needs: iscodeclean
2725
runs-on: ubuntu-16.04
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
describe("Test default keyboard shortcuts", () => {
2+
it.skip("should be able to navigate to label tab with default shortcut", () => {
3+
cy.visit("http://localhost:6001")
4+
5+
cy.contains("New File").click()
6+
7+
cy.wait(500)
8+
9+
// TODO this doesn't trigger hot keys for some reason, I'm not sure how
10+
// good the support for testing keyboard shortcuts in cypress is
11+
cy.get("body").trigger("keydown", {
12+
keyCode: 51,
13+
release: false,
14+
location: 0,
15+
which: 51,
16+
key: "3",
17+
code: "Digit3",
18+
})
19+
20+
cy.contains("Percent Complete")
21+
})
22+
})

package-lock.json

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
"build:babel": "cross-env NODE_ENV=production babel ./src --out-dir=./lib && cp ./package.json ./lib/package.json && node ./lib/lib/fix-deps.js",
1313
"build:vanilla": "parcel build -d ./lib -o vanilla.js ./src/vanilla/index.js",
1414
"build:vanilla:dev": "parcel ./src/vanilla/index.js",
15-
"build:web": "CI=false react-scripts build",
16-
"build:desktop": "cross-env CI=false REACT_APP_DESKTOP=true PUBLIC_URL=./ react-scripts build && electron-builder build && cp ./desktop/entitlements.mac.plist ./build/entitlements.mac.plist",
15+
"build:web": "react-scripts build",
16+
"build:desktop": "cross-env REACT_APP_DESKTOP=true PUBLIC_URL=./ react-scripts build && electron-builder build && cp ./desktop/entitlements.mac.plist ./build/entitlements.mac.plist",
1717
"start:desktop:dev": "USE_DEV_SERVER=yes electron ./desktop",
1818
"start:desktop": "electron ./desktop",
1919
"release:lib": "npm run build && cd lib && npm publish",
@@ -97,6 +97,7 @@
9797
"react-ace": "^7.0.4",
9898
"react-data-table-component": "^6.2.2",
9999
"react-dropzone": "^10.1.8",
100+
"react-hotkeys": "^2.0.0",
100101
"react-icons": "^3.9.0",
101102
"react-image-annotate": "^1.0.6",
102103
"react-scripts": "^3.4.1",

src/App.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import useElectron from "./utils/use-electron.js"
77
import { AppConfigProvider } from "./components/AppConfig"
88
import { AuthProvider } from "./utils/auth-handlers/use-auth.js"
99
import { LabelHelpProvider } from "./components/LabelHelpView"
10+
import { HotkeyStorageProvider } from "./components/HotkeyStorage"
1011
import "./App.css"
1112

1213
export const App = () => {
@@ -17,7 +18,9 @@ export const App = () => {
1718
<AuthProvider>
1819
<LabelHelpProvider>
1920
<ToastProvider>
20-
{Boolean(electron) ? <DesktopApp /> : <LocalStorageApp />}
21+
<HotkeyStorageProvider>
22+
{Boolean(electron) ? <DesktopApp /> : <LocalStorageApp />}
23+
</HotkeyStorageProvider>
2124
</ToastProvider>
2225
</LabelHelpProvider>
2326
</AuthProvider>

src/components/AddAuthFromTemplateDialog/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import isEmpty from "lodash/isEmpty"
99
import Survey from "material-survey/components/Survey"
1010
import ErrorToasts from "../ErrorToasts"
1111
import useErrors from "../../utils/use-errors.js"
12-
import Amplify, { Auth as AWSAmplifyAuth } from "aws-amplify"
12+
import Amplify from "aws-amplify"
1313
import { useAppConfig } from "../AppConfig"
1414
import * as colors from "@material-ui/core/colors"
1515

src/components/AdvancedOptionsView/index.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
import React from "react"
1+
import React, { useState } from "react"
22
import Box from "@material-ui/core/Box"
33
import MuiButton from "@material-ui/core/Button"
44
import { useUpdate } from "react-use"
55
import { styled } from "@material-ui/core/styles"
66
import usePosthog from "../../utils/use-posthog"
77
import { useAppConfig } from "../AppConfig"
8+
import { useHotkeyStorage } from "../HotkeyStorage"
9+
import KeyboardShortcutManagerDialog from "../KeyboardShortcutManagerDialog"
810

911
const Button = styled(MuiButton)({
1012
margin: 8,
@@ -14,6 +16,8 @@ export const AdvancedOptionsView = ({ onClickEditJSON, onClearLabelData }) => {
1416
const forceUpdate = useUpdate()
1517
const posthog = usePosthog()
1618
const { fromConfig, setInConfig } = useAppConfig()
19+
const { hotkeys, changeHotkey } = useHotkeyStorage()
20+
const [hotkeyDialogOpen, setHotkeyDialogOpen] = useState(false)
1721

1822
return (
1923
<Box padding={2}>
@@ -89,6 +93,22 @@ export const AdvancedOptionsView = ({ onClickEditJSON, onClearLabelData }) => {
8993
Label Help API Key
9094
</Button>
9195
)}
96+
<Button
97+
variant="outlined"
98+
onClick={() => {
99+
setHotkeyDialogOpen(true)
100+
}}
101+
>
102+
Change/View Hotkeys
103+
</Button>
104+
<KeyboardShortcutManagerDialog
105+
open={hotkeyDialogOpen}
106+
hotkeyList={hotkeys}
107+
onClose={() => setHotkeyDialogOpen(false)}
108+
onChangeHotkey={(hotkey, newBinding) =>
109+
changeHotkey(hotkey.id, newBinding)
110+
}
111+
/>
92112
</Box>
93113
)
94114
}

src/components/AppConfig/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useMemo, useContext, createContext } from "react"
22
import { useLocalStorage } from "react-use"
3+
import { defaultHotkeys } from "../HotkeyStorage"
34

45
const configKeyNames = [
56
"auth.provider",
@@ -13,6 +14,7 @@ const configKeyNames = [
1314
"auth.cognito.storage.aws_s3.region",
1415
"labelhelp.disabled",
1516
"labelhelp.apikey",
17+
...defaultHotkeys.map(({ id }) => `hotkeys.${id}`),
1618
]
1719

1820
// NOTE: appConfig should not allow any nested values

src/components/ConfigureInterface/index.js

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,39 @@ import useEventCallback from "use-event-callback"
2222

2323
const noop = () => {}
2424

25-
const Container = styled("div")({ padding: 24 })
25+
const Container = styled("div")({
26+
padding: 24,
27+
"&.emptyState": {
28+
textAlign: "center",
29+
backgroundColor: colors.blue[800],
30+
minHeight: "70vh",
31+
padding: 64,
32+
"& .bigText": {
33+
textAlign: "left",
34+
fontSize: 48,
35+
color: "#fff",
36+
fontWeight: "bold",
37+
marginBottom: 48,
38+
},
39+
},
40+
})
41+
42+
const BigButton = styled(Button)({
43+
padding: 10,
44+
width: 200,
45+
height: 150,
46+
boxShadow: "0px 3px 5px rgba(0,0,0,0.3)",
47+
margin: 12,
48+
backgroundColor: "#fff",
49+
"& .bigIcon": {
50+
marginTop: 16,
51+
width: 64,
52+
height: 64,
53+
},
54+
"&:hover": {
55+
backgroundColor: "#fff",
56+
},
57+
})
2658

2759
const NoOptions = styled("div")({
2860
fontSize: 18,
@@ -114,6 +146,30 @@ export const ConfigureInterface = ({
114146
clearTimeout(timeout)
115147
}
116148
}, [previewChangedTime])
149+
150+
if (!iface.type || iface.type === "empty") {
151+
return (
152+
<Container className="emptyState">
153+
<div className="bigText">Choose an Interface:</div>
154+
{templates
155+
.filter((t) => t.name !== "Empty")
156+
.map((template) => (
157+
<BigButton
158+
key={template.name}
159+
onClick={() => onChange(template.dataset.interface)}
160+
>
161+
<div>
162+
<div>{template.name}</div>
163+
<div>
164+
<template.Icon className="bigIcon" />
165+
</div>
166+
</div>
167+
</BigButton>
168+
))}
169+
</Container>
170+
)
171+
}
172+
117173
return (
118174
<Container>
119175
<Heading>Interface Type</Heading>

0 commit comments

Comments
 (0)