This article aims to further customize you existing Issue Tracker application described in "Create an Issue Tracker App with Supabase in 15 Minutes".
This article is part of a series. If you haven't read the first part, you can find it here.
Windmill has a community website called Windmill Hub where - among other Scripts and Flows - you can find the full version of this App.
Where we left off
In the previous article, we created a basic Issue Tracker application with Supabase. We uploaded a few issues, displayed them in a table and created scripts to add new ones and delete them. There is only one part missing of the CRUD functionality - updating the issues.
Updating issues
For now, we are going to enable users to update only the status
and the
severity
properties of an issue but feel free to customize it your needs.
Let's start with adding titles for the update form:
-
Insert a
Text
component. -
Enter
Update Issue
as the input. -
Select
Subtitle
as the style. -
Align it vertically on the bottom.
-
Insert below a second
Text
component. -
Enter
${b?.selectedRow?.summary || '(Select a row in the table)'}
as the input.tipThe
b
variable is a reference to theTable
component. If you have a different ID for it, you need to change it accordingly. -
Enter
color: #6e6e6e;
in the Extra Style argument.
Next, we need to add a Select
component for the status
property:
-
Insert a
Text
component. -
Enter
Status
as the input. -
Select
Label
as the style. -
Align it vertically on the bottom.
-
Insert below a
Select
component. -
Enter these 3 items in the Configuration:
{ "label": "PENDING" }
{ "label": "WORKED ON" }
{ "label": "FINISHED" }
-
Set the Item Key argument to
label
.
Repeat the previous steps for the severity
property as well but with the
following items:
{ "label": "LOW" }
{ "label": "MEDIUM" }
{ "label": "HIGH" }
Finally, we need to add a Button
component to submit the form:
-
Insert a
Button
component. -
Enter
Update Issue
as the Label. -
Align it to the bottom-left corner.
-
Find the ID of the
Load Issues
background runnable and checkRecompute
on it in theRecompute others
section. -
Click
Create an inline script
, selectDeno
as language, name itUpdate Issue
and paste in the following code:import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
type Supabase = {
url: string;
key: string;
};
export async function main(auth: Supabase, issue: any, status?: string, severity?: string) {
if (!(issue && (status || severity))) {
return 'Make sure that an issue is selected in the table';
}
const client = createClient(auth.url, auth.key);
await client
.from('issues')
.update({
...issue,
status: status || issue.status,
severity: severity || issue.severity
})
.filter('id', 'eq', issue.id);
return '';
} -
Select your Supabase resource for the
auth
argument of the script in theSettings
pane on the right. -
Select the
selectedRow
property of theTable
component for theissue
argument. -
Select the
result
property of the correspondingSelect
component for thestatus
andseverity
argument.
More charts
Now that we have a fully functional issue tracker, let's add one more chart,
namely a line chart to display the number of issues in the past days. Let's
start with adding a Number
input to control how many days we want to display:
- Insert a
Number
component. - Enter
Days
as the Placeholder. - Enter
30
as the Default Value.
Next, create a title for the chart and use the value of the recently added number input:
-
Insert a
Text
component. -
Enter
Number of Issues Created in the Past ${ac.result || 30} Days
as the input.tipThe
ac
variable is a reference to the previously addedNumber
component. If you have a different ID for it, you need to change it accordingly. -
Select
Subtitle
as the style. -
Align it vertically on the bottom.
Lastly, add the actual chart component to display the data:
-
Insert a
Bar/Line Chart
component. -
Toggle the Line attribute.
-
Click
Create an inline script
, selectDeno
as language, name itLast Issues Chart Data
and paste in the following code:export async function main(issues: { created_at: string }[], days: number = 30) {
if (!issues?.length) {
return { data: [], labels: [] };
}
const dates = [...Array(days)]
.map((_, i) => {
const d = new Date();
d.setDate(d.getDate() - i);
return d.toISOString().split('T')[0];
})
.reverse();
const issueNumbers = dates.map((date) => {
return issues.filter(({ created_at }) => created_at.startsWith(date)).length;
});
return {
data: issueNumbers,
labels: dates
};
} -
Select the
result
property of theLoad Issues
background runnable for theissues
argument. -
Select the
result
property of the recently createdNumber
component for thedays
argument.
Responsive layout
Before finishing our app, the final step is to make the layout responsive. The
component layout can be configured in 2 views: desktop
and mobile
, which can
be toggled in the header row, next to the Editor-Preview mode switch. The
desktop
view is used by default and is shown when the window width is greater
than 690px and the mobile
view is shown when the width is less than or equal
to 690px. The views are saved separately, so moving the components around in one
of them will not affect the other. Let's switch to the mobile
view and place
the components to resemble the following layout.
You can self-host Windmill using a
docker compose up
, or go with the cloud app.