|
|
|
@ -1,6 +1,6 @@ |
|
|
|
|
import React, { useState, useEffect, useCallback } from 'react'; |
|
|
|
|
import { useAuth } from '../../../lib/useAuth'; |
|
|
|
|
import { Box, CircularProgress, IconButton, Typography, FormControl, Select, MenuItem, TextField, Menu, Button } from '@material-ui/core'; |
|
|
|
|
import { Box, CircularProgress, IconButton, Typography, FormControl, Select, MenuItem, TextField, Menu, Button, Card, CardHeader, CardContent, CardActions } from '@material-ui/core'; |
|
|
|
|
import { getIntegrations, createIntegration, modifyIntegration, deleteIntegration } from '../../../lib/backend/integrations'; |
|
|
|
|
import AddIcon from '@material-ui/icons/Add'; |
|
|
|
|
import EditIcon from '@material-ui/icons/Edit'; |
|
|
|
@ -31,57 +31,61 @@ function EditSpotifyClientCredentialsDetails(props: { |
|
|
|
|
onChangeClientSecret: (v: string) => void, |
|
|
|
|
}) { |
|
|
|
|
return <Box> |
|
|
|
|
<Box display="flex" alignItems="center"> |
|
|
|
|
<Typography>Client id:</Typography> |
|
|
|
|
{props.editing ? |
|
|
|
|
<Box mt={1} mb={1}> |
|
|
|
|
<TextField |
|
|
|
|
variant="outlined" |
|
|
|
|
disabled={!props.editing} |
|
|
|
|
value={props.clientId || ""} |
|
|
|
|
label="Client Id:" |
|
|
|
|
fullWidth |
|
|
|
|
onChange={(e: any) => props.onChangeClientId(e.target.value)} |
|
|
|
|
/> : |
|
|
|
|
<Typography>{props.clientId}</Typography>} |
|
|
|
|
/> |
|
|
|
|
</Box> |
|
|
|
|
<Box display="flex" alignItems="center"> |
|
|
|
|
<Typography>Client secret:</Typography> |
|
|
|
|
{props.editing ? |
|
|
|
|
<Box mt={1} mb={1}> |
|
|
|
|
<TextField |
|
|
|
|
variant="outlined" |
|
|
|
|
disabled={!props.editing} |
|
|
|
|
value={props.clientSecret || ""} |
|
|
|
|
label="Client secret:" |
|
|
|
|
fullWidth |
|
|
|
|
onChange={(e: any) => props.onChangeClientSecret(e.target.value)} |
|
|
|
|
/> : |
|
|
|
|
<Typography>{props.clientSecret}</Typography>} |
|
|
|
|
/> |
|
|
|
|
</Box> |
|
|
|
|
</Box>; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function EditIntegration(props: EditIntegrationProps) { |
|
|
|
|
let IntegrationHeaders: Record<any, any> = { |
|
|
|
|
[serverApi.IntegrationType.SpotifyClientCredentials]: <Box display="flex" alignItems="center"> |
|
|
|
|
<StoreLinkIcon |
|
|
|
|
[serverApi.IntegrationType.SpotifyClientCredentials]: |
|
|
|
|
<Box display="flex" alignItems="center"> |
|
|
|
|
<Box mr={1}><StoreLinkIcon |
|
|
|
|
style={{ height: '40px', width: '40px' }} |
|
|
|
|
whichStore={ExternalStore.Spotify} |
|
|
|
|
/> |
|
|
|
|
/></Box> |
|
|
|
|
<Typography>Spotify</Typography> |
|
|
|
|
</Box> |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return <Box display="flex" flexDirection="column" border={1}> |
|
|
|
|
{IntegrationHeaders[props.integration.type]} |
|
|
|
|
<Box display="flex" alignItems="center"> |
|
|
|
|
<Typography>Name:</Typography> |
|
|
|
|
{props.editing ? |
|
|
|
|
return <Card variant="outlined"> |
|
|
|
|
<CardHeader |
|
|
|
|
avatar={ |
|
|
|
|
IntegrationHeaders[props.integration.type] |
|
|
|
|
} |
|
|
|
|
> |
|
|
|
|
</CardHeader> |
|
|
|
|
<CardContent> |
|
|
|
|
<Box mt={1} mb={1}> |
|
|
|
|
<TextField |
|
|
|
|
variant="outlined" |
|
|
|
|
value={props.integration.name || ""} |
|
|
|
|
label="Name" |
|
|
|
|
fullWidth |
|
|
|
|
disabled={!props.editing} |
|
|
|
|
onChange={(e: any) => props.onChange({ |
|
|
|
|
...props.integration, |
|
|
|
|
name: e.target.value, |
|
|
|
|
}, props.editing)} |
|
|
|
|
/> : |
|
|
|
|
<Typography>{props.integration.name}</Typography>} |
|
|
|
|
/> |
|
|
|
|
</Box> |
|
|
|
|
{props.integration.type === serverApi.IntegrationType.SpotifyClientCredentials && |
|
|
|
|
<EditSpotifyClientCredentialsDetails |
|
|
|
@ -104,6 +108,8 @@ function EditIntegration(props: EditIntegrationProps) { |
|
|
|
|
}, props.editing)} |
|
|
|
|
/> |
|
|
|
|
} |
|
|
|
|
</CardContent> |
|
|
|
|
<CardActions> |
|
|
|
|
{!props.editing && !props.submitting && <IconButton |
|
|
|
|
onClick={() => { props.onChange(props.integration, true); }} |
|
|
|
|
><EditIcon /></IconButton>} |
|
|
|
@ -117,7 +123,8 @@ function EditIntegration(props: EditIntegrationProps) { |
|
|
|
|
onClick={() => testSpotify(props.upstreamId || 0)} |
|
|
|
|
>Test</Button>} |
|
|
|
|
{props.submitting && <CircularProgress />} |
|
|
|
|
</Box > |
|
|
|
|
</CardActions> |
|
|
|
|
</Card> |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function AddIntegrationMenu(props: { |
|
|
|
@ -198,10 +205,11 @@ export default function IntegrationSettingsEditor(props: {}) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const deleteEditor = (state: EditorState) => { |
|
|
|
|
if (!state.upstreamId) { |
|
|
|
|
throw new Error('Cannot delete integration: has no upstream') |
|
|
|
|
} |
|
|
|
|
deleteIntegration(state.upstreamId).then((response: any) => { |
|
|
|
|
let promise: Promise<void> = state.upstreamId ?
|
|
|
|
|
deleteIntegration(state.upstreamId) : |
|
|
|
|
(async () => {})(); |
|
|
|
|
|
|
|
|
|
promise.then((response: any) => { |
|
|
|
|
let cpy = _.cloneDeep(editors).filter( |
|
|
|
|
(e: any) => e.id !== state.id |
|
|
|
|
); |
|
|
|
@ -225,13 +233,12 @@ export default function IntegrationSettingsEditor(props: {}) { |
|
|
|
|
}); |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
// FIXME: add button should show a drop-down to choose a fixed integration type.
|
|
|
|
|
// Otherwise we need dynamic switching of the type's fields.
|
|
|
|
|
return <> |
|
|
|
|
<Box> |
|
|
|
|
{editors === null && <CircularProgress />} |
|
|
|
|
{editors && <> |
|
|
|
|
{editors.map((state: EditorState) => <EditIntegration |
|
|
|
|
{editors && <Box display="flex" flexDirection="column" alignItems="center" flexWrap="wrap"> |
|
|
|
|
{editors.map((state: EditorState) => <Box m={1} width="90%"> |
|
|
|
|
<EditIntegration |
|
|
|
|
upstreamId={state.upstreamId} |
|
|
|
|
integration={state.integration} |
|
|
|
|
original={state.original} |
|
|
|
@ -276,11 +283,12 @@ export default function IntegrationSettingsEditor(props: {}) { |
|
|
|
|
setEditors(cpy); |
|
|
|
|
deleteEditor(state); |
|
|
|
|
}} |
|
|
|
|
/>)} |
|
|
|
|
/> |
|
|
|
|
</Box>)} |
|
|
|
|
<IconButton onClick={onOpenAddMenu}> |
|
|
|
|
<AddIcon /> |
|
|
|
|
</IconButton> |
|
|
|
|
</>} |
|
|
|
|
</Box>} |
|
|
|
|
</Box> |
|
|
|
|
<AddIntegrationMenu |
|
|
|
|
position={addMenuPos} |
|
|
|
|