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'; interface Props { siteId: string; hideHeader?: boolean; } function Integrations(props: Props) { const { integrationsStore, projectsStore } = useStore(); const initialSiteId = projectsStore.siteId; const siteId = integrationsStore.integrations.siteId; 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.filter((cat: any) => { if (activeFilter === 'all') { return true; } return cat.key === activeFilter; }); const filters = integrations.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 && 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 = [ { title: 'Issue Reporting', key: 'issue-reporting', description: 'Seamlessly report issues or share issues with your team right from OpenReplay.', isProject: false, icon: 'exclamation-triangle', integrations: [ { title: 'Jira', subtitle: '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: 'Github', subtitle: '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: 'Backend Logging', key: 'backend-logging', isProject: true, icon: 'terminal', description: 'Sync your backend errors with sessions replays and see what happened front-to-back.', docs: () => ( Sync your backend errors with sessions replays and see what happened front-to-back. ), integrations: [ { title: 'Sentry', subtitle: 'Integrate Sentry with session replays to seamlessly observe backend errors.', slug: 'sentry', icon: 'integrations/sentry', component: , }, { title: 'Elasticsearch', subtitle: 'Integrate Elasticsearch with session replays to seamlessly observe backend errors.', slug: 'elasticsearch', icon: 'integrations/elasticsearch', component: , }, { title: 'Datadog', subtitle: 'Incorporate DataDog to visualize backend errors alongside session replay, for easy troubleshooting.', slug: 'datadog', icon: 'integrations/datadog', component: , }, { title: 'Dynatrace', subtitle: '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: 'Collaboration', key: 'collaboration', isProject: false, icon: 'file-code', description: 'Share your sessions with your team and collaborate on issues.', integrations: [ { title: 'Slack', subtitle: '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: 'MS Teams', subtitle: '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: 'Plugins', key: 'plugins', isProject: true, icon: 'chat-left-text', docs: () => ( Plugins capture your application’s store, monitor queries, track performance issues and even assist your end user through live sessions. ), 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: 'Capture Redux actions/state and inspect them later on while replaying session recordings.', icon: 'integrations/redux', component: , }, { title: 'VueX', subtitle: 'Capture VueX mutations/state and inspect them later on while replaying session recordings.', icon: 'integrations/vuejs', component: , }, { title: 'Pinia', subtitle: 'Capture Pinia mutations/state and inspect them later on while replaying session recordings.', icon: 'integrations/pinia', component: , }, { title: 'GraphQL', subtitle: '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: 'NgRx', subtitle: 'Capture NgRx actions/state and inspect them later on while replaying session recordings.\n', icon: 'integrations/ngrx', component: , }, { title: 'MobX', subtitle: 'Capture MobX mutations and inspect them later on while replaying session recordings.', icon: 'integrations/mobx', component: , }, { title: 'Profiler', subtitle: 'Plugin allows you to measure your JS functions performance and capture both arguments and result for each call.', icon: 'integrations/openreplay', component: , }, { title: 'Assist', subtitle: '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: 'Zustand', subtitle: '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: , // },