import {Component, Fragment} from 'react'; import styled from '@emotion/styled'; import reduce from 'lodash/reduce'; import {computed, makeObservable} from 'mobx'; import {Observer} from 'mobx-react'; import type {FormProps} from 'sentry/components/forms/form'; import Form from 'sentry/components/forms/form'; import JsonForm from 'sentry/components/forms/jsonForm'; import FormModel from 'sentry/components/forms/model'; import type {JsonFormObject} from 'sentry/components/forms/types'; import List from 'sentry/components/list'; import ListItem from 'sentry/components/list/listItem'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import PanelHeader from 'sentry/components/panels/panelHeader'; import Switch from 'sentry/components/switchButton'; import {Tooltip} from 'sentry/components/tooltip'; import {t, tn} from 'sentry/locale'; import FooterWithButtons from './components/footerWithButtons'; import HeaderWithHelp from './components/headerWithHelp'; const LAMBDA_COUNT_THRESHOLD = 10; type LambdaFunction = {FunctionName: string; Runtime: string}; type Props = { initialStepNumber: number; lambdaFunctions: LambdaFunction[]; }; type State = { submitting: boolean; }; const getLabel = (func: LambdaFunction) => func.FunctionName; export default class AwsLambdaFunctionSelect extends Component { constructor(props: Props) { super(props); makeObservable(this, {allStatesToggled: computed}); } state: State = { submitting: false, }; model = new FormModel(); get initialData() { const {lambdaFunctions} = this.props; const initialData = lambdaFunctions.reduce((accum, func) => { accum[func.FunctionName] = true; return accum; }, {}); return initialData; } get lambdaFunctions() { return this.props.lambdaFunctions.sort((a, b) => getLabel(a).toLowerCase() < getLabel(b).toLowerCase() ? -1 : 1 ); } get enabledCount() { const data = this.model.getTransformedData(); return reduce(data, (acc: number, val: boolean) => (val ? acc + 1 : acc), 0); } get allStatesToggled() { // check if any of the lambda functions have a falsy value // no falsy values means everything is enabled return Object.values(this.model.getData()).every(val => val); } get formFields() { const data = this.model.getTransformedData(); return Object.entries(data).map(([name, value]) => ({name, value})); } handleSubmit = () => { this.setState({submitting: true}); }; handleToggle = () => { const newState = !this.allStatesToggled; this.lambdaFunctions.forEach(lambda => { this.model.setValue(lambda.FunctionName, newState, {quiet: true}); }); }; renderWhatWeFound = () => { const count = this.lambdaFunctions.length; return (

{tn( 'We found %s function with a Node or Python runtime', 'We found %s functions with Node or Python runtimes', count )}

); }; renderLoadingScreen = () => { const count = this.enabledCount; const text = count > LAMBDA_COUNT_THRESHOLD ? t('This might take a while\u2026', count) : t('This might take a sec\u2026'); return (

{t('Adding Sentry to %s functions', count)}

{text}
); }; renderCore = () => { const {initialStepNumber} = this.props; const FormHeader = ( {t('Lambda Functions')} {() => ( )} ); const formFields: JsonFormObject = { fields: this.lambdaFunctions.map(func => ({ name: func.FunctionName, type: 'boolean', required: false, label: getLabel(func), alignRight: true, })), }; return (
{this.renderWhatWeFound()}
{t('Decide which functions you would like to enable for Sentry monitoring')} FormHeader} forms={[formFields]} />
); }; render() { return ( {this.state.submitting ? this.renderLoadingScreen() : this.renderCore()} {() => ( )} ); } } const Wrapper = styled('div')` padding: 100px 50px 50px 50px; `; // TODO(ts): Understand why styled is not correctly inheriting props here const StyledForm = styled(Form)` margin-top: 10px; `; const Header = styled('div')` text-align: left; margin-bottom: 10px; `; const LoadingWrapper = styled('div')` padding: 50px; text-align: center; `; const StyledLoadingIndicator = styled(LoadingIndicator)` margin: 0; `; const SwitchHolder = styled('div')` display: flex; `; const StyledSwitch = styled(Switch)` margin: auto; `; // padding is based on fom control width const StyledPanelHeader = styled(PanelHeader)` padding-right: 36px; `;