Empiece a realizar un seguimiento de su progreso
Inicio de Trailhead
Inicio de Trailhead

Instalar la aplicación de ejemplo

Objetivos de aprendizaje

Después de completar esta unidad, podrá:
  • Instalar la aplicación de ejemplo Record Viewer.
  • Comprender la estructura de la aplicación Record Viewer.
  • Ver un registro en la aplicación Record Viewer.

Instalar la aplicación Record Viewer

Vamos a examinar el código en profundidad. Para obtener información sobre la API de la interfaz de usuario, debe instalar la aplicación de ejemplo Record Viewer. Utilice la aplicación Record Viewer para crear, leer, actualizar y eliminar registros. Dado que se trata de una aplicación de ejemplo, también incluye una interfaz de usuario que muestra las respuestas JSON de la API de la interfaz de usuario. Cree un registro de oportunidad en la aplicación de ejemplo Record Viewer.
Sugerencia

Sugerencia

Para completar el reto práctico al final de esta unidad, debe realizar estos pasos. Si no tiene un Trailhead Playground, desplácese al reto y cree uno ahora.

  1. Si no tiene Git instalado, haga esto en primer lugar.
  2. Duplique el repositorio de Git de Record Viewer. Si no sabe cómo duplicar un repositorio, consulte Duplicación de un repositorio en la Ayuda de GitHub.
  3. Record Viewer se ejecuta en un contenedor de Docker. Instale la versión estable de Docker Engine (Community). Docker le solicita crear una cuenta para descargar el software.
  4. Inicie Docker.
Nota

Nota

En Windows, en Configuración de Docker, seleccione Unidades compartidas y seleccione la unidad local donde duplicó la aplicación Record Viewer.

Record Viewer es una aplicación conectada, la cual es una aplicación que se comunica con Salesforce mediante API. La aplicación no se ejecuta en Salesforce Platform, pero se conecta mediante API. Para definir cómo la aplicación Record Viewer se autentica con Salesforce, vaya a Configuración y cree una aplicación conectada.

  1. En su Trailhead Playground, vaya a Configuración, ingrese Aplicación y seleccione Gestor de aplicaciones.
  2. Haga clic en Nueva aplicación conectada e ingrese la siguiente configuración:
    • Nombre de aplicación conectada: RecordViewer
    • Email de contacto: Su dirección de email
  3. Seleccione Activar configuración de OAuth e ingrese la siguiente configuración:
    • URL de devolución de llamadas: https://localhost:8443/oauth-redirect
    • Ámbitos de OAuth seleccionados: Acceder a sus datos y gestionarlos (api)
  4. Haga clic en Guardar.
  5. En la página Nueva aplicación conectada, haga clic en Continuar.
  6. Copie y guarde la clave de consumidor (llamada también Id. de cliente de OAuth). La necesitará más adelante.
Para permitir que Record Viewer realice solicitudes HTTP en Salesforce desde un navegador web, configure el uso compartido de recursos de origen cruzado (CORS) en su Trailhead Playground.
  1. En Configuración, ingrese CORS y seleccione CORS.
  2. Haga clic en Nuevo.
  3. Para Patrón de URL de origen, ingrese https://localhost:8443.
  4. Haga clic en Guardar.

Para construir la aplicación Record Viewer e iniciar el servidor, utilice una interfaz de la línea de comandos como Terminal de MacOS o el Símbolo del sistema de Windows.

En primer lugar, utilice el comando cd para cambiar de directorios al directorio de RecordViewer que duplicó en su equipo local. Sustituya la siguiente ruta por la ruta al directorio de RecordViewer. Por ejemplo, si el directorio de RecordViewer está en su directorio de usuarios de Mac, ingrese cd ~/RecordViewer.
cd /replace/with/path/to/RecordViewer

A continuación, ejecute estos comandos de Docker.

docker-compose build && docker-compose up -d
Para iniciar la aplicación Record Viewer, en un navegador abra https://localhost:8443.
Nota

Nota

La aplicación Record Viewer utiliza un certificado SSL autofirmado para que los navegadores puedan indicarle que su conexión no es privada. Es seguro hacer clic y cargar la aplicación. En Chrome, haga clic en Opciones avanzadas y Continuar al sitio. En Firefox, haga clic en Opciones avanzadas y agregue una excepción. En Internet Explorer, haga clic en Continuar a este sitio web. En Safari, haga clic en Mostrar detalles y Visitar este sitio web.

Nota

Nota

Si localhost no se conecta, utilice la dirección IP de su equipo en su lugar, por ejemplo https://192.168.34.34:8443. Utilice también este valor en el patrón de URL de inicio de sesión de CORS.

Para autorizar Record Viewer para realizar solicitudes en Salesforce, ingrese la URL de inicio de sesión de Salesforce (https://login.salesforce.com) y la clave de consumidor que guardó en la aplicación conectada, y haga clic en Iniciar sesión.Pantalla de inicio de sesión de la aplicación Record Viewer.

Para conceder permiso a la aplicación Record Viewer para acceder a su organización de Salesforce, compruebe si su nombre de usuario es correcto y haga clic en Permitir.Pantalla ¿Permitir el acceso?

Nota

Nota

Por último, el usuario cierra la sesión de Salesforce. Para volver a autorizar la aplicación, cargue la página de inicio de sesión: https://localhost:8443/login. Ingrese la URL de inicio de sesión de Salesforce (https://login.salesforce.com) y la clave de consumidor que guardó en la aplicación conectada.

Utilizar la aplicación Record Viewer

Utilice Record Viewer para ver, modificar, crear y eliminar registros de Salesforce. Record Viewer utiliza la API de la interfaz de usuario para realizar estas operaciones sobre registros de Salesforce. La aplicación también le ofrece una manera cómoda de mirar la respuesta JSON de la API de la interfaz de usuario.

Antes de que miremos un registro en Record Viewer, echemos un vistazo a un registro en Salesforce para que podamos comparar.
  1. En un navegador, abra la organización de Salesforce que utilizó para crear la aplicación conectada RecordViewer.
  2. Haga clic en Cuentas y, a continuación, haga clic en Nueva.
  3. Para Nombre de cuenta, ingrese Contenedores universales
  4. Para Teléfono, introduzca 206 555 1212 y haga clic en Guardar.
  5. Para ver la página de detalles del registro del nuevo registro, haga clic en Detalles.
Detalles de registro Cuenta en Lightning Experience
Ahora miremos el mismo registro en la aplicación Record Viewer.
  1. En un navegador, abra https://localhost:8443.
  2. Bajo Elementos recientes, haga clic en Contenedores universales.
    Nota

    Nota

    Si no ve la aplicación Contenedores universales, actualice la página.

La aplicación Record Viewer muestra la página de detalles del registro.Detalles del registro Cuenta en la aplicación Record Viewer

Hablamos sobre el poder de la API de la interfaz de usuario, que reside en que sus respuestas respetan los cambios en los metadatos realizados en la organización de Salesforce. Así que retiremos un campo del formato Cuenta en la organización de Salesforce y veamos qué pasa en Record Viewer.

Contenedores universales tiene un número de teléfono, pero la página de detalles del registro también tiene un campo Fax. Nadie tiene ya máquinas de fax, así que retiremos eso del formato de página.

  1. En su Trailhead Playground, desde Configuración, ingrese Objeto y seleccione Gestor de objetos.
  2. Haga clic en Cuenta | Formatos de página | Formato de cuenta.
  3. En el editor de formatos de página, haga clic para retirar el campo Fax y haga clic en Guardar.

Editor de formatos de página con el campo Fax seleccionado

Ahora vuelva a la aplicación Record Viewer y haga clic en View Record (Ver registro) para volver a cargar el registro Contenedores universales. ¡Voilà! El campo Fax desaparece y no cambió una sola línea de código.Detalles del registro Cuenta en la aplicación Record Viewer sin el campo Fax

En este caso, retiró el campo del formato. En una situación real, el administrador no tiene que notificarle que cambió un formato, ¡su aplicación simplemente responde!

Estructura de la aplicación Record Viewer

Para trabajar con la API de la interfaz de usuario, puede utilizar cualquier marco web o lenguaje que permita realizar solicitudes HTTP. Dispone de Polymer, React, Angular, Vue, iOS o Android. Utilice la tecnología que prefiera.

La aplicación Record Viewer es una aplicación de una sola página creada con React, Redux y Redux-Saga. Revisaremos rápidamente los fundamentos de estas tecnologías cuando examinemos la estructura de archivos de la aplicación. Si no está familiarizado con React y Redux, no supone ningún problema. Solo necesita captar las ideas generales.

Su objetivo es saber cómo acceder a los recursos de la API de la interfaz de usuario y cómo gestionar las respuestas. Cada marco y lenguaje completa estas tareas de formas ligeramente distintas, pero los conceptos fundamentales son los mismos y la API se comporta del mismo modo.

La aplicación Record Viewer se creó mediante lo siguiente:

  • Pug. Genera páginas HTML a partir de plantillas del lado del servidor.
  • React. Es una biblioteca de JavaScript para crear componentes personalizados y combinarlos para crear interfaces de usuario.
  • Redux. Incluye el estado de una aplicación React en un almacén, que es un único objeto de JavaScript inmutable. Los componentes de React distribuyen objetos de JavaScript llamados acciones, las cuales son interceptadas por reductores. Los reductores son funciones de JavaScript que utilizan acciones como entradas para actualizar el estado de Redux.
  • Redux-Saga. Como en el caso de los reductores, los sagas son funciones de JavaScript que se ejecutan cuando interceptan una acción. Los sagas gestionan las solicitudes asíncronas para la API de la interfaz de usuario. Al final de una operación asíncrona, los sagas distribuyen una acción, la cual es interceptada por un reductor que actualiza el almacén. Los sagas evitan confusiones en el caso de las devoluciones de llamada.
  • Node.js. Tiempo de ejecución del lado del servidor para aplicaciones de JavaScript.

Veamos cómo funcionan estos conceptos abstractos en el mundo real. Inicie su IDE favorito y abra la carpeta RecordViewer que duplicó desde GitHub. Estructura de archivos de la aplicación Record Viewer en VS Code. Carpeta de acciones, carpeta de componentes, carpeta de contenedores, carpeta de aplicaciones auxiliares, carpeta de reductores y carpeta de sagas.

Primero, vayamos a la carpeta de vistas, que contiene las plantillas HTML de Pug. La aplicación incluye tres vistas: la página de inicio (donde ingresó la información de inicio de sesión de Salesforce), la página de vista del registro (que es el principal contenedor de la aplicación) y una página de error (que esperamos que no viera). La cuarta plantilla de Pug es un redireccionamiento de autenticación de OAuth.

Si se autentica correctamente, la plantilla recordView.pug se carga y llama a renderRoot, que se define en el archivo root.js. A partir de este punto, la aplicación Record Viewer ejecuta el código del lado del cliente cargado en esta página web única.
<!-- /views/recordView.pug -->

doctype html
html
  block head
    title Record Viewer
    // Metadata and style sheet links removed to keep sample short

    script(type='text/javascript', src='https://code.jquery.com/jquery-2.0.3.min.js')
    script(type='text/javascript', src='root.js')

  body
    .slds-grid.slds-wrap
      nav.slds-col.slds-size--1-of-1
        .slds-page-header
          p.slds-page-header__title.slds-truncate.slds-align-middle
            a(href='/recordView') Record Viewer
          p.slds-page-header__info powered by User Interface API
    #root
    script.
      $( document ).ready(function() {
        let rootNode = document.getElementById("root");
        renderRoot("#{targetUrl}", "#{accessToken}", "#{recordId}", rootNode);
      });
El archivo /client-src/root.js arranca la aplicación. Conecta el componente raíz RecordViewerWrapper con la raíz de los reductores de estado de Redux y el middleware de Saga. Recuerde que los reductores actualizan el estado y los sagas realizan solicitudes en la API de la interfaz de usuario y distribuyen acciones que contienen los resultados.
/* Excerpt from /client-src/root.js */

// Root renderer for record viewer.
global.renderRoot = function(instanceUrl, accessToken, recordId, rootNode) {
  const sagaMiddleware = createSagaMiddleware()
  const store = createStore(rootReducer, {login:{instanceUrl, accessToken}, record:{recordId}}, applyMiddleware(sagaMiddleware));
  sagaMiddleware.run(rootSaga);

  ReactDOM.render(
    <Provider store={store}>
      <div>
        <RecordViewerWrapper />
      </div>
    </Provider>,
    rootNode);
}
El componente RecordViewerWrapper.js de React se incluye en la carpeta de contenedores. Se trata de un componente conectado de nivel superior que contiene el componente RecordViewer. La función mapStateToProps indica cómo enlazar el estado de Redux con las propiedades de RecordViewer.
/* Excerpt from /client-src/containers/RecordViewerWrapper.js */

// Presentational Component that uses state to decide how to
// construct the RecordViewer.
const mapStateToProps = (state) => {
  if (state.record.record) {
    return {
      screen: 'RECORD',
      record: state.record.record,
      headerRecordId: state.header.recordId,
      mode: state.record.mode,
      context: state.context,
      prevMode: state.record.prevMode,
      creds: state.login,
      picklists : state.picklists,
      depGraph: state.depGraph,
      rawjson: state.rawjson,
      error: state.error
    }
  } else if (state.record.recordId) {
    return {
      screen: 'FETCH_RECORD',
      recordId: state.record.recordId,
      mode: 'View',
      context: state.context,
      creds: state.login,
      rawjson: state.rawjson,
      error: state.error
    }
  }
 
  // Additional mappings removed to shorten sample
RecordViewWrapper incluye además una función mapDispatchToProps que asigna acciones de Redux a propiedades de React para que los componentes de React puedan distribuir acciones en respuesta a varios eventos. ¿Se acuerda de las acciones? Se utilizan como entradas para los reductores, los cuales son funciones que cambian el estado de la aplicación.
/* Excerpt from /client-src/containers/RecordViewerWrapper.js */

const mapDispatchToProps = (dispatch) => {
  return {
    onFetchRecord: (creds, id, context) => {
      dispatch(actions.fetchRecord(creds, id, context))
    },
    onRecordClick: (creds, id, context) => {
      dispatch(actions.fetchRecord(creds, id, context))
    },
    onViewRecordClick: (creds, id, context) => {
      dispatch(actions.fetchRecord(creds, id, context))
    },
    onFormFactorSelect: (formFactor, recordId) => {
      dispatch(actions.updateFormFactor(formFactor, recordId))
    },

   // Additional mappings removed to shorten sample
Finalmente, el método connect() conecta estas dos asignaciones con el componente RecordViewer simple.
/* Excerpt from /client-src/containers/RecordViewerWrapper.js */

const RecordViewerWrapper = connect(
  mapStateToProps,
  mapDispatchToProps
) (RecordViewer)

export default RecordViewerWrapper

Las acciones, los reductores y los sagas residen (cómodamente) en las carpetas de acciones, reductores y sagas.

Una acción es un objeto simple que debe incluir la propiedad type y puede incluir otras propiedades. La propiedad type identifica la acción. Todas las acciones se definen en el archivo /actions/index.js.
/* Excerpt from /client-src/actions/index.js */

export const fetchEntities = (creds) => {
  return {
    type: 'FETCH_ENTITIES',
    creds
  }
}

export const receiveEntities = (entities) => {
  return {
    type: 'RECEIVE_ENTITIES',
    entities,
    receivedAt: Date.now()
  }
}
Sigamos la alegre ruta de la acción fetchEntities. El archivo rootSaga.js registra todos los sagas en la aplicación Record Viewer. Cuando una acción se envía al almacén y su propiedad type coincide con una cadena en una función takeEvery, la función inicia el saga correspondiente. El tipo de acción FETCH_ENTITIES genera el saga entitiesFetcher.
/* /client-src/sagas/rootSaga.js */

import { takeEvery } from 'redux-saga'

import recentItemsFetcher from './recentItemsFetcher'
import recordFetcher from './recordFetcher'
import recordDeleter from './recordDeleter'
import recordUpdater from './recordUpdater'
import entitiesFetcher from './entitiesFetcher'
import recordCreator from './recordCreator'
import cloneDefaultsFetcher from './cloneDefaultsFetcher'
import createDefaultsFetcher from './createDefaultsFetcher'
import picklistsFetcher from './picklistsFetcher'
import depGraphValueUpdater from './depGraphValueUpdater'

export default function* rootSaga() {
  yield takeEvery('FETCH_RECORD', recordFetcher)
  yield takeEvery('FETCH_RECENT_ITEMS', recentItemsFetcher)
  yield takeEvery('DELETE_RECORD', recordDeleter)
  yield takeEvery('SAVE_RECORD', recordUpdater)
  yield takeEvery('FETCH_ENTITIES', entitiesFetcher)
  yield takeEvery('CREATE_RECORD', recordCreator)
  yield takeEvery('FETCH_CREATE_DEFAULTS', createDefaultsFetcher);
  yield takeEvery('FETCH_CLONE_DEFAULTS', cloneDefaultsFetcher);
  yield takeEvery('FETCH_PICKLISTS', picklistsFetcher);
  yield takeEvery('UPDATE_DEP_GRAPH_FIELD_VALUE', depGraphValueUpdater)
}
El saga entitiesFetcher.js realiza una solicitud saga en la API de la interfaz de usuario para obtener una lista de objetos compatibles con la API. El recurso de la API de la interfaz de usuario es /ui-api/object-info. Explicaremos cómo crear la URL completa en una unidad posterior. Si está familiarizado con las API de REST de Salesforce, ya comprende por qué todas utilizan el mismo patrón. Además, como en el caso de otras API de REST de Salesforce, la API de la interfaz de usuario utiliza OAuth 2.0. El token de portador se pasa al encabezado Authorization. Establecemos el encabezado X-Chatter-Entity-Encoding en false para que la respuesta no se codifique.
/* /client-src/sagas/entitiesFetcher.js */

import { call, put } from 'redux-saga/effects'

import { receiveEntities } from '../actions'

export default function* entitiesFetcher(action) {

  let mruUrl = action.creds.instanceUrl + '/services/data/v48.0/ui-api/object-info'

  let req = {
    method: 'GET',
    headers: {
      'Authorization' : 'Bearer ' + action.creds.accessToken,
      'X-Chatter-Entity-Encoding': false}
    }

  try {
    const response = yield call(fetch, mruUrl, req)
    const responseJson = yield response.json()
    yield put(receiveEntities(responseJson))
  } catch(err) {
    console.error('Describe sobjects error: ' + JSON.stringify(err))
  }
}
¿Ve la línea yield put(receiveEntities(responseJson))? Busque receiveEntities en el ejemplo de código anterior de /actions/index.js. ¿Ve la acción receiveEntities? Seguro que sí. Si la operación de la API de la interfaz de usuario es correcta, el saga envía la acción receiveEntities que contiene la respuesta JSON. El reductor entities.js intercepta la acción y la utiliza como una entrada para actualizar el estado de Redux.
/* /client-src/reducers/entities.js */

const entities = (state = {sobjects: []}, action) => {
  switch (action.type) {
    case 'RECEIVE_ENTITIES':
      return {
        sobjects: action.entities.objects,
        receivedAt: action.receivedAt
      }
    default:
      return state
  }
}

export default entities

El reductor actualiza una parte del estado de Redux. Después de realizar este cambio, los componentes de React que se suscriben a esta parte del estado se actualizan automáticamente.

En la aplicación Record Viewer, los componentes de React que crean el HTML se incluyen en la carpeta de componentes. Estos componentes definen las partes de la interfaz de usuario de la aplicación. El componente CreateableEntitiesList.js define la interfaz de usuario que muestra un menú en la aplicación Record Viewer. El menú contiene la lista de objetos compatibles devueltos por la llamada a /ui-api/object-info. La aplicación RecordViewer recibe las entidades y las muestra en el componente CreateableEntitiesList.Menú emergente Crear nuevo registro con una lista de objetos que crear.
Sugerencia

Sugerencia

El código de RecordViewer suele utilizar el término entities (entidades), que significa objetos. Por lo tanto, si ve algo como CreateableEntitiesList, puede convertirlo en una lista de objetos que se pueden crear. Es decir, puede crear un registro a partir de cualquier objeto de la lista. Estos objetos son compatibles con la API de la interfaz de usuario.

En React, puede construir componentes para crear la interfaz de usuario, lo que significa que los componentes principales se pueden crear a partir de componentes secundarios anidados. Cuando desarrolle una aplicación, divida la funcionalidad en componentes simples y combínelos para formar componentes más complejos.

Al examinar los nombres de los componentes de la carpeta de componentes, puede afirmar que la aplicación Record Viewer tiene como finalidad última el trabajo con registros (por ejemplo, Record.js, RecordButton.js, RecordSection.js). Examine el código de los componentes y vea los componentes secundarios anidados. Por ejemplo, el componente RecordSection incluye componentes RecordRow anidados.
/* Excerpt from /client-src/components/RecordSection.js */

// Component that displays a Record section.
const RecordSection = ({section, error, editValues, picklists, onFieldValueUpdate, allowEdit, index, objectInfo, onEditDepGraph, uiMode, recordView}) => {

  return (
    <tbody>
      { section.useHeading &&
       <tr>
         <td colSpan="4" key={'sectionHeading' + index} className="slds-text-heading--small slds-p-left--medium slds-p-top--small slds-p-bottom--medium">
           {section.heading}
         </td>
       </tr>
      }
      {section.rows.map((row, i) =>
        <RecordRow
          key={'sectionRow' + index + ',' + i}
          allowEdit={allowEdit}
          uiMode={uiMode}
          picklists={picklists}
          onFieldValueUpdate={onFieldValueUpdate}
          error={error}
          editValues={editValues}
          row={row}
          sectionIndex={index}
          rowIndex={i} 
          objectInfo={objectInfo}
          recordView={recordView}
          onEditDepGraph={onEditDepGraph}/>
      )}
   </tbody>
  );
}
Por su cuenta, vaya a su IDE y examine el componente de registro (Record.js). Incluye <RecordSection>, <DepGraphEditor> y varios componentes <RecordButton>.

Por último, y no por ello menos importante, la carpeta de aplicaciones auxiliares incluye algunas funciones de aplicaciones auxiliares de JavaScript. Estas funciones transforman las respuestas de la API de la interfaz de usuario en modelos de datos que potencian la capacidad de la interfaz de usuario de Record Viewer. El código de recordLayout.js crea el modelo de datos interno para los formatos y el código de depGraphHelper.js crea el editor de listas de selección dependientes. Profundizaremos en estos archivos más adelante.