<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: dashboard</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/dashboard.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2021-03-21T05:50:25+00:00</updated><author><name>Simon Willison</name></author><entry><title>Weeknotes: django-sql-dashboard widgets</title><link href="https://simonwillison.net/2021/Mar/21/django-sql-dashboard-widgets/#atom-tag" rel="alternate"/><published>2021-03-21T05:50:25+00:00</published><updated>2021-03-21T05:50:25+00:00</updated><id>https://simonwillison.net/2021/Mar/21/django-sql-dashboard-widgets/#atom-tag</id><summary type="html">
    &lt;p&gt;A few small releases this week, for &lt;code&gt;django-sql-dashboard&lt;/code&gt;, &lt;code&gt;datasette-auth-passwords&lt;/code&gt; and &lt;code&gt;datasette-publish-vercel&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;django-sql-dashboard widgets and permissions&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://github.com/simonw/django-sql-dashboard"&gt;django-sql-dashboard&lt;/a&gt;, my subset-of-Datasette-for-Django-and-PostgreSQL continues to come together.&lt;/p&gt;
&lt;p&gt;New this week: widgets and permissions.&lt;/p&gt;
&lt;p&gt;To recap: this Django app borrows some ideas from Datasette: it encourages you to create a read-only PostgreSQL user and grant authenticated users the ability to run one or more raw SQL queries directly against your database.&lt;/p&gt;
&lt;p&gt;You can execute more than one SQL query and combine them into a saved dashboard, which will then show multiple tables containing the results.&lt;/p&gt;
&lt;p&gt;This week I added support for dashboard widgets. You can construct SQL queries to return specific column patterns which will then be rendered on the page in different ways.&lt;/p&gt;
&lt;p&gt;There are four widgets at the moment: "big number", bar chart, HTML and Markdown.&lt;/p&gt;
&lt;p&gt;Big number is the simplest: define a SQL query that returns two columns called &lt;code&gt;label&lt;/code&gt; and &lt;code&gt;big_number&lt;/code&gt; and the dashboard will display that result as a big number:&lt;/p&gt;
&lt;div class="highlight highlight-source-sql"&gt;&lt;pre&gt;&lt;span class="pl-k"&gt;select&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;Entries&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;as&lt;/span&gt; label, &lt;span class="pl-c1"&gt;count&lt;/span&gt;(&lt;span class="pl-k"&gt;*&lt;/span&gt;) &lt;span class="pl-k"&gt;as&lt;/span&gt; big_number &lt;span class="pl-k"&gt;from&lt;/span&gt; blog_entry;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img alt="Entries: 2804 - an example of a big number display" src="https://static.simonwillison.net/static/2021/dashboard-big-number.png" style="max-width:100%;" /&gt;&lt;/p&gt;
&lt;p&gt;Bar chart is more sophisticated: return columns named &lt;code&gt;bar_label&lt;/code&gt; and &lt;code&gt;bar_quantity&lt;/code&gt; to display a bar chart of the results:&lt;/p&gt;
&lt;div class="highlight highlight-source-sql"&gt;&lt;pre&gt;&lt;span class="pl-k"&gt;select&lt;/span&gt;
  to_char(date_trunc(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;month&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;, created), &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;YYYY-MM&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="pl-k"&gt;as&lt;/span&gt; bar_label,
  &lt;span class="pl-c1"&gt;count&lt;/span&gt;(&lt;span class="pl-k"&gt;*&lt;/span&gt;) &lt;span class="pl-k"&gt;as&lt;/span&gt; bar_quantity
&lt;span class="pl-k"&gt;from&lt;/span&gt;
  blog_entry
&lt;span class="pl-k"&gt;group by&lt;/span&gt;
  bar_label
&lt;span class="pl-k"&gt;order by&lt;/span&gt;
  &lt;span class="pl-c1"&gt;count&lt;/span&gt;(&lt;span class="pl-k"&gt;*&lt;/span&gt;) &lt;span class="pl-k"&gt;desc&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img alt="A bar chart showing the result of that query" src="https://static.simonwillison.net/static/2021/dashboard-bar-chart.png" style="max-width:100%;" /&gt;&lt;/p&gt;
&lt;p&gt;HTML and Markdown are simpler: they display the rendered HTML or Markdown, after filtering it through the Bleach library to strip any harmful elements or scripts.&lt;/p&gt;
&lt;div class="highlight highlight-source-sql"&gt;&lt;pre&gt;&lt;span class="pl-k"&gt;select&lt;/span&gt;
  &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;## Ten most recent blogmarks (of &lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; 
  &lt;span class="pl-k"&gt;||&lt;/span&gt; &lt;span class="pl-c1"&gt;count&lt;/span&gt;(&lt;span class="pl-k"&gt;*&lt;/span&gt;) &lt;span class="pl-k"&gt;||&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt; total)&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;as&lt;/span&gt; markdown &lt;span class="pl-k"&gt;from&lt;/span&gt; blog_blogmark;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I'm running the dashboard application on this blog, and I've set up &lt;a href="https://simonwillison.net/dashboard/example-dashboard/"&gt;an example dashboard&lt;/a&gt; here that illustrates the different types of widget.&lt;/p&gt;
&lt;p&gt;&lt;img alt="An example dashboard with several different widgets" src="https://static.simonwillison.net/static/2021/dashboard-example.png" style="max-width:100%;" /&gt;&lt;/p&gt;
&lt;p&gt;Defining custom widgets is easy: take the column names you would like to respond to, sort them alphabetically, join them with hyphens and create a custom widget in a template file with that name.&lt;/p&gt;
&lt;p&gt;So if you wanted to build a widget that looks for &lt;code&gt;label&lt;/code&gt; and &lt;code&gt;geojson&lt;/code&gt; columns and renders that data on a &lt;a href="https://leafletjs.com/"&gt;Leaflet map&lt;/a&gt;, you would create a &lt;code&gt;geojson-label.html&lt;/code&gt; template and drop it into your Django &lt;code&gt;templates/django-sql-dashboard/widgets&lt;/code&gt; folder. See &lt;a href="https://django-sql-dashboard.readthedocs.io/en/latest/widgets.html#custom-widgets"&gt;the custom widgets documentation&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;Which reminds me: I decided a README wasn't quite enough space for documentation here, so I started a &lt;a href="https://django-sql-dashboard.readthedocs.io/"&gt;Read The Docs documentation site&lt;/a&gt; for the project.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.datasette.io/"&gt;Datasette&lt;/a&gt; and &lt;a href="https://sqlite-utils.datasette.io/"&gt;sqlite-utils&lt;/a&gt; both use &lt;a href="https://www.sphinx-doc.org/"&gt;Sphinx&lt;/a&gt; and &lt;a href="https://docutils.sourceforge.io/rst.html"&gt;reStructuredText&lt;/a&gt; for their documentation.&lt;/p&gt;
&lt;p&gt;For &lt;code&gt;django-sql-dashboard&lt;/code&gt; I've decided to try out Sphinx and Markdown instead, using &lt;a href="https://myst-parser.readthedocs.io/"&gt;MyST&lt;/a&gt; - a Markdown flavour and parser for Sphinx.&lt;/p&gt;
&lt;p&gt;I picked this because I want to add inline help to &lt;code&gt;django-sql-dashboard&lt;/code&gt;, and since it ships with Markdown as a dependency already (to power the Markdown widget) my hope is that using Markdown for the documentation will allow me to ship some of the user-facing docs as part of the application itself. But it's also a fun excuse to try out MyST, which so far is working exactly as advertised.&lt;/p&gt;
&lt;p&gt;I've seen people in the past avoid Sphinx entirely because they preferred Markdown to reStructuredText, so MyST feels like an important addition to the Python documentation ecosystem.&lt;/p&gt;
&lt;h4&gt;HTTP Basic authentication&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://datasette.io/plugins/datasette-auth-passwords"&gt;datasette-auth-passwords&lt;/a&gt; implements password-based authentication to Datasette. The plugin defaults to providing a username and password login form which sets a signed cookie identifying the current user.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/simonw/datasette-auth-passwords/releases/tag/0.4"&gt;Version 0.4&lt;/a&gt; introduces &lt;a href="https://github.com/simonw/datasette-auth-passwords/issues/15"&gt;optional support&lt;/a&gt; for HTTP Basic authentication instead - where the user's browser handles the authentication prompt.&lt;/p&gt;
&lt;p&gt;Basic auth has some disadvantages - most notably that it doesn't support logout without the user entirely closing down their browser. But it's useful for a number of reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It's easy to protect every resource on a website with it - including static assets. Adding &lt;code&gt;"http_basic_auth": true&lt;/code&gt; to your plugin configuration adds this protection, covering all of Datasette's resources.&lt;/li&gt;
&lt;li&gt;It's much easier to authenticate with from automated scripts. &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;roquests&lt;/code&gt; and &lt;code&gt;httpx&lt;/code&gt; all have simple built-in support for passing basic authentication usernames and passwords, which makes it a useful target for scripting - without having to install an additional authentication plugin such as &lt;a href="https://datasette.io/plugins/datasette-auth-tokens"&gt;datasette-auth-tokens&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'm continuing to flesh out authentication options for Datasette, and adding this to &lt;code&gt;datasette-auth-passwords&lt;/code&gt; is one of those small improvements that should pay off long into the future.&lt;/p&gt;
&lt;h4&gt;A fix for datasette-publish-vercel&lt;/h4&gt;
&lt;p&gt;Datasette instances published to &lt;a href="https://vercel.com/"&gt;Vercel&lt;/a&gt; using the &lt;a href="https://datasette.io/plugins/datasette-publish-vercel"&gt;datasette-publish-vercel&lt;/a&gt; have previously been affected by an obscure Vercel bug: &lt;a href="https://github.com/vercel/vercel/issues/5575"&gt;characters such as + in the query string&lt;/a&gt; were being lost due to Vercel unescaping encoded characters before the request got to the Python application server.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://vercel.com/changelog/correcting-request-urls-with-python-serverless-functions"&gt;Vercel fixed this&lt;/a&gt; earlier this month, and the latest release of &lt;code&gt;datasette-publish-vercel&lt;/code&gt; includes their fix by switching to the new &lt;code&gt;@vercel/python&lt;/code&gt; builder. Thanks &lt;a href="https://twitter.com/styfle"&gt;@styfle&lt;/a&gt; from Vercel for shepherding this fix through!&lt;/p&gt;
&lt;h4&gt;New photos on Niche Museums&lt;/h4&gt;
&lt;p&gt;My Niche Museums project has been in hiberation since the start of the pandemic. Now that vaccines are rolling out it feels like there might be an end to this thing, so I've started thinking about my museum hobby again.&lt;/p&gt;
&lt;p&gt;I added some new photos to the site today - on the entries for &lt;a href="https://www.niche-museums.com/17"&gt;Novelty Automation&lt;/a&gt;, &lt;a href="https://www.niche-museums.com/21"&gt;DEVIL-ish Little Things&lt;/a&gt;, &lt;a href="https://www.niche-museums.com/24"&gt;Evergreen Aviation &amp;amp; Space Museum&lt;/a&gt; and &lt;a href="https://www.niche-museums.com/33"&gt;California State Capitol Dioramas&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hopefully someday soon I'll get to visit and add an entirely new museum!&lt;/p&gt;
&lt;h4&gt;Releases this week&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/simonw/django-sql-dashboard"&gt;django-sql-dashboard&lt;/a&gt;&lt;/strong&gt;: &lt;a href="https://github.com/simonw/django-sql-dashboard/releases/tag/0.4a1"&gt;0.4a1&lt;/a&gt; - (&lt;a href="https://github.com/simonw/django-sql-dashboard/releases"&gt;10 releases total&lt;/a&gt;) - 2021-03-21
&lt;br /&gt;Django app for building dashboards using raw SQL queries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/simonw/datasette-publish-vercel"&gt;datasette-publish-vercel&lt;/a&gt;&lt;/strong&gt;: &lt;a href="https://github.com/simonw/datasette-publish-vercel/releases/tag/0.9.2"&gt;0.9.2&lt;/a&gt; - (&lt;a href="https://github.com/simonw/datasette-publish-vercel/releases"&gt;14 releases total&lt;/a&gt;) - 2021-03-20
&lt;br /&gt;Datasette plugin for publishing data using Vercel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/simonw/datasette-auth-passwords"&gt;datasette-auth-passwords&lt;/a&gt;&lt;/strong&gt;: &lt;a href="https://github.com/simonw/datasette-auth-passwords/releases/tag/0.4"&gt;0.4&lt;/a&gt; - (&lt;a href="https://github.com/simonw/datasette-auth-passwords/releases"&gt;9 releases total&lt;/a&gt;) - 2021-03-19
&lt;br /&gt;Datasette plugin for authentication using passwords&lt;/li&gt;
&lt;/ul&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/authentication"&gt;authentication&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/dashboard"&gt;dashboard&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/zeit-now"&gt;zeit-now&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/weeknotes"&gt;weeknotes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django-sql-dashboard"&gt;django-sql-dashboard&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sphinx-docs"&gt;sphinx-docs&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="authentication"/><category term="dashboard"/><category term="django"/><category term="postgresql"/><category term="projects"/><category term="zeit-now"/><category term="weeknotes"/><category term="django-sql-dashboard"/><category term="sphinx-docs"/></entry><entry><title>Google Dashboard</title><link href="https://simonwillison.net/2009/Nov/5/dashboard/#atom-tag" rel="alternate"/><published>2009-11-05T14:03:56+00:00</published><updated>2009-11-05T14:03:56+00:00</updated><id>https://simonwillison.net/2009/Nov/5/dashboard/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.google.com/dashboard/"&gt;Google Dashboard&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
New Google product which shows exactly how much information Google have stored against your account, all on one page. This is a really useful tool, and hopefully will help set a powerful precedent for other sites to follow.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/dashboard"&gt;dashboard&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/google"&gt;google&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/privacy"&gt;privacy&lt;/a&gt;&lt;/p&gt;



</summary><category term="dashboard"/><category term="google"/><category term="privacy"/></entry></feed>