Skip to content

Commit e65f01f

Browse files
authored
fix: Merge pull request #250 from UniversalDataTool/fix/refactor-and-fix-sample-index-propagation
Refactor and fix sample index propagation, introduce S3 IAM Authentication (boilerplate), Introduce CORS Proxy (boilerplate)
2 parents 801bf86 + a3d727f commit e65f01f

File tree

37 files changed

+890
-637
lines changed

37 files changed

+890
-637
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"@sentry/browser": "^5.15.4",
8383
"any-shell-escape": "^0.1.1",
8484
"aws-amplify": "^3.0.6",
85+
"aws-sign": "^1.0.0",
8586
"axios": "^0.19.2",
8687
"bent": "^7.1.0",
8788
"brace": "^0.11.1",
@@ -106,7 +107,7 @@
106107
"react-hotkeys": "^2.0.0",
107108
"react-i18next": "^11.4.0",
108109
"react-icons": "^3.9.0",
109-
"react-image-annotate": "^1.5.0",
110+
"react-image-annotate": "^1.5.3",
110111
"react-material-workspace-layout": "^0.1.6",
111112
"react-scripts": "^3.4.1",
112113
"react-select": "^3.0.8",
Lines changed: 13 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,22 @@
11
// @flow
2-
import React from "react"
3-
4-
import SvgIcon from "@material-ui/core/SvgIcon"
5-
6-
const CognitoIcon = (props) => {
7-
return (
8-
<SvgIcon {...props} viewBox="0 0 75 75">
9-
<g id="Reference">
10-
<rect
11-
id="Red_Light_BG"
12-
data-name="Red Light BG"
13-
style={{ fill: "#d6242d" }}
14-
width="75"
15-
height="75"
16-
/>
17-
<g id="Product_Icon" data-name="Product Icon">
18-
<path
19-
style={{ fill: "#fff" }}
20-
d="M55,15H16.46a3.92,3.92,0,0,0-3.71,4.1v24.8A3.92,3.92,0,0,0,16.46,48H37.75V46H16.46a2,2,0,0,1-1.71-2.1V27h18V42a1,1,0,0,0,1,1h8V41H35.2V40.7a7.74,7.74,0,0,1,5.53-7.43,5.91,5.91,0,0,0,4.92,0,7.82,7.82,0,0,1,4.42,3.42l1.7-1v0a9.8,9.8,0,0,0-4.34-3.82,5.4,5.4,0,0,0,1.27-3.48,5.5,5.5,0,0,0-11,0A5.42,5.42,0,0,0,39,31.8a9.67,9.67,0,0,0-4.22,3.62V22h17v13.7h0V36h2V27h3V37h2l0-17.9A3.92,3.92,0,0,0,55,15ZM43.2,24.87a3.48,3.48,0,0,1,3.5,3.46,3.43,3.43,0,0,1-1.81,3,3.57,3.57,0,0,1-3.39,0,3.44,3.44,0,0,1-1.8-3A3.48,3.48,0,0,1,43.2,24.87ZM53.75,25V21a1,1,0,0,0-1-1h-19a1,1,0,0,0-1,1v4h-18v-5.9A2,2,0,0,1,16.46,17H55a2,2,0,0,1,1.73,2.1V25Z"
21-
/>
22-
<rect
23-
style={{ fill: "#fff" }}
24-
x="16.77"
25-
y="31.95"
26-
width="10.98"
27-
height="2"
28-
/>
29-
<rect
30-
style={{ fill: "#fff" }}
31-
x="16.77"
32-
y="36.95"
33-
width="6.98"
34-
height="2"
35-
/>
36-
<rect
37-
style={{ fill: "#fff" }}
38-
x="25.77"
39-
y="36.95"
40-
width="2.98"
41-
height="2"
42-
/>
43-
<path style={{ fill: "#fff" }} d="M51.78,35.65h0v0Z" />
44-
<path
45-
style={{ fill: "#fff" }}
46-
d="M52.14,60.05a10.11,10.11,0,1,1,1.22-20.14h0a10.12,10.12,0,0,1,6.46,16.61,10.47,10.47,0,0,1-3.37,2.57A10.19,10.19,0,0,1,52.14,60.05Zm0-18.22a8,8,0,0,0-3.69.9,8.11,8.11,0,0,0,7.16,14.55,8.2,8.2,0,0,0,2.71-2.07,8.11,8.11,0,0,0-5.19-13.32h0A8.22,8.22,0,0,0,52.12,41.83Z"
47-
/>
48-
<path
49-
style={{ fill: "#fff" }}
50-
d="M50.55,54.2h0a1,1,0,0,1-.71-.29l-3.23-3.23L48,49.27l2.52,2.52,5.7-5.71,1.42,1.42-6.42,6.41A1,1,0,0,1,50.55,54.2Z"
51-
/>
52-
<path style={{ fill: "#fff" }} d="M51.78,35.65h0v0Z" />
53-
</g>
54-
</g>
55-
</SvgIcon>
56-
)
57-
}
2+
import CognitoIcon from "./cognito-icon.js"
3+
import SdStorageOutlinedIcon from "@material-ui/icons/SdStorageOutlined"
4+
import AccountTreeIcon from "@material-ui/icons/AccountTree"
585

596
export default [
607
{
618
name: "AWS - Cognito",
629
provider: "cognito",
6310
Icon: CognitoIcon,
64-
dataset: {
65-
interface: {},
66-
samples: [],
67-
},
11+
},
12+
{
13+
name: "AWS - S3 (IAM)",
14+
provider: "s3iam",
15+
Icon: SdStorageOutlinedIcon,
16+
},
17+
{
18+
name: "Proxy",
19+
provider: "proxy",
20+
Icon: AccountTreeIcon,
6821
},
6922
]
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// @flow
2+
3+
import React from "react"
4+
import SvgIcon from "@material-ui/core/SvgIcon"
5+
6+
const CognitoIcon = (props) => {
7+
return (
8+
<SvgIcon {...props} viewBox="0 0 75 75">
9+
<g id="Reference">
10+
<rect
11+
id="Red_Light_BG"
12+
data-name="Red Light BG"
13+
style={{ fill: "#d6242d" }}
14+
width="75"
15+
height="75"
16+
/>
17+
<g id="Product_Icon" data-name="Product Icon">
18+
<path
19+
style={{ fill: "#fff" }}
20+
d="M55,15H16.46a3.92,3.92,0,0,0-3.71,4.1v24.8A3.92,3.92,0,0,0,16.46,48H37.75V46H16.46a2,2,0,0,1-1.71-2.1V27h18V42a1,1,0,0,0,1,1h8V41H35.2V40.7a7.74,7.74,0,0,1,5.53-7.43,5.91,5.91,0,0,0,4.92,0,7.82,7.82,0,0,1,4.42,3.42l1.7-1v0a9.8,9.8,0,0,0-4.34-3.82,5.4,5.4,0,0,0,1.27-3.48,5.5,5.5,0,0,0-11,0A5.42,5.42,0,0,0,39,31.8a9.67,9.67,0,0,0-4.22,3.62V22h17v13.7h0V36h2V27h3V37h2l0-17.9A3.92,3.92,0,0,0,55,15ZM43.2,24.87a3.48,3.48,0,0,1,3.5,3.46,3.43,3.43,0,0,1-1.81,3,3.57,3.57,0,0,1-3.39,0,3.44,3.44,0,0,1-1.8-3A3.48,3.48,0,0,1,43.2,24.87ZM53.75,25V21a1,1,0,0,0-1-1h-19a1,1,0,0,0-1,1v4h-18v-5.9A2,2,0,0,1,16.46,17H55a2,2,0,0,1,1.73,2.1V25Z"
21+
/>
22+
<rect
23+
style={{ fill: "#fff" }}
24+
x="16.77"
25+
y="31.95"
26+
width="10.98"
27+
height="2"
28+
/>
29+
<rect
30+
style={{ fill: "#fff" }}
31+
x="16.77"
32+
y="36.95"
33+
width="6.98"
34+
height="2"
35+
/>
36+
<rect
37+
style={{ fill: "#fff" }}
38+
x="25.77"
39+
y="36.95"
40+
width="2.98"
41+
height="2"
42+
/>
43+
<path style={{ fill: "#fff" }} d="M51.78,35.65h0v0Z" />
44+
<path
45+
style={{ fill: "#fff" }}
46+
d="M52.14,60.05a10.11,10.11,0,1,1,1.22-20.14h0a10.12,10.12,0,0,1,6.46,16.61,10.47,10.47,0,0,1-3.37,2.57A10.19,10.19,0,0,1,52.14,60.05Zm0-18.22a8,8,0,0,0-3.69.9,8.11,8.11,0,0,0,7.16,14.55,8.2,8.2,0,0,0,2.71-2.07,8.11,8.11,0,0,0-5.19-13.32h0A8.22,8.22,0,0,0,52.12,41.83Z"
47+
/>
48+
<path
49+
style={{ fill: "#fff" }}
50+
d="M50.55,54.2h0a1,1,0,0,1-.71-.29l-3.23-3.23L48,49.27l2.52,2.52,5.7-5.71,1.42,1.42-6.42,6.41A1,1,0,0,1,50.55,54.2Z"
51+
/>
52+
<path style={{ fill: "#fff" }} d="M51.78,35.65h0v0Z" />
53+
</g>
54+
</g>
55+
</SvgIcon>
56+
)
57+
}
58+
59+
export default CognitoIcon

src/components/AddAuthFromTemplateDialog/index.js

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,35 @@ const forms = {
8686
},
8787
],
8888
},
89+
s3iam: {
90+
questions: [
91+
{
92+
name: "auth.s3iam.access_key_id",
93+
title: "Access Key ID",
94+
placeholder: "",
95+
type: "text",
96+
isRequired: true,
97+
},
98+
{
99+
name: "auth.s3iam.secret_access_key",
100+
title: "Secret Access Key",
101+
placeholder: "",
102+
type: "text",
103+
isRequired: true,
104+
},
105+
],
106+
},
107+
proxy: {
108+
questions: [
109+
{
110+
name: "auth.proxy.corsproxy",
111+
type: "text",
112+
title: "CORS Proxy",
113+
description:
114+
"Some requests for images or APIs (like AWS S3) are blocked by browsers for security reasons, this CORs proxy will be used to enable blocked functionality when not using the desktop application.",
115+
},
116+
],
117+
},
89118
}
90119

91120
export default ({ open, onClose, onSelect, onFinish, onAuthConfigured }) => {
@@ -95,6 +124,18 @@ export default ({ open, onClose, onSelect, onFinish, onAuthConfigured }) => {
95124
const [errors, addError] = useErrors()
96125
const { appConfig, setAppConfig, fromConfig, setInConfig } = useAppConfig()
97126

127+
const getDefaultsFromConfig = (form) => {
128+
const questionIds = form.questions.map((q) => q.name)
129+
const defaults = {}
130+
for (const questionId of questionIds) {
131+
const configValue = fromConfig(questionId)
132+
if (configValue !== undefined) {
133+
defaults[questionId] = configValue
134+
}
135+
}
136+
return defaults
137+
}
138+
98139
// TODO useAppConfig to load in existing configuration
99140

100141
const validateAuthProvider = async (answers) => {
@@ -121,15 +162,15 @@ export default ({ open, onClose, onSelect, onFinish, onAuthConfigured }) => {
121162
} catch (err) {
122163
addError("Invalid Cognito config: " + err.toString())
123164
}
124-
125-
setAppConfig({
126-
...appConfig,
127-
...answers,
128-
"auth.provider": answers.provider,
129-
})
130-
// TODO some kind of success message
131-
onClose()
132165
}
166+
setAppConfig({
167+
...appConfig,
168+
...answers,
169+
"auth.provider": answers.provider,
170+
})
171+
// TODO some kind of success message
172+
onClose()
173+
setAuthProvider(null)
133174
}
134175

135176
return (
@@ -181,22 +222,7 @@ export default ({ open, onClose, onSelect, onFinish, onAuthConfigured }) => {
181222
validateAuthProvider(answers)
182223
}}
183224
defaultAnswers={{
184-
"auth.cognito.identity_pool_id": fromConfig(
185-
"auth.cognito.identity_pool_id"
186-
),
187-
"auth.cognito.region": fromConfig("auth.cognito.region"),
188-
"auth.cognito.user_pool_id": fromConfig(
189-
"auth.cognito.user_pool_id"
190-
),
191-
"auth.cognito.user_pool_web_client_id": fromConfig(
192-
"auth.cognito.user_pool_web_client_id"
193-
),
194-
"auth.cognito.storage.aws_s3.bucket": fromConfig(
195-
"auth.cognito.storage.aws_s3.bucket"
196-
),
197-
"auth.cognito.storage.aws_s3.region": fromConfig(
198-
"auth.cognito.storage.aws_s3.region"
199-
),
225+
...getDefaultsFromConfig(forms[authProvider]),
200226
"auth.provider": fromConfig("auth.provider"),
201227
}}
202228
/>

src/components/AppConfig/index.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,21 @@ const configKeyNames = [
1212
"auth.cognito.authentication_flow_type",
1313
"auth.cognito.storage.aws_s3.bucket",
1414
"auth.cognito.storage.aws_s3.region",
15+
"auth.s3iam.access_key_id",
16+
"auth.s3iam.secret_access_key",
17+
"auth.proxy.corsproxy",
1518
"labelhelp.disabled",
1619
"labelhelp.apikey",
1720
...defaultHotkeys.map(({ id }) => `hotkeys.${id}`),
1821
]
1922

23+
const defaultAppConfig = {
24+
"auth.proxy.corsproxy":
25+
// TODO this is currently deployed on @seveibar's cloudflare, it'd be
26+
// better if it was deployed on the organization's cloudflare
27+
"https://corsproxy.seve.workers.dev/corsproxy/?apiurl={URL}",
28+
}
29+
2030
// NOTE: appConfig should not allow any nested values
2131
export const AppConfigContext = createContext({
2232
appConfig: {},
@@ -37,6 +47,9 @@ export const AppConfigProvider = ({ children }) => {
3747
if (!configKeyNames.includes(key)) {
3848
throw new Error(`Unknown config key name "${key}"`)
3949
}
50+
if (appConfig[key] === undefined) {
51+
return defaultAppConfig[key]
52+
}
4053
return appConfig[key]
4154
},
4255
setInConfig: (key, value) => {

src/components/AudioTranscription/index.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
// @flow weak
22

3-
import React, { useState } from "react"
3+
import React from "react"
44
import getTaskDescription from "../../utils/get-task-description.js"
55
import SampleContainer from "../SampleContainer"
66
import NLPAnnotator from "react-nlp-annotate/components/NLPAnnotator"
7+
import useClobberedState from "../../utils/use-clobbered-state"
78

89
export default (props) => {
9-
const [currentSampleIndex, changeCurrentSampleIndex] = useState(0)
10+
const [currentSampleIndex, changeCurrentSampleIndex] = useClobberedState(
11+
props.sampleIndex,
12+
0
13+
)
1014

1115
const sample = props.samples[currentSampleIndex]
1216

@@ -20,7 +24,15 @@ export default (props) => {
2024
getTaskDescription(props.samples[currentSampleIndex]) ||
2125
props.interface.description
2226
}
23-
onChangeSample={(sampleIndex) => changeCurrentSampleIndex(sampleIndex)}
27+
onChangeSample={(sampleIndex) => {
28+
if (props.containerProps.onExit) {
29+
props.containerProps.onExit(
30+
sampleIndex > currentSampleIndex ? "go-to-next" : "go-to-previous"
31+
)
32+
} else {
33+
changeCurrentSampleIndex(sampleIndex)
34+
}
35+
}}
2436
>
2537
<NLPAnnotator
2638
key={(props.sampleIndex || 0) + currentSampleIndex}

src/components/CollaborateButton/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export default ({
135135
<PeopleIcon />
136136
</IconButton>
137137
<PopupBox className={sessionBoxOpen ? "" : "hidden"}>
138-
<h1>{t("collobrate")}</h1>
138+
<h1>{t("collaborate")}</h1>
139139
{!inSession ? (
140140
<>
141141
<h2>{t("join-a-session")}</h2>

src/components/Composite/index.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import InterfaceIcon from "../InterfaceIcon"
99
import KeyboardArrowRightIcon from "@material-ui/icons/KeyboardArrowRight"
1010
import Checkbox from "@material-ui/core/Checkbox"
1111
import Box from "@material-ui/core/Box"
12+
import useClobberedState from "../../utils/use-clobbered-state"
1213

1314
import { useTranslation } from "react-i18next"
1415

@@ -29,7 +30,10 @@ const StyledButton = styled(Button)({
2930
})
3031

3132
export const Composite = (props) => {
32-
const [currentSampleIndex, changeCurrentSampleIndex] = useState(0)
33+
const [currentSampleIndex, changeCurrentSampleIndex] = useClobberedState(
34+
props.sampleIndex,
35+
0
36+
)
3337
const {
3438
interface: { fields },
3539
} = props
@@ -53,6 +57,7 @@ export const Composite = (props) => {
5357
},
5458
],
5559
}}
60+
onExit={() => changeSelectedField(null)}
5661
onSaveTaskOutputItem={(indexZero, output) => {
5762
props.onSaveTaskOutputItem(currentSampleIndex, {
5863
...sample.annotation,
@@ -71,7 +76,15 @@ export const Composite = (props) => {
7176
totalSamples={props.samples.length}
7277
taskOutput={props.samples.map((s) => s.annotation)}
7378
description={getTaskDescription(sample) || props.interface.description}
74-
onChangeSample={(sampleIndex) => changeCurrentSampleIndex(sampleIndex)}
79+
onChangeSample={(sampleIndex) => {
80+
if (props.containerProps.onExit) {
81+
props.containerProps.onExit(
82+
sampleIndex > currentSampleIndex ? "go-to-next" : "go-to-previous"
83+
)
84+
} else {
85+
changeCurrentSampleIndex(sampleIndex)
86+
}
87+
}}
7588
>
7689
<Title>Fields</Title>
7790
{fields.map((field, index) => (

0 commit comments

Comments
 (0)