357 lines
11 KiB
TypeScript
357 lines
11 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
||
import { connect } from 'react-redux';
|
||
import { useModal } from 'App/components/Modal';
|
||
import cn from 'classnames';
|
||
|
||
import { fetch, init } from 'Duck/integrations/actions';
|
||
import { fetchIntegrationList, setSiteId } from 'Duck/integrations/integrations';
|
||
import SiteDropdown from 'Shared/SiteDropdown';
|
||
import ReduxDoc from './ReduxDoc';
|
||
import VueDoc from './VueDoc';
|
||
import GraphQLDoc from './GraphQLDoc';
|
||
import NgRxDoc from './NgRxDoc';
|
||
import MobxDoc from './MobxDoc';
|
||
import ProfilerDoc from './ProfilerDoc';
|
||
import AssistDoc from './AssistDoc';
|
||
import PiniaDoc from './PiniaDoc';
|
||
import ZustandDoc from './ZustandDoc';
|
||
import MSTeams from './Teams';
|
||
import DocCard from 'Shared/DocCard/DocCard';
|
||
import { PageTitle, Tooltip } from 'UI';
|
||
import withPageTitle from 'HOCs/withPageTitle';
|
||
|
||
import BugsnagForm from './BugsnagForm';
|
||
import CloudwatchForm from './CloudwatchForm';
|
||
import DatadogForm from './DatadogForm';
|
||
import ElasticsearchForm from './ElasticsearchForm';
|
||
import GithubForm from './GithubForm';
|
||
import IntegrationItem from './IntegrationItem';
|
||
import JiraForm from './JiraForm';
|
||
import NewrelicForm from './NewrelicForm';
|
||
import RollbarForm from './RollbarForm';
|
||
import SentryForm from './SentryForm';
|
||
import SlackForm from './SlackForm';
|
||
import StackdriverForm from './StackdriverForm';
|
||
import SumoLogicForm from './SumoLogicForm';
|
||
import IntegrationFilters from 'Components/Client/Integrations/IntegrationFilters';
|
||
|
||
interface Props {
|
||
fetch: (name: string, siteId: string) => void;
|
||
init: () => void;
|
||
fetchIntegrationList: (siteId: any) => void;
|
||
integratedList: any;
|
||
initialSiteId: string;
|
||
setSiteId: (siteId: string) => void;
|
||
siteId: string;
|
||
hideHeader?: boolean;
|
||
loading?: boolean;
|
||
}
|
||
|
||
function Integrations(props: Props) {
|
||
const { initialSiteId, hideHeader = false, loading = false } = props;
|
||
const { showModal } = useModal();
|
||
const [integratedList, setIntegratedList] = useState<string[]>([]);
|
||
const [activeFilter, setActiveFilter] = useState<string>('all');
|
||
|
||
useEffect(() => {
|
||
const list = props.integratedList
|
||
.filter((item: any) => item.integrated)
|
||
.map((item: any) => item.name);
|
||
setIntegratedList(list);
|
||
}, [props.integratedList]);
|
||
|
||
useEffect(() => {
|
||
props.fetchIntegrationList(initialSiteId);
|
||
props.setSiteId(initialSiteId);
|
||
}, []);
|
||
|
||
const onClick = (integration: any, width: number) => {
|
||
if (integration.slug && integration.slug !== 'slack' && integration.slug !== 'msteams') {
|
||
props.fetch(integration.slug, props.siteId);
|
||
}
|
||
|
||
showModal(
|
||
React.cloneElement(integration.component, {
|
||
integrated: integratedList.includes(integration.slug)
|
||
}),
|
||
{ right: true, width }
|
||
);
|
||
};
|
||
|
||
const onChangeSelect = ({ value }: any) => {
|
||
props.setSiteId(value.value);
|
||
props.fetchIntegrationList(value.value);
|
||
};
|
||
|
||
const onChange = (key: string) => {
|
||
setActiveFilter(key);
|
||
};
|
||
|
||
const filteredIntegrations = integrations.filter((cat: any) => {
|
||
if (activeFilter === 'all') {
|
||
return true;
|
||
}
|
||
|
||
return cat.key === activeFilter;
|
||
});
|
||
|
||
const filters = integrations.map((cat: any) => ({
|
||
key: cat.key,
|
||
title: cat.title,
|
||
icon: cat.icon,
|
||
}));
|
||
|
||
|
||
return (
|
||
<>
|
||
<div className='mb-4 p-5 bg-white rounded-lg border'>
|
||
{!hideHeader && <PageTitle title={<div>Integrations</div>} />}
|
||
|
||
<IntegrationFilters onChange={onChange} activeItem={activeFilter} filters={filters}/>
|
||
</div>
|
||
|
||
<div className='mb-4' />
|
||
|
||
{filteredIntegrations.map((cat: any) => (
|
||
<div className='grid grid-cols-3 mt-4 gap-3 auto-cols-max'>
|
||
{cat.integrations.map((integration: any) => (
|
||
<IntegrationItem
|
||
integrated={integratedList.includes(integration.slug)}
|
||
integration={integration}
|
||
onClick={() =>
|
||
onClick(integration, cat.title === 'Plugins' ? 500 : 350)
|
||
}
|
||
hide={
|
||
(integration.slug === 'github' &&
|
||
integratedList.includes('jira')) ||
|
||
(integration.slug === 'jira' &&
|
||
integratedList.includes('github'))
|
||
}
|
||
/>
|
||
))}
|
||
</div>
|
||
))}
|
||
</>
|
||
);
|
||
}
|
||
|
||
export default connect(
|
||
(state: any) => ({
|
||
initialSiteId: state.getIn(['site', 'siteId']),
|
||
integratedList: state.getIn(['integrations', 'list']) || [],
|
||
loading: state.getIn(['integrations', 'fetchRequest', 'loading']),
|
||
siteId: state.getIn(['integrations', 'siteId'])
|
||
}),
|
||
{ fetch, init, fetchIntegrationList, setSiteId }
|
||
)(withPageTitle('Integrations - OpenReplay Preferences')(Integrations));
|
||
|
||
|
||
const integrations = [
|
||
{
|
||
title: 'Issue Reporting',
|
||
key: 'issue-reporting',
|
||
description: 'Seamlessly report issues or share issues with your team right from OpenReplay.',
|
||
isProject: false,
|
||
icon: 'integrations/issue-reporting',
|
||
integrations: [
|
||
{
|
||
title: 'Jira',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'jira',
|
||
category: 'Errors',
|
||
icon: 'integrations/jira',
|
||
component: <JiraForm />
|
||
},
|
||
{
|
||
title: 'Github',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'github',
|
||
category: 'Errors',
|
||
icon: 'integrations/github',
|
||
component: <GithubForm />
|
||
},
|
||
{
|
||
title: 'Slack',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'slack',
|
||
category: 'Errors',
|
||
icon: 'integrations/slack',
|
||
component: <SlackForm />,
|
||
shared: true
|
||
},
|
||
{
|
||
title: 'MS Teams',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'msteams',
|
||
category: 'Errors',
|
||
icon: 'integrations/teams',
|
||
component: <MSTeams />,
|
||
shared: true
|
||
}
|
||
]
|
||
},
|
||
{
|
||
title: 'Backend Logging',
|
||
key: 'backend-logging',
|
||
isProject: true,
|
||
description:
|
||
'Sync your backend errors with sessions replays and see what happened front-to-back.',
|
||
docs: () => (
|
||
<DocCard
|
||
title='Why use integrations?'
|
||
icon='question-lg'
|
||
iconBgColor='bg-red-lightest'
|
||
iconColor='red'
|
||
>
|
||
Sync your backend errors with sessions replays and see what happened front-to-back.
|
||
</DocCard>
|
||
),
|
||
integrations: [
|
||
{ title: 'Sentry', slug: 'sentry', icon: 'integrations/sentry', component: <SentryForm /> },
|
||
{
|
||
title: 'Bugsnag',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'bugsnag',
|
||
icon: 'integrations/bugsnag',
|
||
component: <BugsnagForm />
|
||
},
|
||
{
|
||
title: 'Rollbar',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'rollbar',
|
||
icon: 'integrations/rollbar',
|
||
component: <RollbarForm />
|
||
},
|
||
{
|
||
title: 'Elasticsearch',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'elasticsearch',
|
||
icon: 'integrations/elasticsearch',
|
||
component: <ElasticsearchForm />
|
||
},
|
||
{
|
||
title: 'Datadog',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'datadog',
|
||
icon: 'integrations/datadog',
|
||
component: <DatadogForm />
|
||
},
|
||
{
|
||
title: 'Sumo Logic',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'sumologic',
|
||
icon: 'integrations/sumologic',
|
||
component: <SumoLogicForm />
|
||
},
|
||
{
|
||
title: 'Stackdriver',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'stackdriver',
|
||
icon: 'integrations/google-cloud',
|
||
component: <StackdriverForm />
|
||
},
|
||
{
|
||
title: 'CloudWatch',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'cloudwatch',
|
||
icon: 'integrations/aws',
|
||
component: <CloudwatchForm />
|
||
},
|
||
{
|
||
title: 'Newrelic',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
slug: 'newrelic',
|
||
icon: 'integrations/newrelic',
|
||
component: <NewrelicForm />
|
||
}
|
||
]
|
||
},
|
||
{
|
||
title: 'Collaboration',
|
||
key: 'collaboration',
|
||
isProject: false,
|
||
description: 'Share your sessions with your team and collaborate on issues.',
|
||
integrations: []
|
||
},
|
||
{
|
||
title: 'State Management',
|
||
key: 'state-management',
|
||
isProject: true,
|
||
description: 'Sync your Redux or VueX store with sessions replays and see what happened front-to-back.',
|
||
integrations: []
|
||
},
|
||
{
|
||
title: 'Plugins',
|
||
key: 'plugins',
|
||
isProject: true,
|
||
docs: () => (
|
||
<DocCard
|
||
title='What are plugins?'
|
||
icon='question-lg'
|
||
iconBgColor='bg-red-lightest'
|
||
iconColor='red'
|
||
>
|
||
Plugins capture your application’s store, monitor queries, track performance issues and even
|
||
assist your end user through live sessions.
|
||
</DocCard>
|
||
),
|
||
description:
|
||
'Reproduce issues as if they happened in your own browser. Plugins help capture your application\'s store, HTTP requeets, GraphQL queries, and more.',
|
||
integrations: [
|
||
{
|
||
title: 'Redux',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
icon: 'integrations/redux', component: <ReduxDoc />
|
||
},
|
||
{
|
||
title: 'VueX',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
icon: 'integrations/vuejs',
|
||
component: <VueDoc />
|
||
},
|
||
{
|
||
title: 'Pinia',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
icon: 'integrations/pinia',
|
||
component: <PiniaDoc />
|
||
},
|
||
{
|
||
title: 'GraphQL',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
icon: 'integrations/graphql',
|
||
component: <GraphQLDoc />
|
||
},
|
||
{
|
||
title: 'NgRx',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
icon: 'integrations/ngrx',
|
||
component: <NgRxDoc />
|
||
},
|
||
{
|
||
title: 'MobX',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
icon: 'integrations/mobx',
|
||
component: <MobxDoc />
|
||
},
|
||
{
|
||
title: 'Profiler',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
icon: 'integrations/openreplay',
|
||
component: <ProfilerDoc />
|
||
},
|
||
{
|
||
title: 'Assist',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
icon: 'integrations/openreplay',
|
||
component: <AssistDoc />
|
||
},
|
||
{
|
||
title: 'Zustand',
|
||
subtitle: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||
icon: '',
|
||
header: '🐻',
|
||
component: <ZustandDoc />
|
||
}
|
||
]
|
||
}
|
||
];
|