Quill is a react library and management system that allows SaaS companies to build dashboards quickly with the flexibility of code, while allowing non-engineers to manage queries and chart types in parallel.
To gain insight on how Quill works, you will walk through building a lightweight version of Quill. For simplicity, no need to worry about multi-tenancy (separating data by organization), authentication, etc.
/dashboard/:name
/chart/:id
Dashboards
, Charts
, Transations
, Customer
, Products
.<Chart />
& <Dashboard />
Components<Dashboard />
should have a date filter, with three subcomponents.Last 90 days
, Last 30 days
, Current month
)Previous period
, Previous 90 days
, Previous 30 days
, Previous month
) with default value to be Previous period
.onClickDashboardItem: (dashboardItem: Chart) => void
callback function that fires when a chart in the dashboard is clickedsqlQuery: ”select * from transactions”
and dateField: { table: “transactions, field: “created_at” }
, it should apply a filter to the query so that the transactions
table created_at
field ranges only between the startDate
and endDate
of the date filter. I recommend using WITH statements or subqueries.LAST_90_DAYS
, new range filtered via the date filter in the UI is CURRENT_MONTH
, so we already have that data surfaced on the frontend and can filter it without fetching new data)** Endpoints**
/dashboard/:name
fetches a dashboard by name with the list of charts with that dashboardName
/chart/:id
fetches a chart by id
Database Schema
Dashboard
{
name: string,
id: string,
dateFilter: {
name: string,
initialDateRange: 'LAST_90_DAYS' | 'LAST_30_DAYS' | 'CURRENT_MONTH'
}
}
Chart
{
name: string,
id: string,
dashboardName: string,
chartType: 'line' | 'bar',
sqlQuery: string,
xAxisField: string,
yAxisField: string,
dateField: { table: string, field: string};
}
Datasource for queries
I recommend quickly spinning up a postgres database using supabase and using the table editor to upload a csv of fake data. You can also use their AI SQL editor to create fake data. For simplicity, you can also use this as your database for dashboards/charts, even though this isn’t how it works in prod (this is the analog of Quill’s customer’s db, while the db above is Quill’s db)
<Chart />
Use recharts as your charting library and date-fns for calculating date ranges and formatting dates.
Props
chartId: string
fetches chart by id from the servercontainerStyle: React.CSSProperties
wraps the chart in a container<Dashboard />
Renders a grid of Charts associated with the dashboard name.
Props
name: string
fetches dashboard by name from the servercontainerStyle: React.CSSProperties
wraps the dashboard in a containeronClickDashboardItem: (dashboardItem: Chart) => void
callback function that fires when a chart in the dashboard is clickedThe <Dashboard />
should have a date filter, with three subcomponents
Example of what a date filter might look like:
Note that the comparison data will be added to the chart in gray, with the value of the most recent bucket and its comparison displayed above the chart, and the percentage increase/decrease is noted in green/red. Display both metrics (most recent bucket of current range vs. most recent bucket of comparison range)
The min and max date of the x-axis of the graph will be determined by the Preset dropdown’s range, so if there are mismatched ranges (30 days vs 90 days), then you will cut off the comparison, only showing the first 30 days. In the inverse case, the comparison will be incomplete (it will only display for the first 30 days of the 90 day range).
There are three cases of date filtering:
sqlQuery: ”select * from transactions”
and dateField: { table: “transactions, field: “created_at” }
, it should apply a filter to the query so that the transactions
table created_at
field ranges only between the startDate
and endDate
of the date filter. I recommend using WITH statements or subqueries.LAST_90_DAYS
, new range filtered via the date filter in the UI is CURRENT_MONTH
, so we already have that data surfaced on the frontend and can filter it without fetching new data)Date bucketing
Bucketing by date should be the next largest unit of the date range. 90 days ⇒ bucket by month. Current Month ⇒ bucket by week. Note that date ranges can be custom (via the calendar), so the bucketing has to work with any date range, not just the presets.
Message shawn@quill.co with questions!