import withPageTitle from 'HOCs/withPageTitle'; import { observer } from 'mobx-react-lite'; import React, { useEffect, useState } from 'react'; import { useModal } from 'App/components/Modal'; import { useStore } from 'App/mstore'; import IntegrationFilters from 'Components/Client/Integrations/IntegrationFilters'; import { PageTitle } from 'UI'; import DocCard from 'Shared/DocCard/DocCard'; import SiteDropdown from 'Shared/SiteDropdown'; import DatadogForm from './Backend/DatadogForm/DatadogFormModal'; import DynatraceFormModal from './Backend/DynatraceForm/DynatraceFormModal'; import ElasticsearchForm from './Backend/ElasticForm/ElasticFormModal'; import SentryForm from './Backend/SentryForm/SentryFormModal'; import GithubForm from './GithubForm'; import IntegrationItem from './IntegrationItem'; import JiraForm from './JiraForm'; import ProfilerDoc from './ProfilerDoc'; import SlackForm from './SlackForm'; import MSTeams from './Teams'; import AssistDoc from './Tracker/AssistDoc'; import GraphQLDoc from './Tracker/GraphQLDoc'; import MobxDoc from './Tracker/MobxDoc'; import NgRxDoc from './Tracker/NgRxDoc'; import PiniaDoc from './Tracker/PiniaDoc'; import ReduxDoc from './Tracker/ReduxDoc'; import VueDoc from './Tracker/VueDoc'; import ZustandDoc from './Tracker/ZustandDoc'; import { TFunction } from 'i18next'; import { useTranslation } from 'react-i18next'; interface Props { siteId: string; hideHeader?: boolean; } function Integrations(props: Props) { const { t } = useTranslation(); const { integrationsStore, projectsStore } = useStore(); const initialSiteId = projectsStore.siteId; const { siteId } = integrationsStore.integrations; const fetchIntegrationList = integrationsStore.integrations.fetchIntegrations; const storeIntegratedList = integrationsStore.integrations.list; const { hideHeader = false } = props; const { showModal, hideModal } = useModal(); const [integratedList, setIntegratedList] = useState([]); const [activeFilter, setActiveFilter] = useState('all'); useEffect(() => { const list = integrationsStore.integrations.integratedServices.map( (item: any) => item.name, ); setIntegratedList(list); }, [storeIntegratedList]); useEffect(() => { if (siteId) { void fetchIntegrationList(siteId); } else if (initialSiteId) { integrationsStore.integrations.setSiteId(initialSiteId); } }, [siteId]); const onClick = (integration: any, width: number) => { if ( integration.slug && integration.slug !== 'slack' && integration.slug !== 'msteams' ) { const intName = integration.slug as | 'sentry' | 'bugsnag' | 'rollbar' | 'elasticsearch' | 'datadog' | 'sumologic' | 'stackdriver' | 'cloudwatch' | 'newrelic'; if (integrationsStore[intName]) { void integrationsStore[intName].fetchIntegration(siteId); } } showModal( React.cloneElement(integration.component, { integrated: integratedList.includes(integration.slug), siteId, onClose: hideModal, }), { right: true, width }, ); }; const onChange = (key: string) => { setActiveFilter(key); }; const filteredIntegrations = integrations(t).filter((cat: any) => { if (activeFilter === 'all') { return true; } return cat.key === activeFilter; }); const filters = integrations(t).map((cat: any) => ({ key: cat.key, title: cat.title, label: cat.title, icon: cat.icon, })); const allIntegrations = filteredIntegrations.flatMap( (cat) => cat.integrations, ); const onChangeSelect = ({ value }: any) => { integrationsStore.integrations.setSiteId(value.value); }; return ( <>
{!hideHeader && {t('Integrations')}
} />}
{allIntegrations.map((integration, i) => ( onClick( integration, filteredIntegrations.find((cat) => cat.integrations.includes(integration), )?.title === 'Plugins' ? 500 : 350, ) } hide={ (integration.slug === 'github' && integratedList.includes('jira')) || (integration.slug === 'jira' && integratedList.includes('github')) } /> ))}
); } export default withPageTitle('Integrations - OpenReplay Preferences')( observer(Integrations), ); const integrations = (t: TFunction) => [ { title: t('Issue Reporting'), key: 'issue-reporting', description: t( 'Seamlessly report issues or share issues with your team right from OpenReplay.', ), isProject: false, icon: 'exclamation-triangle', integrations: [ { title: t('Jira'), subtitle: t( 'Integrate Jira with OpenReplay to enable the creation of a new ticket directly from a session.', ), slug: 'jira', category: 'Errors', icon: 'integrations/jira', component: , }, { title: t('Github'), subtitle: t( 'Integrate GitHub with OpenReplay to enable the direct creation of a new issue from a session.', ), slug: 'github', category: 'Errors', icon: 'integrations/github', component: , }, ], }, { title: t('Backend Logging'), key: 'backend-logging', isProject: true, icon: 'terminal', description: t( 'Sync your backend errors with sessions replays and see what happened front-to-back.', ), docs: () => ( {t( 'Sync your backend errors with sessions replays and see what happened front-to-back.', )} ), integrations: [ { title: t('Sentry'), subtitle: t( 'Integrate Sentry with session replays to seamlessly observe backend errors.', ), slug: 'sentry', icon: 'integrations/sentry', component: , }, { title: t('Elasticsearch'), subtitle: t( 'Integrate Elasticsearch with session replays to seamlessly observe backend errors.', ), slug: 'elasticsearch', icon: 'integrations/elasticsearch', component: , }, { title: t('Datadog'), subtitle: t( 'Incorporate DataDog to visualize backend errors alongside session replay, for easy troubleshooting.', ), slug: 'datadog', icon: 'integrations/datadog', component: , }, { title: t('Dynatrace'), subtitle: t( 'Integrate Dynatrace with session replays to link backend logs with user sessions for faster issue resolution.', ), slug: 'dynatrace', icon: 'integrations/dynatrace', useIcon: true, component: , }, ], }, { title: t('Collaboration'), key: 'collaboration', isProject: false, icon: 'file-code', description: t( 'Share your sessions with your team and collaborate on issues.', ), integrations: [ { title: t('Slack'), subtitle: t( 'Integrate Slack to empower every user in your org with the ability to send sessions to any Slack channel.', ), slug: 'slack', category: 'Errors', icon: 'integrations/slack', component: , shared: true, }, { title: t('MS Teams'), subtitle: t( 'Integrate MS Teams to empower every user in your org with the ability to send sessions to any MS Teams channel.', ), slug: 'msteams', category: 'Errors', icon: 'integrations/teams', component: , shared: true, }, ], }, // { // title: 'State Management', // key: 'state-management', // isProject: true, // icon: 'layers-half', // description: 'Sync your Redux or VueX store with sessions replays and see what happened front-to-back.', // integrations: [] // }, { title: t('Plugins'), key: 'plugins', isProject: true, icon: 'chat-left-text', docs: () => ( {t( 'Plugins capture your application’s store, monitor queries, track performance issues and even assist your end user through live sessions.', )} ), description: t( "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: t('Redux'), subtitle: t( 'Capture Redux actions/state and inspect them later on while replaying session recordings.', ), icon: 'integrations/redux', component: , }, { title: t('VueX'), subtitle: t( 'Capture VueX mutations/state and inspect them later on while replaying session recordings.', ), icon: 'integrations/vuejs', component: , }, { title: t('Pinia'), subtitle: t( 'Capture Pinia mutations/state and inspect them later on while replaying session recordings.', ), icon: 'integrations/pinia', component: , }, { title: t('GraphQL'), subtitle: t( 'Capture GraphQL requests and inspect them later on while replaying session recordings. This plugin is compatible with Apollo and Relay implementations.', ), icon: 'integrations/graphql', component: , }, { title: t('NgRx'), subtitle: t( 'Capture NgRx actions/state and inspect them later on while replaying session recordings.\n', ), icon: 'integrations/ngrx', component: , }, { title: t('MobX'), subtitle: t( 'Capture MobX mutations and inspect them later on while replaying session recordings.', ), icon: 'integrations/mobx', component: , }, { title: t('Profiler'), subtitle: t( 'Plugin allows you to measure your JS functions performance and capture both arguments and result for each call.', ), icon: 'integrations/openreplay', component: , }, { title: t('Assist'), subtitle: t( 'OpenReplay Assist allows you to support your users by seeing their live screen and instantly hopping on call (WebRTC) with them without requiring any 3rd-party screen sharing software.\n', ), icon: 'integrations/openreplay', component: , }, { title: t('Zustand'), subtitle: t( 'Capture Zustand mutations/state and inspect them later on while replaying session recordings.', ), icon: 'integrations/zustand', // header: '🐻', component: , }, ], }, ]; /** * * @deprecated * */ // { // title: 'Sumo Logic', // subtitle: // 'Integrate Sumo Logic with session replays to seamlessly observe backend errors.', // slug: 'sumologic', // icon: 'integrations/sumologic', // component: , // }, // { // title: 'Bugsnag', // subtitle: // 'Integrate Bugsnag to access the OpenReplay session linked to the JS exception within its interface.', // slug: 'bugsnag', // icon: 'integrations/bugsnag', // component: , // }, // { // title: 'Rollbar', // subtitle: // 'Integrate Rollbar with session replays to seamlessly observe backend errors.', // slug: 'rollbar', // icon: 'integrations/rollbar', // component: , // }, // { // title: 'Google Cloud', // subtitle: // 'Integrate Google Cloud to view backend logs and errors in conjunction with session replay', // slug: 'stackdriver', // icon: 'integrations/google-cloud', // component: , // }, // { // title: 'CloudWatch', // subtitle: // 'Integrate CloudWatch to see backend logs and errors alongside session replay.', // slug: 'cloudwatch', // icon: 'integrations/aws', // component: , // }, // { // title: 'Newrelic', // subtitle: // 'Integrate NewRelic with session replays to seamlessly observe backend errors.', // slug: 'newrelic', // icon: 'integrations/newrelic', // component: , // },