Descubriendo Google AppSheet en 48 horas
El pasado viernes 7 de julio por la mañana pensaba que Google AppSheet, la herramienta visual de construcción de soluciones de automatización de Google, su niña bonita del "sin-código" o "poco-código", no era mi cup of tea, que diría un hijo o hija de la Gran Bretaña.
Y apenas setenta y dos horas después aquí me tienes, poniendo en pausa en un arranque de fogoso entusiasmo estival el segundo artículo sobre las manías de la API de Google Chat que te prometí hace escasas semanas, para intentar contarte algo que aún no tengo muy claro qué es 😆.
Sí, puedes llamarme voluble. Mi pareja me lo espeta continuamente. Y no os faltará a ambos razón.
Pero qué demonios, la vida del divulgador tecnológico debe vivirse peligrosamente en ocasiones, así que vamos a la aventura. Espero al menos conseguir que este artículo tenga cierta coherencia, porque en cualquier caso lo que estás leyendo tiene bien poco de meditado.
Lo que pretendo aquí y ahora es hacerte partícipe de mis impresiones iniciales usando Google AppSheet a lo largo de un intenso fin de semana de aprendizaje.
Aprovechando que hace nada estábamos en periodo electoral —y no está muy claro que no lo volvamos a estar pronto 🙄— lo que sí puedo prometerte y de hecho te prometo es una cantidad posiblemente indecente de capturas de pantalla. Prepárate un termo de buen café o té 🧊 y acompáñame en este viaje iniciático particular a AppSheet.
🇺🇸 Instead, you might want to check out an slightly updated version of this post in this four-part series in English.
TABLA DE CONTENIDOS
¿Qué es Google AppSheet?
Para empezar, tengo que decirte que AppSheet tiene muchas horas de vuelo. Y no es un invento de Google.
Google compró AppSheet a no sé quién en 2020, cuando ya llevaba cosa de 8 años en el mercado, para seguidamente cargarse App Maker —mira que les gusta hacer estas cosas 😏—, su herramienta estrella (hasta entonces) de creación de aplicaciones de "poco código". Anda que menudo cabreo se pillaron algunos en aquel momento. Y con razón.
No voy a pretender por tanto descubrirle AppSheet a nadie. Si es que además yo no soy más que un recién llegado que simplemente está explorando las posibilidades de esta plataforma y disfrutando como un niño mientras lo hago, que de eso se trata. De hecho, tengo que confesarte que desde mi encuentro con Coda, ningún otro artefacto TIC me había enganchado de un modo tan obsesivo. Y eso es mucho decir.
Si quieres saber de qué va AppSheet no puedo dejar de recomendarte está presentación que preparó mi muy querido y nunca suficientemente bien ponderado Luis Loscertales para su intenso taller Mi primera App con Google AppSheet en el encuentro de GEG Spain Volvemos 10x (Valencia, mayo de 2022). Por cierto, ¡qué grande aquel encuentro! 🤗
O mejor aún, puedes contemplar a Luis en acción mañica en esta sesión en directo que tuvo la gentileza de desarrollar en nuestra comunidad de 🤓 frik... digo usuarios de Apps Script, Apps Script Ñ.
Un visionario, mi amigo Luis, qué duda cabe.
Pero esto no es un tutorial (creo). Solo unas impresiones de uso que pretenden destacar las características diferenciadoras de AppSheet... así que prosigamos.
AppSheet y tus datos
Básicamente, AppSheet utiliza los datos almacenados en diversos servicios y plataformas y ofrece una interfaz visual para construir cómodamente aplicaciones sobre ellos, con una fuerte orientación al consumo desde dispositivos móviles, eso sí.
Como puedes ver, la conectividad de AppSheet es abundante y generosa.
Tengo que decir que me llaman poderosamente la atención las integraciones con Google Calendar, Forms (a través de un complemento) y Drive.
De hecho, me resulta especialmente intrigante esta última, puesto que al parecer permite construir una tabla de datos a partir de los archivos contenidos en una carpeta de Drive, tratándolos como filas en las que sus metadatos (ID interno, ruta, nombre, fecha de creación, último editor y tipo de archivo) constituyen las columnas (campos) de la tabla. Definitivamente, algo que tengo que probar, tiene pinta de que podría resultar útil en casos de uso relacionados con la gestión documental, por ejemplo para organizar la documentación de los sistemas de gestión de calidad asociados a todas esas normas ISO tan fantásticas (no hay emoji pero sí cierta ironía).
También me parece destacable la posibilidad relativamente reciente (octubre 2022) de almacenar los datos de manera integrada dentro de AppSheet usando sus propias bases de datos. Y por cierto, me pregunto si esto tendrá algo que ver con aquel inefable experimento del Area 120 de Google llamado Tables 🤔.
☝ Google AppSheet es un servicio "core" de Google Workspace y por tanto está cubierto por el mismo paraguas legal que el resto de los servicios principales de esta plataforma por lo que hace a las condiciones de uso, seguridad y privacidad de los datos tratados. Cuando se utiliza desde una cuenta personal, por el contrario, aplican estas condiciones específicas.
¡Y por si fuera poco, contamos también con un conector nativo para Looker Studio! Pardiez, muy bien, esta gente de AppSheet de verdad que sabe cómo hacerme sentir a mis anchas.
AppSheet y yo
Bien, ahora que ya (no) te he explicado qué es AppSheet 😉, ha llegado el momento de comenzar a hablar de qué demonios he estado haciendo durante un número probablemente excesivo de horas a lo largo de cierto fin de semana del mes de julio.
Pero antes, otro circunloquio.
No estoy totalmente seguro de que los aprendizajes más profundos y duraderos se logren siempre tirándose de cabeza a la piscina para tratar de resolver un problema concreto sin comprobar antes hasta qué altura llega el agua.
Aunque sí creo firmemente que a menudo puede ser este el camino más motivador.
Por esa razón, y tras haber sobrellevado una semana en mi centro en la que el equipo docente había hablado mucho (pero mucho) acerca de cómo mejorar los procesos de tutorización, orientación y seguimiento general de alumnado, no se me ocurrió nada mejor que convertir este objetivo en el motor de mi aprendizaje de AppSheet.
Pues este es mi miniproyecto del finde ✌️, una app creada con #AppSheet para ayudar a mis tutores a la hora de hacer el seguimiento del alumnado, con múltiples niveles de acceso y 🔐👀 a nivel de registro.
— Pablo Felip (@pfelipm) July 9, 2023
Por cierto, cómo molan los formularios dinámicos 🤩. pic.twitter.com/Hiu1OeA7NW
¿Te cuento cómo ha ido la cosa?
AppSheet y mis datos
Un tipo muy listo dijo una vez esto tan interesante:
Algoritmos + Estructuras de datos = Programas
De hecho, creo que hasta escribió un libro para explicar bien su ocurrencia 😜. Así que para que entiendas mejor algunas de las cosas que me han gustado de AppSheet (y otras que no tanto), empezará hablándote de los datos que mi app, aún fabricada aquel viernes por la tarde del material del que están hechos los sueños, debía masticar.
Pero a lo que íbamos (fin del circunloquio)...
En mi centro usamos mucho las hojas de cálculo de Google.
Y cuando digo mucho, es mucho.
Sí, hacemos como que sabemos que las hojas de cálculo no son bases de datos, pero aún así movemos toda clase de información desde otros sistemas hacia ellas cuando los flujos de trabajo que estos proporcionan no se ajustan totalmente a nuestras necesidades. Es posible que a ti te pasa lo mismo.
¡Silos de datos!, exclamarán algunos. Supervivencia, lo llamo yo.
Como la información de partida necesaria para desarrollar el proceso de atención al alumnado del que te hablaba hace un momento (estudiantes, grupos, tutores...) ya la tenemos en hojas de cálculo, me pareció que lo natural sería por tanto basar mi app ágilTutor, vaya el nombre por delante 😬, en ellas.
Lo de menos (ahora) son los detalles del diseño relacional. Pero para que puedas contextualizar de la mejor manera posible lo que te voy a contar a continuación, me gustaría enseñarte este diagrama que muestra qué tablas de datos intervienen en mi proceso de seguimiento del alumnado y cómo quedan conectadas entre sí.
☝ Que la ligereza y el descaro con los que estoy hablando de los datos y de sus relaciones no te haga pensar equivocadamente que esta es una cuestión menor. Todo lo contrario. Un mal diseño relacional es una bola de nieve que se va haciendo grande a medida que diseñas tu app. Y puede incluso llegar a aplastarte en las etapas finales de su construcción hasta el punto de obligarte a repensarlo todo. Pero esa es otra historia y tal vez será contada en otra ocasión.
Las flechas indican, de manera poco rigurosa, qué información procedente de una tabla se utiliza en otra, estableciendo por tanto una relación entre ambas. Por ejemplo:
- Los tutores quedan identificados por sus direcciones de correo electrónico en la tabla de Tutores.
- La asignación de un tutor determinado a un grupo se realiza en la tabla de Grupos, introduciendo la dirección de correo de un tutor específico en la columna Tutor de la fila que representa al grupo. La dirección de correo del tutor "viaja" por tanto de la tabla de Tutores a la de Grupos.
Lo sé, una descripción de la estructura de datos muy de aquella manera 🙏, pero ya nos vale.
Y empezamos con las sorpresas agradables.
Resulta que AppSheet, a partir del modo en que vamos diseñando la aplicación, extrae la estructura relacional de nuestros datos de manera automática, estructura que puede representar en forma de lista o como un grafo interactivo de lo más vistoso.
Solo tienes que ir a ⚙Settings → Relations para comprobarlo.
Lugares comunes en AppSheet
Así resumiendo mucho, el problema que resuelve AppSheet es el de facilitar la construcción de una interfaz visual para navegar por una jerarquía de tablas de datos relacionadas entre sí. Y además —resulta que eran dos problemas en lugar de uno— permite diseñar automatizaciones molonas encima de todo eso para que la app resultante sea intensamente reactiva.
Si estás haciendo tus pinitos en AppSheet, como es mi caso, yo diría que durante un tiempo vas a pasar muchos ratos en las tres primeras secciones de estas cinco que nos ofrece el editor:
- 📋 Data
- 📱 Views & Format rules
- ⚡ Actions
- 🤖 Automation
- 💬 Chat apps
Todas ellas quedan perfectamente recogidas en la mitad superior de la barra lateral izquierda de accesos directos de AppSheet. Destaco las tres en las que nos vamos a centrar a lo largo del artículo.
Se me ocurre que otra vista de pájaro de AppSheet estaría bien para situarnos, ¿verdad? Aunque esto no sea un tutorial 😜.
Así en plan rapidito:
- Barra superior, da acceso a una serie de funciones generales y a tu perfil de usuario.
- Barra lateral con botones de acceso directo a las diferentes secciones principales o paneles de trabajo del editor.
- Panel secundario para manipular los elementos específicos con los que estés trabajando en cada momento, ya sabes: tablas, vistas, acciones, automatizaciones y apps de chat.
- La zona de trabajo específica de cada uno de los paneles de AppSheet. Aquí es donde vas a pasártelo pipa.
- Área de previsualización de la app. En este emulador podrás probar su aspecto y comportamiento cómodamente, en diferentes tipos de dispositivos (móvil, tableta y navegador de escritorio), al mismo tiempo que la construyes. Funciona francamente bien.
Hechas las presentaciones, vámonos tirando a la piscina 💦.
De tablas y el lenguaje de fórmulas de AppSheet
Tengo que reconocer que lo que más me ha sorprendido de AppSheet ha sido su rico e incluso en ocasiones hasta diría que imaginativo lenguaje de fórmulas, así que voy a dedicar gran parte de este artículo a hablar de él y presentar algunos casos de uso que me parecen muy significativos.
Honestamente, no esperaba encontrarme con algo tan bien parido. Sí, ya he dicho que tenía ciertos perjuicios hacia AppSheet, pero como ya he manifestado mi arrepentimiento en varias ocasiones voy a dejar de fustigarme ipso facto.
Algunas de sus funciones incorporadas te van a recordar mucho a las disponibles en las hojas de cálculo de Google. Pero no te equivoques, hay ciertas cosas que cambian sustancialmente las reglas del juego. Y aquí te presento la primera de ellas:
1️⃣ Puedes acceder a los datos contenidos en cualquier columna de una tabla usando esta interesante sintaxis encorchetada.
Admins[Email]
La expresión anterior devuelve todos los elementos que hay en la columna Email de la tabla Admins, que en este caso solo contiene información en la fila 2 de la hoja de cálculo de la que proceden los datos.
Está claro, ¿verdad? Cuando el origen de los datos es una hoja de cálculo de Google, AppSheet obtiene:
- El nombre de la tabla a partir del nombre de la hoja de trabajo.
- El nombre de la columna a partir del texto introducido en la celda de encabezado.
☝ Si añades un comentario en la celda de encabezado (A1 en el ejemplo anterior), AppSheet lo utilizará en la propiedad DESCRIPTION de la tabla. Estas descripciones pueden resultar útiles en algunas vistas de tu app dado que resultan más descriptivas que los usualmente escuetos nombres de las columnas. De hecho, AppSheet realiza un análisis inteligente de los encabezados de las columnas para tratar de inferir la estructura de tus datos.
☠ Mucho cuidado con cambiar los nombres de las hojas de trabajo en la hoja de cálculo que constituye el origen de datos de tu app . La cosa suele tener apaño, pero por mi corta experiencia yo diría que es mejor evitarlo dado que pueden producir efectos colaterales indeseados. Ah, y esos estupendos chips de persona parece que hoy por hoy confunden a AppSheet, esperemos que no lo hagan por mucho tiempo.
Modificar los nombres de tablas, columnas y otros elementos en AppSheet puede romper la aplicación hasta que se corrijan las referencias a ellos en las fórmulas y expresiones. ¡Dejarlo todo funcionando otra vez puede suponer un trabajo tedioso y delicado!
Si vienes de las hojas de cálculo de Google, algo equivalente podría ser:
{A2:A}
Pero AppSheet renuncia a las archiconocidas referencias basadas en coordenadas, típicas de las hojas de cálculo (ej. A2), para acceder a la información contenida en sus tablas.
Por el contrario, puedes usar expresiones como la anterior, en las que intervienen los nombres significativos de tablas y columnas, para recuperar todos los elementos contenidos en una columna específica de cualquier tabla.
tabla[columna]
¡Seguro que si has utilizado el lenguaje de formulas de herramientas como Notion o Coda te encontrarás como en casa! Yo me siento así en AppSheet, desde luego.
Para AppSheet, como para Notion y Coda, la unidad mínima de información de una tabla no es una celda, sino más bien toda una columna, dado que su funcionamiento se asemeja más al de una base de datos de toda la vida.
¿Quiere esto decir que no podremos acceder con nuestras fórmulas al valor almacenado en una columna de cierta o ciertas filas? En absoluto, pero cada cosa a su tiempo.
Debes saber que bajo su discreto capó, el motor de fórmulas de AppSheet soporta listas de elementos (tienen que ser del mismo tipo), como Coda. Lo que nos devuelve por tanto una expresión como la anterior es precisamente eso, una lista.
También podemos crear listas usando llaves...
{ "Grupo 1", "Grupo 2", "Grupo 3" }
...o bien recurriendo a la función LIST() para construirlas basándonos en otros elementos:
LIST("Grupo 1", "Grupo 2", "Grupo 3")
Incluso tenemos una cierta "aritmética" de listas, dado que podemos sumar (combinar) listas o restarlas (eliminar elementos de la primera de ellas) muy fácilmente:
{ "Grupo 1", "Grupo 2" } + { "Grupo 3" } → { "Grupo 1", "Grupo 2", "Grupo 3" }
{ "Grupo 1", "Grupo 2", "Grupo 3" } - { "Grupo 2" } → { "Grupo 1", "Grupo 3" }
Así como también obtener una nueva lista a partir de la intersección de otras dos dadas:
INTERSECT({ 1, 2, 3, 4, 5 }, { 3, 4, 5, 6 }) → { 3, 4, 5 }
¡Mola, eh! 😏
AppSheet cuenta con un conjunto de funciones para trabajar con listas que no está nada mal (👋 hola de nuevo, Coda 🤩), además de otras tantas que devuelven listas como resultado.
Desgraciadamente no he encontrado un modo evidente de de iterar, dentro de una fórmula, sobre los elementos de una lista para realizar algún cálculo o acción sobre cada uno de ellos, como sí es posible en Coda con las funciones equivalentes ForEach() y FormulaMap(). Yo díría que esta es una debilidad que debería remediarse.
Vale, pero ¿y esto de las listas para qué sirve? Calma, ya voy.
Tengo que hablarte ahora de la segunda de esas cosas que en mi opinión cambian la reglas del juego.
2️⃣ Puedes insertar fórmulas en los lugares más insospechados del editor de AppSheet para tomar decisiones que condicionan el comportamiento de tu aplicación de manera dinámica y extremadamente granular.
Por ejemplo:
- Establecer los permisos de acceso de un usuario sobre cada tabla de datos, determinando sus capacidades de lectura, edición, inserción y eliminación de elementos.
- Crear campos calculados, que AppSheet denomina columnas virtuales. Estas columnas virtuales son visibles en el editor de AppSheet, pero no existen en la hoja de cálculo subyacente (o cualquier otro origen de datos) ni se escriben en ella en ningún momento.
- Obtener y manipular valores de otras tablas, conectadas o no por medio de una relación.
- Ocultar determinadas filas de las tablas a ciertos usuarios de tu aplicación, esto es lograr una forma de seguridad a nivel de fila (registro).
- Establecer valores predeterminados para los campos (columnas) de una tabla.
- Hacer que ciertas columnas no se visualicen en determinadas vistas de tu aplicación.
- Mostrar u ocultar los botones que muestra la aplicación dependiendo de circunstancias diversas.
- Establecer reglas de validación sobre la información introducida por el usuario.
- Aplicar reglas de formato condicional.
- Modificar las etiquetas visibles de los campos que se muestran al usuario de tu aplicación.
- Mostrar mensajes y textos, en general, en distintos idiomas dependiendo de la configuración regional del dispositivo del usuario.
Y seguro que me estoy dejando cosas, que la lista es larga. Muy larga.
Todas estas posibilidades nos proporcionan, como creadores, un control brutal sobre el comportamiento de nuestra aplicación, que podemos diseñar de modo que se adapte a la identidad del usuario (es lo primero en lo que pensé, la verdad) o a muchas otras circunstancias durante su uso.
Como en Coda (otra vez), aunque yo diría que en esta ocasión incluso con mayor versatilidad.
Veamos a continuación diversas situaciones reales en las que se han usado algunas de estas capacidades de AppSheet. Para mostrártelas usaré como ejemplo la pequeña aplicación de seguimiento del alumnado que he desarrollado.
Otorgar permisos de acceso por usuario a una tabla
En nuestro caso, a la de Cursos (por ejemplo), pero lo puedes hacer con cualquier otra.
Esto se consigue en el panel de ajustes ⚙ de la tabla:
Buscamos la sección denominada "Are updates allowed?" No tiene pérdida, está justo debajo del nombre de la tabla.
Date cuenta de que puedes fijar los permisos de acceso de manera incondicional usando los botones Updates / Adds / Deletes y Read-Only. Pero no es eso lo que perseguimos.
Fíjate en ese botón ⚗ con forma de matraz de laboratorio. Te vas a cansar de verlo en AppSheet. Indica que el ajuste junto al que aparece puede establecerse por medio de una fórmula.
Pulsarlo da paso al asistente de fórmulas de AppSheet, que en esta ocasión usaremos para introducir la que puedes ver aquí abajo 👇.
IF(IN(USEREMAIL(), Admins[Email]), "ALL_CHANGES", "READ_ONLY")
En esta fórmula están pasando dos cosas:
- Por una parte, se obtiene la dirección de correo del usuario que está utilizando la aplicación con la función USEREMAIL().
- Por otra parte, tirando del estupendo soporte para listas de AppSheet, usamos la función IN() para lograr que solo los usuarios cuya dirección de correo electrónico aparece en la tabla Admins (que ya conoces de hace un momento) puedan modificar con total libertad (ALL_CHANGES) la información contenida en la tabla de cursos de la aplicación. El resto de usuarios accederá a ella con permiso de solo lectura (READ_ONLY).
Por cierto, fíjate en lo estupendo que es el editor de fórmulas:
- Facilita la introducción de fórmulas en varias líneas, colorea su sintaxis e incluso destaca visualmente los paréntesis de apertura y cierre que están emparejados.
- Dispone de una completa ayuda contextual y ofrece consejos de uso.
- Muestra un rico conjunto de expresiones de ejemplo.
- Cuenta con un explorador con el que recorrer los campos de las tablas.
- Comprueba en tiempo real si la fórmula es correcta y describe su funcionamiento inferido usando lenguaje natural (ya querríamos esto en Sheets, ¿verdad?).
De matrícula, equipo de desarrollo de Google AppSheet 👏.
Crear campos calculados que muestren información de resumen
Aquí la cosa va de mostrar el recuento de grupos y estudiantes por curso escolar.
Para que nos entendamos, algo como esto:
Veamos cómo abordar este tipo de retos en AppSheet.
Primero y principal: las tablas de cursos escolares (Cursos) y grupos activos en el centro (Grupos) están relacionadas a través del campo Curso.
Me parece que es un buen momento para hablar de cómo gestiona AppSheet las relaciones entre tablas, ¿no te parece?
☝ En todo lo que sigue utilizaré los términos columna y campo, por una parte, y fila y registro, por otra, de manera indistinta.
Todas la tablas deben tener un campo clave, es decir, una columna que contiene valores únicos que identificarán unívocamente cada una de las entidades representadas en las filas de la tabla.
Es importante destacar que a menudo esta columna clave se construye combinando mediante fórmulas varias de las columnas de la tabla.
El objetivo siempre es el mismo, garantizar que los valores guardados en la columna clave sean únicos y por tanto no haya ambigüedad alguna a la hora de identificar cada registro de las tablas que debe gestionar nuestra app.
En el caso de la tabla Cursos de nuestro ejemplo usaremos simplemente el nombre del curso escolar, algo como "2023/2024".
En la tabla Grupos nos encontraremos con un campo clave compuesto. Se trata de una columna virtual obtenida concatenando el curso (columna Curso de la tabla relacionada Cursos) y el código de la especialidad (columna Código). Por ejemplo, "DAM (2023/2024)". De este modo nos resultará fácil diferenciar los grupos de cada especialidad que se desarrollan en distintos cursos escolares.
[Código] & " (" & [Curso] & ")"
Lo has visto bien, lo de concatenar va como en las hojas de cálculo de Google (&). También disponemos de la función CONCATENATE().
Además, resulta que AppSheet resulta ser una personita no humana muy proactiva y se toma la molestia de detectar qué tablas parecen estar relacionadas entre sí a partir de la estructura de la hoja de cálculo usada como origen de datos.
Por ejemplo, esta es la definición que se le aplica automáticamente a la columna Curso de la tabla Grupos cuando se importa desde la hoja de cálculo.
Lógicamente, el usuario siempre tiene la última palabra y puede modificar o eliminar las relaciones generadas automáticamente o crear otras nuevas.
Pero centrémonos en la tabla Cursos.
En esta tabla AppSheet crea, también por su cuenta, otra columna virtual llamada Grupos que obtiene de la tabla del mismo nombre la lista de grupos de cada curso escolar por medio de la función REF_ROWS().
☝ Siendo más riguroso, lo que realmente devuelve la función anterior son los valores contenidos en la columna clave de las filas coincidentes de la tabla Grupos.
REF_ROWS("Grupos", "Curso")
Y esto, amigo o amiga, es lo que AppSheet denomina una referencia inversa, que como te puede imaginar nos viene de perlas por muy inversa que sea. Aprende a quererla como se merece.
Ya casi lo tenemos.
Ahora, añadimos otra columna virtual en la tabla Cursos llamada Grupos y estudiantes, que es la que efectuará el recuento de (oh sorpresa) los grupos y los estudiantes.
"Grupos: " &
COUNT([Grupos]) &
" | Estudiantes: " &
COUNT(
FILTER(
"Estudiantes",
[Grupo].[Curso] = [_THISROW].[Curso]
)
)
¡Pero espera un momento! ¿Qué brujería es esta? 👇
[Grupo].[Curso] = [_THISROW].[Curso]
Pues esto, querido amigo o amiga, es la tercera característica del lenguaje de fórmulas de AppSheet que, ya sabes, cambia la reglas del juego.
3️⃣ Puedes saltar entre tablas relacionadas, hasta alcanzar la columna que te interesa, mediante una expresión que encadena nombres de columnas entre corchetes, separadas por puntos.
Vamos por partes.
COUNT([Grupos]) & " | Estudiantes: "
[Grupos] representa la columna virtual, definida en la tabla Cursos, que contiene todos los grupos relacionados con cada una de las filas (cursos escolares) de esta tabla. La función COUNT() obviamente averigua de cuántos grupos se trata en cada caso.
Ya tenemos a los grupos en el bote. Vamos ahora con los estudiantes.
COUNT(FILTER("Estudiantes", [Grupo].[Curso] = [_THISROW].[Curso]))
Usando la función FILTER() nos movemos a la tabla que contiene la información de nuestros estudiantes y nos traemos de ella solo aquellos matriculados en los grupo del curso sobre el que se está realizando el cálculo.
[Grupo] representa el campo, de tipo Ref, de la tabla Estudiantes que se utiliza para establecer una relación con la tabla Grupos. Es decir, vincula cada estudiante con un grupo determinado.
Con esta expresión saltamos a la fila que contiene la información del grupo en el que está matriculado cada estudiante y obtenemos el valor del curso escolar almacenado en la columna Curso.
[Grupo].[Curso]
Este valor se compara con cada uno de los cursos escolares de la tabla Cursos gracias a [_THISROW], que representa cada una de las filas completas de esta tabla sobre la que se está evaluando la fórmula en cada momento.
[_THISROW].[Curso]
En definitiva, de este modo logramos aplicar un filtro que solo devuelve la lista de estudiantes matriculados en los grupos de un curso dado, lista cuya longitud seguidamente calculamos.
Finalmente, se construye una cadena de texto uniendo convenientemente los resultados de ambos recuentos y algunas palabrejas para que todo cobre sentido.
Limpio y directo.
☝ Es evidente que esta filosofía de trabajo presenta grandes paralelismos con la de mi admirada Coda (me da un poco igual si fue antes el huevo o la gallina 🤷). Y es normal, tanto Coda como AppSheet han sido construidas para facilitar el trabajo con tablas de datos relacionadas, así que no es de extrañar que sus creadores hayan adoptado decisiones de diseño hasta cierto punto convergentes. Buena cosa.
¿Vas entendiendo cómo piensa AppSheet?
Vamos con algunos ejemplos adicionales para asegurarnos.
Ordenar y filtrar la lista de opciones en un cuadro desplegable
Como sabes, mi app va de realizar anotaciones de seguimiento de los estudiantes.
Los profes tendrán que usar un formulario como este, en el que primero se seleccionará el grupo y a continuación el estudiante sobre el que realizar el seguimiento.
Para facilitarles las cosas a los sufridos tutores, lo ideal es que en ambos elementos de selección, grupo y estudiante, aparezcan:
- Solo los grupos de los que el profe es tutor.
- Solo la lista de estudiantes del grupo seleccionado.
- Tanto grupos como estudiantes en orden alfabético.
Muy lógico todo.
Como cabía esperar, la tabla de Seguimientos está relacionada con las de Grupos y Estudiantes usando sendos campos de tipo relación (ya sabes, columnas de tipo Ref para AppSheet).
Te la muestro entera para que la conectes mentalmente con el formulario de más arriba.
AppSheet muestra las columnas de tipo relación como controles de lista desplegable en las vistas de tu app que permiten introducir o editar información.
Estas listas se alimentan de los valores almacenados en la columna clave de la tabla al otro lado de la relación. Lo que pasa es que estos valores aparecerán en el orden que determina su posición (fila) en la tabla de origen, sin más. Esto no es del todo adecuado.
Para solucionarlo, podemos usar el ajuste de validación de datos del que disponen las columnas de las tablas de AppSheet.
De manera más específica, tienes que buscar el ajuste Valid if dentro de la sección Data Validity, que inicialmente está colapsada.
Debo reconocer que aquí me atasqué unos minutos.
¿Desde cuando una regla de validación, que entiendo yo debe devolver un valor verdadero o falso para aceptar o rechazar el valor introducido, puede servir para filtrar la lista de posibles opciones?
Pues es que resulta que el dichoso Valid if tiene algo así como dos modos de funcionamiento. Puedes introducir una fórmula que devuelva, bien un resultado booleano, bien una lista de valores posibles, que se mostrarán como opciones dentro del cuadro de lista. Sorpresas nos da AppSheet.
En el caso del campo Grupo, la cosa queda de esta manera.
SORT(
FILTER(
"Grupos",
AND(
OR(
[Tutor] = USEREMAIL(),
IN(USEREMAIL(), Admins[email])
),
IF(
MONTH(TODAY()) >= 7,
LEFT([Curso], 4) = YEAR(TODAY()),
LEFT([Curso], 4) = YEAR(TODAY() - 1)
)
)
),
FALSE
)
Usamos la función SORT() para ordenar la lista de valores admitidos, valores que se obtienen a partir de la lista de grupos, tomada de la tabla Grupos, que:
- Tengan como tutor al usuario actual.
- Sean grupos del curso activo. Para mí los cursos son siempre como "2023/2024", por tanto, un curso "activo" es aquel en el que su primer año coincide con el actual a partir de julio o con el anterior al actual en caso contrario. Un criterio cuestionable, lo sé, pero solo pretende ser un ejemplo.
Con el desplegable de estudiantes la cosa es más fácil:
SORT(
FILTER(
"Estudiantes",
AND(
[Grupo].[Código] = [_THISROW].[Grupo].[Código],
[Grupo].[Curso] = [_THISROW].[Grupo].[Curso]
),
)
)
Aquí le estamos pidiendo educadamente a AppSheet que nos facilite una lista con los estudiantes matriculados en el grupo seleccionado previamente en la lista desplegable de selección de grupo, es decir, aquel grupo que presente coincidencias en los campos Código y Curso con el escogido.
Aún a riesgo de que me llames pesado, me gustaría insistir en esto de ir saltando de una tabla a otra, cual ardilla 🐿 friki de árbol en árbol relacional, utilizando la sintaxis de corchetes y puntos:
[_THISROW].[Grupo].[Código]
Destripemos nuevamente la fórmula que hemos usado hace un momento por lo que hace a las condiciones utilizadas para filtrar los datos:
- [_THISROW] representa la fila actual de la tabla Seguimientos, en este caso el nuevo registro de seguimiento que se está introduciendo a través del formulario.
- La expresión [_THISROW].[Grupo] nos hace saltar a la fila de la tabla Grupos donde se encuentra la información del grupo seleccionado en el primer desplegable del formulario.
- Finalmente, con las expresiones gemelas [_THISROW].[Grupo].[Código] / [Curso] se obtienen el valor del código de especialidad y el curso escolar del grupo, respectivamente, que usaremos como elementos de comparación dentro de la función FILTER() para obtener la relación de estudiantes matriculados en el grupo escogido en el formulario de registro de seguimientos.
Ocultar ciertas filas de una tabla a determinados usuarios
Comencemos por algo fácil: que los tutores solo puedan ver la lista de grupos que tutorizan.
Para ello, abriremos los ajustes ⚙ de la tabla Tutores y localizaremos la opción Security → Security filter.
Esta es la expresión que necesitamos:
OR(USEREMAIL() = [Tutor], IN(USEREMAIL(), Admins[Email]))
¡Bien visto! Los administradores del centro tendrán acceso sin restricciones a todos los registros (ya sabes, filas) de la tabla de grupos.
Vamos a darle a esto de la seguridad a nivel de registro una vuelta de tuerca.
¿Qué pasa si pretendemos ahora que los tutores solo puedan ver aquellos cursos escolares en los que hay grupos de los que son tutores?
¡Vamos a por la seguridad de la tabla Cursos!
Para que cada registro de la tabla de cursos escolares sea visible, necesitamos asegurarnos de que la dirección de correo electrónico del usuario actual aparezca en la columna Tutor de alguna de las filas relacionadas de la tabla Grupos.
Y para efectuar esta comprobación necesitamos introducir una nueva función, la muy polivalente SELECT().
OR(
IN(USEREMAIL(), SELECT(Grupos[Tutor], ([Curso] = [_THISROW].[Curso]))),
IN(USEREMAIL(), Admins[Email])
)
Yo creo que a estas alturas de la fiesta no hacen falta muchas más aclaraciones sobre la fórmula de aquí arriba (dime que sí 🙏).
Casi se me olvida. Como ves, me he aficionado a que mi app se comporte de modo distinto según el usuario que la utiliza en cada momento. No son manías, es que realmente se trata de una característica extremadamente conveniente, por no decir necesaria muy a menudo.
Y parece que para los diseñadores de AppSheet, también. Por esa razón, han dispuesto un procedimiento muy cómodo que te permitirá verificar su correcto funcionamiento, asumiendo distintas identidades, mientras se encuentran en desarrollo.
Solo tienes que introducir la dirección de correo electrónico del usuario con el que deseas probarla en el recuadro bajo la vista previa. Sin claves. Sin líos.
Y para terminar esta sección, algo vistoso y facilito.
Establecer valores predeterminados para las columnas de una tabla
Los ajustes de las columnas de una tabla incluyen una sugerente sección denominada Auto Compute.
En ella encontrarás un ajuste denominado Initial value. Yo lo he usado, por ejemplo, en el campo Foto de la tabla Estudiantes para crear una imagen predeterminada que muestra las iniciales del estudiante.
Naturalmente, el tutor tiene la capacidad de sustituirla cuando quiera por una imagen real que, por cierto, puede ser tomada in situ usando la cámara del móvil. Ventajas de la vida móvil.
TEXT_ICON(INITIALS([Nombre]))
La función TEXT_ICON() es una pequeña genialidad que genera una imagen a partir del texto que se le pasa como parámetro. Como lo bueno, si breve, dos veces bueno, la combino con INITIALS() para obtener las iniciales del estudiante.
En el lado no tan genial del lenguaje de fórmula de AppSheet, me ha extrañado mucho no encontrar ninguna función para trabajar con expresiones regulares. Tal vez no haya buscado bastante.
Es cierto que tenemos por ahí la más que interesante función EXTRACT() y de que, en cualquier caso, podemos tirar de fórmulas en la hoja de cálculo que alimentan a las tablas de AppSheet, pero no podía dejar pasar la oportunidad de poner algún pero 😁.
Con este último ejemplo creo que ya hemos hablado suficientemente del fascinante lenguaje de fórmulas de AppSheet, aunque lo cierto es que nos va a resultar difícil escapar totalmente de él en lo que queda de artículo 🙃.
Ha llegado el momento de que te cuente algunas de las cosas que me han llamado la atención de las vistas de AppSheet.
Una AppSheet con vistas
Las vistas (Views en AppSheet) controlan cómo se mostrará la información contenida en las tablas.
Para manipularlas usaremos el panel de vistas de AppSheet, que aquí te muestro de manera general.
Cuatro pinceladas sobre las vistas (ya sabes, esto no es un tutorial). Si quieres saber más cosas pégale una leída reposada a todo lo que cuentan aquí.
1️⃣ Cada vista está asociada a una tabla de datos.
Las vistas también pueden estar basadas en una "rebanada" (slice) de una tabla. Estas rebanadas pueden mostrar un subconjunto de las filas y columnas de la tabla original. Hablaremos de ellas en un santiamén.
2️⃣ Existen tres conjuntos distintos de vistas atendiendo al lugar donde aparecen los botones o elementos de la interfaz de la app que las activan.
- Vistas de navegación principales (Primary navigation). Los correspondientes botones que las activan se mostrarán en un lugar destacado en la parte inferior de tu app. Utiliza estas vistas para mostrar el conjunto de elementos contenidos en cualquiera de tus tablas. Yo he dispuesto aquí accesos rápidos a la gestión de seguimientos, grupos y estudiantes de cada tutor, dado que en mi opinión constituyen las áreas de mayor interés en mi aplicación.
- Vistas de navegación en el menú lateral (Menu navigation). Son como las anteriores, solo que se lanzan desde el menú principal. En este menú escamoteable he situado accesos a tantas vistas como entidades (tablas) maneja mi aplicación, con la excepción de la tabla de administradores que, de modo absolutamente intencionado, mantengo oculta y debe ser manipulada exclusivamente en el ámbito de la hoja de cálculo).
- Vistas de referencia (Reference views). Se accede a ellas desde las vistas de navegación anteriores. Sirven para ver un registro en detalle, editarlo o mostrar datos relacionados en una vista secundaria dentro de otra principal. Aquí, por ejemplo, puedes apreciar una del tercer tipo, que muestra la lista de grupos de un curso escolar específico.
3️⃣ Puedes escoger en qué lugar de la interfaz de usuario de la app aparecerán tus vistas y de qué modo mostrarán los datos de las tablas de datos.
Para modificar el tipo de vista, que determinará cómo se van a mostrar los datos, se utiliza el ajuste View type del editor de vistas. Calendario, tarjetas, galería, mapa, gráfico, formulario... tienes una gran variedad de vistas donde elegir, cada una con sus particularidades. Lo mejor es probarlas todas para familiarizarse con ellas y ser capaz de decidir rápidamente cuál es la más apropiada en cada caso de uso.
La posición donde aparece el botón o elemento de menú utilizado para activar una vista determinada se controla utilizando el ajuste Position, que se encuentra justamente debajo del que permite seleccionar el tipo de vista.
Además, y como cabía esperar, el orden de las vistas en el menú de navegación también puede establecerse cómodamente.
El panel de edición de vistas de AppSheet ofrece enormes posibilidades de personalización, pero hay que tener en cuenta que los ajustes disponibles cambian dependiendo del tipo de vista escogida.
En general, podrás actuar sobre aspectos como la ordenación y el agrupamiento (con múltiples criterios) de las filas de la tabla, el número y posición de las columnas a mostrar y un largo etcétera de parámetros que controlan tanto la presentación como el comportamiento de las vistas.
Las vistas incluso pueden ocultarse también de manera condicional utilizando expresiones como las que ya hemos visto en el apartado dedicado al lenguaje de fórmulas de AppSheet.
4️⃣ AppSheet creará vistas de referencia para tus tablas de manera automática.
Para diferenciarlas, AppSheet las nombrará añadiendo los sufijos _Detail, _Form o _Inline al nombre de la tabla en la que se basan, según se trate de vistas de detalle, edición o secundarias, respectivamente.
Al igual que las vistas de navegación y referencia creadas por el usuario, las que han sido generadas por el sistema de manera espontánea también pueden personalizarse. El alcance de esta personalización depende igualmente del tipo de vista de referencia del que se trate.
También es posible sustituir completamente cualquiera de las vistas automáticas por otras propias. Para ello solo hay que crear una nueva vista de referencia basada en el mismo origen de datos.
Rebanadas de datos y vistas personalizadas
Es muy poco probable que puedas evitar las rebanadas de datos (Slices) en tu viaje por AppSheet.
Como te adelantaba hace un rato cuando hablábamos de las vistas, puedes usar las rebanadas de datos para escoger el subconjunto de las filas y columnas de una tabla que deseas mostrar.
¿Pero esto no lo hacíamos usando expresiones calculadas en el filtro de seguridad de la tabla?
Pues sí, pero aunque el resultado es similar, las rebanadas no funcionan exactamente igual. Esto lo vas a entender perfectamente si lees este artículo sobre los filtros de seguridad que encontrarás en la ayuda oficial de AppSheet, pero te lo resumo rapidito:
- Los filtros de seguridad se aplican en el backend de AppSheet, es decir, la prueba lógica definida en el filtro se realiza sobre cada una de las filas del conjunto de datos antes de que sean enviadas a tu dispositivo para su visualización.
- Cuando se utiliza una rebanada de datos, en cambio, el proceso de filtrado se aplica en el cliente. AppSheet tiene por tanto que enviar la tabla completa, lo que resulta menos eficiente.
A pesar de esta diferencia, que puede llegar a ser crítica cuando manejamos una gran cantidad de datos, hay ocasiones en las que no tendremos más remedio que usar rebanadas de datos.
¿Cuándo?
Pues por ejemplo cuando queremos que los datos de una tabla se muestren de distintas maneras en diferentes vistas de nuestra aplicación. Veamos una situación real.
En mi app de seguimiento del alumnado me interesa que cada tutor o tutora únicamente tenga acceso a sus cosas (grupos, estudiantes, registros de seguimiento, etc.). En el caso de los grupos, por ejemplo, usábamos una regla de seguridad como esta sobre la tabla de Grupos:
OR(USEREMAIL() = [Tutor], IN(USEREMAIL(), Admins[Email]))
De esto modos cada tutor solo verá sus grupos en la app, pero los administradores tendrán acceso a todos ellos para realizar un seguimiento general.
El problema es que si esos usuarios con funciones administrativas además también tutorizan grupos, esto de "verlo todo" puede resultar contraproducente para ellos en el día a día.
Por esa razón he creado una rebanada denominada Mis grupos basada en la tabla Grupos que limita la visibilidad también a los administradores.
Veamos algunos elementos significativos en el panel de edición de esta rebanada de datos:
- Podemos crear ➕ tantas rebanadas de datos en cada tabla como queramos. Todas ellas quedarán agrupadas de manera jerárquica bajo la tabla en la que se basan.
- Aquí es donde se introduce la expresión de filtro. Esto ya nos lo sabemos 😏.
- A continuación se eligen las columnas a mostrar. Los iconos con puntos a la izquierda del nombre de cada una permiten cambiar el orden en el que se van a mostrar. No se aprecia en la imagen, pero al pasar la rata sobre cualquier columna, a su derecha aparecerá un botón ➖ para eliminarla de la rebanada de datos.
- También podemos personalizar la lista y disposición de las acciones que queremos que se muestren en las vistas asociadas a esta rebanada de datos.
- Finalmente, también se puede definir el modo de acceso. Fíjate en que a diferencia del ajuste análogo disponible a nivel de tabla, aquí no existe la posibilidad de utilizar una expresión calculada (supongo que no se puede tener todo, siempre).
Ahora solo queda crear una nueva vista en la sección de navegación princial para la rebanada de datos que acabamos de crear y... ¡et voilá!
Pues ya te digo, saber bailar con soltura en esta ensalada de...
🥗 Tablas → Rebanadas → Vistas → Acciones 🥗
...elementos todos ellos relacionados entre sí, resulta clave a la hora de dotar a nuestra aplicación AppSheet de una interfaz de usuario atractiva, pero también para diseñar una experiencia de manejo que resulte intuitiva, ágil y satisfactoria para tus usuarios. ¡Dale a esto unas cuantas vueltas 🧠!
☝ Las rebanadas tiene otro superpoder que resulta mucho menos evidente. Las podemos usar también para generar vistas secundarias diferentes en función de la vista principal en la que nos encontremos en cada ocasión, sustituyendo en su caso a las generadas por el sistema (las que llevan el sufijo _Inline).
Por ejemplo:
- Al mostrar la lista de estudiantes de un grupo determinado no querremos que aparezca en ella la columna que indica el grupo en el que está matriculado (vista de detalle de grupo, vista secundaria de estudiantes), dado que todos ellos pertenecen al mismo.
- En cambio, tal vez sí queramos tener información sobre el grupo en el que está matriculado el estudiante en una vista que muestra la lista de todos los estudiantes de un determinado tutor (vista de detalle de tutor, vista secundaria de estudiantes).
Podemos pensar en otra situación análoga al analizar cómo se relaciona la información de estudiantes y registros de seguimiento:
- Parece bastante razonable que la vista que muestra la lista completa de registros de seguimiento incluya el nombre del estudiante.
- Pero cuando esa lista se despliega como vista secundaria dentro de la que muestra exclusivamente la información de un estudiante específico, ver su nombre (repetido) en cada uno de los seguimientos es totalmente redundante.
Esto se consigue del siguiente modo (dentro esquema):
Lo que estamos haciendo es:
- Crear una rebanada de datos a partir de la tabla de registros de seguimiento cuyo aspecto deseamos personalizar cuando aparezca como vista secundaria en la vista de detalle de un estudiante. En los ajustes de la rebanada de datos no se aplicará ningún filtro sobre los datos.
- Crear una vista asociada a la rebanada de datos. Aquí es donde se seleccionan las columnas que realmente se desean mantener visibles.
- Modificar la referencia inversa desde Estudiantes a Seguimientos sin alumnos establecida mediante la fórmula REF_ROWS() para que recupere los seguimientos a través de la rebanada de datos que acabamos de configurar, en lugar de hacerlo directamente desde la tabla de estudiantes.
REF_ROWS("Seguimientos sin alumno", "Estudiante")
⚠️ No te olvides de ajustar también de manera acorde el nombre de la tabla referenciada (Referenced table name) en la columna de tipo Ref para que la nueva vista sea utilizada en lugar de la vista secundaria por defecto (de tipo inline) generada por AppSheet.
¿Te gustaría mirarle las tripas a un app que usa esta técnica? Tus deseos son órdenes para mí, aquí la tienes.
Realmente solo estamos usando la nueva rebanada de datos como un "señuelo" para que, al abrir la vista de detalle de un estudiante, AppSheet utilice la vista secundaria de seguimientos sin los nombres de los estudiantes que hemos preparado para este caso específico.
Si en algún momento necesitáramos mostrar la lista de seguimientos en un contexto distinto, por ejemplo dentro de la vista que muestra los detalles de un grupo —ahí lo suyo sería esconder la columna que indica el grupo en el que se ha registrado el seguimiento—, haríamos exactamente lo mismo pero ajustando la relación inversa en la tabla Grupos.
¿Cómo lo ves?
Se trata de una técnica, al parecer bastante habitual en AppSheet, pero que personalmente me ha parecido un poco ortopédica (extraña, si no hablas español de España).
☝ Se me ocurre que tal vez podría usarse una estrategia alternativa, introducir expresiones calculadas, basadas en la función CONTEXT(), en el campo Show if para establecer de manera dinámica la visibilidad de las vistas. De esta función hablaremos justo a continuación.
En fin, por ahora es lo que hay... hasta donde yo sé 🤷♂️.
Formato condicional
Intensamente enfrascado como estaba en tratar de entender el funcionamiento de todo este tinglado de vistas y acciones de AppSheet (de las acciones hablaremos brevemente en el siguiente apartado) mientras construía mi app de seguimiento del alumnado, casi no reparé en que AppSheet permite también aplicar reglas de formato a las columnas de tus tablas.
Yo he utilizado en mi app tres de estas reglas para destacar el campo que recoge la valoración de los registros de seguimiento del alumnado. Así queda la cosa en la vista de seguimientos:
Siguiendo fielmente los principios de AppSheet, el formato condicional se establece usando expresiones construidas con su lenguaje de fórmulas. Estas reglas pueden ser aplicadas a una o más columnas de una tabla dada, pero no de manera específica a las rebanadas de datos que hayas definido a partir de ellas.
Los ajustes del formato condicional de AppSheet son generosos.
Por un lado, es posible escoger un icono que refuerce visualmente el resultado y establecer tanto su color como el del texto que se muestra en el campo sobre el que se aplica la regla.
Por otro lado, y como cabía esperar, también podemos intervenir sobre los atributos de formato del texto.
Una regla como la que te muestro se aplicaría en todas las vistas basadas en la tabla Seguimientos. ¿Qué pasa entonces si solo queremos que funcione en alguna de ellas?
Para lograrlo, podemos crear expresiones condicionales que tengan en cuenta en el contexto el que se está aplicando la regla gracias a la función CONTEXT().
Por ejemplo:
AND([Valoración] = "Positivo", CONTEXT("View") = "Seguimientos")
De este modo la regla solo tendría efecto en la vista llamada Seguimientos. ¿Te da esto ideas para resolver el problema que teníamos con las rebanadas de datos y las vistas secundarias?
Para reglas que contemplen muchos más casos probablemente quieras usar las funciones SWITCH() o IFS().
☝ No dejes de husmear en la ayuda de CONTEXT() para averiguar qué otra información del contexto de ejecución puede proporcionarte.
Sí, el formato condicional suele ser, en cualquier herramienta que lo admita, una de esas funciones "baratas" que dan mucho más de lo que cuestan.
AppSheet y sus buenas acciones
Este artículo ya se está alargando probablemente más de lo humanamente soportable, especialmente en un caluroso mes de agosto, cuando inicialmente solo pretendía ser una toma de contacto personal con AppSheet. Como dijo alguien, "estos son mis principios, si no le gustan tengo otros".
Es hora de que aligere un poco para ir acabando.
Por esa razón solo voy a planear sobre las acciones (Actions) de AppSheet. Y no porque piense que se trata de un tema menor, más bien todo lo contrario, sino porque es hora de irte dejando para que explores AppSheet en la intimidad.
Tal y como se explica con todo detalle en este artículo de la ayuda de AppSheet, las acciones sirven para movernos dentro de la app, manipular los datos que maneja e interactuar con algunos servicios externos disponibles en el dispositivo del usuario.
Simplificando un poco, tenemos dos tipos de acciones:
- Las de usuario, que crearemos nosotros. Como esta, por ejemplo, que opera sobre los registros de la tabla Grupos.
- Las de sistema, que se van a ir generando automáticamente para cada una de las tablas y vistas de la aplicación. Se trata de acciones comunes de navegación, como modificar, eliminar o añadir registros, que AppSheet nos ahorrará tener que crear por nuestra cuenta. Por ejemplo, aquí las que me encontré de buenas a primeras tras crear una vista para mi tabla de Tutores:
Esto de que las acciones de navegación típicas se vayan generando automágicamente es muy interesante. Fíjate en la vista de mi app que muestra la lista de tutores y tutoras:
En ella puedes ver cuatro botones que representan otras tantas de esas enigmáticas acciones de sistema:
- ✉️ Enviar correo electrónico al tutor.
- 📝 Modificar información del tutor.
- 🗑 Eliminar tutor.
- ➕ Añadir un nuevo tutor.
☝ AppSheet crea automáticamente una acción de tipo enviar correo electrónico cuando detecta un campo de tipo email en la tabla de datos en la que se basa la vista.
Estas cuatro acciones tienen una correspondencia directa con los cuatro elementos (Add, Compose Email, Delete y Edit) que tenemos en el panel de acciones de la tabla Tutores, dos capturas de pantalla más arriba.
Seguro que ya vas encajando las piezas.
¿Pero cómo es que a ese tipo 🙋♂️ que aparece al final de la lista le falta este ✉️ botón?
Pues muy fácil. Ese tipo —que soy yo mismo— es quien está probando la app en el momento de realizar la captura. Lógicamente, no tiene demasiado sentido que un tutor pueda enviarse un correo electrónico a sí mismo, por muy solo que se sienta, ¿no te parece?
Lo has adivinado, en AppSheet también es posible hacer que ciertas acciones estén o no disponibles de manera contextual. ¿Cómo? Pues ya te lo puedes imaginar, porque llevamos un buen rato haciendo cosas parecidas.
Echémosle un vistazo a la acción Compose Email...
...concretamente a sus ajustes de comportamiento (Behavior).
AND(NOT(ISBLANK([Email])), USEREMAIL() <> [Email])
Gracias a los ajustes de comportamiento (sección Behavior) de esta acción conseguimos que el icono que permite activarla solo se muestre cuando la dirección de correo del usuario que está interaccionando con la app sea diferente al indicado en el registro del tutor. Mediante la función ISBLANK() nos aseguramos de que la comprobación tenga sentido.
No las he usado en esta ocasión, pero las opciones de confirmación, justo debajo de la fórmula, permiten introducir un control adicional que resulta útil en el caso de acciones de tipo destructivo o que puedan suponer consecuencias importantes.
El editor de acciones ofrece posibilidades adicionales de configuración, algunas son de tipo visual (icono, texto)...
...otras se utilizan para indicar cómo debe mostrarse el botón de la acción (botón principal, en el grupo de botones destacados o con un tamaño menor, junto a otros elementos de la vista):
Cómo no, también nos encontramos con la posibilidad de efectuar una parametrización avanzada de la acción escogida. En este caso (envío de un correo electrónico) podemos establecer el destinatario, el texto del asunto e incluso el cuerpo del mensaje, una vez más incluso usando expresiones calculadas.
Incluso contaremos con un espacio, en el fondo del panel de ajustes, en el que dejar anotaciones que nos ofrezcan contexto si al volver a ella pasado un tiempo no recordamos su propósito o cualquier otro detalle significativo.
Para concluir este breve recorrido por las acciones de AppSheet, debo mencionar que inicialmente me encontré con que al tratar de modificar el orden de los botones de acción de una vista...
...el panel de ordenación, análogo al utilizado en las vistas, se abría incorrectamente, sin mostrar la lista en la que deben aparecer los elementos de acción para ser arrastrados a las posiciones deseadas.
En mi caso la solución pasó simplemente por cambiar al editor clásico...
...para, una vez allí, hacer clic en el botón ⚙ Rearrange actions del panel Behavior.
Eso pareció "desatascar" el panel de reordenación en el nuevo editor, que a partir de ese momento ya funcionó correctamente.
Muy bien esto de las acciones, la verdad, y mira que estoy intentando ser crítico a lo largo y ancho de este artículo.
Cajón de sastre y comentarios finales
Si has llegado hasta aquí del tirón (o de cualquier otro modo) eres todo un campeón o campeona. Muchas gracias por pasar tu valioso tiempo acompañándome en este viaje de descubrimiento.
Comencé a escribir este artículo el pasado 10 de julio, pero la cosa se truncó pocos días después por diversas razones. Hay meses y meses... y cuando te topas con uno de los segundos más vale doblegarse como un junco al viento (que diría una Bene Gesserit) y dejarlo pasar sin ofrecer resistencia.
Mientras ahora escribo y reescribo esta sección de cierre es 7 de agosto, mi primer día de vacaciones de verano. Releyendo el artículo para proseguir desde donde lo dejé hace casi tres semanas, soy aún más consciente que cuando lo inicié de que este es probablemente uno de los más dispersos y fragmentarios que he escrito nunca.
Sin embargo, creo que merece echar a volar puesto que el impacto que me causó AppSheet hace casi un mes no se ha desvanecido. Y para mí es importante dejar constancia de ello en este espacio de aprendizaje personal, aunque sea de un modo tan imperfecto.
Me dejo un pequeño cajón de sastre para el final, puesto que hay muchos aspectos de AppSheet con los que no tuve apenas la oportunidad de trabajar a lo largo de las 48 horas de aquel fin de semana del que hablaba al comienzo de este artículo.
Por ejemplo, no te he hablado de todos esos asistentes inteligentes que salpican el editor de AppSheet y a menudo parecen adivinar lo que estás pensando...
...o te permiten describir lo que necesitas usando lenguaje natural:
Ni de las potentes funciones basadas en aprendizaje automático (OCR y modelos predictivos) que encontrarás en el panel 💡Intelligence del editor. Solo disponibles a partir del plan Enterprise Standard, eso sí.
Tampoco de las numerosas funciones que pueden usarse para incorporar información del usuario y tomar decisiones mediante expresiones construidas con el lenguaje de fórmulas de AppSheet en multitud de contextos, algunos de los cuales hemos explorado a lo largo de este artículo. Y es que además de la ya conocida función USEREMAIL() tenemos otras como:
Y hablando de la toma de decisiones basada en el contexto, ¿sabías que AppSheet cuenta con una serie de características que permiten definir ajustes por usuario?
El sistema se basa en una tabla de datos oculta, que sin embargo se comporta como una convencional, con sus vistas y tal, con la que puedes implementar en tu app un panel personal de preferencias privado para cada uno de tus usuarios. Los valores de estas preferencias pueden utilizarse en expresiones para tomar decisiones de comportamiento, visibilidad, acceso a datos o simplemente mostrar mensajes en el idioma del usuario, gracias a las facilidades nativas de localización.
Me ha gustado mucho también que AppSheet se tome tan en serio eso de documentar las apps que te ayuda a crear. Además del grafo de relaciones y de los espacios específicos para comentar cosas como vistas y acciones, cuenta también con una sección en la que puedes registrar detalles generales de propósito, diseño y otros documentos de referencia. La encontrarás en:
⚙Settings → Information → App Documentation
Al final de ella aparece este enlace...
...que conduce a una página de documentación generada automáticamente en la que se recogen de manera sorprendentemente exhaustiva todos los detalles de implementación de la app.
Pero las ausencias más notorias en este artículo son, sin lugar a dudas, las protagonizadas por las automatizaciones y las apps de Chat, dos funcionalidades que yo no he incorporado ¿aún? a mi app de aprendizaje.
Con las automatizaciones solo he estado haciendo algunas pruebas. Resulta que en tanto mantengas la app en modo desarrollo —no ha sido aún desplegada para su uso normal en producción— no es posible enviar correos electrónicos a los destinatarios reales al ejecutar el flujo de trabajo.
En su lugar, se envían correos simulados al propietario de la app.
Por eso me pareció interesante explorar la posibilidad de invocar una función Apps Script externa, que es la que realmente realiza el envío de los correos, para trascender así esta limitación.
Y así de lejos llega mi experiencia con las automatizaciones de AppSheet 😅, pero es más que obvio que son piedra angular de esta herramienta. Es como tener un Zapier o Make en plan local para hacer cositas sin tocar código.
Con respecto a la creación de apps de Chat con AppSheet, nada que contar por el momento, pero me parece una propuesta de valor enormemente atractiva.
En resumen, creo que AppSheet es una herramienta absolutamente fantástica que merece mucha atención. Está claro que para Google es muy importante, como demuestra el hecho de que desde el 17 de julio el plan Core de AppSheet ha pasado a estar incluido en nueve ediciones adicionales de Google Workspace 🎉 (anuncio oficial).
Y si aún no estás listo para contratar un plan de pago, recuerda que puedes utilizar casi todas las funciones de AppSheet para uso personal y desarrollo de prototipos, con solo pequeñas limitaciones, tanto desde cuentas personales como corporativas.
Para concluir, me gustaría reiterar que todo lo que te he contado a lo largo y ancho de este artículo es el resultado de un aterrizaje de fin de semana en una herramienta compleja como es AppSheet. Ponlo todo entre muchas comillas, es probable que haya alguna que otra inexactitud o que simplemente las cosas puedan hacerse de un modo más correcto o eficiente. Nadie nace enseñado.
Es tu turno, anímate a compartir tu experiencia usando AppSheet, el cajón de comentarios de aquí abajo es todo tuyo 👇💬 .