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 }}>
|
||||
<Typography variant="body2">
|
||||
{formatMessage('app.connections', { count: countTranslation(Math.round(Math.random() * 100)) })}
|
||||
{formatMessage('app.connectionCount', { count: countTranslation(Math.round(Math.random() * 100)) })}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ px: 2 }}>
|
||||
<Typography variant="body2">
|
||||
{formatMessage('app.flows', { count: countTranslation(Math.round(Math.random() * 100)) })}
|
||||
{formatMessage('app.flowCount', { count: countTranslation(Math.round(Math.random() * 100)) })}
|
||||
</Typography>
|
||||
</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 FLOWS = '/flows';
|
||||
export const EXPLORE = '/explore';
|
||||
export const APP_PATH = (appSlug: string) => `/app/${appSlug}`;
|
||||
export const APP_PATH_PATTERN = '/app/:slug';
|
||||
export const APP = (appSlug: string) => `/app/${appSlug}`;
|
||||
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.apps": "My Apps",
|
||||
"drawer.explore": "Explore",
|
||||
"app.connections": "{count} connections",
|
||||
"app.flows": "{count} flows"
|
||||
"app.connectionCount": "{count} connections",
|
||||
"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 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 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 (
|
||||
<Box sx={{ py: 3 }}>
|
||||
<Container>
|
||||
<Grid container sx={{ mb: 3 }}>
|
||||
<Grid item xs={6}>
|
||||
<PageTitle>Application!</PageTitle>
|
||||
<>
|
||||
<Box sx={{ py: 3 }}>
|
||||
<Container>
|
||||
<Grid container sx={{ mb: 3 }}>
|
||||
<Grid item xs="auto" sx={{ mr: 1.5 }}>
|
||||
<AppIcon url={app.iconUrl} name={app.name} />
|
||||
</Grid>
|
||||
|
||||
<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 item xs={6} justifyContent="flex-end">
|
||||
<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>
|
||||
</Container>
|
||||
</Box>
|
||||
</Container>
|
||||
</Box>
|
||||
|
||||
<Route exact path={URLS.APP_ADD_CONNECTION_PATTERN}>
|
||||
<AddAppConnection onClose={goToApplicationPage} />
|
||||
</Route>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@@ -33,7 +33,7 @@ export default function Applications() {
|
||||
</Grid>
|
||||
|
||||
{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>
|
||||
</Box>
|
||||
|
@@ -24,7 +24,7 @@ export default (
|
||||
<Explore />
|
||||
</Route>
|
||||
|
||||
<Route path={URLS.APP_PATH_PATTERN}>
|
||||
<Route path={URLS.APP_PATTERN}>
|
||||
<Application />
|
||||
</Route>
|
||||
|
||||
|
Reference in New Issue
Block a user