diff --git a/packages/web/src/adminSettingsRoutes.tsx b/packages/web/src/adminSettingsRoutes.tsx index de392567..ae59a296 100644 --- a/packages/web/src/adminSettingsRoutes.tsx +++ b/packages/web/src/adminSettingsRoutes.tsx @@ -12,6 +12,7 @@ import UserInterface from 'pages/UserInterface'; import * as URLS from 'config/urls'; import Can from 'components/Can'; import AdminApplications from 'pages/AdminApplications'; +import AdminApplication from 'pages/AdminApplication'; // TODO: consider introducing redirections to `/` as fallback export default ( @@ -119,6 +120,17 @@ export default ( } /> + + + + + + } + /> + } diff --git a/packages/web/src/components/AdminApplicationSettings/index.tsx b/packages/web/src/components/AdminApplicationSettings/index.tsx new file mode 100644 index 00000000..515eac15 --- /dev/null +++ b/packages/web/src/components/AdminApplicationSettings/index.tsx @@ -0,0 +1,123 @@ +import { useMemo } from 'react'; +import useAppConfig from 'hooks/useAppConfig.ee'; +import useFormatMessage from 'hooks/useFormatMessage'; +import Divider from '@mui/material/Divider'; +import Paper from '@mui/material/Paper'; +import Stack from '@mui/material/Stack'; +import LoadingButton from '@mui/lab/LoadingButton'; +import { useMutation } from '@apollo/client'; +import { useSnackbar } from 'notistack'; + +import { CREATE_APP_CONFIG } from 'graphql/mutations/create-app-config'; +import { UPDATE_APP_CONFIG } from 'graphql/mutations/update-app-config'; + +import Form from 'components/Form'; +import { Switch } from './style'; + +type AdminApplicationSettingsProps = { + appKey: string; +}; + +function AdminApplicationSettings( + props: AdminApplicationSettingsProps +): React.ReactElement { + const { appConfig, loading } = useAppConfig(props.appKey); + const [createAppConfig, { loading: loadingCreateAppConfig }] = useMutation( + CREATE_APP_CONFIG, + { + refetchQueries: ['GetAppConfig'], + } + ); + const [updateAppConfig, { loading: loadingUpdateAppConfig }] = useMutation( + UPDATE_APP_CONFIG, + { + refetchQueries: ['GetAppConfig'], + } + ); + + const formatMessage = useFormatMessage(); + const { enqueueSnackbar } = useSnackbar(); + + const handleSubmit = async (values: any) => { + try { + if (!appConfig) { + await createAppConfig({ + variables: { + input: { key: props.appKey, ...values }, + }, + }); + } else { + await updateAppConfig({ + variables: { + input: { id: appConfig.id, ...values }, + }, + }); + } + enqueueSnackbar(formatMessage('adminAppsSettings.successfullySaved'), { + variant: 'success', + }); + } catch (error) { + throw new Error('Failed while saving!'); + } + }; + + const defaultValues = useMemo( + () => ({ + allowCustomConnection: appConfig?.allowCustomConnection || false, + shared: appConfig?.shared || false, + disabled: appConfig?.disabled || false, + }), + [appConfig] + ); + + return ( +
( + + + + + + + + + + + + {formatMessage('adminAppsSettings.save')} + + + + )} + >
+ ); +} + +export default AdminApplicationSettings; diff --git a/packages/web/src/components/AdminApplicationSettings/style.ts b/packages/web/src/components/AdminApplicationSettings/style.ts new file mode 100644 index 00000000..a32940c1 --- /dev/null +++ b/packages/web/src/components/AdminApplicationSettings/style.ts @@ -0,0 +1,7 @@ +import { styled } from '@mui/material/styles'; +import SwitchBase from 'components/Switch'; + +export const Switch = styled(SwitchBase)` + justify-content: space-between; + margin: 0; +`; diff --git a/packages/web/src/components/Switch/index.tsx b/packages/web/src/components/Switch/index.tsx index c996675f..f5afd269 100644 --- a/packages/web/src/components/Switch/index.tsx +++ b/packages/web/src/components/Switch/index.tsx @@ -25,6 +25,7 @@ export default function Switch(props: SwitchProps): React.ReactElement { onChange, label, FormControlLabelProps, + className, ...switchProps } = props; @@ -45,6 +46,7 @@ export default function Switch(props: SwitchProps): React.ReactElement { }, }) => ( `${ADMIN_SETTINGS}/apps/${appKey}`; +export const ADMIN_APP_PATTERN = `${ADMIN_SETTINGS}/apps/:appKey`; +export const ADMIN_APP_SETTINGS_PATTERN = `${ADMIN_SETTINGS}/apps/:appKey/settings`; +export const ADMIN_APP_AUTH_CLIENTS_PATTERN = `${ADMIN_SETTINGS}/apps/:appKey/auth-clients`; +export const ADMIN_APP_CONNECTIONS_PATTERN = `${ADMIN_SETTINGS}/apps/:appKey/connections`; +export const ADMIN_APP_CONNECTIONS = (appKey: string) => + `${ADMIN_SETTINGS}/apps/${appKey}/connections`; +export const ADMIN_APP_SETTINGS = (appKey: string) => + `${ADMIN_SETTINGS}/apps/${appKey}/settings`; +export const ADMIN_APP_AUTH_CLIENTS = (appKey: string) => + `${ADMIN_SETTINGS}/apps/${appKey}/auth-clients`; export const DASHBOARD = FLOWS; diff --git a/packages/web/src/graphql/mutations/create-app-config.ts b/packages/web/src/graphql/mutations/create-app-config.ts new file mode 100644 index 00000000..46c0c742 --- /dev/null +++ b/packages/web/src/graphql/mutations/create-app-config.ts @@ -0,0 +1,13 @@ +import { gql } from '@apollo/client'; + +export const CREATE_APP_CONFIG = gql` + mutation CreateAppConfig($input: CreateAppConfigInput) { + createAppConfig(input: $input) { + id + key + allowCustomConnection + shared + disabled + } + } +`; diff --git a/packages/web/src/graphql/mutations/update-app-config.ts b/packages/web/src/graphql/mutations/update-app-config.ts new file mode 100644 index 00000000..5bdcbc36 --- /dev/null +++ b/packages/web/src/graphql/mutations/update-app-config.ts @@ -0,0 +1,13 @@ +import { gql } from '@apollo/client'; + +export const UPDATE_APP_CONFIG = gql` + mutation UpdateAppConfig($input: UpdateAppConfigInput) { + updateAppConfig(input: $input) { + id + key + allowCustomConnection + shared + disabled + } + } +`; diff --git a/packages/web/src/locales/en.json b/packages/web/src/locales/en.json index b9f9ec93..0931fe67 100644 --- a/packages/web/src/locales/en.json +++ b/packages/web/src/locales/en.json @@ -248,5 +248,13 @@ "roleMappingsForm.save": "Save", "roleMappingsForm.notFound": "No role mappings have found.", "roleMappingsForm.successfullySaved": "Role mappings have been saved.", - "adminApps.title": "Apps" + "adminApps.title": "Apps", + "adminApps.connections": "Connections", + "adminApps.authClients": "Auth clients", + "adminApps.settings": "Settings", + "adminAppsSettings.allowCustomConnection": "Allow custom connection", + "adminAppsSettings.shared": "Shared", + "adminAppsSettings.disabled": "Disabled", + "adminAppsSettings.save": "Save", + "adminAppsSettings.successfullySaved": "Settings have been saved." } diff --git a/packages/web/src/pages/AdminApplication/index.tsx b/packages/web/src/pages/AdminApplication/index.tsx new file mode 100644 index 00000000..7b567ad9 --- /dev/null +++ b/packages/web/src/pages/AdminApplication/index.tsx @@ -0,0 +1,129 @@ +import * as React from 'react'; +import { useQuery } from '@apollo/client'; +import { + Link, + Route, + Navigate, + Routes, + useParams, + useMatch, +} from 'react-router-dom'; +import { useTheme } from '@mui/material/styles'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import Box from '@mui/material/Box'; +import Grid from '@mui/material/Grid'; +import Tabs from '@mui/material/Tabs'; +import Tab from '@mui/material/Tab'; + +import useFormatMessage from 'hooks/useFormatMessage'; +import { GET_APP } from 'graphql/queries/get-app'; +import * as URLS from 'config/urls'; + +import AppIcon from 'components/AppIcon'; +import Container from 'components/Container'; +import PageTitle from 'components/PageTitle'; +import AdminApplicationSettings from 'components/AdminApplicationSettings'; + +type AdminApplicationParams = { + appKey: string; +}; + +export default function AdminApplication(): React.ReactElement | null { + const theme = useTheme(); + const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md')); + const formatMessage = useFormatMessage(); + + const connectionsPathMatch = useMatch({ + path: URLS.ADMIN_APP_CONNECTIONS_PATTERN, + end: false, + }); + const settingsPathMatch = useMatch({ + path: URLS.ADMIN_APP_SETTINGS_PATTERN, + end: false, + }); + const authClientsPathMatch = useMatch({ + path: URLS.ADMIN_APP_AUTH_CLIENTS_PATTERN, + end: false, + }); + + const { appKey } = useParams() as AdminApplicationParams; + const { data, loading } = useQuery(GET_APP, { variables: { key: appKey } }); + + const app = data?.getApp || {}; + + if (loading) return null; + + return ( + + + + + + + + {app.name} + + + + + + + + + + + + + + } + /> + Auth clients} + /> + App connections} + /> + + } + /> + + + + + + ); +}