<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://tech.uvoo.io/index.php?action=history&amp;feed=atom&amp;title=Vuetify_%26_vue-postgrest_todos</id>
	<title>Vuetify &amp; vue-postgrest todos - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://tech.uvoo.io/index.php?action=history&amp;feed=atom&amp;title=Vuetify_%26_vue-postgrest_todos"/>
	<link rel="alternate" type="text/html" href="https://tech.uvoo.io/index.php?title=Vuetify_%26_vue-postgrest_todos&amp;action=history"/>
	<updated>2026-04-24T06:24:42Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.2</generator>
	<entry>
		<id>https://tech.uvoo.io/index.php?title=Vuetify_%26_vue-postgrest_todos&amp;diff=5620&amp;oldid=prev</id>
		<title>Busk at 10:30, 10 August 2025</title>
		<link rel="alternate" type="text/html" href="https://tech.uvoo.io/index.php?title=Vuetify_%26_vue-postgrest_todos&amp;diff=5620&amp;oldid=prev"/>
		<updated>2025-08-10T10:30:15Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table class=&quot;diff diff-contentalign-left diff-editfont-monospace&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 10:30, 10 August 2025&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l7&quot; &gt;Line 7:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 7:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;# Vue 3 + Vite + Vuetify&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;# Vue 3 + Vite + Vuetify&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt; &lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;```&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;npm create vite@latest vue-pg-todos -- --template vue&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;npm create vite@latest vue-pg-todos -- --template vue&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;cd vue-pg-todos&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;cd vue-pg-todos&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;npm i vuetify @mdi/font vue-postgrest&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;npm i vuetify @mdi/font vue-postgrest&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt; &lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;```&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;main.ts&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;main.ts&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt; &lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;```&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;// src/main.ts&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;// src/main.ts&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l56&quot; &gt;Line 56:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 59:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;import TodosCrud from './components/TodosCrud.vue'&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;import TodosCrud from './components/TodosCrud.vue'&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/script&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/script&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;−&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins class=&quot;diffchange diffchange-inline&quot;&gt;```&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;---&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;---&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l62&quot; &gt;Line 62:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 65:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;CRUD component&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;CRUD component&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt; &lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;```&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;!-- src/components/TodosCrud.vue --&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;!-- src/components/TodosCrud.vue --&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;template&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;template&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l296&quot; &gt;Line 296:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 300:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;})&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;})&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/script&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/script&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt; &lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;```&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l302&quot; &gt;Line 302:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 307:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;PostgREST side (example table)&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;PostgREST side (example table)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt; &lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;```&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- example schema&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- example schema&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;CREATE TABLE public.todos(&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;CREATE TABLE public.todos(&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l311&quot; &gt;Line 311:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 317:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;GRANT SELECT, INSERT, UPDATE, DELETE ON public.todos TO anon;  -- or your web role&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;GRANT SELECT, INSERT, UPDATE, DELETE ON public.todos TO anon;  -- or your web role&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt; &lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;```&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Busk</name></author>
	</entry>
	<entry>
		<id>https://tech.uvoo.io/index.php?title=Vuetify_%26_vue-postgrest_todos&amp;diff=5619&amp;oldid=prev</id>
		<title>Busk: Created page with &quot;Perfect—here’s a Vue + Vuetify + vue-postgrest CRUD example for a todos table. It shows list, add, edit, and delete using v-data-table and dialogs. It uses vue-postgrest...&quot;</title>
		<link rel="alternate" type="text/html" href="https://tech.uvoo.io/index.php?title=Vuetify_%26_vue-postgrest_todos&amp;diff=5619&amp;oldid=prev"/>
		<updated>2025-08-10T10:27:37Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;Perfect—here’s a Vue + Vuetify + vue-postgrest CRUD example for a todos table. It shows list, add, edit, and delete using v-data-table and dialogs. It uses vue-postgrest...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Perfect—here’s a Vue + Vuetify + vue-postgrest CRUD example for a todos table. It shows list, add, edit, and delete using v-data-table and dialogs. It uses vue-postgrest’s pg mixin, pg.$new() for creates, and per-row item.$patch() / item.$delete() for updates/deletes (that’s how the library is designed). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Project setup&lt;br /&gt;
&lt;br /&gt;
# Vue 3 + Vite + Vuetify&lt;br /&gt;
npm create vite@latest vue-pg-todos -- --template vue&lt;br /&gt;
cd vue-pg-todos&lt;br /&gt;
npm i vuetify @mdi/font vue-postgrest&lt;br /&gt;
&lt;br /&gt;
main.ts&lt;br /&gt;
&lt;br /&gt;
// src/main.ts&lt;br /&gt;
import { createApp } from 'vue'&lt;br /&gt;
import App from './App.vue'&lt;br /&gt;
&lt;br /&gt;
// Vuetify&lt;br /&gt;
import 'vuetify/styles'&lt;br /&gt;
import { createVuetify } from 'vuetify'&lt;br /&gt;
import { aliases, mdi } from 'vuetify/iconsets/mdi'&lt;br /&gt;
import '@mdi/font/css/materialdesignicons.css'&lt;br /&gt;
const vuetify = createVuetify({&lt;br /&gt;
  icons: { defaultSet: 'mdi', aliases, sets: { mdi } },&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
// vue-postgrest&lt;br /&gt;
import VuePostgrest from 'vue-postgrest'&lt;br /&gt;
&lt;br /&gt;
// Create app&lt;br /&gt;
const app = createApp(App)&lt;br /&gt;
&lt;br /&gt;
// Point to your PostgREST base URL&lt;br /&gt;
app.use(VuePostgrest, {&lt;br /&gt;
  apiRoot: 'http://localhost:3000/',   // e.g. http://localhost:3000/&lt;br /&gt;
  // headers: { Authorization: `Bearer ${yourJWT}` }  // if you use JWT&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
app.use(vuetify).mount('#app')&lt;br /&gt;
&lt;br /&gt;
App.vue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- src/App.vue --&amp;gt;&lt;br /&gt;
&amp;lt;template&amp;gt;&lt;br /&gt;
  &amp;lt;v-app&amp;gt;&lt;br /&gt;
    &amp;lt;v-main&amp;gt;&lt;br /&gt;
      &amp;lt;v-container class=&amp;quot;py-8&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;TodosCrud /&amp;gt;&lt;br /&gt;
      &amp;lt;/v-container&amp;gt;&lt;br /&gt;
    &amp;lt;/v-main&amp;gt;&lt;br /&gt;
  &amp;lt;/v-app&amp;gt;&lt;br /&gt;
&amp;lt;/template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;script setup lang=&amp;quot;ts&amp;quot;&amp;gt;&lt;br /&gt;
import TodosCrud from './components/TodosCrud.vue'&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
CRUD component&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- src/components/TodosCrud.vue --&amp;gt;&lt;br /&gt;
&amp;lt;template&amp;gt;&lt;br /&gt;
  &amp;lt;v-card&amp;gt;&lt;br /&gt;
    &amp;lt;v-card-title class=&amp;quot;d-flex justify-space-between&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;span class=&amp;quot;text-h6&amp;quot;&amp;gt;Todos&amp;lt;/span&amp;gt;&lt;br /&gt;
      &amp;lt;div class=&amp;quot;d-flex ga-2&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;v-text-field&lt;br /&gt;
          v-model=&amp;quot;search&amp;quot;&lt;br /&gt;
          density=&amp;quot;compact&amp;quot;&lt;br /&gt;
          hide-details&lt;br /&gt;
          label=&amp;quot;Search title&amp;quot;&lt;br /&gt;
          prepend-inner-icon=&amp;quot;mdi-magnify&amp;quot;&lt;br /&gt;
          style=&amp;quot;max-width: 280px&amp;quot;&lt;br /&gt;
          @keyup.enter=&amp;quot;refresh&amp;quot;&lt;br /&gt;
        /&amp;gt;&lt;br /&gt;
        &amp;lt;v-btn color=&amp;quot;primary&amp;quot; prepend-icon=&amp;quot;mdi-plus&amp;quot; @click=&amp;quot;openCreate&amp;quot;&amp;gt;&lt;br /&gt;
          Add&lt;br /&gt;
        &amp;lt;/v-btn&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/v-card-title&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;v-data-table&lt;br /&gt;
      :items=&amp;quot;todos&amp;quot;&lt;br /&gt;
      :headers=&amp;quot;headers&amp;quot;&lt;br /&gt;
      :search=&amp;quot;search&amp;quot;&lt;br /&gt;
      :loading=&amp;quot;pg.$get.isPending&amp;quot;&lt;br /&gt;
      item-key=&amp;quot;id&amp;quot;&lt;br /&gt;
      class=&amp;quot;elevation-1&amp;quot;&lt;br /&gt;
    &amp;gt;&lt;br /&gt;
      &amp;lt;template #item.done=&amp;quot;{ item }&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;v-checkbox-btn v-model=&amp;quot;item.done&amp;quot; @change=&amp;quot;saveInline(item)&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;/template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;template #item.actions=&amp;quot;{ item }&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;v-btn&lt;br /&gt;
          size=&amp;quot;small&amp;quot;&lt;br /&gt;
          icon=&amp;quot;mdi-pencil&amp;quot;&lt;br /&gt;
          variant=&amp;quot;text&amp;quot;&lt;br /&gt;
          @click=&amp;quot;openEdit(item)&amp;quot;&lt;br /&gt;
        /&amp;gt;&lt;br /&gt;
        &amp;lt;v-btn&lt;br /&gt;
          size=&amp;quot;small&amp;quot;&lt;br /&gt;
          color=&amp;quot;error&amp;quot;&lt;br /&gt;
          icon=&amp;quot;mdi-delete&amp;quot;&lt;br /&gt;
          variant=&amp;quot;text&amp;quot;&lt;br /&gt;
          @click=&amp;quot;confirmDelete(item)&amp;quot;&lt;br /&gt;
        /&amp;gt;&lt;br /&gt;
      &amp;lt;/template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      &amp;lt;template #no-data&amp;gt;&lt;br /&gt;
        &amp;lt;v-alert type=&amp;quot;info&amp;quot; variant=&amp;quot;tonal&amp;quot;&amp;gt;No todos yet.&amp;lt;/v-alert&amp;gt;&lt;br /&gt;
      &amp;lt;/template&amp;gt;&lt;br /&gt;
    &amp;lt;/v-data-table&amp;gt;&lt;br /&gt;
  &amp;lt;/v-card&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;!-- Create/Edit dialog --&amp;gt;&lt;br /&gt;
  &amp;lt;v-dialog v-model=&amp;quot;dialog.open&amp;quot; max-width=&amp;quot;520px&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;v-card :title=&amp;quot;dialog.mode === 'create' ? 'Add Todo' : 'Edit Todo'&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;v-card-text&amp;gt;&lt;br /&gt;
        &amp;lt;v-form ref=&amp;quot;formRef&amp;quot; @submit.prevent=&amp;quot;submitDialog&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;v-text-field&lt;br /&gt;
            v-model=&amp;quot;dialog.model.title&amp;quot;&lt;br /&gt;
            label=&amp;quot;Title&amp;quot;&lt;br /&gt;
            :rules=&amp;quot;[v =&amp;gt; !!v || 'Required']&amp;quot;&lt;br /&gt;
            required&lt;br /&gt;
          /&amp;gt;&lt;br /&gt;
          &amp;lt;v-switch v-model=&amp;quot;dialog.model.done&amp;quot; label=&amp;quot;Done?&amp;quot; /&amp;gt;&lt;br /&gt;
        &amp;lt;/v-form&amp;gt;&lt;br /&gt;
        &amp;lt;v-alert&lt;br /&gt;
          v-if=&amp;quot;errorMessage&amp;quot;&lt;br /&gt;
          type=&amp;quot;error&amp;quot;&lt;br /&gt;
          variant=&amp;quot;tonal&amp;quot;&lt;br /&gt;
          class=&amp;quot;mt-4&amp;quot;&lt;br /&gt;
          :text=&amp;quot;errorMessage&amp;quot;&lt;br /&gt;
        /&amp;gt;&lt;br /&gt;
      &amp;lt;/v-card-text&amp;gt;&lt;br /&gt;
      &amp;lt;v-card-actions&amp;gt;&lt;br /&gt;
        &amp;lt;v-spacer /&amp;gt;&lt;br /&gt;
        &amp;lt;v-btn variant=&amp;quot;text&amp;quot; @click=&amp;quot;closeDialog&amp;quot;&amp;gt;Cancel&amp;lt;/v-btn&amp;gt;&lt;br /&gt;
        &amp;lt;v-btn :loading=&amp;quot;saving&amp;quot; color=&amp;quot;primary&amp;quot; @click=&amp;quot;submitDialog&amp;quot;&amp;gt;&lt;br /&gt;
          Save&lt;br /&gt;
        &amp;lt;/v-btn&amp;gt;&lt;br /&gt;
      &amp;lt;/v-card-actions&amp;gt;&lt;br /&gt;
    &amp;lt;/v-card&amp;gt;&lt;br /&gt;
  &amp;lt;/v-dialog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;!-- Delete confirm --&amp;gt;&lt;br /&gt;
  &amp;lt;v-dialog v-model=&amp;quot;confirm.open&amp;quot; max-width=&amp;quot;440px&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;v-card title=&amp;quot;Delete todo?&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;v-card-text&amp;gt; This action cannot be undone. &amp;lt;/v-card-text&amp;gt;&lt;br /&gt;
      &amp;lt;v-card-actions&amp;gt;&lt;br /&gt;
        &amp;lt;v-spacer /&amp;gt;&lt;br /&gt;
        &amp;lt;v-btn variant=&amp;quot;text&amp;quot; @click=&amp;quot;confirm.open = false&amp;quot;&amp;gt;Cancel&amp;lt;/v-btn&amp;gt;&lt;br /&gt;
        &amp;lt;v-btn color=&amp;quot;error&amp;quot; :loading=&amp;quot;saving&amp;quot; @click=&amp;quot;doDelete&amp;quot;&amp;gt;&lt;br /&gt;
          Delete&lt;br /&gt;
        &amp;lt;/v-btn&amp;gt;&lt;br /&gt;
      &amp;lt;/v-card-actions&amp;gt;&lt;br /&gt;
    &amp;lt;/v-card&amp;gt;&lt;br /&gt;
  &amp;lt;/v-dialog&amp;gt;&lt;br /&gt;
&amp;lt;/template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;script lang=&amp;quot;ts&amp;quot;&amp;gt;&lt;br /&gt;
import { defineComponent, ref, computed } from 'vue'&lt;br /&gt;
import { pg } from 'vue-postgrest' // mixin that wires PostgREST queries &amp;amp; models. 1&lt;br /&gt;
&lt;br /&gt;
export default defineComponent({&lt;br /&gt;
  name: 'TodosCrud',&lt;br /&gt;
  mixins: [pg],&lt;br /&gt;
  data() {&lt;br /&gt;
    return {&lt;br /&gt;
      // vue-postgrest mixin config: point to the &amp;quot;todos&amp;quot; route&lt;br /&gt;
      pgConfig: {&lt;br /&gt;
        route: 'todos',&lt;br /&gt;
        query: {&lt;br /&gt;
          select: ['id', 'title', 'done', 'created_at'],&lt;br /&gt;
          order: { id: 'asc' },      // server-side ordering. 2&lt;br /&gt;
        },&lt;br /&gt;
        count: 'exact',               // Prefer: count=exact, enables pg.$range.totalCount. 3&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      search: '',&lt;br /&gt;
      headers: [&lt;br /&gt;
        { title: 'ID', key: 'id', sortable: true, width: 80 },&lt;br /&gt;
        { title: 'Title', key: 'title', sortable: true },&lt;br /&gt;
        { title: 'Done', key: 'done', sortable: true, width: 110 },&lt;br /&gt;
        { title: 'Created', key: 'created_at', sortable: true, width: 200 },&lt;br /&gt;
        { title: 'Actions', key: 'actions', sortable: false, width: 120 },&lt;br /&gt;
      ],&lt;br /&gt;
&lt;br /&gt;
      dialog: {&lt;br /&gt;
        open: false as boolean,&lt;br /&gt;
        mode: 'create' as 'create' | 'edit',&lt;br /&gt;
        model: null as any,   // will hold a vue-postgrest GenericModel. 4&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      confirm: {&lt;br /&gt;
        open: false as boolean,&lt;br /&gt;
        item: null as any,&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      saving: false,&lt;br /&gt;
      errorMessage: '',&lt;br /&gt;
    }&lt;br /&gt;
  },&lt;br /&gt;
  computed: {&lt;br /&gt;
    // this.pg is a GenericCollection of GenericModels that wrap items. 5&lt;br /&gt;
    todos(): any[] {&lt;br /&gt;
      return (this as any).pg&lt;br /&gt;
    },&lt;br /&gt;
  },&lt;br /&gt;
  methods: {&lt;br /&gt;
    refresh() {&lt;br /&gt;
      (this as any).pg.$get()  // re-fetch list. exposes pending/error flags. 6&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    openCreate() {&lt;br /&gt;
      // Create a new client-side model with default values. 7&lt;br /&gt;
      this.dialog.model = (this as any).pg.$new({&lt;br /&gt;
        title: '',&lt;br /&gt;
        done: false,&lt;br /&gt;
      })&lt;br /&gt;
      this.dialog.mode = 'create'&lt;br /&gt;
      this.errorMessage = ''&lt;br /&gt;
      this.dialog.open = true&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    openEdit(item: any) {&lt;br /&gt;
      // Clone the model so cancel won't mutate the table immediately&lt;br /&gt;
      this.dialog.model = (this as any).pg.$new({&lt;br /&gt;
        id: item.id,&lt;br /&gt;
        title: item.title,&lt;br /&gt;
        done: item.done,&lt;br /&gt;
      })&lt;br /&gt;
      this.dialog.mode = 'edit'&lt;br /&gt;
      this.errorMessage = ''&lt;br /&gt;
      this.dialog.open = true&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    async submitDialog() {&lt;br /&gt;
      this.saving = true&lt;br /&gt;
      this.errorMessage = ''&lt;br /&gt;
      try {&lt;br /&gt;
        if (this.dialog.mode === 'create') {&lt;br /&gt;
          // POST create; return=minimal keeps model lightweight. 8&lt;br /&gt;
          await this.dialog.model.$post({ return: 'minimal' })&lt;br /&gt;
        } else {&lt;br /&gt;
          // PATCH update only changed columns when possible. 9&lt;br /&gt;
          await this.dialog.model.$patch()&lt;br /&gt;
        }&lt;br /&gt;
        this.closeDialog()&lt;br /&gt;
        this.refresh()&lt;br /&gt;
      } catch (e: any) {&lt;br /&gt;
        this.errorMessage = e?.message || 'Save failed'&lt;br /&gt;
      } finally {&lt;br /&gt;
        this.saving = false&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    closeDialog() {&lt;br /&gt;
      this.dialog.open = false&lt;br /&gt;
      this.dialog.model = null&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    async saveInline(item: any) {&lt;br /&gt;
      // Toggle &amp;quot;done&amp;quot; via inline checkbox → PATCH the row. 10&lt;br /&gt;
      try {&lt;br /&gt;
        await item.$patch({ columns: ['done'] })&lt;br /&gt;
      } catch (e) {&lt;br /&gt;
        // revert UI if it fails&lt;br /&gt;
        item.done = !item.done&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    confirmDelete(item: any) {&lt;br /&gt;
      this.confirm.item = item&lt;br /&gt;
      this.confirm.open = true&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    async doDelete() {&lt;br /&gt;
      if (!this.confirm.item) return&lt;br /&gt;
      this.saving = true&lt;br /&gt;
      try {&lt;br /&gt;
        await this.confirm.item.$delete()  // DELETE the row. 11&lt;br /&gt;
        this.confirm.open = false&lt;br /&gt;
        this.refresh()&lt;br /&gt;
      } catch (e) {&lt;br /&gt;
        // surface a toast/snackbar in a real app&lt;br /&gt;
      } finally {&lt;br /&gt;
        this.saving = false&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
  },&lt;br /&gt;
})&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
PostgREST side (example table)&lt;br /&gt;
&lt;br /&gt;
-- example schema&lt;br /&gt;
CREATE TABLE public.todos(&lt;br /&gt;
  id serial PRIMARY KEY,&lt;br /&gt;
  title text NOT NULL,&lt;br /&gt;
  done boolean NOT NULL DEFAULT false,&lt;br /&gt;
  created_at timestamptz NOT NULL DEFAULT now()&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
GRANT SELECT, INSERT, UPDATE, DELETE ON public.todos TO anon;  -- or your web role&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Why this works&lt;br /&gt;
&lt;br /&gt;
vue-postgrest exposes a pg mixin that fetches a route (table/view) and returns a GenericCollection of GenericModels in this.pg. You can mutate model fields with v-model and persist via model.$patch(); create via pg.$new(...).$post(); delete via model.$delete(). &lt;br /&gt;
&lt;br /&gt;
query.order / query.select and other keys map directly to PostgREST query syntax (ordering, filtering). &lt;br /&gt;
&lt;br /&gt;
count: 'exact' enables total counts via Content-Range, useful if you later add server-side pagination UI. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you want server-side pagination with v-data-table (using headers for sort → passing to pgConfig.query.order, and using limit/offset with pg.$range.totalCount), I can wire that up too.&lt;/div&gt;</summary>
		<author><name>Busk</name></author>
	</entry>
</feed>