Skip to content

Commit 9f049c2

Browse files
committed
Make QueryEditor as a reusable react component
1 parent 4ed1f00 commit 9f049c2

File tree

16 files changed

+2478
-2397
lines changed

16 files changed

+2478
-2397
lines changed

README.md

Lines changed: 54 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -2,105 +2,53 @@
22

33
This Trino Query UI is a new UI component that can be integrated into Trino and run directly from the Trino installation at the `/query/` path. For testing, it can also be run separately and can proxy to a Trino running locally or elsewhere.
44

5+
> **Warning**
6+
> This package is under heavy development and is not yet recommended for production workloads. Treat the current release as an early-stage demo; production-ready builds and documentation will follow soon.
7+
58
![Trino Query UI Demo](demos.gif "Trino Query UI Demo")
69

710
Implementation details:
8-
* React Typescript project with Vite
9-
* Using Node.js v20+
10-
* Monaco editor + ANTLR parser using Trino language
11-
12-
## Building and Shipping in Trino
13-
14-
The Query UI builds just like the existing UI in Trino.
15-
1. First you build the TypeScript into Javascript and CSS
16-
2. Then copy the distributable path into Trino.
17-
3. Then modify Trino to respond to the query ui path.
11+
* React TypeScript project with Vite
12+
* Uses Node.js v20+
13+
* Monaco editor + ANTLR parser using the Trino language
1814

19-
### Building for Integration
15+
## Installation
2016

2117
```
22-
cd precise
23-
npm run build
18+
npm install trino-query-ui
2419
```
2520

26-
### Copying into Trino
27-
28-
mkdir -p $TRINO_HOME/core/trino-main/src/main/resources/query_ui_webapp/
29-
cp -r dist/* $TRINO_HOME/core/trino-main/src/main/resources/query_ui_webapp/
30-
31-
### Modifying Trino to Respond to /query/
32-
33-
Modify `$TRINO_HOME/core/trino-main/src/main/java/io/trino/server/ui/WebUiStaticResource.java`:
34-
35-
Add `/query/` path. Note any path can be used:
36-
37-
```java
38-
@GET
39-
@Path("/query")
40-
public Response getQuery(@BeanParam ExternalUriInfo externalUriInfo)
41-
{
42-
return Response.seeOther(externalUriInfo.absolutePath("/query/")).build();
43-
}
44-
45-
// asset files are always visible
46-
@ResourceSecurity(PUBLIC)
47-
@GET
48-
@Path("/query/assets/{path: .*}")
49-
public Response getQueryAssetsFile(@PathParam("path") String path)
50-
throws IOException
51-
{
52-
return getQueryFile("assets/" + path);
53-
}
54-
55-
@ResourceSecurity(PUBLIC)
56-
@GET
57-
@Path("/query/{path: .*}")
58-
public Response getQueryFile(@PathParam("path") String path)
59-
throws IOException
60-
{
61-
if (path.isEmpty()) {
62-
path = "index.html";
63-
}
64-
65-
String fullPath = "/query_ui_webapp/" + path;
66-
if (!isCanonical(fullPath)) {
67-
return Response.status(NOT_FOUND).build();
68-
}
69-
70-
URL resource = getClass().getResource(fullPath);
71-
if (resource == null) {
72-
return Response.status(NOT_FOUND).build();
73-
}
74-
75-
return Response.ok(resource.openStream()).build();
76-
}
77-
78-
private static boolean isCanonical(String fullPath)
79-
{
80-
try {
81-
return new URI(fullPath).normalize().getPath().equals(fullPath);
82-
}
83-
catch (URISyntaxException e) {
84-
return false;
85-
}
86-
}
21+
## Quick Start
22+
23+
```tsx
24+
import { QueryEditor } from 'trino-query-ui'
25+
import 'trino-query-ui/dist/index.css'
26+
27+
function App() {
28+
return <div>anyad<QueryEditor /></div>
29+
}
30+
31+
export default App
8732
```
8833

34+
8935
## Development
9036

91-
### Setup the Coding Environment
37+
### Build and Run
9238

93-
Tested on Ubuntu and Windows.
39+
1. Install Node.js (v20 or newer) from <https://nodejs.org/en/download/>
40+
2. Install the dependencies and run the dev server:
41+
```
42+
cd precise
43+
npm install
44+
npm run dev
45+
```
9446

95-
1. Install node.js <https://nodejs.org/en/download/> at least v20
96-
2. Create an NPM enviroment using Vite: `npm create vite@latest`, pick *React*, then *Typescript*
97-
3. In the precise folder, install monaco `npm install @monaco-editor/react`
98-
4. Install Typescript Runtime for ANTLR4 `npm install antlr4ng` and the cli `npm install --save-dev antlr4ng-cli`
99-
because <https://github.com/tunnelvisionlabs/antlr4ts> seems abandoned?
47+
The local URL will be displayed, and you can open it in your browser.
10048

101-
### Setup Proxying to Local Trino Instance
49+
### Set Up Proxying to a Local Trino Instance
10250

103-
To run outside of Trino, update the contents of the `vite.config.ts` with the following so that queries can be properly proxied over to Trino's query endpoint running on `http://localhost:8080` or any other proxy path required.
51+
Update `vite.config.ts` with the following so that queries can be properly proxied to Trino's query endpoint running on `http://localhost:8080` (or any other path you require).
10452

10553
```tsx
10654
import { defineConfig } from 'vite'
@@ -119,64 +67,53 @@ export default defineConfig({
11967
},
12068
},
12169
},
70+
...
12271
});
12372
```
12473

125-
### Build and Run
126-
127-
To run, start:
128-
129-
```shell
130-
cd precise
131-
npm install
132-
npm run dev
133-
```
134-
135-
The local URL will be be displayed which you can open in your browser.
136-
13774
### Building the Parser
13875

139-
To build parser: `npm run antlr4ng`, as configured in **package.json**
76+
Run `npm run antlr4ng` to build the parser, as configured in **package.json**.
14077

141-
### Linting and code formatting
78+
### Linting and Code Formatting
14279

14380
To check code quality and formatting:
14481

14582
```shell
14683
npm run check
14784
```
14885

149-
This command runs both eslint and prettier, as defined in **package.json**
86+
This command runs both ESLint and Prettier, as defined in **package.json**.
15087

15188
## Philosophy
15289

153-
This UI's purpose is to provide an environment where once the cluster is stood up, executing queries and exploring data sets can be done right away. The idended use cases are:
90+
This UI's purpose is to provide an environment where, once the cluster is up, you can immediately execute queries and explore data sets. The intended use cases are:
15491
* Initial proof-of-concept queries.
15592
* Exploration of data sets.
15693
* Performance analysis.
157-
* Adhoc query execution.
94+
* Ad hoc query execution.
15895
* Quickly enabling a data engineering team to start work before other integrations are in place.
15996
* Early demos.
16097

161-
The approach taken:
162-
1. Direct integration into Trino UI
163-
- No need for additional authentication hop (although it could be added in the future)
164-
- Auth as the user executing the query if using Oauth2
98+
The approach:
99+
1. Direct integration into the Trino UI
100+
- No need for an additional authentication hop (although it could be added in the future)
101+
- Authenticates as the user executing the query when using OAuth2
165102
- Trino does the heavy lifting
166-
2. Don't need to think, just write a query
167-
- Autocomplete must be aware of not just Trino language but tables and columns
168-
- Syntax highlighting, validation
169-
- Comprehensive catalog explorer
170-
3. No black box query execution
171-
- Show progress and details of execution: people ask "why is my query slow" but mostly this is because they are only shown a spinner for 10 minutes.
172-
- Link to Trino query UI to drill into query performance
173-
- Show stages and split counts like Trino console client
174-
4. Easy to navigate
103+
2. Remove friction so you can simply write a query
104+
- Autocomplete understands the Trino language, tables, and columns
105+
- Provides syntax highlighting and validation
106+
- Offers a comprehensive catalog explorer
107+
3. Avoid black-box query execution
108+
- Show progress and execution details. People ask "why is my query slow?" mostly because they only see a spinner for minutes.
109+
- Link to the Trino Query UI to drill into query performance
110+
- Show stages and split counts like the Trino console client
111+
4. Keep the experience easy to navigate
175112

176113
### Gaps and Future Direction
177114

178-
* The ability to save queries and use source control requires either back end capabilities in the Trino service or can utilize Trino to write queries as tables.
115+
* Saving queries and using source control require either backend capabilities in the Trino service or leveraging Trino to write queries as tables.
179116
* No autocomplete for the Trino function list.
180-
* Basic graphing capabilities - looking at a table is not enough even for inspecting data sets.
181-
* No LLM copilot integration yet, this is done badly in many query UIs and if done well could make query crafting very fast, and solve other issues like translation from other query languages.
182-
* Parameters and string replace: this is partly implemented in `SubstitutionEditor` and should support both SQL parameters and string replacement.
117+
* Basic graphing capabilities are still missing—looking at a table alone is not enough even for inspecting data sets.
118+
* No LLM copilot integration yet. Many query UIs implement this poorly, but, done well, it could make query crafting fast and help translate from other query languages.
119+
* Parameters and string replacement are only partly implemented in `SubstitutionEditor` and should support both SQL parameters and string replacement.

precise/.eslintignore

Lines changed: 0 additions & 1 deletion
This file was deleted.

precise/eslint.config.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import js from '@eslint/js'
2+
import globals from 'globals';
3+
import tsParser from '@typescript-eslint/parser'
4+
import tsPlugin from '@typescript-eslint/eslint-plugin'
5+
import reactHooksPlugin from 'eslint-plugin-react-hooks';
6+
import reactRefreshPlugin from 'eslint-plugin-react-refresh';
7+
8+
export default [
9+
js.configs.recommended,
10+
{
11+
files: ['**/*.ts', '**/*.tsx'],
12+
languageOptions: {
13+
parser: tsParser,
14+
ecmaVersion: 'latest',
15+
sourceType: 'module',
16+
globals: {
17+
...globals.browser,
18+
process: 'readonly',
19+
React: 'readonly',
20+
},
21+
},
22+
plugins: {
23+
'@typescript-eslint': tsPlugin,
24+
},
25+
rules: {
26+
...tsPlugin.configs.recommended.rules,
27+
'@typescript-eslint/no-unused-expressions': [
28+
'error',
29+
{
30+
allowShortCircuit: true,
31+
allowTernary: true,
32+
},
33+
],
34+
'@typescript-eslint/no-explicit-any': 'off',
35+
'@typescript-eslint/no-unused-vars': 'off',
36+
},
37+
},
38+
{
39+
files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'],
40+
plugins: {
41+
'react-hooks': reactHooksPlugin,
42+
},
43+
rules: {
44+
...reactHooksPlugin.configs.recommended.rules,
45+
},
46+
},
47+
{
48+
files: ['**/*.{js,jsx,ts,tsx}'], // Match all JS/TS files
49+
plugins: {
50+
'react-refresh': reactRefreshPlugin,
51+
},
52+
rules: {
53+
'react-refresh/only-export-components': [
54+
'warn',
55+
{ allowConstantExport: true },
56+
],
57+
// Fix and enable separately
58+
// 'eol-last': ['warn', 'always'],
59+
// 'no-multiple-empty-lines': ['warn', { max: 1, maxEOF: 0 }],
60+
},
61+
},
62+
{
63+
files: ['src/utils/ProgressBar.tsx'],
64+
rules: {
65+
'@typescript-eslint/no-empty-object-type': 'off',
66+
},
67+
},
68+
{
69+
files: ['src/generated/**/*.ts'],
70+
linterOptions: {
71+
reportUnusedDisableDirectives: false,
72+
},
73+
},
74+
{
75+
ignores: ['dist', 'src/generated/**', '.eslintrc.cjs'],
76+
},
77+
];

precise/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="UTF-8" />
55
<link rel="icon" type="image/png" href="/commander_bunbun.png" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<title>Trino Query Editor</title>
7+
<title>Trino Query Editor - Example app</title>
88
</head>
99
<body>
1010
<div id="root"></div>

0 commit comments

Comments
 (0)