feat: Extend apps with further data
This commit is contained in:
@@ -7,7 +7,7 @@ const queryType = new GraphQLObjectType({
|
|||||||
name: 'Query',
|
name: 'Query',
|
||||||
fields: {
|
fields: {
|
||||||
getApps: {
|
getApps: {
|
||||||
type: GraphQLList(GraphQLString),
|
type: GraphQLList(appType),
|
||||||
args: {
|
args: {
|
||||||
name: { type: GraphQLString }
|
name: { type: GraphQLString }
|
||||||
},
|
},
|
||||||
|
@@ -7,6 +7,7 @@ const appType = new GraphQLObjectType({
|
|||||||
name: { type: GraphQLString },
|
name: { type: GraphQLString },
|
||||||
iconUrl: { type: GraphQLString },
|
iconUrl: { type: GraphQLString },
|
||||||
docUrl: { type: GraphQLString },
|
docUrl: { type: GraphQLString },
|
||||||
|
primaryColor: { type: GraphQLString },
|
||||||
fields: { type: GraphQLList(fieldType) }
|
fields: { type: GraphQLList(fieldType) }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -1,12 +1,15 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
static folderPath = __dirname + '/../apps'
|
static folderPath = __dirname + '/../apps';
|
||||||
static list = fs.readdirSync(this.folderPath);
|
static list = fs.readdirSync(this.folderPath);
|
||||||
|
|
||||||
static findAll(name?: string): string[] {
|
static findAll(name?: string): object[] {
|
||||||
if(!name) return this.list;
|
if(!name) return this.list.map((name) => this.findOneByName(name));
|
||||||
return this.list.filter((app) => app.includes(name.toLowerCase()));
|
|
||||||
|
return this.list
|
||||||
|
.filter((app) => app.includes(name.toLowerCase()))
|
||||||
|
.map((name) => this.findOneByName(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
static findOneByName(name: string): object {
|
static findOneByName(name: string): object {
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
"graphql": "^15.6.0",
|
"graphql": "^15.6.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
"react-hook-form": "^7.17.2",
|
||||||
"react-intl": "^5.20.12",
|
"react-intl": "^5.20.12",
|
||||||
"react-router-dom": "^5.3.0",
|
"react-router-dom": "^5.3.0",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
|
@@ -2,13 +2,16 @@ import DialogTitle from '@mui/material/DialogTitle';
|
|||||||
import DialogContent from '@mui/material/DialogContent';
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
import DialogContentText from '@mui/material/DialogContentText';
|
import DialogContentText from '@mui/material/DialogContentText';
|
||||||
import Dialog from '@mui/material/Dialog';
|
import Dialog from '@mui/material/Dialog';
|
||||||
|
import type { App } from 'types/app';
|
||||||
|
|
||||||
type AddAppConnectionProps = {
|
type AddAppConnectionProps = {
|
||||||
onClose: (value: string) => void;
|
onClose: (value: string) => void;
|
||||||
|
application: App;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function AddAppConnection(props: AddAppConnectionProps){
|
export default function AddAppConnection(props: AddAppConnectionProps){
|
||||||
const { onClose } = props;
|
const { application, onClose } = props;
|
||||||
|
const { name } = application;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={true} onClose={onClose}>
|
<Dialog open={true} onClose={onClose}>
|
||||||
@@ -16,7 +19,7 @@ export default function AddAppConnection(props: AddAppConnectionProps){
|
|||||||
|
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText tabIndex={-1}>
|
<DialogContentText tabIndex={-1}>
|
||||||
Here comes the "add connection" dialog
|
Add a connection to {name}
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
@@ -7,9 +7,9 @@ type AppIconProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function AppIcon(props: AppIconProps) {
|
export default function AppIcon(props: AppIconProps) {
|
||||||
const { color = '#00adef', name, url } = props;
|
const { color, name, url } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Avatar component="span" variant="square" sx={{ bgcolor: color }} src={url} alt={name} />
|
<Avatar component="span" variant="square" sx={{ bgcolor: `#${color}` }} src={url} alt={name} />
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,36 +1,32 @@
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import Card from '@mui/material/Card';
|
import Card from '@mui/material/Card';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Avatar from '@mui/material/Avatar';
|
|
||||||
import CardActionArea from '@mui/material/CardActionArea';
|
import CardActionArea from '@mui/material/CardActionArea';
|
||||||
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
||||||
|
|
||||||
import useFormatMessage from 'hooks/useFormatMessage';
|
import useFormatMessage from 'hooks/useFormatMessage';
|
||||||
|
import AppIcon from 'components/AppIcon';
|
||||||
|
import * as URLS from 'config/urls';
|
||||||
|
import type { App } from 'types/app';
|
||||||
import { CardContent, Typography, DesktopOnlyBreakline } from './style';
|
import { CardContent, Typography, DesktopOnlyBreakline } from './style';
|
||||||
|
|
||||||
type AppRowProps = {
|
type AppRowProps = {
|
||||||
icon?: React.ReactNode;
|
application: App;
|
||||||
name: string;
|
|
||||||
connectionNumber?: number;
|
|
||||||
flowNumber?: number;
|
|
||||||
to: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const countTranslation = (value: React.ReactNode) => (<><strong>{value}</strong><DesktopOnlyBreakline /></>);
|
const countTranslation = (value: React.ReactNode) => (<><strong>{value}</strong><DesktopOnlyBreakline /></>);
|
||||||
|
|
||||||
function AppRow(props: AppRowProps) {
|
function AppRow(props: AppRowProps) {
|
||||||
const formatMessage = useFormatMessage();
|
const formatMessage = useFormatMessage();
|
||||||
const { name, to } = props;
|
const { name, primaryColor, iconUrl } = props.application;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link to={to}>
|
<Link to={URLS.APP(name.toLowerCase())}>
|
||||||
<Card sx={{ my: 2 }}>
|
<Card sx={{ my: 2 }}>
|
||||||
<CardActionArea>
|
<CardActionArea>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Box>
|
<Box>
|
||||||
<Avatar variant="square">
|
<AppIcon name={name} url={iconUrl} color={primaryColor} />
|
||||||
{name[0].toUpperCase()}
|
|
||||||
</Avatar>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
|
20
packages/web/src/components/TextField/index.tsx
Normal file
20
packages/web/src/components/TextField/index.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Controller, Control, FieldValues } from "react-hook-form";
|
||||||
|
import MuiTextField from "@mui/material/TextField";
|
||||||
|
|
||||||
|
type TextFieldProps = {
|
||||||
|
control: Control<FieldValues>;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function TextField({ control, name }: TextFieldProps) {
|
||||||
|
return (
|
||||||
|
<Controller
|
||||||
|
name="MyCheckbox"
|
||||||
|
control={control}
|
||||||
|
defaultValue={false}
|
||||||
|
rules={{ required: true }}
|
||||||
|
render={({ field }) => <MuiTextField {...field} />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@@ -6,6 +6,7 @@ export const GET_APP = gql`
|
|||||||
name
|
name
|
||||||
iconUrl
|
iconUrl
|
||||||
docUrl
|
docUrl
|
||||||
|
primaryColor
|
||||||
fields {
|
fields {
|
||||||
key
|
key
|
||||||
label
|
label
|
||||||
|
@@ -2,6 +2,22 @@ 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) {
|
||||||
|
name
|
||||||
|
iconUrl
|
||||||
|
docUrl
|
||||||
|
primaryColor
|
||||||
|
fields {
|
||||||
|
key
|
||||||
|
label
|
||||||
|
type
|
||||||
|
required
|
||||||
|
readOnly
|
||||||
|
placeholder
|
||||||
|
description
|
||||||
|
docUrl
|
||||||
|
clickToCopy
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
@@ -38,7 +38,7 @@ export default function Application() {
|
|||||||
<Container>
|
<Container>
|
||||||
<Grid container sx={{ mb: 3 }}>
|
<Grid container sx={{ mb: 3 }}>
|
||||||
<Grid item xs="auto" sx={{ mr: 1.5 }}>
|
<Grid item xs="auto" sx={{ mr: 1.5 }}>
|
||||||
<AppIcon url={app.iconUrl} name={app.name} />
|
<AppIcon url={app.iconUrl} color={app.primaryColor} name={app.name} />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs>
|
<Grid item xs>
|
||||||
@@ -95,7 +95,7 @@ export default function Application() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Route exact path={URLS.APP_ADD_CONNECTION_PATTERN}>
|
<Route exact path={URLS.APP_ADD_CONNECTION_PATTERN}>
|
||||||
<AddAppConnection onClose={goToApplicationPage} />
|
<AddAppConnection onClose={goToApplicationPage} application={app} />
|
||||||
</Route>
|
</Route>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@@ -8,8 +8,8 @@ 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 * as URLS from 'config/urls';
|
||||||
|
|
||||||
import { GET_APPS } from 'graphql/queries/get-apps';
|
import { GET_APPS } from 'graphql/queries/get-apps';
|
||||||
|
import type { App } from 'types/app';
|
||||||
|
|
||||||
export default function Applications() {
|
export default function Applications() {
|
||||||
const [appName, setAppName] = useState(null);
|
const [appName, setAppName] = useState(null);
|
||||||
@@ -32,8 +32,8 @@ export default function Applications() {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{data?.getApps?.map((name: string) => (
|
{data?.getApps?.map((app: App) => (
|
||||||
<AppRow key={name} name={name} to={URLS.APP(name)} />
|
<AppRow key={app.name} application={app} />
|
||||||
))}
|
))}
|
||||||
</Container>
|
</Container>
|
||||||
</Box>
|
</Box>
|
||||||
|
21
packages/web/src/types/app.ts
Normal file
21
packages/web/src/types/app.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
type AppFields = {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
type: string;
|
||||||
|
required: boolean,
|
||||||
|
readOnly: boolean,
|
||||||
|
placeholder: string;
|
||||||
|
description: string;
|
||||||
|
docUrl: string;
|
||||||
|
clickToCopy: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
type App = {
|
||||||
|
name: string;
|
||||||
|
iconUrl: string;
|
||||||
|
docUrl: string;
|
||||||
|
primaryColor: string;
|
||||||
|
fields: AppFields;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type { App, AppFields };
|
@@ -12953,6 +12953,11 @@ react-error-overlay@^6.0.9:
|
|||||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
|
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
|
||||||
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
|
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
|
||||||
|
|
||||||
|
react-hook-form@^7.17.2:
|
||||||
|
version "7.17.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.17.2.tgz#235f15bb65c13e7a1198d33f2db24bcc9e27b303"
|
||||||
|
integrity sha512-oBaHwlYnbpzSFdNrs43QpcM+K2A0kUeNjV86ECYkCimlR1Ctl+tz4oQQd9plfGYkO7PJGLVMOVpUtL5EHjAcYQ==
|
||||||
|
|
||||||
react-intl@^5.20.12:
|
react-intl@^5.20.12:
|
||||||
version "5.20.12"
|
version "5.20.12"
|
||||||
resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-5.20.12.tgz#1a4969d15c381378cae35912fa2ec7010e27b4f7"
|
resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-5.20.12.tgz#1a4969d15c381378cae35912fa2ec7010e27b4f7"
|
||||||
|
Reference in New Issue
Block a user