<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Q-A on TanHo.ca</title><link>https://tanho.ca/tags/q-a/</link><description>Recent content in Q-A on TanHo.ca</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright> © 2026 Tan Ho. Unless otherwise specified, content is licensed with [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).</copyright><lastBuildDate>Fri, 02 Oct 2026 14:22:39 -0400</lastBuildDate><atom:link href="https://tanho.ca/tags/q-a/index.xml" rel="self" type="application/rss+xml"/><item><title>DSLC Slack: Debugging Netlify Deploys</title><link>https://tanho.ca/posts/2024-12-19_deploy-debugging/</link><pubDate>Thu, 19 Dec 2024 00:00:00 +0000</pubDate><guid>https://tanho.ca/posts/2024-12-19_deploy-debugging/</guid><description>&lt;div class="flex px-4 py-3 rounded-md bg-primary-100 dark:bg-primary-900"&gt;&#10; &lt;span class="text-primary-400 ltr:pr-3 rtl:pl-3 flex items-center"&gt;&#10; &lt;span class="relative block icon"&gt;&#10; &lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"&gt;&lt;path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"&gt;&lt;/path&gt;&lt;/svg&gt;&#10; &lt;/span&gt;&#10; &lt;/span&gt;&#10; &lt;span class="dark:text-neutral-300"&gt;I greatly enjoy the DSLC Slack Community (&lt;a href="https://dslc.io/join" target="_blank"&gt;&#10; dslc.io/join&lt;/a&gt;),&#10;and spend a fair bit of time answering questions! This post is part of a &lt;a href="https://tanho.ca/tags/dslc-slack"&gt;&#10; series&lt;/a&gt;&#10;where I curate some interesting questions and/or answers that I’ve come across there.&lt;/span&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 class="relative group"&gt;Question&#10; &lt;div id="question" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#question" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;blockquote&gt;&lt;p&gt;Hi all! I&amp;rsquo;m having a hard time understanding why netlify checks on a Pull Request&#10;with only a empty line added in the commit are failing for a blogdown website.&#10;I created &lt;a href="https://github.com/MetaDocencia/SitioWeb/pull/226" target="_blank" rel="noreferrer"&gt;this PR&lt;/a&gt; as a&#10;small example, but basically any kind of PR is failing nevermind its content,&#10;and the site is published-rendered without problem if we commit directly to main.&lt;/p&gt;&#10;&lt;p&gt;I&amp;rsquo;m super puzzled by this, does anyone have any tips on how can I debug it? Thanks &amp;#x1f64f;&lt;/p&gt;&#10;&lt;p&gt;- MC Nanton&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h2 class="relative group"&gt;Answer&#10; &lt;div id="answer" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#answer" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;Let&amp;rsquo;s look through some of your Netlify deploy logs. I found these from your GitHub&#10;repo automated checks:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href="https://app.netlify.com/sites/metadocencia/deploys/6758b3ee5881ee0009315995" target="_blank" rel="noreferrer"&gt;failing deploy logs for your PR&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://app.netlify.com/sites/metadocencia/deploys/67587beefabc760008a03d0b" target="_blank" rel="noreferrer"&gt;successful deploy logs for your main branch&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://github.com/MetaDocencia/SitioWeb" target="_blank" rel="noreferrer"&gt;repo link&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10; &#10;&#10;&#10;&#10;&lt;div&#10; &#10; class="flex px-4 py-3 rounded-md shadow bg-primary-100 dark:bg-primary-900"&#10; &#10; &gt;&#10; &lt;span&#10; &#10; class="text-primary-400 pe-3 flex items-center"&#10; &#10; &gt;&#10; &lt;span class="relative block icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"&gt;&lt;path fill="currentColor" d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z"/&gt;&lt;/svg&gt;&#10;&lt;/span&gt;&#10; &lt;/span&gt;&#10;&#10; &lt;span&#10; &#10; class="dark:text-neutral-300"&#10; &#10; &gt;editor&amp;rsquo;s note: archived the deploy logs in question to&#10;&lt;a href="https://gist.github.com/tanho63/09ccc1edec99c4b95227cc18b8dc7957" target="_blank" rel="noreferrer"&gt;this gist&lt;/a&gt;&#10;just in case the deploy logs are deleted at some point&lt;/span&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;p&gt;It seems like your&#10;&lt;a href="https://app.netlify.com/sites/metadocencia/deploys/6758b3ee5881ee0009315995#L100" target="_blank" rel="noreferrer"&gt;PR deploy logs&lt;/a&gt;&#10;show this warning immediately before failing:&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WARN 2024/12/10 21:35:19 Module &amp;#34;hugo-academic&amp;#34; is not compatible with this Hugo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;version; run &amp;#34;hugo mod graph&amp;#34; for more information.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;and this definitely doesn&amp;rsquo;t show up on your main deploy logs. Let&amp;rsquo;s try to figure out&#10;where your hugo versions are specified. Here&amp;rsquo;s a relevant section of the deploy logs:&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4:35:19 PM: ❯ Current directory&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4:35:19 PM: /opt/build/repo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4:35:19 PM: ​&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4:35:19 PM: ❯ Config file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4:35:19 PM: /opt/build/repo/netlify.toml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4:35:19 PM: ​&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4:35:19 PM: ❯ Context&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4:35:19 PM: deploy-preview&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;The logs say that the file responsible for specifying hugo version is netlify.toml,&#10;so let&amp;rsquo;s have a look at what that looks like on GitHub&#10;&lt;a href="https://github.com/MetaDocencia/SitioWeb/blob/74e10134f18b5e08a99059d1cb927a14be3afb60/netlify.toml" target="_blank" rel="noreferrer"&gt;right now&lt;/a&gt;:&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;HUGO_VERSION&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;0.64.0&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Notice that it specifies &lt;code&gt;context.production&lt;/code&gt; here, and that the context for the&#10;failing logs is &lt;code&gt;deploy-preview&lt;/code&gt;. If we go back into the failing logs, we can confirm&#10;that the hugo-version specified here isn&amp;rsquo;t working properly:&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4:35:12 PM: Installing Hugo 0.57.2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;So a solution that should work is to update the netlify.toml to specify the&#10;HUGO_VERSION for the deploy-preview context:&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;HUGO_VERSION&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;0.64.0&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deploy-preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;HUGO_VERSION&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;0.64.0&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;and this should do the trick. You might need to push it to main instead of to a PR&#10;branch though, Netlify usually uses the config from the main repo branch.&lt;/p&gt;&#10;&lt;p&gt;(Update: this solution worked!)&lt;/p&gt;&#10;</description><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://tanho.ca/posts/2024-12-19_deploy-debugging/featured.jpg"/></item><item><title>DSLC Slack: Changing Window Titles in Shiny</title><link>https://tanho.ca/posts/2020-10-22_shinywindowtitles/</link><pubDate>Tue, 20 Oct 2020 00:00:00 +0000</pubDate><guid>https://tanho.ca/posts/2020-10-22_shinywindowtitles/</guid><description>&lt;div class="flex px-4 py-3 rounded-md bg-primary-100 dark:bg-primary-900"&gt;&#10; &lt;span class="text-primary-400 ltr:pr-3 rtl:pl-3 flex items-center"&gt;&#10; &lt;span class="relative block icon"&gt;&#10; &lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"&gt;&lt;path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"&gt;&lt;/path&gt;&lt;/svg&gt;&#10; &lt;/span&gt;&#10; &lt;/span&gt;&#10; &lt;span class="dark:text-neutral-300"&gt;I greatly enjoy the DSLC Slack Community (&lt;a href="https://dslc.io/join" target="_blank"&gt;&#10; dslc.io/join&lt;/a&gt;),&#10;and spend a fair bit of time answering questions! This post is part of a &lt;a href="https://tanho.ca/tags/dslc-slack"&gt;&#10; series&lt;/a&gt;&#10;where I curate some interesting questions and/or answers that I’ve come across there.&lt;/span&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 class="relative group"&gt;&lt;code&gt;Dhiraj&lt;/code&gt; asks:&#10; &lt;div id="dhiraj-asks" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#dhiraj-asks" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;blockquote&gt;&lt;p&gt;I have a shiny application which uses the navbarPage() layout. The app has multiple tabPanels with their own titles. Is it possible to have the windowTitle of the navbarPage dynamic to show the titles of the tabPanels ?&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h2 class="relative group"&gt;Answer&#10; &lt;div id="answer" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#answer" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;Here&amp;rsquo;s a minimal example of the Shiny and JS code you&amp;rsquo;ll need:&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shiny&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tidyverse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;custom_js&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Shiny.addCustomMessageHandler(&amp;#34;handler_windowtitle&amp;#34;, switch_window_title );&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;function switch_window_title(message){&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; document.title = message;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;}&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ui&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nf"&gt;navbarPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;navbarpage&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;displayed_tab&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;script&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;custom_js&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;tabPanel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;StrangePlanet&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;tabPanel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;DarthVader&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;observeEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;displayed_tab&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="nf"&gt;sendCustomMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;handler_windowtitle&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;displayed_tab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;shinyApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;If you give navbarPage an ID, it&amp;rsquo;ll create an &lt;code&gt;input&lt;/code&gt; variable that can be accessed as &lt;code&gt;input${id}&lt;/code&gt;, returning the value argument of the tabPanel. In this case, tabPanel returns the &lt;code&gt;title&lt;/code&gt; argument as the default value - you can specify something else if you prefer.&lt;/p&gt;&#10;&lt;p&gt;In a production app, I&amp;rsquo;d also move the JS into a separate JS file (stored in www) and use &lt;code&gt;includeJS()&lt;/code&gt; instead of using the &lt;code&gt;tags$script&lt;/code&gt; method.&lt;/p&gt;&#10;</description><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://tanho.ca/posts/2020-10-22_shinywindowtitles/featured.jpg"/></item><item><title>DSLC Slack: Explaining Shiny to Your IT Team</title><link>https://tanho.ca/posts/2020-10-15_explaining-shiny/</link><pubDate>Thu, 15 Oct 2020 00:00:00 +0000</pubDate><guid>https://tanho.ca/posts/2020-10-15_explaining-shiny/</guid><description>&lt;div class="flex px-4 py-3 rounded-md bg-primary-100 dark:bg-primary-900"&gt;&#10; &lt;span class="text-primary-400 ltr:pr-3 rtl:pl-3 flex items-center"&gt;&#10; &lt;span class="relative block icon"&gt;&#10; &lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"&gt;&lt;path fill="currentColor" d="M256 32C114.6 32 .0272 125.1 .0272 240c0 49.63 21.35 94.98 56.97 130.7c-12.5 50.37-54.27 95.27-54.77 95.77c-2.25 2.25-2.875 5.734-1.5 8.734C1.979 478.2 4.75 480 8 480c66.25 0 115.1-31.76 140.6-51.39C181.2 440.9 217.6 448 256 448c141.4 0 255.1-93.13 255.1-208S397.4 32 256 32z"&gt;&lt;/path&gt;&lt;/svg&gt;&#10; &lt;/span&gt;&#10; &lt;/span&gt;&#10; &lt;span class="dark:text-neutral-300"&gt;I greatly enjoy the DSLC Slack Community (&lt;a href="https://dslc.io/join" target="_blank"&gt;&#10; dslc.io/join&lt;/a&gt;),&#10;and spend a fair bit of time answering questions! This post is part of a &lt;a href="https://tanho.ca/tags/dslc-slack"&gt;&#10; series&lt;/a&gt;&#10;where I curate some interesting questions and/or answers that I’ve come across there.&lt;/span&gt;&#10;&lt;/div&gt;&#10;&#10;&#10;&lt;h2 class="relative group"&gt;&lt;code&gt;Piranha&lt;/code&gt; asks:&#10; &lt;div id="piranha-asks" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#piranha-asks" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;blockquote&gt;&lt;p&gt;Hello,&#10;This might be bit of a stretch&amp;hellip;. I could use a bit of help in prepping for some upcoming conversations with the head of my company&amp;rsquo;s IT/Security.&lt;/p&gt;&#10;&lt;p&gt;I am trying to get IT support for Shiny (currently IT supports Tableau).&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt;: Is there any kind of high level summary of this Admin Guide document?&#10;&lt;a href="https://docs.rstudio.com/shiny-server/" target="_blank" rel="noreferrer"&gt;https://docs.rstudio.com/shiny-server/&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;More specifically, I want to summarize the official document into about a 3-5 slide presentation. Topics that I want to include:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;What is Shiny? (3-5 bullet points, in language that a &amp;ldquo;traditional&amp;rdquo; IT person will understand)&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;How to think about security and authentication for both the Shiny Server free and Pro.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;How to think about Dockerizing an application.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;I attempted to summarize the official docs into a 3-5 slide PowerPoint (ugh, yes, PowerPoint!), but am really struggling. This is a massive document and I am not an IT person!&lt;br&gt;&#10;Any pointers would be really helpful.&lt;br&gt;&#10;Thanks!&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h2 class="relative group"&gt;Answer (by me)&#10; &lt;div id="answer-by-me" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#answer-by-me" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;I don&amp;rsquo;t know if I have a document to point you at, but I would suggest a mental&#10;model where you separate Shiny the app (the app.R file and all of the things&#10;included in it) from the ways you deploy Shiny. Writing out some of my personal&#10;thoughts on it:&lt;/p&gt;&#10;&lt;p&gt;Shiny (the app):&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;is an R package that allows you to write UI (client-side) and server-side&#10;logic in R, which can be implemented quickly (from a code-writing perspective)&#10;and powerfully (leverages all of the modelling/data-wrangling packages and&#10;abilities of R).&lt;/li&gt;&#10;&lt;li&gt;has an architecture consisting of a client (the browser) and a server (an&#10;R process). The two are connected by a&#10;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" target="_blank" rel="noreferrer"&gt;websocket&lt;/a&gt;&#10;that receives state changes from the client, such as new values for input controls,&#10;and distributes state changes from the server, such as new output values.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Shiny is not self-contained because it relies on R and other libraries (Shiny,&#10;as well as whatever else you use in the app) that are installed onto the server.&#10;Docker is one of the best ways to handle this, because it creates a container that&#10;holds an installation of R and all of the relevant packages, and can be version-locked&#10;to ensure stability. Once a Shiny app has been dockerized, it can be turned over&#10;to a devops team to deploy, and the devops team does not have to know R or Shiny&#10;in order to use the app.&lt;/p&gt;&#10;&lt;p&gt;This allows for a division of expertise:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;the data scientist makes the app, and makes sure the docker container builds&#10;and works as intended&lt;/li&gt;&#10;&lt;li&gt;the devops engineer can take care of the details with deploying and securing&#10;the apps, by controlling/restricting access to the container itself rather than&#10;forcing the data scientist to worry about it inside the app.&lt;/li&gt;&#10;&lt;li&gt;Both the data scientist and the devops engineer should responsible for&#10;performance:&#10;&lt;ul&gt;&#10;&lt;li&gt;data scientist by improving the code for efficiency&lt;/li&gt;&#10;&lt;li&gt;engineer by supplying the containers with the right amount of processing&#10;power/memory/load-balancing&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;A dedicated devops person can pretty easily deploy a docker container into an&#10;existing app/microservices system, if such already exists.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;At the other end of the spectrum, &lt;a href="http://shinyapps.io/" target="_blank" rel="noreferrer"&gt;shinyapps.io&lt;/a&gt; and RS&#10;Connect are solutions that RStudio provides to help data teams who want this&#10;sort of devops process but don&amp;rsquo;t want to have the work done in house. They&amp;rsquo;ll&#10;manage the servers for you and make it very easy for R users to just upload all&#10;of the app data and configs, and they&amp;rsquo;ll manage deployment, performance and&#10;authentication for you.&lt;/p&gt;&#10;&lt;p&gt;I&amp;rsquo;m a data generalist for a small team, and manage the full stack from data&#10;import/wrangle/model to app dev to app deploy. I wouldn&amp;rsquo;t necessarily recommend&#10;that path if your team is large enough - let devops be devops and data scientists&#10;be data scientists where possible!&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;Some followup questions&#10; &lt;div id="some-followup-questions" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#some-followup-questions" aria-label="Anchor"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;blockquote&gt;&lt;p&gt;In a discussion earlier this week, a person from IT asked me &amp;ldquo;I dont know R,&#10;can you tell me how Shiny connects to the user&amp;rsquo;s browser?&amp;rdquo; I didn&amp;rsquo;t know much&#10;about WebSocket technology at the time, so my response was: &amp;ldquo;Shiny comes with&#10;its own webserver, but a common practice is to use nginx webserver in front of&#10;the shiny app&amp;rdquo;.&lt;/p&gt;&#10;&lt;p&gt;Now that I know a bit more&amp;hellip;would it be accurate to some something along these&#10;lines: &amp;ldquo;Shiny uses WebSocket technology to create a 2-way communication between&#10;the server and the browser. This allows the data scientist to leverage the full&#10;data-processing and analytical capabilities of R. In our current process, we need&#10;to do processing/analysis in one tool (e.g. SAS, R) and visualization/sharing&#10;in Tableau/Excel - creating lots of inefficiencies. Using Shiny, we can fine-tune&#10;and scale our analysis to exactly what is needed by the client and serve that&#10;via a Shiny dashboard.&amp;rdquo;&lt;/p&gt;&#10;&lt;p&gt;Furthermore, &amp;ldquo;From the data science team&amp;rsquo;s perspective, this is our &lt;strong&gt;ask&lt;/strong&gt;.&#10;We need the ability to deliver interactive analysis to our clients at scale.&#10;Can you help us do that in a secure way? We&amp;rsquo;ll build the Shiny app and dockerize&#10;it. We need help from IT to provide secure access by clients&amp;rdquo;.&lt;/p&gt;&#10;&lt;/blockquote&gt;&lt;p&gt;and response:&lt;/p&gt;&#10;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;Shiny uses WebSocket technology to create a 2-way communication between the server and the browser&lt;/code&gt;&lt;/p&gt;&#10;&lt;/blockquote&gt;&lt;p&gt;I cribbed that chunk from here:&#10;&lt;a href="https://community.rstudio.com/t/is-there-any-equivalent-of-web-sockets-in-shiny-world/17908" target="_blank" rel="noreferrer"&gt;https://community.rstudio.com/t/is-there-any-equivalent-of-web-sockets-in-shiny-world/17908&lt;/a&gt;.&#10;If you&amp;rsquo;re hoping to communicate how Shiny works to an IT person, I would use the&#10;wording as described rather than paraphrasing it too much - receives state&#10;changes from client and distributes state changes from server is high-level&#10;enough for most IT people to understand - and you lose something by abstracting&#10;beyond that.&lt;/p&gt;&#10;&lt;blockquote&gt;&lt;p&gt;Using Shiny, we can fine-tune and scale our analysis to exactly what is needed&#10;by the client and serve that via a Shiny dashboard&lt;/p&gt;&#10;&lt;/blockquote&gt;&lt;p&gt;I&amp;rsquo;d change this to say that it allows you to use the same R code that you use to&#10;process and generate the data right in the app, which allows you to package the&#10;&amp;ldquo;business logic&amp;rdquo; right into the app for immediate interactive analyses. I&amp;rsquo;m not&#10;familiar with your team and the ask - but identifying the docker container as&#10;the handoff point where IT helps deploy the app and serve it securely and&#10;effectively to clients is a good start. That lets IT do the security bit.&lt;/p&gt;&#10;</description><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://tanho.ca/posts/2020-10-15_explaining-shiny/featured.jpg"/></item></channel></rss>