feat: Edge integration page (#4657)
## About the changes 
@ -44,6 +44,7 @@ import { IntegrationDelete } from './IntegrationDelete/IntegrationDelete';
|
|||||||
import { IntegrationStateSwitch } from './IntegrationStateSwitch/IntegrationStateSwitch';
|
import { IntegrationStateSwitch } from './IntegrationStateSwitch/IntegrationStateSwitch';
|
||||||
import { capitalizeFirst } from 'utils/capitalizeFirst';
|
import { capitalizeFirst } from 'utils/capitalizeFirst';
|
||||||
import { useUiFlag } from 'hooks/useUiFlag';
|
import { useUiFlag } from 'hooks/useUiFlag';
|
||||||
|
import { IntegrationHowToSection } from '../IntegrationHowToSection/IntegrationHowToSection';
|
||||||
|
|
||||||
type IntegrationFormProps = {
|
type IntegrationFormProps = {
|
||||||
provider?: AddonTypeSchema;
|
provider?: AddonTypeSchema;
|
||||||
@ -305,6 +306,7 @@ export const IntegrationForm: VFC<IntegrationFormProps> = ({
|
|||||||
hidden={true}
|
hidden={true}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
|
<IntegrationHowToSection provider={provider} />
|
||||||
<StyledRaisedSection>
|
<StyledRaisedSection>
|
||||||
<IntegrationStateSwitch
|
<IntegrationStateSwitch
|
||||||
checked={formValues.enabled}
|
checked={formValues.enabled}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
import { AddonTypeSchema } from 'openapi';
|
||||||
|
import { VFC } from 'react';
|
||||||
|
import { StyledRaisedSection } from '../IntegrationForm/IntegrationForm.styles';
|
||||||
|
import { Typography } from '@mui/material';
|
||||||
|
import { IntegrationIcon } from '../IntegrationList/IntegrationIcon/IntegrationIcon';
|
||||||
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
|
||||||
|
interface IIntegrationHowToSectionProps {
|
||||||
|
provider?: Pick<AddonTypeSchema, 'howTo' | 'name'>;
|
||||||
|
title?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const IntegrationHowToSection: VFC<IIntegrationHowToSectionProps> = ({
|
||||||
|
provider,
|
||||||
|
title = 'How does it work?',
|
||||||
|
}) => {
|
||||||
|
if (!provider?.name || !provider?.howTo) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledRaisedSection>
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
component="h3"
|
||||||
|
sx={theme => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: theme.spacing(1),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<IntegrationIcon name={provider.name} /> {title}
|
||||||
|
</Typography>
|
||||||
|
<ReactMarkdown>{provider!.howTo || ''}</ReactMarkdown>
|
||||||
|
</StyledRaisedSection>
|
||||||
|
);
|
||||||
|
};
|
@ -106,7 +106,7 @@ export const AvailableIntegrations: VFC<IAvailableIntegrationsProps> = ({
|
|||||||
<IntegrationCard
|
<IntegrationCard
|
||||||
icon="unleash"
|
icon="unleash"
|
||||||
title="Unleash Edge"
|
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 versitile."
|
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"
|
link="/integrations/view/edge"
|
||||||
configureActionText="Learn more"
|
configureActionText="Learn more"
|
||||||
/>
|
/>
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
||||||
import { styled } from '@mui/material';
|
import { Divider, Typography, styled } from '@mui/material';
|
||||||
|
import edgeMode from './assets/edge-mode.svg';
|
||||||
import { IntegrationIcon } from '../../IntegrationList/IntegrationIcon/IntegrationIcon';
|
import offlineMode from './assets/edge-offline.svg';
|
||||||
import { ReactMarkdown } from 'react-markdown/lib/react-markdown';
|
import edgeChaining from './assets/edge-daisy-chaining.svg';
|
||||||
import LaunchIcon from '@mui/icons-material/Launch';
|
import LaunchIcon from '@mui/icons-material/Launch';
|
||||||
|
import { IntegrationHowToSection } from 'component/integrations/IntegrationHowToSection/IntegrationHowToSection';
|
||||||
|
import { formatAssetPath } from 'utils/formatPath';
|
||||||
|
|
||||||
const StyledContainer = styled('div')(({ theme }) => ({
|
const StyledContainer = styled('div')(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -11,6 +13,12 @@ const StyledContainer = styled('div')(({ theme }) => ({
|
|||||||
gap: theme.spacing(2),
|
gap: theme.spacing(2),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const StyledDescription = styled('div')(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: theme.spacing(3),
|
||||||
|
}));
|
||||||
|
|
||||||
const StyledGrayContainer = styled('div')(({ theme }) => ({
|
const StyledGrayContainer = styled('div')(({ theme }) => ({
|
||||||
backgroundColor: theme.palette.background.elevation1,
|
backgroundColor: theme.palette.background.elevation1,
|
||||||
borderRadius: theme.shape.borderRadiusLarge,
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
@ -20,15 +28,31 @@ const StyledGrayContainer = styled('div')(({ theme }) => ({
|
|||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledIconLine = styled('div')(({ theme }) => ({
|
const StyledDescriptionHeader = styled(Typography)(({ theme }) => ({
|
||||||
display: 'flex',
|
marginTop: theme.spacing(1),
|
||||||
alignItems: 'center',
|
marginBottom: theme.spacing(1),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledLink = styled('a')({
|
const StyledLink = styled('a')({
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const StyledFigure = styled('figure')(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
marginLeft: 0,
|
||||||
|
marginRight: 0,
|
||||||
|
marginTop: theme.spacing(1.5),
|
||||||
|
marginBottom: theme.spacing(3),
|
||||||
|
gap: theme.spacing(1),
|
||||||
|
flexDirection: 'column',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledFigcaption = styled('figcaption')(({ theme }) => ({
|
||||||
|
fontSize: theme.typography.body2.fontSize,
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
textAlign: 'center',
|
||||||
|
}));
|
||||||
|
|
||||||
export const EDGE_INFO = {
|
export const EDGE_INFO = {
|
||||||
name: 'unleash',
|
name: 'unleash',
|
||||||
displayName: 'Unleash Edge',
|
displayName: 'Unleash Edge',
|
||||||
@ -41,8 +65,7 @@ Unleash Edge offers two important features:
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const EdgeIntegration = () => {
|
export const EdgeIntegration = () => {
|
||||||
const { name, displayName, description, documentationUrl, howTo } =
|
const { displayName, description, documentationUrl } = EDGE_INFO;
|
||||||
EDGE_INFO;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormTemplate
|
<FormTemplate
|
||||||
@ -52,12 +75,10 @@ export const EdgeIntegration = () => {
|
|||||||
documentationLinkLabel="Unleash Edge documentation"
|
documentationLinkLabel="Unleash Edge documentation"
|
||||||
>
|
>
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledGrayContainer>
|
<IntegrationHowToSection
|
||||||
<StyledIconLine>
|
provider={EDGE_INFO}
|
||||||
<IntegrationIcon name={name} /> How does it work?
|
title="Why would you need Edge?"
|
||||||
</StyledIconLine>
|
/>
|
||||||
<ReactMarkdown>{howTo}</ReactMarkdown>
|
|
||||||
</StyledGrayContainer>
|
|
||||||
<StyledGrayContainer>
|
<StyledGrayContainer>
|
||||||
<StyledLink
|
<StyledLink
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@ -74,6 +95,12 @@ export const EdgeIntegration = () => {
|
|||||||
/>
|
/>
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
</StyledGrayContainer>
|
</StyledGrayContainer>
|
||||||
|
<Divider
|
||||||
|
sx={theme => ({
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
marginBottom: theme.spacing(2),
|
||||||
|
})}
|
||||||
|
/>
|
||||||
<iframe
|
<iframe
|
||||||
src="https://www.youtube-nocookie.com/embed/6uIdF-yByWs?si=rPzsFCM_2IheaTUo"
|
src="https://www.youtube-nocookie.com/embed/6uIdF-yByWs?si=rPzsFCM_2IheaTUo"
|
||||||
title="YouTube video player"
|
title="YouTube video player"
|
||||||
@ -85,6 +112,94 @@ export const EdgeIntegration = () => {
|
|||||||
aspectRatio: '16/9',
|
aspectRatio: '16/9',
|
||||||
}}
|
}}
|
||||||
></iframe>
|
></iframe>
|
||||||
|
<StyledDescription>
|
||||||
|
<section>
|
||||||
|
<StyledDescriptionHeader variant="h3">
|
||||||
|
Modes
|
||||||
|
</StyledDescriptionHeader>
|
||||||
|
<Typography variant="body1">
|
||||||
|
Edge currently supports 2 different modes:{' '}
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://docs.getunleash.io/reference/unleash-edge#edge"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Edge
|
||||||
|
</a>{' '}
|
||||||
|
Edge – Connection to upstream node
|
||||||
|
(Unleash instance or another Edge). Supports
|
||||||
|
dynamic tokens, metrics and other advanced
|
||||||
|
features;
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://docs.getunleash.io/reference/unleash-edge#offline"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Offline
|
||||||
|
</a>{' '}
|
||||||
|
– No connection to upstream node. Full
|
||||||
|
control of data and tokens;
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</Typography>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<StyledDescriptionHeader variant="h3">
|
||||||
|
Edge
|
||||||
|
</StyledDescriptionHeader>
|
||||||
|
<Typography variant="body1">
|
||||||
|
Edge mode is the "standard" mode for Unleash Edge
|
||||||
|
and the one you should default to in most cases. It
|
||||||
|
connects to an upstream node, such as your Unleash
|
||||||
|
instance, and uses that as the source of truth for
|
||||||
|
feature toggles.
|
||||||
|
</Typography>
|
||||||
|
<StyledFigure>
|
||||||
|
<img src={formatAssetPath(edgeMode)} alt="test" />
|
||||||
|
<StyledFigcaption>Edge mode</StyledFigcaption>
|
||||||
|
</StyledFigure>
|
||||||
|
<Typography>
|
||||||
|
Other than connecting Edge directly to your Unleash
|
||||||
|
instance, it's also possible to connect to another
|
||||||
|
Edge instance (daisy chaining). You can have as many
|
||||||
|
Edge nodes as you'd like between the Edge node your
|
||||||
|
clients are accessing and the Unleash server, and
|
||||||
|
it's also possible for multiple nodes to connect to
|
||||||
|
a single upstream one.
|
||||||
|
</Typography>
|
||||||
|
<StyledFigure>
|
||||||
|
<img
|
||||||
|
src={formatAssetPath(edgeChaining)}
|
||||||
|
alt="test"
|
||||||
|
/>
|
||||||
|
<StyledFigcaption>
|
||||||
|
Edge daisy chaining
|
||||||
|
</StyledFigcaption>
|
||||||
|
</StyledFigure>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<StyledDescriptionHeader variant="h3">
|
||||||
|
Offline
|
||||||
|
</StyledDescriptionHeader>
|
||||||
|
<Typography>
|
||||||
|
Offline mode is useful when there is no connection
|
||||||
|
to an upstream node, such as your Unleash instance
|
||||||
|
or another Edge instance, or as a tool to make
|
||||||
|
working with Unleash easier during development.
|
||||||
|
</Typography>
|
||||||
|
<StyledFigure>
|
||||||
|
<img
|
||||||
|
src={formatAssetPath(offlineMode)}
|
||||||
|
alt="test"
|
||||||
|
/>
|
||||||
|
<StyledFigcaption>Edge offline</StyledFigcaption>
|
||||||
|
</StyledFigure>
|
||||||
|
</section>
|
||||||
|
</StyledDescription>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
</FormTemplate>
|
</FormTemplate>
|
||||||
);
|
);
|
||||||
|
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 24 KiB |
@ -1,11 +1,11 @@
|
|||||||
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
||||||
import { Divider, styled } from '@mui/material';
|
import { Divider, styled } from '@mui/material';
|
||||||
|
|
||||||
import { IntegrationIcon } from '../../IntegrationList/IntegrationIcon/IntegrationIcon';
|
import cr from './assets/cr.png';
|
||||||
import cr from 'assets/img/jira/cr.png';
|
import connect from './assets/connect.png';
|
||||||
import connect from 'assets/img/jira/connect.png';
|
import manage from './assets/manage.png';
|
||||||
import manage from 'assets/img/jira/manage.png';
|
|
||||||
import { JiraImageContainer } from './JiraImageContainer';
|
import { JiraImageContainer } from './JiraImageContainer';
|
||||||
|
import { IntegrationHowToSection } from 'component/integrations/IntegrationHowToSection/IntegrationHowToSection';
|
||||||
|
|
||||||
const StyledContainer = styled('div')(({ theme }) => ({
|
const StyledContainer = styled('div')(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -22,12 +22,6 @@ const StyledGrayContainer = styled('div')(({ theme }) => ({
|
|||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledIconLine = styled('div')(({ theme }) => ({
|
|
||||||
display: 'flex',
|
|
||||||
marginLeft: theme.spacing(1),
|
|
||||||
alignItems: 'center',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledLink = styled('a')({
|
const StyledLink = styled('a')({
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
});
|
});
|
||||||
@ -39,10 +33,14 @@ export const JIRA_INFO = {
|
|||||||
'Create, connect, manage, and approve Unleash feature flags directly from Jira',
|
'Create, connect, manage, and approve Unleash feature flags directly from Jira',
|
||||||
documentationUrl:
|
documentationUrl:
|
||||||
'https://docs.getunleash.io/reference/integrations/jira-cloud-plugin-installation',
|
'https://docs.getunleash.io/reference/integrations/jira-cloud-plugin-installation',
|
||||||
|
howTo: ` - Create a new feature flag directly within Jira, or connect existing flags to any Jira issue.
|
||||||
|
- Keep track of your flag status for each environment.
|
||||||
|
- Activate/deactivate feature flags directly within Jira.
|
||||||
|
- Initiate change requests when guarded flags are activated/deactivated within Jira.`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const JiraIntegration = () => {
|
export const JiraIntegration = () => {
|
||||||
const { name, displayName, description, documentationUrl } = JIRA_INFO;
|
const { displayName, description, documentationUrl } = JIRA_INFO;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormTemplate
|
<FormTemplate
|
||||||
@ -52,28 +50,7 @@ export const JiraIntegration = () => {
|
|||||||
documentationLinkLabel="Jira documentation"
|
documentationLinkLabel="Jira documentation"
|
||||||
>
|
>
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledGrayContainer>
|
<IntegrationHowToSection provider={JIRA_INFO} />
|
||||||
<StyledIconLine>
|
|
||||||
<IntegrationIcon name={name} /> How does it work?
|
|
||||||
</StyledIconLine>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
Create a new feature flag directly within Jira, or
|
|
||||||
connect existing flags to any Jira issue.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Keep track of your flag status for each environment.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Activate/deactivate feature flags directly within
|
|
||||||
Jira.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Initiate change requests when guarded flags are
|
|
||||||
activated/deactivated within Jira.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</StyledGrayContainer>
|
|
||||||
<StyledGrayContainer>
|
<StyledGrayContainer>
|
||||||
<StyledLink
|
<StyledLink
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
Before Width: | Height: | Size: 243 KiB After Width: | Height: | Size: 243 KiB |
Before Width: | Height: | Size: 243 KiB After Width: | Height: | Size: 243 KiB |
Before Width: | Height: | Size: 243 KiB After Width: | Height: | Size: 243 KiB |
@ -20,6 +20,8 @@ export interface AddonTypeSchema {
|
|||||||
documentationUrl: string;
|
documentationUrl: string;
|
||||||
/** A description of the addon type. */
|
/** A description of the addon type. */
|
||||||
description: string;
|
description: string;
|
||||||
|
/** A long description of how to use this addon type. This will be displayed on the top of configuration page. Can contain markdown. */
|
||||||
|
howTo?: string;
|
||||||
/** A list of [Unleash tag types](https://docs.getunleash.io/reference/tags#tag-types) that this addon uses. These tags will be added to the Unleash instance when an addon of this type is created. */
|
/** A list of [Unleash tag types](https://docs.getunleash.io/reference/tags#tag-types) that this addon uses. These tags will be added to the Unleash instance when an addon of this type is created. */
|
||||||
tagTypes?: TagTypeSchema[];
|
tagTypes?: TagTypeSchema[];
|
||||||
/** The addon provider's parameters. Use these to configure an addon of this provider type. Items with `required: true` must be provided. */
|
/** The addon provider's parameters. Use these to configure an addon of this provider type. Items with `required: true` must be provided. */
|
||||||
|
@ -22,6 +22,7 @@ const dataDogDefinition: IAddonDefinition = {
|
|||||||
displayName: 'Datadog',
|
displayName: 'Datadog',
|
||||||
description: 'Allows Unleash to post updates to Datadog.',
|
description: 'Allows Unleash to post updates to Datadog.',
|
||||||
documentationUrl: 'https://docs.getunleash.io/docs/addons/datadog',
|
documentationUrl: 'https://docs.getunleash.io/docs/addons/datadog',
|
||||||
|
howTo: 'The Datadog integration allows Unleash to post Updates to Datadog when a feature toggle is updated.',
|
||||||
parameters: [
|
parameters: [
|
||||||
{
|
{
|
||||||
name: 'url',
|
name: 'url',
|
||||||
|
@ -22,6 +22,7 @@ const teamsDefinition: IAddonDefinition = {
|
|||||||
displayName: 'Microsoft Teams',
|
displayName: 'Microsoft Teams',
|
||||||
description: 'Allows Unleash to post updates to Microsoft Teams.',
|
description: 'Allows Unleash to post updates to Microsoft Teams.',
|
||||||
documentationUrl: 'https://docs.getunleash.io/docs/addons/teams',
|
documentationUrl: 'https://docs.getunleash.io/docs/addons/teams',
|
||||||
|
howTo: 'The MicrosoftTeams integration allows Unleash to post Updates when a feature toggle is updated.',
|
||||||
parameters: [
|
parameters: [
|
||||||
{
|
{
|
||||||
name: 'url',
|
name: 'url',
|
||||||
|
@ -34,6 +34,7 @@ const webhookDefinition: IAddonDefinition = {
|
|||||||
description:
|
description:
|
||||||
'A Webhook is a generic way to post messages from Unleash to third party services.',
|
'A Webhook is a generic way to post messages from Unleash to third party services.',
|
||||||
documentationUrl: 'https://docs.getunleash.io/docs/addons/webhook',
|
documentationUrl: 'https://docs.getunleash.io/docs/addons/webhook',
|
||||||
|
howTo: 'The Webhook Addon introduces a generic way to post messages from Unleash to third party services. Unleash allows you to define a webhook which listens changes in Unleash and post them to a third party services.',
|
||||||
parameters: [
|
parameters: [
|
||||||
{
|
{
|
||||||
name: 'url',
|
name: 'url',
|
||||||
|