# Chart The Chart view of a Quill Report ```tsx App.tsx import { QuillProvider, Chart } from "@quillsql/react"; const MyChart = () => ( ); ``` A simple component that displays the given data in one of many chart types. Make sure `QuillProvider` is a parent of the `Chart` component. ### Automatically fetch data by id If you know the id of the chart you would like to display, you can pass in the reportId to the Chart component and it will load and display the data for that chart. ```jsx import { QuillProvider, Chart } from "@quillsql/react"; function App() { return ( ); } ``` ### Pass data directly into the chart Alternatively, if you have the actual data you would like to display (eg. you fetched the data using our `useQuill` hook) you can also pass in a `QuillReport` directly to the Chart component and it will display that data without async fetching. ```jsx import { QuillProvider, Chart } from "@quillsql/react"; function App() { const report = useQuill("664283fb4db8ad000bfe54d7"); return ( ); } ``` ## Props The chart id. The most usage is through a detail page built to navigate from the dashboard - using the onClick callback to get the reportId, and navigating to a route (say, reports/:id) where the url param is passed in as the reportId. For a standalone table, you can find the reportId in the Quill Portal and pass it in directly. When config is passed, the chart will not refetch the given report and will instead simply render the report it was given. A `config` must be passed if `reportId` is not present. A report to render, if any. When a reportId is passed, the chart will first fetch the data necessary to render this chart, and then it will render the report that it receives from the server. See the API Reference for a `QuillReport` [here](/components/dashboard#quill-report). A `reportId` must be passed if `config` is not present. A list of color strings used to color the chart. For example, a pie chart would use the colors for each section and a bar chart would use the colors for each bar. Whether to show animations on render complete. Whether to hide the x axis. Whether to hide the y axis. Whether to hide the cartesian grid lines. Whether the date range filter should be hidden. Whether to hide the horizontal cartesian grid lines. Whether to hide the vertical cartesian grid lines. Whether to hide the all but the first of the X-Axis ticks. Whether the cartesian grid lines show as dashed or solid. The color of cartesian grid lines. Whether the comparison range shows as dashed for date comparison line charts (as opposed to the default solid line). An optional function that takes a report and theme and returns a map of keys used in that report to the colors they should use. The color values support RGB hexcodes and CSS color literals. ```js function mapColorsToFields(report, theme): ColorMapType { return { amount: { primary: 'red', comparison: 'gray', primaryGradientStart: 'red', primaryGradientStop: 'lightred', comparisonGradientStart: '#EFEFEF', comparisonGradientStop: '#EFEFEF00', }, total: { primary: 'red' }, }; } ``` ### ColorMapType ```ts export type ColorMapType = { [field: string]: { primary: string; comparison?: string; primaryGradientStart?: string; primaryGradientStop?: string; comparisonGradientStart?: string; comparisonGradientStop?: string; }; } ``` Styles the top-level container of the Chart. This can be useful for TailwindCSS-style classname strings. The CSS styles that wrap the chart. # Dashboard A list of Quill Reports grouped into Metrics, Charts, and Tables. ```tsx App.tsx import { QuillProvider, Dashboard } from "@quillsql/react"; function App() { return ( ); } ``` Dynamically displays a filterable grid of charts, metrics, and tables with live data from your database. Once implemented, Quill lets you perform zero-downtime, zero-code updates to your dashboard on an org-level as well as company-wide. Make sure `QuillProvider` is a parent of the `Dashboard` component. Don't have a dashboard name yet? Learn how to [create a dashboard](https://docs.quillsql.com/portal/chart) in the Quill portal to get started. ## Examples [![Edit \[Ant Design\] Quill React Components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/devbox/ant-design-quill-react-components-9qcs8k?embed=1) ```tsx import { Dashboard } from "@quillsql/react"; import { AntDateRangePickerComponent } from "./ui/ant/DateRangePickerComponent"; import { AntTableComponent } from "./ui/ant/TableComponent"; import { AntSelectComponent } from "./ui/ant/SelectComponent"; import { AntChartComponent } from "./ui/ant/ChartComponent"; import { AntMetricComponent } from "./ui/ant/MetricComponent"; export function AntDashboard() { return ( ); } ``` [![Edit \[Material Design\] Quill React Components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/devbox/material-design-quill-react-components-d862dk?embed=1) ```tsx import { Dashboard } from "@quillsql/react"; import { MaterialDateRangePickerComponent } from "./ui/material/DateRangePickerComponent"; import { MaterialTableComponent } from "./ui/material/TableComponent"; import { MaterialSelectComponent } from "./ui/material/SelectComponent"; import { MaterialChartComponent } from "./ui/material/ChartComponent"; import { MaterialMetricComponent } from "./ui/material/MetricComponent"; import { MaterialFilterContainerComponent } from "./ui/material/Layout"; export function MaterialDashboard() { return ( ); } ``` ## Props The name of the dashboard you created in the Quill Portal. A component that wraps a report for 'metric' chart types. The current report. See the API Reference for a `QuillReport` [here](/components/dashboard#quill-report). A callback that should be fired when the user clicks on this report. Whether this report is loading. An error message that resulted from the loading of this report, if any. A component that wraps a report for non-metric, non-table chart types. The current report. See the API Reference for a `QuillReport` [here](/components/dashboard#quill-report). A callback that should be fired when the user clicks on this report. Whether this report is loading. An error message that resulted from the loading of this report, if any. The child of a chart component is a chart graph by default. You can override this behavior by not passing children in your implemented version and instead rendering your own Chart. A component that wraps a report for 'table' chart types. The current report. See the API Reference for a `QuillReport` [here](/components/dashboard#quill-report). A callback that should be fired when the user clicks on this report. Whether this report is loading. An error message that resulted from the loading of this report, if any. A select component. ```jsx Example export function SelectComponent({ value, label, width, onChange, options }) { return ( ); } ``` The value of the select element. The width of the select element in pixels. The label above the select element. An event callback that is fired when the select value changes. An array of value, label pairs which represent the select options. A date range picker component. The date preset. The label above the date range picker. The current date range. A set of options to select presets from. A callback that is fired when the selected date range changes. An event callback that is fired when the preset value changes. A component that wraps each dashboard section. Each dashboard is grouped into three sections: metrics, charts, and tables (in that order). Some sections may be empty, in which case they are omitted. The name of the section. The children of the dashboard section. A component that wraps all dashboard sections. The children of the dashboard section. A component that wraps the row of dashboard filters. The children of the filter container. A fallback component displayed when an active dashboard has no reports. Callback function that fires when a report is clicked. A common use case is navigating to a new page based on the report's id. A dashboard is composed of a list of reports that could be metrics, charts, or tables. See the API Reference for a `QuillReport` [here](/components/dashboard#quill-report). A callback that is fired when the loading status of the dashboard changes. Whether to hide dashboard filters. Whether the date range filters on the dashboard are hidden. Whether to hide the xAxis for all charts on this dashboard. Whether to hide the yAxis for all charts on this dashboard. Whether to hide the cartesian grid for all charts on this dashboard. The line style for comparison ranges on all line charts on this dashboard. Applies the following classes to the ReportBuilder. This container is the parent of all the filtering buttons as well as any dashboard sections. This can be useful for TailwindCSS-style classname strings. The CSS styles that wrap the dashboard container. This container is the parent of all the filtering buttons as well as any dashboard sections. The styles for the chart container. ## QuillReport The report's unique id. The name of the report. The name of the dashboard this report belongs to. The rows of data returned from this report's query. The columns data returned from this report's query. The type of this chart. The table and field this chart uses for date filtering. The pivot used in this query, if any. The pivot title. The aggregation type for the values in this pivot. The row field. The type of the row field. The column field, if any. The type of the column field, if any. The value field, if any. The type of the value field, if any. The formatted primary range aggregation value, if any. The formatted comparison range aggregation value, if any. The percent change in the aggragations, if any. The label of the xAxis. The field to use for the report's xAxis. The format for the report's xAxis. A list of metadata bout the yAxes of this report. The relative ordering of this report in relation to its siblings. Ordering starts at 1 and counts up. Reports in the same section are first grouped by `chartType` and then each group is sorted by `order`. Currently, the first group is `metric` and the last group is `table` with the rest of the reports in between. The rows of data returned from this report's query over the comparison date range as opposed to the primary date range. A map of filters that have been applied to this query. # useFormat A simple way to format data from Quill ```tsx App.tsx import { format } from "@quillsql/react"; function formatExample() { format(123.45, "dollar_cents"); // "$123.45" format(123, "dollar_cents"); // "$123.00" } ``` The value of the thing being formatted. The Quill format type of how you want to format the value. # Quickstart Add Quill to your app in less than a minute ### 1. Install dependencies Install `@quillsql/react` using your favorite package manager: ```bash npm npm install @quillsql/react ``` ```bash yarn yarn add @quillsql/react ``` ```bash pnpm pnpm add @quillsql/react ``` ```bash bun bun add @quillsql/react ``` ### 2. Add QuillProvider You connect Quill to React with the `QuillProvider` component. Similar to React's `Context.Provider`, `QuillProvider` wraps your React app and places Quill Client on the context, enabling you to access it from anywhere in your component tree. In App.js, let's wrap our React app with an `QuillProvider`. We suggest putting the `QuillProvider` somewhere high in your app, above any component that might need to access Quill data. ```js App.js import { QuillProvider } from "@quillsql/react"; import MyApp from "./MyApp"; function App() { // Replace organizationId and publicKey with your values return ( ); } ``` ### 3. Add your first component After your QuillProvider is hooked up, you can add Quill Components to your app. Let's start with the dashboard we created in the [portal tutorial](/portal). You can find the dashboard **name** in the portal at [https://app.quill.co](https://app.quill.co). Underlying queries and charts can be updated via the Quill Portal, and the dashboard will render the newest version. ```js App.js import { QuillProvider, Dashboard } from "@quillsql/react"; function MyDashboardPage() { return ; } ``` # QuillProvider A context provider that wraps all quill components ```tsx App.tsx import { QuillProvider } from "@quillsql/react"; function App() { return ( {children} ); } ``` The quill provider allows all the quill components in your app to share information which lets your dashboards render fast and update dynamically. Similar to React's `Context.Provider`, `QuillProvider` wraps your React app and places Quill Client on the context, enabling you to access it from anywhere in your component tree. We suggest putting the QuillProvider somewhere high in your app, above any component that might need to access your quill data. ### With OrgId If you're using the Quill Cloud, you can pass in your public key and the current organizationId (if any) and the Quill Provider will automatically connect to the hosted Quill Cloud. ```jsx With OrgId {children} ``` ### With QueryEndpoint If you're self-hosting Quill, you can point the Quill Provider to the location of the server running the Quill SDK. You may also pass a map of query headers that will be forwarded to your server with every request Quill sends. This can be useful if the `/quill` endpoint is behind a preexisting auth middleware. ```jsx With QueryEndpoint {children} ``` ## Props The public Quill API key. This can be found in the Quill portal in the "Settings" tab. The environment this app is running in (eg. "production"). The organization id of the user. Required if not passing a queryEndpoint. If this value is not passed in on the frontend, it should be passed in on the backend if you are using a self-hosted server. The url of your self-hosted server running the quill server SDK, if any. Additional query headers passed along with all requests to the custom query endpoint, if any. Whether to include credentials with requests to the query endpoint. A custom theme used throughout your dashboard. The children of the provider. This is usually the rest of your app. # ReportBuilder A UI component for creating and editing Quill Reports ```tsx App.tsx import { QuillProvider, ReportBuilder } from "@quillsql/react"; function App() { return ( ); } ``` Allows non-technical users to build SQL queries using either UI or AI and then edit them on the fly. Once users have constructed a query they like, they can click a button and add that report to their dashboard or export it as a CSV. Make sure `QuillProvider` is a parent of the `ReportBuilder` component. ## Examples [![Edit \[Ant Design\] Quill React Components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/devbox/ant-design-quill-react-components-9qcs8k?embed=1) ```tsx Ant Design import { ReportBuilder } from "@quillsql/react"; import { AntButton, AntDeleteButton, AntSecondaryButton, } from "./ui/ant/Button"; import { AntCard } from "./ui/ant/Card"; import { AntCheckbox } from "./ui/ant/Checkbox"; import { AntSelectColumn, AntDraggableColumn, AntColumnSearchEmptyState, } from "./ui/ant/Column"; import { AntTextInput } from "./ui/ant/Input"; import { AntChartBuilderFormContainer, AntChartBuilderInputColumnContainer, AntChartBuilderInputRowContainer, AntContainer, AntErrorMessageComponent, AntLoadingComponent, AntPivotColumnContainer, AntPivotRowContainer, AntSidebar, } from "./ui/ant/Layout"; import { AntModal } from "./ui/ant/Modal"; import { AntPopover, AntFilterPopover, AntSortPopover, AntLimitPopover, } from "./ui/ant/Popover"; import { AntSelect } from "./ui/ant/Select"; import { AntTable } from "./ui/ant/Table"; import { AntTabs } from "./ui/ant/Tabs"; import { AntSidebarHeading, AntLabel, AntHeader, AntText, AntSubHeader, } from "./ui/ant/Typography"; export function AntReportBuilder() { return ( ); } ``` [![Edit \[Material Design\] Quill React Components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/devbox/material-design-quill-react-components-d862dk?embed=1) ```tsx Material Design import { ReportBuilder } from "@quillsql/react"; import { MaterialButton, MaterialDeleteButton, MaterialSecondaryButton, } from "./ui/material/Button"; import { MaterialCard } from "./ui/material/Card"; import { MaterialCheckbox } from "./ui/material/Checkbox"; import { MaterialSelectColumn, MaterialDraggableColumn, MaterialColumnSearchEmptyState, } from "./ui/material/Column"; import { MaterialTextInput } from "./ui/material/Input"; import { MaterialChartBuilderFormContainer, MaterialChartBuilderInputColumnContainer, MaterialChartBuilderInputRowContainer, MaterialContainer, MaterialErrorMessageComponent, MaterialPivotColumnContainer, MaterialPivotRowContainer, MaterialSidebar, } from "./ui/material/Layout"; import { MaterialModal } from "./ui/material/Modal"; import { MaterialPopover, MaterialFilterPopover, MaterialSortPopover, MaterialLimitPopover, } from "./ui/material/Popover"; import { MaterialSelect } from "./ui/material/Select"; import { MaterialTable } from "./ui/material/Table"; import { MaterialTabs } from "./ui/material/Tabs"; import { MaterialSidebarHeading, MaterialLabel, MaterialHeader, MaterialText, MaterialSubHeader, } from "./ui/material/Typography"; export function MaterialReportBuilder() { return ( ); } ``` ### Prefetch data from a particular table You can pass an `initialTableName` to have the report builder automatically load data from a particular table in your schema. ```tsx App.tsx import { QuillProvider, ReportBuilder } from "@quillsql/react"; function App() { return ( ); } ``` ### Edit an existing report You can pass a `reportId` to have the report builder load the metadata for a pre-existing report. This might be useful if you want to allow your end users to edit the reports they created. ```tsx App.tsx import { QuillProvider, ReportBuilder } from "@quillsql/react"; function App() { return ( ); } ``` ### Query all views in your Quill schema By default, the Quill Report Builder will query all tables in your schema and new reports will be created upon completion. ```tsx App.tsx import { QuillProvider, ReportBuilder } from "@quillsql/react"; function App() { return ( ); } ``` ## Props The default table name to show when first loading the ReportBuilder. See the [prefetch data example](/components/report-builder#prefetch-data-from-a-particular-table) to see an example of how this is used. The dashboard to add reports to once they have been created. Checkout our [UI examples](/components/examples) to see how this is used. The organization that will own the report created through this flow. When using ReportBuilder in your product, you can use this prop to allow your users to create reports for only their organization. A primary button component. ```jsx Example export function ButtonComponent({ onClick, label, disabled, icon }) { return ( ); } ``` A callback fired when the button is clicked. The text content of the button. Whether the button is disabled. An icon to put in front of the label. A secondary button component. ```jsx Example export function SecondaryButtonComponent({ onClick, label, disabled, icon }) { return ( ); } ``` A callback fired when the button is clicked. The text content of the button. Whether the button is disabled. An icon to put in front of the label. A small delete button used to click out of things. Usually an "X" icon. ```jsx Example import { deleteSVG } from "./ui/icons"; export function DeleteButtonComponent({ onClick }) { return ; } ``` A callback fired when the button is clicked. A input element for getting text from the user. ```jsx Example export function TextInputComponent({ id, width, value, label, placeholder, onChange }) { return ( ); } ``` The id of the input element. The width of the input element in pixels. The width of the input element in pixels. The label of the text input component. The placeholder for the input element. An event callback that is fired when the input value changes. A modal component. ```jsx Example import { Modal } from "./ui/modal"; export function ModalComponent({ isOpen, setIsOpen, title, children, width, height }) { return ( {children} ); } ``` Whether the modal is open. A callback to set whether the modal is open. The title of the modal, if any. The body of the modal. The width of the modal, in pixels. The height of the modal, in pixels. A modal component. ```jsx Example import { Modal } from "./ui/modal"; export function ChartBuilderModalComponent({ isOpen, setIsOpen, title, children, width, height }) { return ( {children} ); } ``` Whether the modal is open. A callback to set whether the modal is open. The title of the modal, if any. The body of the modal. The width of the modal, in pixels. The height of the modal, in pixels. A select component. ```jsx Example export function SelectComponent({ value, label, width, onChange, options }) { return ( ); } ``` The value of the select element. The label above the select element. The width of the select element, in pixels. An event callback that is fired when the select value changes. An array of value, label pairs which represent the select options. A table component. ```jsx Example import { Table } from "./ui/table"; import { LoadingSkeleton } from "./ui/loading"; export function TableComponent({ rows, columns, isLoading }) { if (isLoading) return return ; } ``` The rows of the table are an array of objects. The columns of the table are an array of label, field pairs. Whether the table is loading. A popover component. ```jsx Example import { Popover } from "./ui/popover"; export function PopoverComponent({ isOpen, setIsOpen, popoverTitle, popoverChildren }) { return ( {popoverChildren} ); } ``` Whether the popover is open. A callback to set whether the popover is open. The label of the popover trigger, if any. The title of the popover, if any. The body of the popover. A popover component for filters created in the report builder. ```jsx Example import { Popover } from "./ui/popover"; export function FilterPopoverComponent({ isOpen, setIsOpen, popoverTitle, popoverChildren }) { return ( {popoverChildren} ); } ``` Whether the popover is open. A callback to set whether the popover is open. The title of the popover, if any. The body of the popover. The text contents of the filter item. An event callback fired when the user clicks the delete button on the filter. A popover component for sort items created in the report builder. ```jsx Example import { Popover } from "./ui/popover"; export function SortPopoverComponent({ isOpen, setIsOpen, popoverTitle, popoverChildren }) { return ( {popoverChildren} ); } ``` Whether the popover is open. A callback to set whether the popover is open. The title of the popover, if any. The body of the popover. The text contents of the sort item. An event callback fired when the user clicks the delete button on the sort item. A popover component for limits created in the report builder. ```jsx Example import { Popover } from "./ui/popover"; export function LimitPopoverComponent({ isOpen, setIsOpen, popoverTitle, popoverChildren }) { return ( {popoverChildren} ); } ``` Whether the popover is open. A callback to set whether the popover is open. The title of the popover, if any. The body of the popover. The text contents of the limit. An event callback fired when the user clicks the delete button on the limit. A small navigation menu used to switch between two or more states. ```jsx Example import { Tabs, Tab } from "./ui/tabs"; export function TabsComponent({ value, onChange, options }) { return ( {options.map(({ value, label }) => {label})} ); } ``` The value of the currently selected tab. An event callback fired when the selected tab changes. An array of value, label pairs which represent the tabs to display. A checkbox component. ```jsx Example export function CheckboxComponent({ isChecked, label, onChange }) { return ( ); } ``` Whether the checkbox is checked. A label for the checkbox component. An event callback fired when the checkbox's value changes. A container for the left sidebar. ```jsx Example export function SidebarComponent({ children }) { const style = { display: "flex", flexDirection: "column", gap: 24, } return } ``` The children of the sidebar container. A container for the main content (everything right of the sidebar). ```jsx Example export function ContainerComponent({ children }) { const style = { display: "flex", flexDirection: "column", gap: 24, } return
{children}
} ``` The children of the main container.
A component to show while the query results are loading. A component to show selected columns. ```jsx Example export function SelectColumnComponent({ label, isSelected, setSelected, DragHandle }) { return (
{label}
); } ``` The label of the selected column. Whether this column has been selected. A callback that is fired when the user checks this columns' checkbox. The handle the user drags this column by.
A draggable component used to reorder columns. ```jsx Example import { DeleteSVG } from "./ui/icons"; export function DraggableColumnComponent({ label, onDelete, DragHandle }) { return (
{label}
); } ``` The label of the draggable column. A callback that is fired when this column is removed from the query. The handle the user drags this column by.
A heading element for the sidebar. ```jsx Example export function SidebarHeadingComponent({ label }) { return

{label}

; } ``` The text content of the sidebar heading.
A card component used as a dismissable container of pivot information. ```jsx Example import { Card } from "./ui/card"; export function CardComponent({ onClick, onDelete, children }) { const style = { position: 'absolute', top: 0, right: 0 }; return ( {onDelete && } {children} ); } ``` The children of the container. A callback that is fired when the card is clicked. A callback that is fired the card is deleted. A label component. ```jsx Example export function LabelComponent({ label }) { return

{label}

; } ``` The text content of the element.
A header component. ```jsx Example export function HeaderComponent({ label }) { return

{label}

; } ``` The text content of the element.
A simple text component. ```jsx Example export function TextComponent({ label }) { return

{label}

; } ``` The text content of the element.
A sub-header component describes a group of inputs. ```jsx Example export function SubHeaderComponent({ label }) { return

{label}

; } ``` The label of the sub-header component.
A container for each row of inputs for the ChartBuilder form. ```jsx Example export function ChartBuilderInputRowContainer({ children }) { const style = { display: "flex", flexDirection: "row", gap: 12, } return
{children}
} ``` The children of the container.
A container for vertically-stacked rows of inputs for the ChartBuilder form. ```jsx Example export function ChartBuilderInputColumnContainer({ children }) { const style = { display: "flex", flexDirection: "column", gap: 12, } return
{children}
} ``` The children of the container.
A container for each row of inputs for the pivot form. ```jsx Example export function PivotRowContainer({ children }) { const style = { display: "flex", flexDirection: "row", gap: 12, } return
{children}
} ``` The children of the container.
A container for vertically-stacked rows of inputs for the pivot form. ```jsx Example export function PivotColumnContainer({ children }) { const style = { display: "flex", flexDirection: "column", gap: 12, } return
{children}
} ``` The children of the container.
A container for vertically-stacked sections of the chart builder form. ```jsx Example export function ChartBuilderFormContainer({ children }) { const style = { display: "flex", flexDirection: "column", gap: 18, } return
{children}
} ``` The children of the container.
A component that displays error messages. ```jsx Example export function ErrorMessageComponent({ errorMessage }) { return
{errorMessage}
} ``` The error message.
A component to show when no columns match the user's query. Whether the ReportBuilder is in admin mode (default: `false`). Whether the ReportBuilder's AI features are enabled (default: `true`). Whether the PivotModal's AI features are enabled. Whether to show the table format options on the ChartBuilder form. Applies the following classes to the ReportBuilder. This can be useful for TailwindCSS-style classname strings. Custom styling properties for the ReportBuilder's top-level container. A report id that the Report Builder will query from and modify. See the [report id example](/components/report-builder#edit-an-existing-report) to see an example of how this is used. A callback function that will trigger when a new report is created. A callback function that will trigger when a existing report is edited. Whether to hide the copy SQL button. Whether the chart builder is in horizontal view mode. Horizontal view mode is where the chart and table are displayed on the left and the editing form is displayed on the right, rather than being stacked vertically. # SQLEditor A UI component for creating and editing Quill Reports with SQL ```tsx App.tsx import { QuillProvider, SQLEditor } from "@quillsql/react"; function App() { return ( ); } ``` Allows your users to build and write custom SQL queries and then add those queries into their dashboard as a metric, chart, or table. Make sure `QuillProvider` is a parent of the `SQLEditor` component. ## Examples [![Edit \[Ant Design\] Quill React Components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/devbox/ant-design-quill-react-components-9qcs8k?embed=1) ```tsx import { SQLEditor } from "@quillsql/react"; import { AntTable } from "./ui/ant/Table"; import { AntSelectComponent } from "./ui/ant/SelectComponent"; import { AntButton, AntSecondaryButton } from "./ui/ant/Button"; import { AntTextInput } from "./ui/ant/Input"; export function AntSQLEditor() { return ( ); } ``` [![Edit \[Material Design\] Quill React Components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/devbox/material-design-quill-react-components-d862dk?embed=1) ```tsx import { SQLEditor } from "@quillsql/react"; import { MaterialTable } from "./ui/material/Table"; import { MaterialSelect } from "./ui/material/Select"; import { MaterialButton, MaterialSecondaryButton } from "./ui/material/Button"; import { MaterialTextInput } from "./ui/material/Input"; export function MaterialSQLEditor() { return ( ); } ``` ## Props A primary button component. ```jsx Example export function ButtonComponent({ onClick, label, disabled, icon }) { return ( ); } ``` A callback fired when the button is clicked. The text content of the button. Whether the button is disabled. An icon to put in front of the label. A secondary button component. ```jsx Example export function SecondaryButtonComponent({ onClick, label, disabled, icon }) { return ( ); } ``` A callback fired when the button is clicked. The text content of the button. Whether the button is disabled. An icon to put in front of the label. A small delete button used to click out of things. Usually an "X" icon. ```jsx Example import { deleteSVG } from "./ui/icons"; export function DeleteButtonComponent({ onClick }) { return ; } ``` A callback fired when the button is clicked. A input element for getting text from the user. ```jsx Example export function TextInputComponent({ id, width, value, label, placeholder, onChange }) { return ( ); } ``` The id of the input element. The width of the input element in pixels. The width of the input element in pixels. A label for the text input. The placeholder for the input element. An event callback that is fired when the input value changes. A select element for letting the user select from a set of options. ```jsx Example export function SelectComponent({ value, label, width, onChange, options }) { return ( ); } ``` The value of the select. A label for the select. The select options. An event callback that is fired when the selected element changes. The width of the select element in pixels. A table component. ```jsx Example import { Table } from "./ui/table"; import { LoadingSkeleton } from "./ui/loading"; export function TableComponent({ rows, columns, isLoading }) { if (isLoading) return return
; } ``` The rows of the table are an array of objects. The columns of the table are an array of label, field pairs. Whether the table is loading. A component to show while the query results are loading. A card component used as a dismissable container of pivot information. ```jsx Example import { Card } from "./ui/card"; export function CardComponent({ onClick, onDelete, children }) { const style = { position: 'absolute', top: 0, right: 0 }; return ( {onDelete && } {children} ); } ``` The children of the container. A callback that is fired when the card is clicked. A callback that is fired the card is deleted. A modal component to use to open the add to dashboard dialog. ```jsx Example import { Modal } from "./ui/modal"; export function ModalComponent({ isOpen, setIsOpen, title, children, width, height }) { return ( {children} ); } ``` Whether the modal is open. A callback to set whether the modal is open. The title of the modal, if any. The body of the modal. The width of the modal, in pixels. The height of the modal, in pixels. A popover component. ```jsx Example import { Popover } from "./ui/popover"; export function PopoverComponent({ isOpen, setIsOpen, popoverTitle, popoverChildren }) { return ( {popoverChildren} ); } ``` Whether the modal is open. A callback to set whether the modal is open. The label for the trigger of this popover. The title of the popover. The children of this popover. A label component. ```jsx Example export function LabelComponent({ label }) { return

{label}

; } ``` The label of the label component.
A header component. ```jsx Example export function HeaderComponent({ label }) { return

{label}

; } ``` The label of the header component.
A sub-header component describes a group of inputs. ```jsx Example export function SubHeaderComponent({ label }) { return

{label}

; } ``` The label of the sub-header component.
A simple text component. ```jsx Example export function TextComponent({ label }) { return

{label}

; } ``` The label of the text component.
A container for each row of inputs for the ChartBuilder form. The children of the container. A container for vertically-stacked rows of inputs for the ChartBuilder form. The children of the container. A container for each row of inputs for the pivot form. The children of the container. A container for vertically-stacked rows of inputs for the pivot form. The children of the container. A container for vertically-stacked sections of the chart builder form. The children of the container. A component that displays error messages. ```jsx Example export function ErrorMessageComponent({ errorMessage }) { return
{errorMessage}
} ``` The error message.
A callback that is fired when the query changes. A callback that is fired when the data changes. A callback that is fired when the data fields change. A callback that is fired when the data columns change. A callback that is fired when a new report has been added to a dashboard. Whether the ReportBuilder is in admin mode (default: `true`). A callback that is fired when the data columns change. Whether the "new query" button is enabled. Whether to show table format options. Whether to show date field options. Whether to show access control options. An existing report to edit. The default query to use as a placeholder. The default dashboard to add reports to. The title of the ChartBuilder dialog. The label of the button to add the current query to a dashboard. The label of the button to open the ChartBuilder dialog. The name of the current organization. Styles the top-level container of the SQLEditor. This can be useful for TailwindCSS-style classname strings. Custom styling properties for the ReportBuilder's top-level container. # Table The Tabular view of a Quill Report ```tsx App.tsx import { QuillProvider, Table } from "@quillsql/react"; const MyTable = () => (
); ``` A simple component that displays the given data as a table. Make sure `QuillProvider` is a parent of the `Table` component. ## Examples [![Edit \[Ant Design\] Quill React Components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/devbox/ant-design-quill-react-components-9qcs8k?embed=1) ```tsx import { Table, useQuill } from "@quillsql/react"; import { AntTable } from "./ui/ant/Table"; export function AntDesignTable() { const report = useQuill("6644088e6e2470000cbdb109"); if (!report || !report.data) return null; return ; } ``` [![Edit \[Material Design\] Quill React Components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/devbox/material-design-quill-react-components-d862dk?embed=1) ```tsx import { Table, useQuill } from "@quillsql/react"; import { MaterialTable } from "./ui/ant/Table"; export function MaterialDesignTable() { const report = useQuill("6644088e6e2470000cbdb109"); if (!report || !report.data) return null; return (
); } ```
### Automatically fetch data by id If you know the id of the table you would like to display, you can pass in the reportId to the Table component and it will load and display the data for that table. ```jsx import { QuillProvider, Table } from "@quillsql/react"; function App() { return (
); } ``` ### Pass data directly into the table Alternatively, if you have the actual data you would like to display (eg. you fetched the data using our `useQuill` hook) you can also pass in that data directly to the Table component and it will display that data without doing any async fetching. ```jsx Using raw data import { QuillProvider, Table } from "@quillsql/react"; function App() { return (
); } ``` ```jsx Using useQuill import { QuillProvider, Table } from "@quillsql/react"; import { MY_TABLE_ID } from "./constants"; function App() { const report = useQuill(MY_TABLE_ID); return (
); } ``` ## Props The table's id. The most usage is through a detail page built to navigate from the dashboard - using the onClick callback to get the report id, and navigating to a route (say, reports/:id) where the url param is passed in as the reportId. For a standalone table, you can find the reportId in the Quill Portal and pass it in directly. When a `reportId` is passed, the table will first fetch the data necessary to render this table, and then it will render the rows and columns that it receives from the server. A `reportId` must be passed if `rows` and `columns` are not present. The rows of the table to show, if any. When `rows` and `columns` are passed, the table will not refetch the given report and will instead simply render the rows and columns it was given. Both `rows` and `columns` must be passed if `reportId` is not present. The columns of the table to show, if any. When `rows` and `columns` are passed, the table will not refetch the given report and will instead simply render the rows and columns it was given. Both `rows` and `columns` must be passed if `reportId` is not present. The placeholder filename to use when downloading this table as a csv file. Whether to hide the download csv button. Whether this table component is loading. A callback that is fired when the user clicks download csv. A loading component to show when the table is loading. Styles the top-level container of the Table. This can be useful for TailwindCSS-style classname strings. The CSS styles that wrap the table. # Custom Themes Customize your dashboard by passing a custom theme For pixel-perfect control over theming and styling, all Quill components accept custom components as props. See our [dashboard docs](/components/dashboard.mdx) for an example. ```tsx App.tsx import { QuillProvider } from "@quillsql/react"; // You can a custom theme to be applied to the default Quill // components, or you can pass your own components with // pixel-perfect styling. const MY_CUSTOM_THEME = { fontFamily: "Inter; Helvetica", backgroundColor: "#FFFFFF", primaryTextColor: "#364153", secondaryTextColor: "#6C727F", chartLabelFontFamily: "Inter; Helvetica", chartLabelColor: "#666666", chartTickColor: "#CCCCCC", chartColors: ["#4E80EE", "#E14F62", "#55B5A6", "#E9A23B"], borderColor: "#E5E7EB", primaryButtonColor: "#364153", secondaryButtonColor: "#384151", borderWidth: 1, labelFontWeight: 500, fontSize: 14, loadingStateBackgroundColor: "#F9F9FA", hoverBackgroundColor: "#F4F4F5", }; function App() { return ( {children} ); } ``` ## QuillTheme The font family you want Quill to use. This is usually the same font your app uses. ex: "Inter" The default font size you want Quill to use. This is usually the same as the fontSize of your app (eg. 16 for "16px"). The background color you want Quill to use. This is usually the same background color your app uses. ex: "#FFFFFF" The background color you want Quill to use while hovering. The color you want Quill to use for primary text. This is usually the same primary text color color your app uses. ex: "#000000" The text color you want Quill to use for secondary text. This is usually the same secondary font color your app uses. ex: "#888888" The font family you want Quill to use for chart labels. This is usually the same as your base font family. ex: "Inter" The text color you want Quill to use for chart labels. This is usually the same as or similar to the secondary color your app uses. ex: "#666666" The color you want Quill to use for chart ticks. This is usually the same as or similar to the secondary color your app uses. ex: "#CCCCCC" The chart colors you want Quill to use. This is usually the same as the primary and secondary colors your app uses. You can pass in as many colors as you want, and you can also override these by passing in an array for the colors prop in the Chart component. ex: \['#6269E9', '#E14F62'] The border color you want Quill to use. This is usually the same as or similar to the border color your app uses. ex: "#CCCCCC" The border width you want Quill to use. This is usually the same as or similar to the border width your app uses. ex: 1 (ie. "1px") The color of the primary buttons you want Quill to use. Typically, you can just pass in a custom button with the styling you want instead of using this. The color of the secondary buttons you want Quill to use. Typically, you can just pass in a custom button with the styling you want instead of using this. The font weight you want Quill to use for buttons. Typically, you can just pass in a custom button with the styling you want instead of using this. (eg. 600\) The font weight you want Quill to use for labels. Typically, you can just pass in a custom label component with the styling you want instead of using this. (eg. 400) The background color you want Quill to use while in a loading state. This is usually the same as the background color you app uses (eg. '#FFFFFF'). # useExport A simple way to export data from Quill ```tsx App.tsx import { QuillProvider, useQuill } from "@quillsql/react"; function CustomComponent() { // pass in any report created in the Quill Portal const { downloadCSV } = useExport(QUILL_ID); return ; } function App() { return ( ); } ``` Make sure `QuillProvider` is a parent of the component using the `useExport` hook. The id of the report you created in the Quill Portal. Don't have an id yet? Learn how to [create a chart](https://docs.quillsql.com/portal/chart) in the Quill portal to get started. # useQuill A pragmatic data API for your data ```tsx App.tsx import { QuillProvider, useQuill } from "@quillsql/react"; function CustomComponent() { // pass in any report created in the Quill Portal const report = useQuill(QUILL_ID); return
{JSON.stringify(report, null, 2)}
; } function App() { return ( ); } ``` ```json Sample Response { data: { name: "My Report", rows: [...], columns: [...], chartType: "table", fields: [...], xAxisField: "created_at", yAxisField: "amount", xAxisLabel: "Created" yAxisLabel: "Total Amount", queryString: "SELECT * FROM transactions;", }, loading: false, error: null } ``` Make sure `QuillProvider` is a parent of the component using the `useQuill` hook. ## Props The id of the report you created in the Quill Portal. Don't have an id yet? Learn how to [create a chart](https://docs.quillsql.com/portal/chart) in the Quill portal to get started. # Create a chart Build your first chart with Quill in less than a minute This guide assumes you have already created a dashboard. If you haven't done that yet, check out our guide on how to create your first dashboard [here](/portal/dashboard). There are two ways to create a chart with Quill, with SQL or without SQL. Create a chart with the power of SQL Create a chart from a user interface ## With SQL (SQLEditor) The SQL Editor is a powerful SQL-based code editor that you can use in your product to help your users create and edit their own reports. ### 1. Enter a query or ask AI Use the code editor to enter a SQL query. Alternatively, you can also use the text box to ask AI to write a SQL query for you using your available schemas. When you're finished with your query, click `Run Query` to execute that query against your database. ### 2. Edit your query Take a look at the response table to make sure the data was what you expected. If it isn't, you can either manually update the SQL query using the code editor or you can use the text box again to have the AI fix the query. If the query didn't work at all, you can also have the AI automatically fix the broken query by clicking `Fix with AI`: ### 3. Edit the chart Once you are satisfied with your query and the query results, click `Add to dashboard` in the bottom right to turn the query into a report. Here, you can edit the name of the chart, the dashboard this chart should belong to, the chart type, and much more. For a more detailed guide for each of each option, see [Editing a Chart](#editing-a-chart) below. ## No Code (ReportBuilder) The Report Builder is an easy-to-use, AI-enabled query creation tool that you can use in your product to allow nontechnical users to create and edit their own reports without knowing SQL. ### 1. Create a report or ask AI To create a report using the ReportBuilder, you can either ask AI to generate a report for you or use the interface on the left sidebar to select columns. ### 2. Edit the report Once you have a report that is populated with data, you can edit the report using AI or the left sidebar. To apply a filter, simply select the column you wish to filter against and then how you would like to filter (the options change based on the type of the column). To apply one- or two-dimensional groupings or aggregations you can add a pivot which will orient your data based on the columns and aggregation type you select. You can sort the data in the report by one or more columns using the sort feature and you can limit the number of rows returned in the report using the limit feature. ### 3. Edit the chart Once you are satisfied with your query and the query results, click `Add to dashboard` in the bottom right to turn the query into a report. Here, you can edit the name of the chart, the dashboard this chart should belong to, the chart type, and much more. For a more detailed guide for each of each option, see [Editing a Chart](#editing-a-chart) below. ## Editing a Chart Once you have created a query, you can edit the resulting chart before adding it to your dashboard. You can edit the name of the chart, the dashboard this chart should belong to, the chart type, and much more. When used in an embedded flow where the dashboard is known ahead of time, developers can pre-select this dashboard and the option will be hidden in this form. ### Pivots Editing queries with SQL gives you fine-grain control over your data, but you can also add a pivot to the result of the query to apply extra groupings or breakdowns to get exactly the information you want. ### Chart Axis You can update the axis information for each chart by selecting which columns to use for each axis, what labels to give those columns (defaults to the name of the column), and the formatting type that should be applied to values for that axis. ### Table Info In Quill, every chart is backed by a SQL query. The results of that query are represented as a table which can be useful for reporting or sharing with other teams. Similar to the chart axis you can change the columns, labels, and formatting applied to this table. ### Date Field For dashboards with date filters, you can select which date field to use for this query. This column will be used when filtering all charts on that dashboard by a common date filter automatically. ### Organization Access By default, this chart will only be visible for your current organization (in this case, "Acme") but you can make this chart visible to all organizations by toggling the organization access toggle. This option can also be disabled. ## Next Steps With chart and a dashboard, you're ready to start using Quill. If you'd like, you can also add a new view to give Quill access to even more data for making charts! Add a SQL view with Quill in less than a minute. # Create a dashboard Build your first dashboard with Quill in less than a minute This guide assumes you have already connected your database with Quill. If you haven't done that yet, check out our onboarding guide [here](/portal/quickstart). When you first get started with the Quill platform, you will see an environment without any dashboards. Click on the "create new dashboard" button to get started. ### 1. Create a dashboard Let's start by giving your new dashboard a name. The dashboard name should be unique, clear, and easy to remember. If you would like to automatically filter every chart in this dashboard by date, you can keep the date filter option selected. Additionally, if you would like to compare this date range against historical ranges (eg. compare "Last 90 days" against "Previous 90 days") you can select the `Date comparison` feature. Finally, if you would like to automatically filter every chart in this table by a string field on your schema (eg. filtering by user, merchant, etc.) you can add as many string filters as you would like. Remember, you can always create more than one dashboard. ### 2. Save your dashboard When you're done, go ahead and hit save. You should see your dashboard in the top-left of the screen. Since Quill automatically partitions by organization, you can select an organization in the top-right to filter any dashboard by (eg. "Acme") or you can select "All Organizations" to show all data. ### 3. Manage your dashboards If you ever want to create a new dashboard, click on the dashboard dropdown and select "New Dashboard". You can also edit the settings for any existing dashboard by selecting that dashboard and clicking "Manage" in the dropdown. That will open the Manage Dashboard modal which allows you to edit the title of the dashboard, add and remove filters, edit the order of charts, and delete the dashboard. ### Next Steps Now that you've created a dashboard, you're ready to create your first chart! Check out our guides on how to create your first chart below. Build your first dashboard with Quill in less than a minute. # Quickstart Get up and running with Quill in less than a minute ### 1. Create a read-only user To create a read-only user in PostgreSQL, do the following: ```SQL PostgreSQL -- Replace 'password' with a strong password. CREATE USER quill_read_only WITH PASSWORD 'password'; ``` ```SQL PostgreSQL -- Allows the user to connect to the database. GRANT CONNECT ON DATABASE your_database TO quill_read_only; ``` ```SQL PostgreSQL -- Allows the user to access the objects within the schema. GRANT USAGE ON SCHEMA your_schema TO quill_read_only; ``` ```SQL PostgreSQL -- Allows the user to read data from the tables. GRANT SELECT ON ALL TABLES IN SCHEMA your_schema TO quill_read_only; ``` The connection string for the read-only user we just created will be something like: `postgresql://quill_read_only:password@db.example.com:5432/your_database`. To create a read-only user in Big Query, do the following: In the Google Cloud Console, navigate to the IAM & Admin > Service Accounts page. Click `Create Service Account` and follow the prompts to create a new service account. Grant the `bigquery.dataViewer` role to the service account for a dataset. You can do this by navigating to the dataset’s Permissions page and adding the service account with the `bigquery.dataViewer` role. Create a new JSON key for the service account by clicking the `Actions` dropdown next to the service account on the IAM & Admin > Service Accounts page, and then selecting `Create Key`. Select `JSON` as the key type and click `Create`. This will prompt you to save it one your local machine. In the next step you’ll upload this JSON file into the Quill Portal. To create a read-only user in Snowflake, do the following: ```SQL Snowflake SQL -- Replace 'password' with a strong password. CREATE USER quill_read_only PASSWORD 'password'; ``` ```SQL Snowflake SQL -- Creates a role specifically for read-only access. CREATE ROLE quill_read_only_role; ``` ```SQL Snowflake SQL -- Allows the role to read data from the tables. GRANT SELECT ON ALL TABLES IN SCHEMA my_schema TO quill_read_only_role; ``` ```SQL Snowflake SQL -- Gives user the permissions of the role GRANT quill_read_only_role TO quill_read_only; ``` To create a read-only user in MySQL, do the following: ```SQL MySQL -- Replace 'password' with a strong password. CREATE USER 'quill_read_only'@'%' IDENTIFIED BY 'password'; ``` ```SQL MySQL -- Allows the user to read data from the tables. GRANT SELECT ON your_database.* TO 'quill_read_only'@'%'; ``` The connection string for the read-only user we just created will be something like: `mysql://quill_read_only:password@db.example.com:3306/your_database`. ### 2. Connect your database Go to [https://app.quill.co/onboard](https://app.quill.co/onboard) and enter the read-only database connection string that we created in the last step. If you're using our fully-managed Quill instance, make sure to add the Quill server to your database IP whitelist, if you have one. Requests from Quill will always come from `34.133.137.225`. For more information about data and access control, you can read our self-hosting guide [here](/selfhost/quickstart.mdx). ### 3. Connect your schema The Quill platform provides powerful filtering and reporting tools to help you get the insights you want, faster. Since Quill provides organization-based filtering out-of-the-box, simply let us know which table to use and Quill will automatically partition your data by organization. ### 4. Add SQL Views Create a cleaned schema that makes it easier to write queries and reports. The views you create here will be used to create charts and tables later on. Don't worry, you can always create and edit these views later. ### Next Steps Once you have connected your database, you're ready to create your first dashboard! Check out our guides on how to create your first dashboard below. Build your first dashboard with Quill in less than a minute. # Create a view Add a SQL view with Quill in less than a minute This guide assumes you have already connected your database with Quill. If you haven't done that yet, check out our onboarding guide [here](/portal/quickstart). When you first get started with the Quill platform, you only see the initial views you created in the onboarding flow. ### 1. Create a view To add a new SQL view, you can click `Add view +` to open a SQL Editor that shows the visible tables that Quill can see in your schema. SQL views can help you organize and group different data together to make it easier to build charts and tables on top of. ### 2. Edit the view and save Go ahead and write some SQL for a new view that you would like to create. Run the query by clicking `Run Query` and make sure the data looks correct. Give your new view a descriptive, clear name and then hit `Create view` to add the view to Quill. You can now query data from that view in charts and dashboards. ### 3. Manage your views If you ever want to edit or delete an existing view, click on the view in the SQL Views list to open the view manager. Be careful when editing and deleting views! Make sure the charts that reference that view are up to date so they don't get out of sync. ### Next Steps Now that you have a view, you're ready to start using Quill! You can come back at any time and add more dashboards, charts, and views. # Data Cache Load dashboards fast by saving frequently used queries ## 1. Install the Quill SDK If you haven't already, start by installing the Quill Server SDK on your machine: ```bash Node.js npm install @quillsql/node ``` ```bash Python pip3 install quillsql ``` ```bash Go go get https://github.com/quill-sql/quill-go ``` ## 2. Create a cache config To get started with the Quill data cache, you can either bring your own cache or use our built-in cache in Quill Cloud. If you bring your own cache, you'll need the connection info such as username, password, host, and port. A typical redis connection string with all of the parts might look something like this: `redis://quill_username:secret_password@example.com:12345` Using Quill Cloud is the easiest way to get started with Quill. Reach out to our team and ask about the Quill data cache to get started. Make sure to add the Quill server to your database IP whitelist, if you have one. Requests from Quill will always come from `34.133.137.225` ```mermaid flowchart LR subgraph yourdomain.com db[(Database)] end subgraph api.quill.co direction LR sdk(Quill SDK) sdk <--> redis(Cache) end web(User) <--> |GET api.quill.co/quill|sdk sdk <--> yourdomain.com ``` With Self-Hosted Quill, your data never leaves your servers. Our code runs on your machines either in your cloud or on-premise. We operate the connected cache in a cache-aside manner which gives great performance in read-heavy situations. ```mermaid flowchart LR subgraph yourdomain.com direction LR sdk(Quill SDK) sdk <--> redis(Cache) sdk <--> db[(Database)] end web(User) <--> |GET yourdomain.com/quill|sdk ``` ## 3. Pass cache to Quill SDK ```js Node import { Quill } from "@quillsql/node"; const quill = new Quill({ privateKey: process.env.QULL_PRIVATE_KEY, databaseConnectionString: process.env.POSTGRES_READ, databaseType: "postgresql", // Just pass a cache config to the Quill instance: cache: { username: process.env.REDIS_USERNAME, password: process.env.REDIS_PASSWORD, host: process.env.REDIS_HOST, port: process.env.REDIS_PORT, cacheType: "redis", // or 'rediss' if SSL encrypted }, }); ``` ```python Python from quillsql import Quill quill = Quill( private_key=os.environ.get("QUILL_PRIVATE_KEY"), database_connection_string=os.environ.get("POSTGRES_READ"), # Just pass a cache config to the Quill instance: cache={ "username": os.environ.get("REDIS_USERNAME"), "password": os.environ.get("REDIS_PASSWORD"), "host": os.environ.get("REDIS_HOST"), "port": os.environ.get("REDIS_PORT"), "cacheType": "redis", # or 'rediss' if SSL encrypted } ) ``` Then you're done! When Quill detects a valid cache configuration it will start using the cache provided to speed up frequently used queries. # Quickstart Get up and running with Quill on your own server in 10 minutes ## 1. Install the Quill SDK ```bash Node.js npm install @quillsql/node ``` ```bash Python pip3 install quillsql ``` ```bash Go go get https://github.com/quill-sql/quill-go ``` ```bash PHP composer require quill.co/quill-php ``` ## 2. Create a new endpoint Instantiate `Quill` with your credentials and add the below `POST` endpoint. This example assumes you have an organization id on the user returned by your auth middleware. Queries will not work properly without the organization id. ```js Node import { Quill } from "@quillsql/node"; const quill = new Quill({ privateKey: process.env.QULL_PRIVATE_KEY, databaseConnectionString: process.env.POSTGRES_READ, databaseType: "postgresql", }); // "authenticateJWT" is your own pre-existing auth middleware app.post("/quill", authenticateJWT, async (req, res) => { // assuming user fetched via auth middleware has an userId const { userId } = req.user; const { metadata } = req.body; const result = await quill.query({ tenants: [{ tenantField: "user_id", tenantIds: [userId] }] metadata, }); res.send(result); }); ``` ```python Python from quillsql import Quill quill = Quill( private_key=os.environ.get("QUILL_PRIVATE_KEY"), database_connection_string=os.environ.get("POSTGRES_READ") ) # POST endpoint you create for Quill @app.route('/quill', methods=['POST']) # "token_required" is your own pre-existing auth middleware @token_required def quill_endpoint(): data = request.json # assuming current user comes from existing auth # org_id is the id on the organizations table that you # use with Quill (ex: organizations, businesses, companies, stores etc) return quill.query(current_user.org_id, data) ``` ```go Go import (     "github.com/quill-sql/quill-go" ) client := quill.NewClient(quill.ClientParams{ PrivateKey: os.Getenv("QUILL_PRIVATE_KEY"), DatabaseConnectionString: os.Getenv("POSTGRES_READ") }) // Add an endpoint http.HandleFunc("/quill", func(w http.ResponseWriter, r *http.Request) {     // fetch organizationID from your existing auth middleware    organizationID, _ := r.Context().Value(OrganizationIDContextKey).(string)     // Convert json body.metadata to RequestMetadata     body := &quill.RequestBody{}     err := json.NewDecoder(r.Body).Decode(body)     if err != nil {         http.Error(w, err.Error(), http.StatusBadRequest)         return     }     result, err := client.Query(organizationID, body.Metadata)     if err != nil {        http.Error(w, err.Error(), http.StatusBadRequest)        return     }     w.Header().Set("Content-Type", "application/json")     json.NewEncoder(w).Encode(result) }) ``` ```php PHP $data['metadata'], 'orgId' => $orgId ]; $response = $quill->query($params); header('Content-Type: application/json'); $body = json_encode($response, JSON_PRETTY_PRINT); echo $body; exit; } ``` ## 3. Connect the frontend You connect Quill to React with the `QuillProvider` component. Similar to React's `Context.Provider`, `QuillProvider` wraps your React app and places Quill Client on the context, enabling you to access it from anywhere in your component tree. In App.js, let's wrap our React app with an `QuillProvider`. We suggest putting the `QuillProvider` somewhere high in your app, above any component that might need to access Quill data. ```js App.js import { QuillProvider } from "@quillsql/react"; import Routes from "./Routes"; import UserContext from "./UserContext"; function App() { // Use your existing auth and user context const [user] = useContext(UserContext); return ( ); } ``` See the `QuillProvider` [API docs](/components/quill-provider) for more information.