Dica
Esta lição faz parte de um curso que ensina como construir um aplicativo New Relic do zero. Se ainda não o fez, confira a Visão Geral.
Cada lição do curso se baseia na anterior, portanto, certifique-se de ter concluído a última lição, Personalizar dados NRQL, antes de iniciar esta.
Nas lições anteriores, você criou uma experiência do usuário em seu aplicativo que inclui gráficos e um botão para finalizar seu teste A/B. Você também configurou seus gráficos para consultar dados reais do banco de dados da New Relic. No entanto, você deixou dados simulados em dois gráficos:
- Testes anteriores
- Total de cancelamentos por versão
Ambos os gráficos contêm dados que você não pode obter no New Relic. Past tests mostram informações históricas de testes, enquanto o Total cancellations per version mostra o número de cancelamentos que cada versão vê ao longo do tempo. Concentre-se, primeiro nos Past tests.
Past tests mostram informações históricas de testes, portanto, você precisa armazenar informações sobre cada teste após a conclusão. E você tem todas as ferramentas necessárias para realizar essa tarefa. Primeiro, você tem um botão End test que aciona a ação de salvar. Em segundo lugar, você sabe como usar o NerdGraph e o NerdStorage para armazenar as informações do teste.
Salve as informações do teste no NerdStorage
Mude para o diretório add-nerdstorage/ab-test
do repositório de cursos:
$cd nru-programmability-course/add-nerdstorage/ab-test
Este diretório contém o código que esperamos que seu aplicativo tenha neste ponto do curso. Ao navegar para o diretório correto no início de cada lição, você deixa seu código personalizado para trás, protegendo-se assim de carregar código incorreto de uma lição para outra.
Em nerdlets/ab-test-nerdlet/end-test.js
, crie um método, EndTestButton.endTest()
:
import React from 'react';import { AccountStorageMutation, BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, }
this.showModal = this.showModal.bind(this); this.closeModal = this.closeModal.bind(this); this.endTest = this.endTest.bind(this); }
closeModal() { this.setState({ modalHidden: true }); }
showModal() { this.setState({ modalHidden: false }); }
endTest() { const today = new Date(); const dd = String(today.getDate()).padStart(2, '0'); const mm = String(today.getMonth() + 1).padStart(2, '0'); const yyyy = today.getFullYear(); const endDate = `${mm}-${dd}-${yyyy}`
AccountStorageMutation.mutate( { accountIds: this.props.accountIds, actionType: AccountStorageMutation.ACTION_TYPE.WRITE_DOCUMENT, collection: "past-tests", documentId: endDate, document: { versionADescription: this.props.versionADescription, versionBDescription: this.props.versionBDescription, winner: this.props.selectedVersion, } } )
this.closeModal(); }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version {this.props.selectedVersion}</b> </BlockText>
<Button onClick={this.closeModal}>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.closeModal}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton selectedVersion={this.state.selectedVersion}>End test</EndTestButton> </GridItem> </Grid> }}
Com esse código, você cria uma string de data formatada, endDate
. Em seguida, você altera o armazenamento da conta com uma chamada para AccountStorageMutation.mutate()
. Você passa o identificador da sua conta, o tipo de ação WRITE_DOCUMENT
, "testes passados" como o nome da coleção, endDate
como o documentId
e os dados do documento, que incluem as descrições da versão e o vencedor.
Você passa WRITE_DOCUMENT
porque está criando um novo documento ou atualizando um documento, se já existir um com uma coleção correspondente e documentId
. documentId
é endDate
, o que é útil para criar apenas um registro por dia.
Dica
Se você suspeitasse que poderia concluir vários testes em um dia, seria necessário alterar essa lógica.
Observe this.props.closeModal()
no final do método. Isso fecha o modal que aparece quando você tenta encerrar um teste. Portanto, você pode substituir o retorno de chamada onClick
pelo botão Yes, end test em EndTestButton.render()
:
import React from 'react';import { AccountStorageMutation, BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, }
this.showModal = this.showModal.bind(this); this.closeModal = this.closeModal.bind(this); this.endTest = this.endTest.bind(this); }
closeModal() { this.setState({ modalHidden: true }); }
showModal() { this.setState({ modalHidden: false }); }
endTest() { const today = new Date(); const dd = String(today.getDate()).padStart(2, '0'); const mm = String(today.getMonth() + 1).padStart(2, '0'); const yyyy = today.getFullYear(); const endDate = `${mm}-${dd}-${yyyy}`
AccountStorageMutation.mutate( { accountIds: this.props.accountIds, actionType: AccountStorageMutation.ACTION_TYPE.WRITE_DOCUMENT, collection: "past-tests", documentId: endDate, document: { versionADescription: this.props.versionADescription, versionBDescription: this.props.versionBDescription, winner: this.props.selectedVersion, } } )
this.closeModal(); }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version {this.props.selectedVersion}</b> </BlockText>
<Button onClick={this.closeModal}>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.endTest}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton selectedVersion={this.state.selectedVersion}>End test</EndTestButton> </GridItem> </Grid> }}
Ao finalizar o teste, endTest
armazena os dados do teste no armazenamento da conta e fecha o modal. Isso é apenas metade do comportamento necessário para preencher sua tabela; você também precisa consultar essa coleção no armazenamento da conta.
No arquivo index.js
do seu Nerdlet, passe o ID da conta e as descrições da versão para EndTestSection
:
import React from 'react';import { ChartGroup, Grid, GridItem } from 'nr1';import EndTestSection from './end-test';import NewsletterSignups from './newsletter-signups';import PastTests from './past-tests';import TotalCancellations from './total-cancellations';import TotalSubscriptions from './total-subscriptions';import VersionDescription from './description';import VersionPageViews from './page-views';import VersionTotals from './totals';
const ACCOUNT_ID = 123456 // <YOUR NEW RELIC ACCOUNT ID>const VERSION_A_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter"'const VERSION_B_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter and get a free shirt!"'
export default class AbTestNerdletNerdlet extends React.Component { render() { return <div> <Grid className="wrapper"> <GridItem columnSpan={6}> <VersionDescription description={VERSION_A_DESCRIPTION} version="A" /> </GridItem> <GridItem columnSpan={6}> <VersionDescription description={VERSION_B_DESCRIPTION} version="B" /> </GridItem> <GridItem columnSpan={12}><hr /></GridItem> <GridItem columnSpan={12}><NewsletterSignups /></GridItem> <GridItem columnSpan={6}><TotalSubscriptions /></GridItem> <GridItem columnSpan={6}><TotalCancellations /></GridItem> <GridItem columnSpan={6}> <VersionTotals version='a' accountId={ACCOUNT_ID} /> </GridItem> <GridItem columnSpan={6}> <VersionTotals version='b' accountId={ACCOUNT_ID} /> </GridItem> <ChartGroup> <GridItem columnSpan={6}> <VersionPageViews version='a' /> </GridItem> <GridItem columnSpan={6}> <VersionPageViews version='b' /> </GridItem> </ChartGroup> <GridItem columnSpan={12}> <EndTestSection accountId={ACCOUNT_ID} versionADescription={VERSION_A_DESCRIPTION} versionBDescription={VERSION_B_DESCRIPTION} /> </GridItem> <GridItem columnSpan={12}><PastTests /></GridItem> </Grid> </div> }}
Importante
Certifique-se de substituir <YOUR NEW RELIC ACCOUNT ID>
pelo seu ID de conta New Relic real.
Agora, EndTestSection
pode acessar essas variáveis em seus adereços.
Encaminhe o ID da sua conta e as descrições da versão de EndTestSection
para EndTestButton
:
import React from 'react';import { AccountStorageMutation, BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, }
this.showModal = this.showModal.bind(this); this.closeModal = this.closeModal.bind(this); this.endTest = this.endTest.bind(this); }
closeModal() { this.setState({ modalHidden: true }); }
showModal() { this.setState({ modalHidden: false }); }
endTest() { const today = new Date(); const dd = String(today.getDate()).padStart(2, '0'); const mm = String(today.getMonth() + 1).padStart(2, '0'); const yyyy = today.getFullYear(); const endDate = `${mm}-${dd}-${yyyy}`
AccountStorageMutation.mutate( { accountIds: this.props.accountIds, actionType: AccountStorageMutation.ACTION_TYPE.WRITE_DOCUMENT, collection: "past-tests", documentId: endDate, document: { versionADescription: this.props.versionADescription, versionBDescription: this.props.versionBDescription, winner: this.props.selectedVersion, } } )
this.closeModal(); }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version {this.props.selectedVersion}</b> </BlockText>
<Button onClick={this.closeModal}>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.endTest}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton accountIds={this.props.accountIds} selectedVersion={this.state.selectedVersion} versionADescription={this.props.versionADescription} versionBDescription={this.props.versionBDescription} > End test </EndTestButton> </GridItem> </Grid> }}
Buscar informações de teste do NerdStorage
Em past-tests.js
, atualize PastTests
para buscar dados do armazenamento da conta e exibi-los em TableChart
:
import React from 'react';import { AccountStorageQuery, HeadingText, Spinner, TableChart,} from 'nr1';
export default class PastTests extends React.Component { render() { const historicalData = { metadata: { id: 'past-tests', name: 'Past tests', columns: ['endDate', 'versionADescription', 'versionBDescription', 'winner'], }, data: [], }
return <div> <HeadingText className="chartHeader"> Past tests </HeadingText> <AccountStorageQuery accountIds={this.props.accountIds} collection="past-tests"> {({ loading, error, data }) => { if (loading) { return <Spinner />; } if (error) { console.debug(error); return 'There was an error fetching your data.'; } data.forEach( function (currentValue, index) { historicalData.data.push({ endDate: currentValue.id, versionADescription: currentValue.document.versionADescription, versionBDescription: currentValue.document.versionBDescription, winner: currentValue.document.winner, }) }, data ) return <TableChart data={[historicalData]} fullWidth /> }} </AccountStorageQuery> </div> }}
Primeiro, você removeu os dados simulados de historicalData
. Então, você usou AccountStorageQuery
para buscar dados do NerdStorage. Você passou o identificador da sua conta e o nome da coleção na qual armazenou o documento.
Observe que existem três valores de retorno da consulta:
loading
error
data
Se a consulta estiver em andamento, loading
será true
. Neste caso, você mostra um componente Spinner
interface do usuário para avisar ao usuário que a tabela ainda não está pronta. Se a consulta retornou um erro, você poderá ver informações sobre esse erro na variável error
. Você log essas informações no console para fins de depuração e retorna uma mensagem de erro. Se a consulta for retornada com êxito, você poderá acessar os dados na variável data
. Como os dados não correspondem ao formato exigido pelo TableChart
, você percorre os dados e os formata de acordo com as especificações do TableChart
. Finalmente, você passa historicalData
para seu TableChart
.
No arquivo index.js
do seu Nerdlet, passe seu ACCOUNT_ID
para PastTests
:
import React from 'react';import { ChartGroup, Grid, GridItem } from 'nr1';import EndTestSection from './end-test';import NewsletterSignups from './newsletter-signups';import PastTests from './past-tests';import TotalCancellations from './total-cancellations';import TotalSubscriptions from './total-subscriptions';import VersionDescription from './description';import VersionPageViews from './page-views';import VersionTotals from './totals';
const ACCOUNT_ID = 1234567 // <YOUR NEW RELIC ACCOUNT ID>const VERSION_A_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter"'const VERSION_B_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter and get a free shirt!"'
export default class AbTestNerdletNerdlet extends React.Component { render() { return <div> <Grid className="wrapper"> <GridItem columnSpan={6}> <VersionDescription description={VERSION_A_DESCRIPTION} version="A" /> </GridItem> <GridItem columnSpan={6}> <VersionDescription description={VERSION_B_DESCRIPTION} version="B" /> </GridItem> <GridItem columnSpan={12}><hr /></GridItem> <GridItem columnSpan={12}><NewsletterSignups /></GridItem> <GridItem columnSpan={6}><TotalSubscriptions /></GridItem> <GridItem columnSpan={6}><TotalCancellations /></GridItem> <GridItem columnSpan={6}> <VersionTotals version='a' accountId={ACCOUNT_ID} /> </GridItem> <GridItem columnSpan={6}> <VersionTotals version='b' accountId={ACCOUNT_ID} /> </GridItem> <ChartGroup> <GridItem columnSpan={6}> <VersionPageViews version='a' /> </GridItem> <GridItem columnSpan={6}> <VersionPageViews version='b' /> </GridItem> </ChartGroup> <GridItem columnSpan={12}> <EndTestSection accountId={ACCOUNT_ID} versionADescription={VERSION_A_DESCRIPTION} versionBDescription={VERSION_B_DESCRIPTION} /> </GridItem> <GridItem columnSpan={12}> <PastTests accountId={ACCOUNT_ID} /> </GridItem> </Grid> </div> }}
Importante
Certifique-se de substituir <YOUR NEW RELIC ACCOUNT ID>
pelo seu ID de conta New Relic real.
Navegue até a raiz do seu Nerdpack em nru-programmability-course/add-nerdstorage/ab-test
.
Gere um novo UUID para o seu Nerdpack:
$nr1 nerdpack:uuid -gf
Como você clonou o repositório de cursos que continha um Nerdpack existente, você precisa gerar seu próprio identificador exclusivo. Este UUID mapeia seu Nerdpack para sua conta New Relic. Também permite que seu aplicativo faça solicitações Nerdgraph em nome de sua conta.
Sirva seu aplicativo localmente:
$nr1 nerdpack:serve
Acesse https://one.newrelic.com?nerdpacks=local e visualize seu aplicativo em Apps > Your apps.
A princípio, você não deverá ver nenhum dado.
Clique em End test e aprove sua ação no modal. Agora, você vê os dados em Past tests.
Dica
Se algo não funcionar, use as ferramentas de depuração do seu navegador para tentar identificar o problema.
Assegure-se de que você:
- Copiou o código corretamente da lição
- Gerou um novo UUID
- Substituiu todas as instâncias de
<YOUR NEW RELIC ACCOUNT ID>
no seu projeto pelo seu New Relic ID de conta real
Quando terminar, pare de servir seu aplicativo New Relic pressionando CTRL+C
na janela do terminal do seu servidor local.
Ótimo trabalho! Agora você tem experiência no uso dos componentes de consulta e mutação do NerdStorage. No entanto, ainda há mais um gráfico com dados simulados: Total cancellations per version.
Total cancellations per version é diferente dos outros gráficos em seu aplicativo de teste A/B. Como New Relic não sabe nada sobre quantos usuários cancelam a assinatura do seu boletim informativo, você precisa solicitar essas informações a uma fonte externa. Para os fins deste curso, criamos um serviço de dados externo que fornece dados falsos de cancelamento de newsletters para você consumir em seu aplicativo. Este serviço simulado reside em https://api.nerdsletter.net/cancellations.
Os aplicativos New Relic são aplicativos React, o que significa que você pode usar os recursos React e Javascript para coletar dados não apenas do New Relic, mas de qualquer serviço externo. Em uma lição posterior, você aprenderá como ir além do New Relic em busca de dados que informarão como seu software está ajudando você a atingir seus objetivos de negócios. Mas antes de aprender isso, você precisa saber algo sobre nosso serviço de dados simulados: ele requer um cabeçalho de autorização!
Nesta lição, você aprendeu como usar o NerdStorage para consultar e alterar dados no armazenamento de dados do próprio aplicativo. Embora o NerdStorage seja um ótimo lugar para muitas categorias de dados, não é apropriado para dados confidenciais, como um token que você passaria em um cabeçalho de autorização para um serviço externo. Para isso, você usaria o NerdStorageVault.
Dica
Esta lição faz parte de um curso que ensina como construir um aplicativo New Relic do zero. Continue para a próxima lição: Acesse o NerdStorageVault a partir do seu nerdlet.