feat: Extend App pages with tabs and data
This commit is contained in:
24
packages/web/src/components/AddAppConnection/index.tsx
Normal file
24
packages/web/src/components/AddAppConnection/index.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import DialogTitle from '@mui/material/DialogTitle';
|
||||||
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
|
import DialogContentText from '@mui/material/DialogContentText';
|
||||||
|
import Dialog from '@mui/material/Dialog';
|
||||||
|
|
||||||
|
type AddAppConnectionProps = {
|
||||||
|
onClose: (value: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AddAppConnection(props: AddAppConnectionProps){
|
||||||
|
const { onClose } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={true} onClose={onClose}>
|
||||||
|
<DialogTitle>Add connection</DialogTitle>
|
||||||
|
|
||||||
|
<DialogContent>
|
||||||
|
<DialogContentText tabIndex={-1}>
|
||||||
|
Here comes the "add connection" dialog
|
||||||
|
</DialogContentText>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
15
packages/web/src/components/AppIcon/index.tsx
Normal file
15
packages/web/src/components/AppIcon/index.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import Avatar from '@mui/material/Avatar';
|
||||||
|
|
||||||
|
type AppIconProps = {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
color?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AppIcon(props: AppIconProps) {
|
||||||
|
const { color = '#00adef', name, url } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Avatar component="span" variant="square" sx={{ bgcolor: color }} src={url} alt={name} />
|
||||||
|
);
|
||||||
|
};
|
@@ -41,13 +41,13 @@ function AppRow(props: AppRowProps) {
|
|||||||
|
|
||||||
<Box sx={{ px: 2 }}>
|
<Box sx={{ px: 2 }}>
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">
|
||||||
{formatMessage('app.connections', { count: countTranslation(Math.round(Math.random() * 100)) })}
|
{formatMessage('app.connectionCount', { count: countTranslation(Math.round(Math.random() * 100)) })}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box sx={{ px: 2 }}>
|
<Box sx={{ px: 2 }}>
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">
|
||||||
{formatMessage('app.flows', { count: countTranslation(Math.round(Math.random() * 100)) })}
|
{formatMessage('app.flowCount', { count: countTranslation(Math.round(Math.random() * 100)) })}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
19
packages/web/src/components/TabPanel/index.tsx
Normal file
19
packages/web/src/components/TabPanel/index.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
interface TabPanelProps {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
index: number;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function TabPanel(props: TabPanelProps) {
|
||||||
|
const { children, value, index, ...other } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role="tabpanel"
|
||||||
|
hidden={value !== index}
|
||||||
|
{...other}
|
||||||
|
>
|
||||||
|
{value === index && children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@@ -2,5 +2,11 @@ export const DASHBOARD = '/dashboard';
|
|||||||
export const APPS = '/apps';
|
export const APPS = '/apps';
|
||||||
export const FLOWS = '/flows';
|
export const FLOWS = '/flows';
|
||||||
export const EXPLORE = '/explore';
|
export const EXPLORE = '/explore';
|
||||||
export const APP_PATH = (appSlug: string) => `/app/${appSlug}`;
|
export const APP = (appSlug: string) => `/app/${appSlug}`;
|
||||||
export const APP_PATH_PATTERN = '/app/:slug';
|
export const APP_PATTERN = '/app/:slug';
|
||||||
|
export const APP_CONNECTIONS = (appSlug: string) => `/app/${appSlug}/connections`;
|
||||||
|
export const APP_CONNECTIONS_PATTERN = '/app/:slug/connections';
|
||||||
|
export const APP_ADD_CONNECTION = (appSlug: string) => `/app/${appSlug}/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_PATTERN = '/app/:slug/flows';
|
||||||
|
22
packages/web/src/graphql/queries/get-app.ts
Normal file
22
packages/web/src/graphql/queries/get-app.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
export const GET_APP = gql`
|
||||||
|
query GetApp($name: String!) {
|
||||||
|
getApp (name: $name) {
|
||||||
|
name
|
||||||
|
iconUrl
|
||||||
|
docUrl
|
||||||
|
fields {
|
||||||
|
key
|
||||||
|
label
|
||||||
|
type
|
||||||
|
required
|
||||||
|
readOnly
|
||||||
|
placeholder
|
||||||
|
description
|
||||||
|
docUrl
|
||||||
|
clickToCopy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
@@ -6,6 +6,10 @@
|
|||||||
"drawer.flows": "Flows",
|
"drawer.flows": "Flows",
|
||||||
"drawer.apps": "My Apps",
|
"drawer.apps": "My Apps",
|
||||||
"drawer.explore": "Explore",
|
"drawer.explore": "Explore",
|
||||||
"app.connections": "{count} connections",
|
"app.connectionCount": "{count} connections",
|
||||||
"app.flows": "{count} flows"
|
"app.flowCount": "{count} flows",
|
||||||
|
"app.addConnection": "Add connection",
|
||||||
|
"app.settings": "Settings",
|
||||||
|
"app.connections": "Connections",
|
||||||
|
"app.flows": "Flows"
|
||||||
}
|
}
|
@@ -1,26 +1,102 @@
|
|||||||
import { useCallback, useState } from 'react';
|
import { useQuery } from '@apollo/client';
|
||||||
|
import { Link, Route, Redirect, Switch, useParams, useRouteMatch, useHistory } from 'react-router-dom';
|
||||||
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 IconButton from '@mui/material/IconButton';
|
||||||
|
import Tabs from '@mui/material/Tabs';
|
||||||
|
import Tab from '@mui/material/Tab';
|
||||||
|
import SettingsIcon from '@mui/icons-material/Settings';
|
||||||
|
|
||||||
|
import useFormatMessage from 'hooks/useFormatMessage';
|
||||||
|
import { GET_APP } from 'graphql/queries/get-app';
|
||||||
|
import * as URLS from 'config/urls';
|
||||||
|
|
||||||
|
import AddAppConnection from 'components/AddAppConnection';
|
||||||
|
import AppIcon from 'components/AppIcon';
|
||||||
import Container from 'components/Container';
|
import Container from 'components/Container';
|
||||||
import PageTitle from 'components/PageTitle';
|
import PageTitle from 'components/PageTitle';
|
||||||
import SearchInput from 'components/SearchInput';
|
|
||||||
|
|
||||||
|
type ApplicationParams = {
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
|
||||||
export default function Applications() {
|
export default function Application() {
|
||||||
|
const formatMessage = useFormatMessage();
|
||||||
|
const routeMatch = useRouteMatch([URLS.APP_CONNECTIONS_PATTERN, URLS.APP_FLOWS_PATTERN, URLS.APP_PATTERN]);
|
||||||
|
const { slug } = useParams<ApplicationParams>();
|
||||||
|
const history = useHistory();
|
||||||
|
const { data } = useQuery(GET_APP, { variables: { name: slug } });
|
||||||
|
|
||||||
|
const app = data?.getApp || {};
|
||||||
|
|
||||||
|
const goToApplicationPage = () => history.push(URLS.APP(slug));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<Box sx={{ py: 3 }}>
|
<Box sx={{ py: 3 }}>
|
||||||
<Container>
|
<Container>
|
||||||
<Grid container sx={{ mb: 3 }}>
|
<Grid container sx={{ mb: 3 }}>
|
||||||
<Grid item xs={6}>
|
<Grid item xs="auto" sx={{ mr: 1.5 }}>
|
||||||
<PageTitle>Application!</PageTitle>
|
<AppIcon url={app.iconUrl} name={app.name} />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid container item xs={6} justifyContent="flex-end">
|
<Grid item xs>
|
||||||
|
<PageTitle>{app.name}</PageTitle>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs="auto" justifyContent="flex-end">
|
||||||
|
<IconButton sx={{ mr: 2 }} title={formatMessage('app.settings')}>
|
||||||
|
<SettingsIcon />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<Button variant="contained" component={Link} to={URLS.APP_ADD_CONNECTION(slug)}>
|
||||||
|
{formatMessage('app.addConnection')}
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs>
|
||||||
|
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 2 }}>
|
||||||
|
<Tabs value={routeMatch?.path}>
|
||||||
|
<Tab
|
||||||
|
label={formatMessage('app.connections')}
|
||||||
|
to={URLS.APP_CONNECTIONS(slug)}
|
||||||
|
value={URLS.APP_CONNECTIONS_PATTERN}
|
||||||
|
component={Link}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
label={formatMessage('app.flows')}
|
||||||
|
to={URLS.APP_FLOWS(slug)}
|
||||||
|
value={URLS.APP_FLOWS_PATTERN}
|
||||||
|
component={Link}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Switch>
|
||||||
|
<Route path={URLS.APP_FLOWS_PATTERN}>
|
||||||
|
Flows come here.
|
||||||
|
</Route>
|
||||||
|
|
||||||
|
<Route path={URLS.APP_CONNECTIONS_PATTERN}>
|
||||||
|
Connections come here.
|
||||||
|
</Route>
|
||||||
|
|
||||||
|
<Route exact path={URLS.APP_PATTERN}>
|
||||||
|
<Redirect to={URLS.APP_CONNECTIONS(slug)} />
|
||||||
|
</Route>
|
||||||
|
</Switch>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Container>
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
<Route exact path={URLS.APP_ADD_CONNECTION_PATTERN}>
|
||||||
|
<AddAppConnection onClose={goToApplicationPage} />
|
||||||
|
</Route>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -33,7 +33,7 @@ export default function Applications() {
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{data?.getApps?.map((name: string) => (
|
{data?.getApps?.map((name: string) => (
|
||||||
<AppRow key={name} name={name} to={URLS.APP_PATH(name)} />
|
<AppRow key={name} name={name} to={URLS.APP(name)} />
|
||||||
))}
|
))}
|
||||||
</Container>
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
|
@@ -24,7 +24,7 @@ export default (
|
|||||||
<Explore />
|
<Explore />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
<Route path={URLS.APP_PATH_PATTERN}>
|
<Route path={URLS.APP_PATTERN}>
|
||||||
<Application />
|
<Application />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user