Skip to content

Commit 23bc1ab

Browse files
authored
fix: Merge pull request #179 from UniversalDataTool/feat/keyboard-shortcut-manager
Storybook and Hotkey Fixes
2 parents a6ce5f8 + 49abf64 commit 23bc1ab

File tree

13 files changed

+1780
-2386
lines changed

13 files changed

+1780
-2386
lines changed

package-lock.json

Lines changed: 1462 additions & 2230 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@
4949
"@babel/core": "^7.5.4",
5050
"@material-ui/core": "^4.9.5",
5151
"@material-ui/icons": "^4.9.1",
52-
"@storybook/addon-actions": "^5.3.14",
53-
"@storybook/addon-links": "^5.3.14",
54-
"@storybook/addons": "^5.3.14",
55-
"@storybook/react": "^5.3.14",
52+
"@storybook/addon-actions": "^5.3.19",
53+
"@storybook/addon-links": "^5.3.19",
54+
"@storybook/addons": "^5.3.19",
55+
"@storybook/react": "^5.3.19",
5656
"@testing-library/react-hooks": "^3.2.1",
5757
"ava": "^3.7.0",
5858
"chroma-js": "^2.0.4",
@@ -99,7 +99,7 @@
9999
"react-dropzone": "^10.1.8",
100100
"react-hotkeys": "^2.0.0",
101101
"react-icons": "^3.9.0",
102-
"react-image-annotate": "^1.0.6",
102+
"react-image-annotate": "^1.0.15",
103103
"react-scripts": "^3.4.1",
104104
"react-select": "^3.0.8",
105105
"rfc6902": "^3.0.4",

src/components/AdvancedOptionsView/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const AdvancedOptionsView = ({ onClickEditJSON, onClearLabelData }) => {
1616
const forceUpdate = useUpdate()
1717
const posthog = usePosthog()
1818
const { fromConfig, setInConfig } = useAppConfig()
19-
const { hotkeys, changeHotkey } = useHotkeyStorage()
19+
const { hotkeys, changeHotkey, clearHotkeys } = useHotkeyStorage()
2020
const [hotkeyDialogOpen, setHotkeyDialogOpen] = useState(false)
2121

2222
return (
@@ -105,6 +105,7 @@ export const AdvancedOptionsView = ({ onClickEditJSON, onClearLabelData }) => {
105105
open={hotkeyDialogOpen}
106106
hotkeyList={hotkeys}
107107
onClose={() => setHotkeyDialogOpen(false)}
108+
onClearHotkeys={clearHotkeys}
108109
onChangeHotkey={(hotkey, newBinding) =>
109110
changeHotkey(hotkey.id, newBinding)
110111
}

src/components/DatasetEditor/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import classnames from "classnames"
2020
import LabelView from "../LabelView"
2121
import useIsLabelOnlyMode from "../../utils/use-is-label-only-mode"
2222
import { HotKeys } from "react-hotkeys"
23+
import { useHotkeyStorage } from "../HotkeyStorage"
2324

2425
import "brace/mode/javascript"
2526
import "brace/theme/github"
@@ -121,8 +122,10 @@ export default ({
121122
[changeMode]
122123
)
123124

125+
const { keyMap } = useHotkeyStorage()
126+
124127
return (
125-
<HotKeys handlers={shortcutHandlers}>
128+
<HotKeys allowChanges handlers={shortcutHandlers} keyMap={keyMap}>
126129
<div className={classnames(c.container, "universaldatatool")}>
127130
<Header
128131
title={

src/components/DatasetEditor/index.story.js

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,51 +4,91 @@ import React, { useState } from "react"
44

55
import { storiesOf } from "@storybook/react"
66
import { action } from "@storybook/addon-actions"
7+
import { HotKeys } from "react-hotkeys"
78

89
import DatasetEditor from "./"
910

1011
const Controller = (props) => {
11-
const [dataset, changeOHA] = useState(props.initialOHA)
12+
const [dataset, changeDataset] = useState(props.initialDataset)
1213
return (
1314
<DatasetEditor
1415
dataset={dataset}
1516
onChangeDataset={(...props) => {
16-
changeOHA(...props)
17+
changeDataset(...props)
1718
action("onChangeDataset")(...props)
1819
}}
1920
{...props}
2021
/>
2122
)
2223
}
2324

24-
storiesOf("DatasetEditor", module).add("Basic", () => (
25-
<Controller
26-
initialOHA={{
27-
interface: {
28-
type: "image_segmentation",
29-
labels: ["valid", "invalid"],
30-
regionTypesAllowed: ["bounding-box", "polygon", "point"],
31-
},
32-
samples: [
33-
{
34-
imageUrl:
35-
"https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image1.jpg",
25+
storiesOf("DatasetEditor", module)
26+
.add("Basic", () => (
27+
<Controller
28+
initialDataset={{
29+
interface: {
30+
type: "image_segmentation",
31+
labels: ["valid", "invalid"],
32+
regionTypesAllowed: ["bounding-box", "polygon", "point"],
3633
},
37-
{
38-
imageUrl:
39-
"https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image2.jpg",
40-
},
41-
],
42-
taskOutput: [
43-
{
44-
regionType: "bounding-box",
45-
centerX: 0.5,
46-
centerY: 0.5,
47-
width: 0.25,
48-
height: 0.25,
49-
},
50-
],
51-
}}
52-
onChangeFileName={action("onChangeFileName")}
53-
/>
54-
))
34+
samples: [
35+
{
36+
imageUrl:
37+
"https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image1.jpg",
38+
},
39+
{
40+
imageUrl:
41+
"https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image2.jpg",
42+
},
43+
],
44+
taskOutput: [
45+
{
46+
regionType: "bounding-box",
47+
centerX: 0.5,
48+
centerY: 0.5,
49+
width: 0.25,
50+
height: 0.25,
51+
},
52+
],
53+
}}
54+
onChangeFileName={action("onChangeFileName")}
55+
/>
56+
))
57+
.add("Basic with Hotkeys", () => (
58+
<HotKeys
59+
keyMap={{
60+
zoom_tool: "z",
61+
pan_tool: "p",
62+
}}
63+
>
64+
<Controller
65+
initialDataset={{
66+
interface: {
67+
type: "image_segmentation",
68+
labels: ["valid", "invalid"],
69+
regionTypesAllowed: ["bounding-box", "polygon", "point"],
70+
},
71+
samples: [
72+
{
73+
imageUrl:
74+
"https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image1.jpg",
75+
},
76+
{
77+
imageUrl:
78+
"https://s3.amazonaws.com/asset.workaround.online/example-jobs/sticky-notes/image2.jpg",
79+
},
80+
],
81+
taskOutput: [
82+
{
83+
regionType: "bounding-box",
84+
centerX: 0.5,
85+
centerY: 0.5,
86+
width: 0.25,
87+
height: 0.25,
88+
},
89+
],
90+
}}
91+
onChangeFileName={action("onChangeFileName")}
92+
/>
93+
</HotKeys>
94+
))

src/components/FileContext/use-active-dataset.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { setIn } from "seamless-immutable"
44

55
export const useActiveDataset = () => {
66
const { file, setFile } = useFileContext()
7-
return useMemo(
7+
const result = useMemo(
88
() =>
99
!file || !file.content
1010
? null
@@ -16,4 +16,5 @@ export const useActiveDataset = () => {
1616
},
1717
[file, setFile]
1818
)
19+
return result || {}
1920
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
export const defaultHotkeys = [
2+
{
3+
id: "switch_to_label",
4+
description: "Go to Labels Tab",
5+
binding: "shift+3",
6+
},
7+
{
8+
id: "switch_to_setup",
9+
description: "Go to Setup Tab",
10+
binding: "shift+1",
11+
},
12+
{
13+
id: "switch_to_samples",
14+
description: "Go to Samples Tab",
15+
binding: "shift+2",
16+
},
17+
{
18+
id: "select_tool",
19+
description: "Switch to the Select Tool",
20+
binding: "escape",
21+
},
22+
{
23+
id: "zoom_tool",
24+
description: "Select the Zoom Tool",
25+
binding: "z",
26+
},
27+
{
28+
id: "create_point",
29+
description: "Create a point",
30+
},
31+
{
32+
id: "create_bounding_box",
33+
description: "Create a bounding box",
34+
binding: "b",
35+
},
36+
{
37+
id: "pan_tool",
38+
description: "Select the Pan Tool",
39+
binding: "p",
40+
},
41+
{
42+
id: "create_polygon",
43+
description: "Create a Polygon",
44+
},
45+
{
46+
id: "create_pixel",
47+
description: "Create a Pixel Mask",
48+
},
49+
{
50+
id: "save_and_previous_sample",
51+
description: "Save and go to previous sample",
52+
binding: "a",
53+
},
54+
{
55+
id: "save_and_next_sample",
56+
description: "Save and go to next sample",
57+
binding: "d",
58+
},
59+
{
60+
id: "save_and_exit_sample",
61+
description: "Save and exit current sample",
62+
},
63+
{
64+
id: "exit_sample",
65+
description: "Exit sample without saving",
66+
},
67+
]
68+
export default defaultHotkeys
Lines changed: 20 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,6 @@
11
import React, { createContext, useContext, useMemo } from "react"
2+
import { defaultHotkeys } from "./default-hotkeys"
23
import { useAppConfig } from "../AppConfig"
3-
import { HotKeys } from "react-hotkeys"
4-
5-
export const defaultHotkeys = [
6-
{
7-
id: "switch_to_label",
8-
description: "Go to Labels Tab",
9-
binding: "shift+3",
10-
},
11-
{
12-
id: "switch_to_setup",
13-
description: "Go to Setup Tab",
14-
binding: "shift+1",
15-
},
16-
{
17-
id: "switch_to_samples",
18-
description: "Go to Samples Tab",
19-
binding: "shift+2",
20-
},
21-
{
22-
id: "select_tool",
23-
description: "Switch to the Select Tool",
24-
binding: "escape",
25-
},
26-
{
27-
id: "zoom_tool",
28-
description: "Select the Zoom Tool",
29-
binding: "z",
30-
},
31-
{
32-
id: "create_point",
33-
description: "Create a point",
34-
},
35-
{
36-
id: "pan_tool",
37-
description: "Select the Pan Tool",
38-
},
39-
{
40-
id: "create_polygon",
41-
description: "Create a Polygon",
42-
},
43-
{
44-
id: "create_pixel",
45-
description: "Create a Pixel Mask",
46-
},
47-
{
48-
id: "save_and_previous_sample",
49-
description: "Save and go to previous sample",
50-
},
51-
{
52-
id: "save_and_next_sample",
53-
description: "Save and go to next sample",
54-
},
55-
{
56-
id: "save_and_exit_sample",
57-
description: "Save and exit current sample",
58-
},
59-
{
60-
id: "exit_sample",
61-
description: "Exit sample without saving",
62-
},
63-
]
644

655
export const HotkeyContext = createContext({
666
hotkeys: defaultHotkeys,
@@ -84,24 +24,35 @@ export const HotkeyStorageProvider = ({ children }) => {
8424
[fromConfig]
8525
)
8626

27+
const keyMap = useMemo(() => {
28+
const keyMap = {}
29+
for (const { id, binding } of hotkeys) {
30+
if (!binding) continue
31+
keyMap[id] = binding
32+
}
33+
return keyMap
34+
}, [hotkeys])
35+
8736
const contextValue = useMemo(
8837
() => ({
8938
hotkeys,
39+
keyMap,
40+
clearHotkeys: () => {
41+
for (const { id } of hotkeys) {
42+
setInConfig(`hotkeys.${id}`, null)
43+
}
44+
},
9045
changeHotkey: (id, newBinding) =>
9146
setInConfig(`hotkeys.${id}`, newBinding),
9247
}),
93-
[setInConfig, hotkeys]
48+
[setInConfig, hotkeys, keyMap]
9449
)
9550

96-
const keyMap = useMemo(() => {
97-
const keyMap = {}
98-
for (const { id, binding } of hotkeys) keyMap[id] = binding
99-
return keyMap
100-
}, [hotkeys])
101-
10251
return (
10352
<HotkeyContext.Provider value={contextValue}>
104-
<HotKeys keyMap={keyMap}>{children}</HotKeys>
53+
{children}
10554
</HotkeyContext.Provider>
10655
)
10756
}
57+
58+
export { defaultHotkeys }

0 commit comments

Comments
 (0)