feat: Introduce adding a new app connection
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "lerna run --stream --scope=@*/{web,backend} dev",
|
"start": "lerna run --stream --scope=@*/{web,backend} dev",
|
||||||
"start:web": "lerna run --stream --scope @*/web start",
|
"start:web": "lerna run --stream --scope @*/web dev",
|
||||||
"start:backend": "lerna run --stream --scope @*/backend dev"
|
"start:backend": "lerna run --stream --scope @*/backend dev"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
|
66
packages/web/src/components/AddNewAppConnection/index.tsx
Normal file
66
packages/web/src/components/AddNewAppConnection/index.tsx
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import { useQuery } from '@apollo/client';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import DialogTitle from '@mui/material/DialogTitle';
|
||||||
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
|
import Dialog from '@mui/material/Dialog';
|
||||||
|
import TextField from '@mui/material/TextField';
|
||||||
|
import SearchIcon from '@mui/icons-material/Search';
|
||||||
|
import InputAdornment from '@mui/material/InputAdornment';
|
||||||
|
import List from '@mui/material/List';
|
||||||
|
import ListItem from '@mui/material/ListItem';
|
||||||
|
import ListItemButton from '@mui/material/ListItemButton';
|
||||||
|
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||||
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
|
|
||||||
|
import * as URLS from 'config/urls';
|
||||||
|
import AppIcon from 'components/AppIcon';
|
||||||
|
import type { App } from 'types/app';
|
||||||
|
import { GET_APPS } from 'graphql/queries/get-apps';
|
||||||
|
import useFormatMessage from 'hooks/useFormatMessage';
|
||||||
|
|
||||||
|
type AddNewAppConnectionProps = {
|
||||||
|
onClose: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AddNewAppConnection(props: AddNewAppConnectionProps){
|
||||||
|
const { onClose } = props;
|
||||||
|
const formatMessage = useFormatMessage();
|
||||||
|
const [appName, setAppName] = useState<string | null>(null);
|
||||||
|
const { data } = useQuery(GET_APPS, { variables: {name: appName } });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={true} onClose={onClose} maxWidth="sm" fullWidth>
|
||||||
|
<DialogTitle>{formatMessage('apps.addNewAppConnection')}</DialogTitle>
|
||||||
|
|
||||||
|
<DialogContent>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
variant="filled"
|
||||||
|
label={formatMessage('apps.searchApp')}
|
||||||
|
onChange={(event) => setAppName(event.target.value)}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<SearchIcon />
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<List>
|
||||||
|
{data?.getApps?.map((app: App) => (
|
||||||
|
<ListItem disablePadding key={app.name}>
|
||||||
|
<ListItemButton component={Link} to={URLS.APP_ADD_CONNECTION(app.name.toLowerCase())}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<AppIcon color={app.primaryColor} url={app.iconUrl} name={app.name} />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText primary={app.name} />
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
@@ -14,7 +14,7 @@ type AppRowProps = {
|
|||||||
application: App;
|
application: App;
|
||||||
}
|
}
|
||||||
|
|
||||||
const countTranslation = (value: React.ReactNode) => (<><strong>{value}</strong><DesktopOnlyBreakline /></>);
|
const countTranslation = (value: React.ReactNode) => (<><strong>{value}</strong><br /></>);
|
||||||
|
|
||||||
function AppRow(props: AppRowProps) {
|
function AppRow(props: AppRowProps) {
|
||||||
const formatMessage = useFormatMessage();
|
const formatMessage = useFormatMessage();
|
||||||
|
@@ -20,7 +20,7 @@ export const Typography = styled(MuiTypography)(({ theme }) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
export const DesktopOnlyBreakline = styled('br')(({ theme }) => ({
|
export const DesktopOnlyBreakline = styled('br')(({ theme }) => ({
|
||||||
[theme.breakpoints.down('md')]: {
|
[theme.breakpoints.down('sm')]: {
|
||||||
display: 'none',
|
display: 'none',
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@@ -10,3 +10,5 @@ export const APP_ADD_CONNECTION = (appSlug: string) => `/app/${appSlug}/connecti
|
|||||||
export const APP_ADD_CONNECTION_PATTERN = '/app/:slug/connections/add';
|
export const APP_ADD_CONNECTION_PATTERN = '/app/:slug/connections/add';
|
||||||
export const APP_FLOWS = (appSlug: string) => `/app/${appSlug}/flows`;
|
export const APP_FLOWS = (appSlug: string) => `/app/${appSlug}/flows`;
|
||||||
export const APP_FLOWS_PATTERN = '/app/:slug/flows';
|
export const APP_FLOWS_PATTERN = '/app/:slug/flows';
|
||||||
|
|
||||||
|
export const NEW_APP_CONNECTION = '/apps/new';
|
11
packages/web/src/graphql/cache.ts
Normal file
11
packages/web/src/graphql/cache.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { InMemoryCache } from '@apollo/client';
|
||||||
|
|
||||||
|
const cache = new InMemoryCache({
|
||||||
|
typePolicies: {
|
||||||
|
App: {
|
||||||
|
keyFields: ['key']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default cache;
|
@@ -1,7 +1,7 @@
|
|||||||
import { ApolloClient, InMemoryCache } from '@apollo/client';
|
import { ApolloClient } from '@apollo/client';
|
||||||
|
import cache from './cache';
|
||||||
import appConfig from 'config/app';
|
import appConfig from 'config/app';
|
||||||
|
|
||||||
const cache = new InMemoryCache();
|
|
||||||
const client = new ApolloClient({
|
const client = new ApolloClient({
|
||||||
uri: appConfig.graphqlUrl,
|
uri: appConfig.graphqlUrl,
|
||||||
cache
|
cache
|
||||||
|
@@ -3,6 +3,7 @@ import { gql } from '@apollo/client';
|
|||||||
export const GET_APPS = gql`
|
export const GET_APPS = gql`
|
||||||
query GetApps($name: String) {
|
query GetApps($name: String) {
|
||||||
getApps(name: $name) {
|
getApps(name: $name) {
|
||||||
|
key
|
||||||
name
|
name
|
||||||
iconUrl
|
iconUrl
|
||||||
docUrl
|
docUrl
|
||||||
|
@@ -11,5 +11,9 @@
|
|||||||
"app.addConnection": "Add connection",
|
"app.addConnection": "Add connection",
|
||||||
"app.settings": "Settings",
|
"app.settings": "Settings",
|
||||||
"app.connections": "Connections",
|
"app.connections": "Connections",
|
||||||
"app.flows": "Flows"
|
"app.flows": "Flows",
|
||||||
|
"apps.title": "Apps",
|
||||||
|
"apps.addConnection": "Add connection",
|
||||||
|
"apps.addNewAppConnection": "Add a new app connection",
|
||||||
|
"apps.searchApp": "Search for app"
|
||||||
}
|
}
|
@@ -1,17 +1,23 @@
|
|||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
import { Link, Route, useHistory } from 'react-router-dom';
|
||||||
import { useQuery } from '@apollo/client';
|
import { useQuery } from '@apollo/client';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Grid from '@mui/material/Grid';
|
import Grid from '@mui/material/Grid';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
|
||||||
import Container from 'components/Container';
|
import Container from 'components/Container';
|
||||||
|
import AddNewAppConnection from 'components/AddNewAppConnection';
|
||||||
import PageTitle from 'components/PageTitle';
|
import PageTitle from 'components/PageTitle';
|
||||||
import AppRow from 'components/AppRow';
|
import AppRow from 'components/AppRow';
|
||||||
import SearchInput from 'components/SearchInput';
|
import SearchInput from 'components/SearchInput';
|
||||||
import * as URLS from 'config/urls';
|
import useFormatMessage from 'hooks/useFormatMessage'
|
||||||
import { GET_APPS } from 'graphql/queries/get-apps';
|
import { GET_APPS } from 'graphql/queries/get-apps';
|
||||||
|
import * as URLS from 'config/urls';
|
||||||
import type { App } from 'types/app';
|
import type { App } from 'types/app';
|
||||||
|
|
||||||
export default function Applications() {
|
export default function Applications() {
|
||||||
|
const history = useHistory();
|
||||||
|
const formatMessage = useFormatMessage();
|
||||||
const [appName, setAppName] = useState(null);
|
const [appName, setAppName] = useState(null);
|
||||||
const { data } = useQuery(GET_APPS, { variables: {name: appName } });
|
const { data } = useQuery(GET_APPS, { variables: {name: appName } });
|
||||||
|
|
||||||
@@ -19,22 +25,45 @@ export default function Applications() {
|
|||||||
setAppName(event.target.value);
|
setAppName(event.target.value);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const goToApps = useCallback(() => {
|
||||||
|
history.push(URLS.APPS);
|
||||||
|
}, [history]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ py: 3 }}>
|
<Box sx={{ py: 3 }}>
|
||||||
<Container>
|
<Container>
|
||||||
<Grid container sx={{ mb: 3 }}>
|
<Grid container sx={{ mb: 3 }} spacing={1}>
|
||||||
<Grid item xs={6}>
|
<Grid item xs={12} sm>
|
||||||
<PageTitle>Applications</PageTitle>
|
<PageTitle>{formatMessage('apps.title')}</PageTitle>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid container item xs={6} justifyContent="flex-end">
|
<Grid container item xs={12} sm="auto" justifyContent="flex-end" spacing={2}>
|
||||||
<SearchInput onChange={onSearchChange} />
|
<Grid item xs={12} sm="auto">
|
||||||
|
<SearchInput onChange={onSearchChange} />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm="auto">
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
component={Link}
|
||||||
|
to={URLS.NEW_APP_CONNECTION}
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
|
{formatMessage('apps.addConnection')}
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{data?.getApps?.map((app: App) => (
|
{data?.getApps?.map((app: App) => (
|
||||||
<AppRow key={app.name} application={app} />
|
<AppRow key={app.name} application={app} />
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
<Route exact path={URLS.NEW_APP_CONNECTION}>
|
||||||
|
<AddNewAppConnection onClose={goToApps} />
|
||||||
|
</Route>
|
||||||
</Container>
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@@ -16,7 +16,7 @@ export default (
|
|||||||
<Flows />
|
<Flows />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
<Route path={URLS.APPS}>
|
<Route path={[URLS.APPS, URLS.NEW_APP_CONNECTION]}>
|
||||||
<Applications />
|
<Applications />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user