mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	chore: adapt integrations layout for incoming webhooks (#5828)
https://linear.app/unleash/issue/2-1823/adapt-integrations-page-to-incoming-webhooks-tab-layout Adapts the current integrations page to the incoming webhooks feature, which includes things like: - Displaying both configured and available integrations in a single "page block" - Implement tabs - Add "Incoming Webhooks" integration card - Adapt the existing `IntegrationCard` component to support `onClick` This also includes a small girl scouting fix: Some tabs (like on the roles page) did not correctly reflect the active tab. ### `incomingWebhooks` disabled  ### `incomingWebhooks` enabled Notice the new "Incoming webhooks" tab and integration card. 
This commit is contained in:
		
							parent
							
								
									336eab9c5a
								
							
						
					
					
						commit
						10c3acd27d
					
				@ -15,6 +15,7 @@ import { PageHeader } from 'component/common/PageHeader/PageHeader';
 | 
				
			|||||||
import { Add } from '@mui/icons-material';
 | 
					import { Add } from '@mui/icons-material';
 | 
				
			||||||
import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
 | 
					import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
 | 
				
			||||||
import { IRole } from 'interfaces/role';
 | 
					import { IRole } from 'interfaces/role';
 | 
				
			||||||
 | 
					import { TabLink } from 'component/common/TabNav/TabLink';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledHeader = styled('div')(() => ({
 | 
					const StyledHeader = styled('div')(() => ({
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
@ -91,11 +92,9 @@ export const RolesPage = () => {
 | 
				
			|||||||
                                        key={label}
 | 
					                                        key={label}
 | 
				
			||||||
                                        value={path}
 | 
					                                        value={path}
 | 
				
			||||||
                                        label={
 | 
					                                        label={
 | 
				
			||||||
                                            <CenteredNavLink to={path}>
 | 
					                                            <TabLink to={path}>
 | 
				
			||||||
                                                <span>
 | 
					                                                {label} ({total})
 | 
				
			||||||
                                                    {label} ({total})
 | 
					                                            </TabLink>
 | 
				
			||||||
                                                </span>
 | 
					 | 
				
			||||||
                                            </CenteredNavLink>
 | 
					 | 
				
			||||||
                                        }
 | 
					                                        }
 | 
				
			||||||
                                        sx={{ padding: 0 }}
 | 
					                                        sx={{ padding: 0 }}
 | 
				
			||||||
                                    />
 | 
					                                    />
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										25
									
								
								frontend/src/component/common/TabNav/TabLink.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								frontend/src/component/common/TabNav/TabLink.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import { styled } from '@mui/material';
 | 
				
			||||||
 | 
					import { FC } from 'react';
 | 
				
			||||||
 | 
					import { Link } from 'react-router-dom';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledTabLink = styled(Link)(({ theme }) => ({
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    justifyContent: 'center',
 | 
				
			||||||
 | 
					    alignItems: 'center',
 | 
				
			||||||
 | 
					    width: '100%',
 | 
				
			||||||
 | 
					    height: '100%',
 | 
				
			||||||
 | 
					    textDecoration: 'none',
 | 
				
			||||||
 | 
					    color: 'inherit',
 | 
				
			||||||
 | 
					    padding: theme.spacing(0, 5),
 | 
				
			||||||
 | 
					    '&.active': {
 | 
				
			||||||
 | 
					        fontWeight: 'bold',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ICenteredTabLinkProps {
 | 
				
			||||||
 | 
					    to: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const TabLink: FC<ICenteredTabLinkProps> = ({ to, children }) => (
 | 
				
			||||||
 | 
					    <StyledTabLink to={to}>{children}</StyledTabLink>
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
@ -1,17 +1,17 @@
 | 
				
			|||||||
import { type VFC } from 'react';
 | 
					import { type VFC } from 'react';
 | 
				
			||||||
import { Box, Typography, styled } from '@mui/material';
 | 
					import { Box, Typography, styled } from '@mui/material';
 | 
				
			||||||
import type { AddonTypeSchema } from 'openapi';
 | 
					import type { AddonTypeSchema } from 'openapi';
 | 
				
			||||||
import { PageContent } from 'component/common/PageContent/PageContent';
 | 
					 | 
				
			||||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
 | 
					 | 
				
			||||||
import { IntegrationCard } from '../IntegrationCard/IntegrationCard';
 | 
					import { IntegrationCard } from '../IntegrationCard/IntegrationCard';
 | 
				
			||||||
import { JIRA_INFO } from '../../ViewIntegration/JiraIntegration/JiraIntegration';
 | 
					import { JIRA_INFO } from '../../ViewIntegration/JiraIntegration/JiraIntegration';
 | 
				
			||||||
import { StyledCardsGrid } from '../IntegrationList.styles';
 | 
					import { StyledCardsGrid } from '../IntegrationList.styles';
 | 
				
			||||||
import { RequestIntegrationCard } from '../RequestIntegrationCard/RequestIntegrationCard';
 | 
					import { RequestIntegrationCard } from '../RequestIntegrationCard/RequestIntegrationCard';
 | 
				
			||||||
import { OFFICIAL_SDKS } from './SDKs';
 | 
					import { OFFICIAL_SDKS } from './SDKs';
 | 
				
			||||||
 | 
					import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
				
			||||||
 | 
					import { useUiFlag } from 'hooks/useUiFlag';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IAvailableIntegrationsProps {
 | 
					interface IAvailableIntegrationsProps {
 | 
				
			||||||
    providers: AddonTypeSchema[];
 | 
					    providers: AddonTypeSchema[];
 | 
				
			||||||
    loading?: boolean;
 | 
					    onNewIncomingWebhook: () => void;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledContainer = styled('div')(({ theme }) => ({
 | 
					const StyledContainer = styled('div')(({ theme }) => ({
 | 
				
			||||||
@ -53,219 +53,228 @@ const StyledGrayContainer = styled('div')(({ theme }) => ({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const AvailableIntegrations: VFC<IAvailableIntegrationsProps> = ({
 | 
					export const AvailableIntegrations: VFC<IAvailableIntegrationsProps> = ({
 | 
				
			||||||
    providers,
 | 
					    providers,
 | 
				
			||||||
    loading,
 | 
					    onNewIncomingWebhook,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
 | 
					    const incomingWebhooksEnabled = useUiFlag('incomingWebhooks');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const customProviders = [JIRA_INFO];
 | 
					    const customProviders = [JIRA_INFO];
 | 
				
			||||||
    const serverSdks = OFFICIAL_SDKS.filter((sdk) => sdk.type === 'server');
 | 
					    const serverSdks = OFFICIAL_SDKS.filter((sdk) => sdk.type === 'server');
 | 
				
			||||||
    const clientSdks = OFFICIAL_SDKS.filter((sdk) => sdk.type === 'client');
 | 
					    const clientSdks = OFFICIAL_SDKS.filter((sdk) => sdk.type === 'client');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <PageContent
 | 
					        <StyledContainer>
 | 
				
			||||||
            header={<PageHeader title='Integrations' secondary />}
 | 
					            <StyledSection>
 | 
				
			||||||
            isLoading={loading}
 | 
					                <div>
 | 
				
			||||||
        >
 | 
					                    <Typography component='h3' variant='h2'>
 | 
				
			||||||
            <StyledContainer>
 | 
					                        Unleash crafted
 | 
				
			||||||
                <StyledSection>
 | 
					                    </Typography>
 | 
				
			||||||
                    <StyledCardsGrid>
 | 
					                    <Typography variant='body2' color='text.secondary'>
 | 
				
			||||||
                        {providers
 | 
					                        Unleash is built to be extended. We have crafted
 | 
				
			||||||
                            ?.sort(
 | 
					                        integrations to make it easier for you to get started.
 | 
				
			||||||
                                (a, b) =>
 | 
					                    </Typography>
 | 
				
			||||||
                                    a.displayName?.localeCompare(
 | 
					                </div>
 | 
				
			||||||
                                        b.displayName,
 | 
					                <StyledCardsGrid>
 | 
				
			||||||
                                    ) || 0,
 | 
					                    {providers
 | 
				
			||||||
                            )
 | 
					                        ?.sort(
 | 
				
			||||||
                            .map(
 | 
					                            (a, b) =>
 | 
				
			||||||
 | 
					                                a.displayName?.localeCompare(b.displayName) ||
 | 
				
			||||||
 | 
					                                0,
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                        .map(
 | 
				
			||||||
 | 
					                            ({
 | 
				
			||||||
 | 
					                                name,
 | 
				
			||||||
 | 
					                                displayName,
 | 
				
			||||||
 | 
					                                description,
 | 
				
			||||||
 | 
					                                deprecated,
 | 
				
			||||||
 | 
					                            }) => (
 | 
				
			||||||
 | 
					                                <IntegrationCard
 | 
				
			||||||
 | 
					                                    key={name}
 | 
				
			||||||
 | 
					                                    icon={name}
 | 
				
			||||||
 | 
					                                    title={displayName || name}
 | 
				
			||||||
 | 
					                                    description={description}
 | 
				
			||||||
 | 
					                                    link={`/integrations/create/${name}`}
 | 
				
			||||||
 | 
					                                    deprecated={deprecated}
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                            ),
 | 
				
			||||||
 | 
					                        )}
 | 
				
			||||||
 | 
					                    <ConditionallyRender
 | 
				
			||||||
 | 
					                        condition={incomingWebhooksEnabled}
 | 
				
			||||||
 | 
					                        show={
 | 
				
			||||||
 | 
					                            <IntegrationCard
 | 
				
			||||||
 | 
					                                icon='webhook'
 | 
				
			||||||
 | 
					                                title='Incoming Webhooks'
 | 
				
			||||||
 | 
					                                description='Incoming Webhooks allow third party services to send observable events to Unleash.'
 | 
				
			||||||
 | 
					                                onClick={onNewIncomingWebhook}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    {/* TODO: sort providers from backend with custom providers */}
 | 
				
			||||||
 | 
					                    {customProviders?.map(
 | 
				
			||||||
 | 
					                        ({ name, displayName, description }) => (
 | 
				
			||||||
 | 
					                            <IntegrationCard
 | 
				
			||||||
 | 
					                                key={name}
 | 
				
			||||||
 | 
					                                icon={name}
 | 
				
			||||||
 | 
					                                title={displayName || name}
 | 
				
			||||||
 | 
					                                description={description}
 | 
				
			||||||
 | 
					                                link={`/integrations/view/${name}`}
 | 
				
			||||||
 | 
					                                configureActionText='Learn more'
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
 | 
					                    <RequestIntegrationCard />
 | 
				
			||||||
 | 
					                </StyledCardsGrid>
 | 
				
			||||||
 | 
					            </StyledSection>
 | 
				
			||||||
 | 
					            <StyledSection>
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <Typography component='h3' variant='h2'>
 | 
				
			||||||
 | 
					                        Performance and security
 | 
				
			||||||
 | 
					                    </Typography>
 | 
				
			||||||
 | 
					                    <Typography variant='body2' color='text.secondary'>
 | 
				
			||||||
 | 
					                        Connect Unleash to private, scalable, and distributed
 | 
				
			||||||
 | 
					                        relays.
 | 
				
			||||||
 | 
					                    </Typography>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <StyledCardsGrid>
 | 
				
			||||||
 | 
					                    <IntegrationCard
 | 
				
			||||||
 | 
					                        icon='unleash'
 | 
				
			||||||
 | 
					                        title='Unleash Edge'
 | 
				
			||||||
 | 
					                        description="Unleash Edge is built to help you scale Unleash. As a successor of Unleash Proxy it's even faster and more versatile."
 | 
				
			||||||
 | 
					                        link='/integrations/view/edge'
 | 
				
			||||||
 | 
					                        configureActionText='Learn more'
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <IntegrationCard
 | 
				
			||||||
 | 
					                        icon='unleash'
 | 
				
			||||||
 | 
					                        title='Unleash Proxy'
 | 
				
			||||||
 | 
					                        description='The Unleash Proxy is a lightweight, stateless proxy that sits between your Unleash client SDKs and the Unleash API.'
 | 
				
			||||||
 | 
					                        link='https://docs.getunleash.io/reference/unleash-proxy'
 | 
				
			||||||
 | 
					                        configureActionText='View documentation'
 | 
				
			||||||
 | 
					                        deprecated='Try Unleash Edge instead. It has all the features of Unleash Proxy and more.'
 | 
				
			||||||
 | 
					                        isExternal
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                </StyledCardsGrid>
 | 
				
			||||||
 | 
					            </StyledSection>
 | 
				
			||||||
 | 
					            <StyledSection>
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <Typography component='h3' variant='h2'>
 | 
				
			||||||
 | 
					                        Official SDKs
 | 
				
			||||||
 | 
					                    </Typography>
 | 
				
			||||||
 | 
					                    <Typography variant='body2' color='text.secondary'>
 | 
				
			||||||
 | 
					                        In order to connect your application to Unleash you will
 | 
				
			||||||
 | 
					                        need a client SDK (software developer kit) for your
 | 
				
			||||||
 | 
					                        programming language and an{' '}
 | 
				
			||||||
 | 
					                        <a
 | 
				
			||||||
 | 
					                            href='https://docs.getunleash.io/how-to/how-to-create-api-tokens'
 | 
				
			||||||
 | 
					                            target='_blank'
 | 
				
			||||||
 | 
					                            rel='noopener noreferrer'
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            API token
 | 
				
			||||||
 | 
					                        </a>
 | 
				
			||||||
 | 
					                    </Typography>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <StyledSdksSection>
 | 
				
			||||||
 | 
					                    <StyledSdksGroup>
 | 
				
			||||||
 | 
					                        <Box>
 | 
				
			||||||
 | 
					                            <Typography component='h4' variant='h4'>
 | 
				
			||||||
 | 
					                                Server-side SDKs
 | 
				
			||||||
 | 
					                            </Typography>
 | 
				
			||||||
 | 
					                            <Typography variant='body2' color='text.secondary'>
 | 
				
			||||||
 | 
					                                Server-side clients run on your server and
 | 
				
			||||||
 | 
					                                communicate directly with your Unleash instance.
 | 
				
			||||||
 | 
					                            </Typography>
 | 
				
			||||||
 | 
					                        </Box>
 | 
				
			||||||
 | 
					                        <StyledCardsGrid small>
 | 
				
			||||||
 | 
					                            {serverSdks?.map(
 | 
				
			||||||
                                ({
 | 
					                                ({
 | 
				
			||||||
                                    name,
 | 
					                                    name,
 | 
				
			||||||
                                    displayName,
 | 
					                                    displayName,
 | 
				
			||||||
                                    description,
 | 
					                                    description,
 | 
				
			||||||
                                    deprecated,
 | 
					                                    documentationUrl,
 | 
				
			||||||
                                }) => (
 | 
					                                }) => (
 | 
				
			||||||
                                    <IntegrationCard
 | 
					                                    <IntegrationCard
 | 
				
			||||||
                                        key={name}
 | 
					                                        key={name}
 | 
				
			||||||
                                        icon={name}
 | 
					                                        icon={name}
 | 
				
			||||||
                                        title={displayName || name}
 | 
					                                        title={displayName || name}
 | 
				
			||||||
                                        description={description}
 | 
					                                        description={description}
 | 
				
			||||||
                                        link={`/integrations/create/${name}`}
 | 
					                                        link={documentationUrl}
 | 
				
			||||||
                                        deprecated={deprecated}
 | 
					                                        configureActionText={
 | 
				
			||||||
 | 
					                                            'View documentation'
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        isExternal
 | 
				
			||||||
                                    />
 | 
					                                    />
 | 
				
			||||||
                                ),
 | 
					                                ),
 | 
				
			||||||
                            )}
 | 
					                            )}
 | 
				
			||||||
                        {/* TODO: sort providers from backend with custom providers */}
 | 
					                        </StyledCardsGrid>
 | 
				
			||||||
                        {customProviders?.map(
 | 
					                    </StyledSdksGroup>
 | 
				
			||||||
                            ({ name, displayName, description }) => (
 | 
					                    <StyledSdksGroup>
 | 
				
			||||||
                                <IntegrationCard
 | 
					                        <Box>
 | 
				
			||||||
                                    key={name}
 | 
					                            <Typography component='h4' variant='h4'>
 | 
				
			||||||
                                    icon={name}
 | 
					                                Client-side SDKs
 | 
				
			||||||
                                    title={displayName || name}
 | 
					                            </Typography>
 | 
				
			||||||
                                    description={description}
 | 
					                            <Typography variant='body2' color='text.secondary'>
 | 
				
			||||||
                                    link={`/integrations/view/${name}`}
 | 
					                                Client-side SDKs can connect to the{' '}
 | 
				
			||||||
                                    configureActionText='Learn more'
 | 
					                                <a
 | 
				
			||||||
                                />
 | 
					                                    href='https://docs.getunleash.io/reference/unleash-edge'
 | 
				
			||||||
                            ),
 | 
					                                    target='_blank'
 | 
				
			||||||
                        )}
 | 
					                                    rel='noopener noreferrer'
 | 
				
			||||||
                        <RequestIntegrationCard />
 | 
					 | 
				
			||||||
                    </StyledCardsGrid>
 | 
					 | 
				
			||||||
                </StyledSection>
 | 
					 | 
				
			||||||
                <StyledSection>
 | 
					 | 
				
			||||||
                    <div>
 | 
					 | 
				
			||||||
                        <Typography component='h3' variant='h2'>
 | 
					 | 
				
			||||||
                            Performance and security
 | 
					 | 
				
			||||||
                        </Typography>
 | 
					 | 
				
			||||||
                        <Typography variant='body2' color='text.secondary'>
 | 
					 | 
				
			||||||
                            Connect Unleash to private, scalable, and
 | 
					 | 
				
			||||||
                            distributed relays.
 | 
					 | 
				
			||||||
                        </Typography>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    <StyledCardsGrid>
 | 
					 | 
				
			||||||
                        <IntegrationCard
 | 
					 | 
				
			||||||
                            icon='unleash'
 | 
					 | 
				
			||||||
                            title='Unleash Edge'
 | 
					 | 
				
			||||||
                            description="Unleash Edge is built to help you scale Unleash. As a successor of Unleash Proxy it's even faster and more versatile."
 | 
					 | 
				
			||||||
                            link='/integrations/view/edge'
 | 
					 | 
				
			||||||
                            configureActionText='Learn more'
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                        <IntegrationCard
 | 
					 | 
				
			||||||
                            icon='unleash'
 | 
					 | 
				
			||||||
                            title='Unleash Proxy'
 | 
					 | 
				
			||||||
                            description='The Unleash Proxy is a lightweight, stateless proxy that sits between your Unleash client SDKs and the Unleash API.'
 | 
					 | 
				
			||||||
                            link='https://docs.getunleash.io/reference/unleash-proxy'
 | 
					 | 
				
			||||||
                            configureActionText='View documentation'
 | 
					 | 
				
			||||||
                            deprecated='Try Unleash Edge instead. It has all the features of Unleash Proxy and more.'
 | 
					 | 
				
			||||||
                            isExternal
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                    </StyledCardsGrid>
 | 
					 | 
				
			||||||
                </StyledSection>
 | 
					 | 
				
			||||||
                <StyledSection>
 | 
					 | 
				
			||||||
                    <div>
 | 
					 | 
				
			||||||
                        <Typography component='h3' variant='h2'>
 | 
					 | 
				
			||||||
                            Official SDKs
 | 
					 | 
				
			||||||
                        </Typography>
 | 
					 | 
				
			||||||
                        <Typography variant='body2' color='text.secondary'>
 | 
					 | 
				
			||||||
                            In order to connect your application to Unleash you
 | 
					 | 
				
			||||||
                            will need a client SDK (software developer kit) for
 | 
					 | 
				
			||||||
                            your programming language and an{' '}
 | 
					 | 
				
			||||||
                            <a
 | 
					 | 
				
			||||||
                                href='https://docs.getunleash.io/how-to/how-to-create-api-tokens'
 | 
					 | 
				
			||||||
                                target='_blank'
 | 
					 | 
				
			||||||
                                rel='noopener noreferrer'
 | 
					 | 
				
			||||||
                            >
 | 
					 | 
				
			||||||
                                API token
 | 
					 | 
				
			||||||
                            </a>
 | 
					 | 
				
			||||||
                        </Typography>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    <StyledSdksSection>
 | 
					 | 
				
			||||||
                        <StyledSdksGroup>
 | 
					 | 
				
			||||||
                            <Box>
 | 
					 | 
				
			||||||
                                <Typography component='h4' variant='h4'>
 | 
					 | 
				
			||||||
                                    Server-side SDKs
 | 
					 | 
				
			||||||
                                </Typography>
 | 
					 | 
				
			||||||
                                <Typography
 | 
					 | 
				
			||||||
                                    variant='body2'
 | 
					 | 
				
			||||||
                                    color='text.secondary'
 | 
					 | 
				
			||||||
                                >
 | 
					                                >
 | 
				
			||||||
                                    Server-side clients run on your server and
 | 
					                                    Unleash Edge
 | 
				
			||||||
                                    communicate directly with your Unleash
 | 
					                                </a>{' '}
 | 
				
			||||||
                                    instance.
 | 
					                                or to the{' '}
 | 
				
			||||||
                                </Typography>
 | 
					                                <a
 | 
				
			||||||
                            </Box>
 | 
					                                    href='https://docs.getunleash.io/reference/front-end-api'
 | 
				
			||||||
                            <StyledCardsGrid small>
 | 
					                                    target='_blank'
 | 
				
			||||||
                                {serverSdks?.map(
 | 
					                                    rel='noopener noreferrer'
 | 
				
			||||||
                                    ({
 | 
					 | 
				
			||||||
                                        name,
 | 
					 | 
				
			||||||
                                        displayName,
 | 
					 | 
				
			||||||
                                        description,
 | 
					 | 
				
			||||||
                                        documentationUrl,
 | 
					 | 
				
			||||||
                                    }) => (
 | 
					 | 
				
			||||||
                                        <IntegrationCard
 | 
					 | 
				
			||||||
                                            key={name}
 | 
					 | 
				
			||||||
                                            icon={name}
 | 
					 | 
				
			||||||
                                            title={displayName || name}
 | 
					 | 
				
			||||||
                                            description={description}
 | 
					 | 
				
			||||||
                                            link={documentationUrl}
 | 
					 | 
				
			||||||
                                            configureActionText={
 | 
					 | 
				
			||||||
                                                'View documentation'
 | 
					 | 
				
			||||||
                                            }
 | 
					 | 
				
			||||||
                                            isExternal
 | 
					 | 
				
			||||||
                                        />
 | 
					 | 
				
			||||||
                                    ),
 | 
					 | 
				
			||||||
                                )}
 | 
					 | 
				
			||||||
                            </StyledCardsGrid>
 | 
					 | 
				
			||||||
                        </StyledSdksGroup>
 | 
					 | 
				
			||||||
                        <StyledSdksGroup>
 | 
					 | 
				
			||||||
                            <Box>
 | 
					 | 
				
			||||||
                                <Typography component='h4' variant='h4'>
 | 
					 | 
				
			||||||
                                    Client-side SDKs
 | 
					 | 
				
			||||||
                                </Typography>
 | 
					 | 
				
			||||||
                                <Typography
 | 
					 | 
				
			||||||
                                    variant='body2'
 | 
					 | 
				
			||||||
                                    color='text.secondary'
 | 
					 | 
				
			||||||
                                >
 | 
					                                >
 | 
				
			||||||
                                    Client-side SDKs can connect to the{' '}
 | 
					                                    Unleash front-end API
 | 
				
			||||||
 | 
					                                </a>
 | 
				
			||||||
 | 
					                                , but not to the regular Unleash client API.
 | 
				
			||||||
 | 
					                            </Typography>
 | 
				
			||||||
 | 
					                        </Box>
 | 
				
			||||||
 | 
					                        <StyledCardsGrid small>
 | 
				
			||||||
 | 
					                            {clientSdks?.map(
 | 
				
			||||||
 | 
					                                ({
 | 
				
			||||||
 | 
					                                    name,
 | 
				
			||||||
 | 
					                                    displayName,
 | 
				
			||||||
 | 
					                                    description,
 | 
				
			||||||
 | 
					                                    documentationUrl,
 | 
				
			||||||
 | 
					                                }) => (
 | 
				
			||||||
 | 
					                                    <IntegrationCard
 | 
				
			||||||
 | 
					                                        key={name}
 | 
				
			||||||
 | 
					                                        icon={name}
 | 
				
			||||||
 | 
					                                        title={displayName || name}
 | 
				
			||||||
 | 
					                                        description={description}
 | 
				
			||||||
 | 
					                                        link={documentationUrl}
 | 
				
			||||||
 | 
					                                        configureActionText={
 | 
				
			||||||
 | 
					                                            'View documentation'
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        isExternal
 | 
				
			||||||
 | 
					                                    />
 | 
				
			||||||
 | 
					                                ),
 | 
				
			||||||
 | 
					                            )}
 | 
				
			||||||
 | 
					                        </StyledCardsGrid>
 | 
				
			||||||
 | 
					                    </StyledSdksGroup>
 | 
				
			||||||
 | 
					                    <StyledSdksGroup>
 | 
				
			||||||
 | 
					                        <StyledGrayContainer>
 | 
				
			||||||
 | 
					                            <div>
 | 
				
			||||||
 | 
					                                <Typography component='h4' variant='h3'>
 | 
				
			||||||
 | 
					                                    Community SDKs
 | 
				
			||||||
 | 
					                                </Typography>
 | 
				
			||||||
 | 
					                                <Typography>
 | 
				
			||||||
                                    <a
 | 
					                                    <a
 | 
				
			||||||
                                        href='https://docs.getunleash.io/reference/unleash-edge'
 | 
					                                        href='https://docs.getunleash.io/reference/sdks#community-sdks'
 | 
				
			||||||
                                        target='_blank'
 | 
					                                        target='_blank'
 | 
				
			||||||
                                        rel='noopener noreferrer'
 | 
					                                        rel='noopener noreferrer'
 | 
				
			||||||
                                    >
 | 
					                                    >
 | 
				
			||||||
                                        Unleash Edge
 | 
					                                        Here's some of the fantastic work
 | 
				
			||||||
                                    </a>{' '}
 | 
					                                    </a>{' '}
 | 
				
			||||||
                                    or to the{' '}
 | 
					                                    our community has built to make Unleash work
 | 
				
			||||||
                                    <a
 | 
					                                    in even more contexts.
 | 
				
			||||||
                                        href='https://docs.getunleash.io/reference/front-end-api'
 | 
					 | 
				
			||||||
                                        target='_blank'
 | 
					 | 
				
			||||||
                                        rel='noopener noreferrer'
 | 
					 | 
				
			||||||
                                    >
 | 
					 | 
				
			||||||
                                        Unleash front-end API
 | 
					 | 
				
			||||||
                                    </a>
 | 
					 | 
				
			||||||
                                    , but not to the regular Unleash client API.
 | 
					 | 
				
			||||||
                                </Typography>
 | 
					                                </Typography>
 | 
				
			||||||
                            </Box>
 | 
					                            </div>
 | 
				
			||||||
                            <StyledCardsGrid small>
 | 
					                        </StyledGrayContainer>
 | 
				
			||||||
                                {clientSdks?.map(
 | 
					                    </StyledSdksGroup>
 | 
				
			||||||
                                    ({
 | 
					                </StyledSdksSection>
 | 
				
			||||||
                                        name,
 | 
					            </StyledSection>
 | 
				
			||||||
                                        displayName,
 | 
					        </StyledContainer>
 | 
				
			||||||
                                        description,
 | 
					 | 
				
			||||||
                                        documentationUrl,
 | 
					 | 
				
			||||||
                                    }) => (
 | 
					 | 
				
			||||||
                                        <IntegrationCard
 | 
					 | 
				
			||||||
                                            key={name}
 | 
					 | 
				
			||||||
                                            icon={name}
 | 
					 | 
				
			||||||
                                            title={displayName || name}
 | 
					 | 
				
			||||||
                                            description={description}
 | 
					 | 
				
			||||||
                                            link={documentationUrl}
 | 
					 | 
				
			||||||
                                            configureActionText={
 | 
					 | 
				
			||||||
                                                'View documentation'
 | 
					 | 
				
			||||||
                                            }
 | 
					 | 
				
			||||||
                                            isExternal
 | 
					 | 
				
			||||||
                                        />
 | 
					 | 
				
			||||||
                                    ),
 | 
					 | 
				
			||||||
                                )}
 | 
					 | 
				
			||||||
                            </StyledCardsGrid>
 | 
					 | 
				
			||||||
                        </StyledSdksGroup>
 | 
					 | 
				
			||||||
                        <StyledSdksGroup>
 | 
					 | 
				
			||||||
                            <StyledGrayContainer>
 | 
					 | 
				
			||||||
                                <div>
 | 
					 | 
				
			||||||
                                    <Typography component='h4' variant='h3'>
 | 
					 | 
				
			||||||
                                        Community SDKs
 | 
					 | 
				
			||||||
                                    </Typography>
 | 
					 | 
				
			||||||
                                    <Typography>
 | 
					 | 
				
			||||||
                                        <a
 | 
					 | 
				
			||||||
                                            href='https://docs.getunleash.io/reference/sdks#community-sdks'
 | 
					 | 
				
			||||||
                                            target='_blank'
 | 
					 | 
				
			||||||
                                            rel='noopener noreferrer'
 | 
					 | 
				
			||||||
                                        >
 | 
					 | 
				
			||||||
                                            Here's some of the fantastic work
 | 
					 | 
				
			||||||
                                        </a>{' '}
 | 
					 | 
				
			||||||
                                        our community has built to make Unleash
 | 
					 | 
				
			||||||
                                        work in even more contexts.
 | 
					 | 
				
			||||||
                                    </Typography>
 | 
					 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                            </StyledGrayContainer>
 | 
					 | 
				
			||||||
                        </StyledSdksGroup>
 | 
					 | 
				
			||||||
                    </StyledSdksSection>
 | 
					 | 
				
			||||||
                </StyledSection>
 | 
					 | 
				
			||||||
            </StyledContainer>
 | 
					 | 
				
			||||||
        </PageContent>
 | 
					 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,16 @@
 | 
				
			|||||||
import { AddonSchema, AddonTypeSchema } from 'openapi';
 | 
					import { AddonSchema, AddonTypeSchema } from 'openapi';
 | 
				
			||||||
import useLoading from 'hooks/useLoading';
 | 
					import useLoading from 'hooks/useLoading';
 | 
				
			||||||
import { PageContent } from 'component/common/PageContent/PageContent';
 | 
					 | 
				
			||||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
 | 
					 | 
				
			||||||
import { StyledCardsGrid } from '../IntegrationList.styles';
 | 
					import { StyledCardsGrid } from '../IntegrationList.styles';
 | 
				
			||||||
import { IntegrationCard } from '../IntegrationCard/IntegrationCard';
 | 
					import { IntegrationCard } from '../IntegrationCard/IntegrationCard';
 | 
				
			||||||
import { VFC } from 'react';
 | 
					import { VFC } from 'react';
 | 
				
			||||||
 | 
					import { Typography, styled } from '@mui/material';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledConfiguredSection = styled('section')(({ theme }) => ({
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    flexDirection: 'column',
 | 
				
			||||||
 | 
					    gap: theme.spacing(2),
 | 
				
			||||||
 | 
					    marginBottom: theme.spacing(8),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ConfiguredIntegrationsProps = {
 | 
					type ConfiguredIntegrationsProps = {
 | 
				
			||||||
    loading: boolean;
 | 
					    loading: boolean;
 | 
				
			||||||
@ -17,15 +23,19 @@ export const ConfiguredIntegrations: VFC<ConfiguredIntegrationsProps> = ({
 | 
				
			|||||||
    addons,
 | 
					    addons,
 | 
				
			||||||
    providers,
 | 
					    providers,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
    const counter = addons.length ? `(${addons.length})` : '';
 | 
					 | 
				
			||||||
    const ref = useLoading(loading || false);
 | 
					    const ref = useLoading(loading || false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <PageContent
 | 
					        <StyledConfiguredSection>
 | 
				
			||||||
            header={<PageHeader title={`Configured integrations ${counter}`} />}
 | 
					            <div>
 | 
				
			||||||
            sx={(theme) => ({ marginBottom: theme.spacing(2) })}
 | 
					                <Typography component='h3' variant='h2'>
 | 
				
			||||||
            isLoading={loading}
 | 
					                    Configured integrations
 | 
				
			||||||
        >
 | 
					                </Typography>
 | 
				
			||||||
 | 
					                <Typography variant='body2' color='text.secondary'>
 | 
				
			||||||
 | 
					                    These are the integrations that are currently configured for
 | 
				
			||||||
 | 
					                    your Unleash instance.
 | 
				
			||||||
 | 
					                </Typography>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
            <StyledCardsGrid ref={ref}>
 | 
					            <StyledCardsGrid ref={ref}>
 | 
				
			||||||
                {addons
 | 
					                {addons
 | 
				
			||||||
                    ?.sort(({ id: a }, { id: b }) => a - b)
 | 
					                    ?.sort(({ id: a }, { id: b }) => a - b)
 | 
				
			||||||
@ -56,6 +66,6 @@ export const ConfiguredIntegrations: VFC<ConfiguredIntegrationsProps> = ({
 | 
				
			|||||||
                        );
 | 
					                        );
 | 
				
			||||||
                    })}
 | 
					                    })}
 | 
				
			||||||
            </StyledCardsGrid>
 | 
					            </StyledCardsGrid>
 | 
				
			||||||
        </PageContent>
 | 
					        </StyledConfiguredSection>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { VFC } from 'react';
 | 
					import { VFC } from 'react';
 | 
				
			||||||
import { Link } from 'react-router-dom';
 | 
					import { Link as RouterLink } from 'react-router-dom';
 | 
				
			||||||
import { styled, Tooltip, Typography } from '@mui/material';
 | 
					import { Link, styled, Tooltip, Typography } from '@mui/material';
 | 
				
			||||||
import { IntegrationIcon } from '../IntegrationIcon/IntegrationIcon';
 | 
					import { IntegrationIcon } from '../IntegrationIcon/IntegrationIcon';
 | 
				
			||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
					import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
				
			||||||
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
 | 
					import ChevronRightIcon from '@mui/icons-material/ChevronRight';
 | 
				
			||||||
@ -10,46 +10,56 @@ import type { AddonSchema } from 'openapi';
 | 
				
			|||||||
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
 | 
					import OpenInNewIcon from '@mui/icons-material/OpenInNew';
 | 
				
			||||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
 | 
					import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IIntegrationCardProps {
 | 
					interface IIntegrationCardBaseProps {
 | 
				
			||||||
    id?: string | number;
 | 
					    id?: string | number;
 | 
				
			||||||
    icon?: string;
 | 
					    icon?: string;
 | 
				
			||||||
    title: string;
 | 
					    title: string;
 | 
				
			||||||
    description?: string;
 | 
					    description?: string;
 | 
				
			||||||
    isEnabled?: boolean;
 | 
					    isEnabled?: boolean;
 | 
				
			||||||
    configureActionText?: string;
 | 
					    configureActionText?: string;
 | 
				
			||||||
    link: string;
 | 
					 | 
				
			||||||
    isExternal?: boolean;
 | 
					 | 
				
			||||||
    addon?: AddonSchema;
 | 
					    addon?: AddonSchema;
 | 
				
			||||||
    deprecated?: string;
 | 
					    deprecated?: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledLink = styled(Link)(({ theme }) => ({
 | 
					interface IIntegrationCardWithLinkProps extends IIntegrationCardBaseProps {
 | 
				
			||||||
 | 
					    link: string;
 | 
				
			||||||
 | 
					    isExternal?: boolean;
 | 
				
			||||||
 | 
					    onClick?: never;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IIntegrationCardWithOnClickProps extends IIntegrationCardBaseProps {
 | 
				
			||||||
 | 
					    link?: never;
 | 
				
			||||||
 | 
					    isExternal?: never;
 | 
				
			||||||
 | 
					    onClick: () => void;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type IIntegrationCardProps =
 | 
				
			||||||
 | 
					    | IIntegrationCardWithLinkProps
 | 
				
			||||||
 | 
					    | IIntegrationCardWithOnClickProps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledCard = styled('div')(({ theme }) => ({
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
    flexDirection: 'column',
 | 
					    flexDirection: 'column',
 | 
				
			||||||
    padding: theme.spacing(3),
 | 
					    padding: theme.spacing(3),
 | 
				
			||||||
 | 
					    height: '100%',
 | 
				
			||||||
    borderRadius: `${theme.shape.borderRadiusMedium}px`,
 | 
					    borderRadius: `${theme.shape.borderRadiusMedium}px`,
 | 
				
			||||||
    border: `1px solid ${theme.palette.divider}`,
 | 
					    border: `1px solid ${theme.palette.divider}`,
 | 
				
			||||||
    textDecoration: 'none',
 | 
					 | 
				
			||||||
    color: 'inherit',
 | 
					 | 
				
			||||||
    boxShadow: theme.boxShadows.card,
 | 
					    boxShadow: theme.boxShadows.card,
 | 
				
			||||||
    ':hover': {
 | 
					    ':hover': {
 | 
				
			||||||
        backgroundColor: theme.palette.action.hover,
 | 
					        backgroundColor: theme.palette.action.hover,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledAnchor = styled('a')(({ theme }) => ({
 | 
					const StyledLink = styled(Link)({
 | 
				
			||||||
    display: 'flex',
 | 
					 | 
				
			||||||
    flexDirection: 'column',
 | 
					 | 
				
			||||||
    padding: theme.spacing(3),
 | 
					 | 
				
			||||||
    borderRadius: `${theme.shape.borderRadiusMedium}px`,
 | 
					 | 
				
			||||||
    border: `1px solid ${theme.palette.divider}`,
 | 
					 | 
				
			||||||
    textDecoration: 'none',
 | 
					    textDecoration: 'none',
 | 
				
			||||||
    color: 'inherit',
 | 
					    color: 'inherit',
 | 
				
			||||||
    boxShadow: theme.boxShadows.card,
 | 
					    textAlign: 'left',
 | 
				
			||||||
    ':hover': {
 | 
					}) as typeof Link;
 | 
				
			||||||
        backgroundColor: theme.palette.action.hover,
 | 
					
 | 
				
			||||||
    },
 | 
					const StyledRouterLink = styled(RouterLink)({
 | 
				
			||||||
}));
 | 
					    textDecoration: 'none',
 | 
				
			||||||
 | 
					    color: 'inherit',
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledHeader = styled('div')(({ theme }) => ({
 | 
					const StyledHeader = styled('div')(({ theme }) => ({
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
@ -85,6 +95,7 @@ export const IntegrationCard: VFC<IIntegrationCardProps> = ({
 | 
				
			|||||||
    isEnabled,
 | 
					    isEnabled,
 | 
				
			||||||
    configureActionText = 'Configure',
 | 
					    configureActionText = 'Configure',
 | 
				
			||||||
    link,
 | 
					    link,
 | 
				
			||||||
 | 
					    onClick,
 | 
				
			||||||
    addon,
 | 
					    addon,
 | 
				
			||||||
    deprecated,
 | 
					    deprecated,
 | 
				
			||||||
    isExternal = false,
 | 
					    isExternal = false,
 | 
				
			||||||
@ -102,7 +113,7 @@ export const IntegrationCard: VFC<IIntegrationCardProps> = ({
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const content = (
 | 
					    const content = (
 | 
				
			||||||
        <>
 | 
					        <StyledCard>
 | 
				
			||||||
            <StyledHeader>
 | 
					            <StyledHeader>
 | 
				
			||||||
                <StyledTitle variant='h3' data-loading>
 | 
					                <StyledTitle variant='h3' data-loading>
 | 
				
			||||||
                    <IntegrationIcon name={icon as string} /> {title}
 | 
					                    <IntegrationIcon name={icon as string} /> {title}
 | 
				
			||||||
@ -143,25 +154,37 @@ export const IntegrationCard: VFC<IIntegrationCardProps> = ({
 | 
				
			|||||||
                    elseShow={<ChevronRightIcon />}
 | 
					                    elseShow={<ChevronRightIcon />}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            </StyledAction>
 | 
					            </StyledAction>
 | 
				
			||||||
        </>
 | 
					        </StyledCard>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (isExternal) {
 | 
					    if (onClick) {
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <StyledAnchor
 | 
					            <StyledLink
 | 
				
			||||||
 | 
					                component='button'
 | 
				
			||||||
 | 
					                onClick={() => {
 | 
				
			||||||
 | 
					                    handleClick();
 | 
				
			||||||
 | 
					                    onClick();
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					                {content}
 | 
				
			||||||
 | 
					            </StyledLink>
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    } else if (isExternal) {
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					            <StyledLink
 | 
				
			||||||
                href={link}
 | 
					                href={link}
 | 
				
			||||||
                target='_blank'
 | 
					                target='_blank'
 | 
				
			||||||
                rel='noreferrer'
 | 
					                rel='noreferrer'
 | 
				
			||||||
                onClick={handleClick}
 | 
					                onClick={handleClick}
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
                {content}
 | 
					                {content}
 | 
				
			||||||
            </StyledAnchor>
 | 
					            </StyledLink>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <StyledLink to={link} onClick={handleClick}>
 | 
					            <StyledRouterLink to={link} onClick={handleClick}>
 | 
				
			||||||
                {content}
 | 
					                {content}
 | 
				
			||||||
            </StyledLink>
 | 
					            </StyledRouterLink>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,38 +1,143 @@
 | 
				
			|||||||
import { VFC } from 'react';
 | 
					import { VFC } from 'react';
 | 
				
			||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
					 | 
				
			||||||
import useAddons from 'hooks/api/getters/useAddons/useAddons';
 | 
					import useAddons from 'hooks/api/getters/useAddons/useAddons';
 | 
				
			||||||
import { AvailableIntegrations } from './AvailableIntegrations/AvailableIntegrations';
 | 
					import { AvailableIntegrations } from './AvailableIntegrations/AvailableIntegrations';
 | 
				
			||||||
import { ConfiguredIntegrations } from './ConfiguredIntegrations/ConfiguredIntegrations';
 | 
					import { ConfiguredIntegrations } from './ConfiguredIntegrations/ConfiguredIntegrations';
 | 
				
			||||||
import { AddonSchema } from 'openapi';
 | 
					import { Tab, Tabs, styled, useTheme } from '@mui/material';
 | 
				
			||||||
 | 
					import { Add } from '@mui/icons-material';
 | 
				
			||||||
 | 
					import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
 | 
				
			||||||
 | 
					import { useUiFlag } from 'hooks/useUiFlag';
 | 
				
			||||||
 | 
					import { useIncomingWebhooks } from 'hooks/api/getters/useIncomingWebhooks/useIncomingWebhooks';
 | 
				
			||||||
 | 
					import { PageContent } from 'component/common/PageContent/PageContent';
 | 
				
			||||||
 | 
					import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
				
			||||||
 | 
					import { PageHeader } from 'component/common/PageHeader/PageHeader';
 | 
				
			||||||
 | 
					import { TabLink } from 'component/common/TabNav/TabLink';
 | 
				
			||||||
 | 
					import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
 | 
				
			||||||
 | 
					import { ADMIN } from 'component/providers/AccessProvider/permissions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledHeader = styled('div')(() => ({
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    justifyContent: 'space-between',
 | 
				
			||||||
 | 
					    alignItems: 'center',
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledTabsContainer = styled('div')({
 | 
				
			||||||
 | 
					    flex: 1,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledActions = styled('div')({
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    alignItems: 'center',
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const IntegrationList: VFC = () => {
 | 
					export const IntegrationList: VFC = () => {
 | 
				
			||||||
 | 
					    const { pathname } = useLocation();
 | 
				
			||||||
 | 
					    const navigate = useNavigate();
 | 
				
			||||||
 | 
					    const theme = useTheme();
 | 
				
			||||||
 | 
					    const incomingWebhooksEnabled = useUiFlag('incomingWebhooks');
 | 
				
			||||||
    const { providers, addons, loading } = useAddons();
 | 
					    const { providers, addons, loading } = useAddons();
 | 
				
			||||||
 | 
					    const { incomingWebhooks } = useIncomingWebhooks();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const loadingPlaceholderAddons: AddonSchema[] = Array.from({ length: 4 })
 | 
					    const onNewIncomingWebhook = () => {
 | 
				
			||||||
        .fill({})
 | 
					        navigate('/integrations/incoming-webhooks');
 | 
				
			||||||
        .map((_, id) => ({
 | 
					        // TODO: Implement:
 | 
				
			||||||
            id,
 | 
					        // setSelectedIncomingWebhook(undefined);
 | 
				
			||||||
            provider: 'mock',
 | 
					        // setIncomingWebhookModalOpen(true);
 | 
				
			||||||
            description: 'mock integratino',
 | 
					    };
 | 
				
			||||||
            events: [],
 | 
					
 | 
				
			||||||
            projects: [],
 | 
					    const tabs = [
 | 
				
			||||||
            parameters: {},
 | 
					        {
 | 
				
			||||||
            enabled: false,
 | 
					            label: 'Integrations',
 | 
				
			||||||
        }));
 | 
					            path: '/integrations',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            label: `Incoming webhooks (${incomingWebhooks.length})`,
 | 
				
			||||||
 | 
					            path: '/integrations/incoming-webhooks',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <>
 | 
					        <PageContent
 | 
				
			||||||
            <ConditionallyRender
 | 
					            header={
 | 
				
			||||||
                condition={addons.length > 0}
 | 
					                <ConditionallyRender
 | 
				
			||||||
                show={
 | 
					                    condition={incomingWebhooksEnabled}
 | 
				
			||||||
                    <ConfiguredIntegrations
 | 
					                    show={
 | 
				
			||||||
                        addons={loading ? loadingPlaceholderAddons : addons}
 | 
					                        <StyledHeader>
 | 
				
			||||||
                        providers={providers}
 | 
					                            <StyledTabsContainer>
 | 
				
			||||||
                        loading={loading}
 | 
					                                <Tabs
 | 
				
			||||||
                    />
 | 
					                                    value={pathname}
 | 
				
			||||||
                }
 | 
					                                    indicatorColor='primary'
 | 
				
			||||||
            />
 | 
					                                    textColor='primary'
 | 
				
			||||||
            <AvailableIntegrations providers={providers} loading={loading} />
 | 
					                                    variant='scrollable'
 | 
				
			||||||
        </>
 | 
					                                    allowScrollButtonsMobile
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                    {tabs.map(({ label, path }) => (
 | 
				
			||||||
 | 
					                                        <Tab
 | 
				
			||||||
 | 
					                                            key={label}
 | 
				
			||||||
 | 
					                                            value={path}
 | 
				
			||||||
 | 
					                                            label={
 | 
				
			||||||
 | 
					                                                <TabLink to={path}>
 | 
				
			||||||
 | 
					                                                    {label}
 | 
				
			||||||
 | 
					                                                </TabLink>
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                            sx={{
 | 
				
			||||||
 | 
					                                                padding: 0,
 | 
				
			||||||
 | 
					                                            }}
 | 
				
			||||||
 | 
					                                        />
 | 
				
			||||||
 | 
					                                    ))}
 | 
				
			||||||
 | 
					                                </Tabs>
 | 
				
			||||||
 | 
					                            </StyledTabsContainer>
 | 
				
			||||||
 | 
					                            <StyledActions>
 | 
				
			||||||
 | 
					                                <ConditionallyRender
 | 
				
			||||||
 | 
					                                    condition={pathname.includes(
 | 
				
			||||||
 | 
					                                        'incoming-webhooks',
 | 
				
			||||||
 | 
					                                    )}
 | 
				
			||||||
 | 
					                                    show={
 | 
				
			||||||
 | 
					                                        <ResponsiveButton
 | 
				
			||||||
 | 
					                                            onClick={onNewIncomingWebhook}
 | 
				
			||||||
 | 
					                                            maxWidth={`${theme.breakpoints.values.sm}px`}
 | 
				
			||||||
 | 
					                                            Icon={Add}
 | 
				
			||||||
 | 
					                                            permission={ADMIN}
 | 
				
			||||||
 | 
					                                        >
 | 
				
			||||||
 | 
					                                            New incoming webhook
 | 
				
			||||||
 | 
					                                        </ResponsiveButton>
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                            </StyledActions>
 | 
				
			||||||
 | 
					                        </StyledHeader>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    elseShow={<PageHeader title='Integrations' />}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            isLoading={loading}
 | 
				
			||||||
 | 
					            withTabs={incomingWebhooksEnabled}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <Routes>
 | 
				
			||||||
 | 
					                <Route
 | 
				
			||||||
 | 
					                    path='incoming-webhooks'
 | 
				
			||||||
 | 
					                    element={<span>TODO: Implement</span>}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <Route
 | 
				
			||||||
 | 
					                    path='*'
 | 
				
			||||||
 | 
					                    element={
 | 
				
			||||||
 | 
					                        <>
 | 
				
			||||||
 | 
					                            <ConditionallyRender
 | 
				
			||||||
 | 
					                                condition={addons.length > 0}
 | 
				
			||||||
 | 
					                                show={
 | 
				
			||||||
 | 
					                                    <ConfiguredIntegrations
 | 
				
			||||||
 | 
					                                        addons={addons}
 | 
				
			||||||
 | 
					                                        providers={providers}
 | 
				
			||||||
 | 
					                                        loading={loading}
 | 
				
			||||||
 | 
					                                    />
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                            <AvailableIntegrations
 | 
				
			||||||
 | 
					                                providers={providers}
 | 
				
			||||||
 | 
					                                onNewIncomingWebhook={onNewIncomingWebhook}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                        </>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					            </Routes>
 | 
				
			||||||
 | 
					        </PageContent>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -346,7 +346,7 @@ exports[`returns all baseRoutes 1`] = `
 | 
				
			|||||||
      "advanced": true,
 | 
					      "advanced": true,
 | 
				
			||||||
      "mobile": true,
 | 
					      "mobile": true,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "path": "/integrations",
 | 
					    "path": "/integrations/*",
 | 
				
			||||||
    "title": "Integrations",
 | 
					    "title": "Integrations",
 | 
				
			||||||
    "type": "protected",
 | 
					    "type": "protected",
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
				
			|||||||
@ -350,7 +350,7 @@ export const routes: IRoute[] = [
 | 
				
			|||||||
        menu: {},
 | 
					        menu: {},
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        path: '/integrations',
 | 
					        path: '/integrations/*',
 | 
				
			||||||
        title: 'Integrations',
 | 
					        title: 'Integrations',
 | 
				
			||||||
        component: IntegrationList,
 | 
					        component: IntegrationList,
 | 
				
			||||||
        hidden: false,
 | 
					        hidden: false,
 | 
				
			||||||
 | 
				
			|||||||
@ -4,14 +4,16 @@ import handleErrorResponses from '../httpErrorResponseHandler';
 | 
				
			|||||||
import { useConditionalSWR } from '../useConditionalSWR/useConditionalSWR';
 | 
					import { useConditionalSWR } from '../useConditionalSWR/useConditionalSWR';
 | 
				
			||||||
import useUiConfig from '../useUiConfig/useUiConfig';
 | 
					import useUiConfig from '../useUiConfig/useUiConfig';
 | 
				
			||||||
import { IIncomingWebhook } from 'interfaces/incomingWebhook';
 | 
					import { IIncomingWebhook } from 'interfaces/incomingWebhook';
 | 
				
			||||||
 | 
					import { useUiFlag } from 'hooks/useUiFlag';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ENDPOINT = 'api/admin/incoming-webhooks';
 | 
					const ENDPOINT = 'api/admin/incoming-webhooks';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useIncomingWebhooks = () => {
 | 
					export const useIncomingWebhooks = () => {
 | 
				
			||||||
    const { isEnterprise } = useUiConfig();
 | 
					    const { isEnterprise } = useUiConfig();
 | 
				
			||||||
 | 
					    const incomingWebhooksEnabled = useUiFlag('incomingWebhooks');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { data, error, mutate } = useConditionalSWR(
 | 
					    const { data, error, mutate } = useConditionalSWR(
 | 
				
			||||||
        isEnterprise(),
 | 
					        isEnterprise() && incomingWebhooksEnabled,
 | 
				
			||||||
        { incomingWebhooks: [] },
 | 
					        { incomingWebhooks: [] },
 | 
				
			||||||
        formatApiPath(ENDPOINT),
 | 
					        formatApiPath(ENDPOINT),
 | 
				
			||||||
        fetcher,
 | 
					        fetcher,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user