123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- import {Fragment, useCallback, useEffect, useState} from 'react';
- import styled from '@emotion/styled';
- import {motion} from 'framer-motion';
- import {openInviteMembersModal} from 'sentry/actionCreators/modal';
- import {Alert} from 'sentry/components/alert';
- import {Button} from 'sentry/components/button';
- import ExternalLink from 'sentry/components/links/externalLink';
- import LoadingError from 'sentry/components/loadingError';
- import LoadingIndicator from 'sentry/components/loadingIndicator';
- import type {
- BasePlatformOptions,
- DocsParams,
- } from 'sentry/components/onboarding/gettingStartedDoc/types';
- import {useLoadGettingStarted} from 'sentry/components/onboarding/gettingStartedDoc/utils/useLoadGettingStarted';
- import {
- PlatformOptionsControl,
- useUrlPlatformOptions,
- } from 'sentry/components/onboarding/platformOptionsControl';
- import {t, tct} from 'sentry/locale';
- import ConfigStore from 'sentry/stores/configStore';
- import {useLegacyStore} from 'sentry/stores/useLegacyStore';
- import {space} from 'sentry/styles/space';
- import type {IntegrationProvider} from 'sentry/types/integrations';
- import type {PlatformIntegration, Project} from 'sentry/types/project';
- import {trackAnalytics} from 'sentry/utils/analytics';
- import getDynamicText from 'sentry/utils/getDynamicText';
- import useApi from 'sentry/utils/useApi';
- import useOrganization from 'sentry/utils/useOrganization';
- import SetupIntroduction from 'sentry/views/onboarding/components/setupIntroduction';
- import {AddIntegrationButton} from 'sentry/views/settings/organizationIntegrations/addIntegrationButton';
- import AddInstallationInstructions from './components/integrations/addInstallationInstructions';
- import PostInstallCodeSnippet from './components/integrations/postInstallCodeSnippet';
- export enum InstallationMode {
- AUTO = 'auto',
- MANUAL = 'manual',
- }
- export const platformOptions = {
- installationMode: {
- label: t('Installation Mode'),
- items: [
- {
- label: t('Auto'),
- value: InstallationMode.AUTO,
- },
- {
- label: t('Manual'),
- value: InstallationMode.MANUAL,
- },
- ],
- defaultValue: InstallationMode.AUTO,
- },
- } satisfies BasePlatformOptions;
- type Props = {
- integrationSlug: string;
- platform: PlatformIntegration;
- project: Project;
- };
- function IntegrationSetup({project, integrationSlug, platform}: Props) {
- const [hasError, setHasError] = useState(false);
- const [installed, setInstalled] = useState(false);
- const [provider, setProvider] = useState<IntegrationProvider | null>(null);
- const organization = useOrganization();
- const {isSelfHosted, urlPrefix} = useLegacyStore(ConfigStore);
- const {
- isLoading,
- docs: docsConfig,
- dsn,
- projectKeyId,
- refetch,
- } = useLoadGettingStarted({
- orgSlug: organization.slug,
- projSlug: project.slug,
- platform,
- });
- const selectedPlatformOptions = useUrlPlatformOptions(docsConfig?.platformOptions);
- const api = useApi();
- const fetchData = useCallback(() => {
- if (!integrationSlug) {
- return Promise.resolve();
- }
- const endpoint = `/organizations/${organization.slug}/config/integrations/?provider_key=${integrationSlug}`;
- return api
- .requestPromise(endpoint)
- .then(integrations => {
- setProvider(integrations.providers[0]);
- setHasError(false);
- })
- .catch(error => {
- setHasError(true);
- throw error;
- });
- }, [integrationSlug, api, organization.slug]);
- useEffect(() => {
- fetchData();
- }, [fetchData]);
- const loadingError = (
- <LoadingError
- message={t('Failed to load the integration for the %s platform.', platform.name)}
- onRetry={fetchData}
- />
- );
- const testOnlyAlert = (
- <Alert type="warning">
- Platform documentation is not rendered in for tests in CI
- </Alert>
- );
- const renderIntegrationInstructions = () => {
- if (!provider) {
- return null;
- }
- return (
- <Fragment>
- <motion.p
- variants={{
- initial: {opacity: 0},
- animate: {opacity: 1},
- exit: {opacity: 0},
- }}
- >
- {tct(
- "Don't have have permissions to create a Cloudformation stack? [link:Invite your team instead].",
- {
- link: (
- <Button
- priority="link"
- onClick={() => {
- openInviteMembersModal();
- }}
- aria-label={t('Invite your team instead')}
- />
- ),
- }
- )}
- </motion.p>
- <motion.div
- variants={{
- initial: {opacity: 0},
- animate: {opacity: 1},
- exit: {opacity: 0},
- }}
- >
- <AddInstallationInstructions />
- </motion.div>
- <DocsWrapper>
- <AddIntegrationButton
- provider={provider}
- onAddIntegration={() => setInstalled(true)}
- organization={organization}
- priority="primary"
- size="sm"
- analyticsParams={{view: 'onboarding', already_installed: false}}
- modalParams={{projectId: project.id}}
- />
- </DocsWrapper>
- </Fragment>
- );
- };
- const renderPostInstallInstructions = () => {
- if (!provider) {
- return null;
- }
- return (
- <Fragment>
- <PostInstallCodeSnippet
- provider={provider}
- platform={project.platform}
- isOnboarding
- />
- <ExternalLink
- onClick={() => {
- trackAnalytics('growth.onboarding_view_full_docs', {
- organization,
- });
- }}
- href="https://docs.sentry.io/product/integrations/cloud-monitoring/aws-lambda/"
- >
- {t('View Full Documentation')}
- </ExternalLink>
- </Fragment>
- );
- };
- if (isLoading) {
- return <LoadingIndicator />;
- }
- if (!docsConfig || !dsn || !projectKeyId) {
- return (
- <LoadingError
- message={t(
- 'The getting started documentation for this platform is currently unavailable.'
- )}
- onRetry={refetch}
- />
- );
- }
- const docParams: DocsParams<any> = {
- api,
- projectKeyId,
- dsn,
- organization,
- platformKey: platform.id,
- projectId: project.id,
- projectSlug: project.slug,
- isFeedbackSelected: false,
- isPerformanceSelected: false,
- isProfilingSelected: false,
- isReplaySelected: false,
- isSelfHosted,
- platformOptions: selectedPlatformOptions,
- sourcePackageRegistries: {
- isLoading: false,
- data: undefined,
- },
- urlPrefix,
- };
- return (
- <Fragment>
- <SetupIntroduction
- stepHeaderText={t('Automatically instrument %s SDK', platform.name)}
- platform={platform.id}
- />
- <PlatformOptionsControl
- platformOptions={platformOptions}
- onChange={docsConfig.onboarding.onPlatformOptionsChange?.(docParams)}
- />
- <Divider />
- {installed ? renderPostInstallInstructions() : renderIntegrationInstructions()}
- {getDynamicText({
- value: !hasError ? null : loadingError,
- fixed: testOnlyAlert,
- })}
- </Fragment>
- );
- }
- const DocsWrapper = styled(motion.div)``;
- DocsWrapper.defaultProps = {
- initial: {opacity: 0, y: 40},
- animate: {opacity: 1, y: 0},
- exit: {opacity: 0},
- };
- const Divider = styled('hr')`
- height: 1px;
- width: 100%;
- background: ${p => p.theme.border};
- border: none;
- margin-bottom: ${space(3)};
- `;
- export default IntegrationSetup;
|