Skip to content

Commit 89a33b7

Browse files
committed
Refactor code structure and error handling across multiple files; improve shared components and API signal management
1 parent 56dc41a commit 89a33b7

File tree

10 files changed

+519
-321
lines changed

10 files changed

+519
-321
lines changed

.github/workflows/ga-build-image.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ name: '🐳 Build Docker Image'
55
on:
66
push:
77
branches: ['master']
8-
8+
99
jobs:
1010
build-image:
1111
name: 🏗️ Build Image

api/routes.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -515,11 +515,11 @@ const defs = {
515515
const dep = DeploymentsCollection.get(deployment)
516516

517517
if (!dep) {
518-
throw respond.NotFound({ message: 'Deployment not found' })
518+
throw new respond.NotFoundError({ message: 'Deployment not found' })
519519
}
520520

521521
if (!dep?.databaseEnabled) {
522-
throw respond.BadRequest({
522+
throw new respond.BadRequestError({
523523
message: 'Database not enabled for deployment',
524524
})
525525
}
@@ -528,25 +528,31 @@ const defs = {
528528
if (!project) throw respond.NotFound({ message: 'Project not found' })
529529
if (!project.isPublic && !ctx.user?.isAdmin) {
530530
if (!userInTeam(project.teamId, ctx.user?.userEmail)) {
531-
throw respond.Forbidden({
531+
throw new respond.ForbiddenError({
532532
message: 'Access to project queries denied',
533533
})
534534
}
535535
}
536536

537537
const { sqlEndpoint, sqlToken } = dep
538538
if (!sqlEndpoint || !sqlToken) {
539-
throw respond.BadRequest({
539+
throw new respond.BadRequestError({
540540
message: 'SQL endpoint or token not configured for deployment',
541541
})
542542
}
543543

544-
const startTime = performance.now()
545-
const data = await runSQL(sqlEndpoint, sqlToken, sql)
544+
try {
545+
const startTime = performance.now()
546+
const data = await runSQL(sqlEndpoint, sqlToken, sql)
546547

547-
return {
548-
duration: (performance.now() - startTime) / 1000, // in seconds
549-
rows: data,
548+
return {
549+
duration: (performance.now() - startTime) / 1000, // in seconds
550+
rows: data,
551+
}
552+
} catch (error) {
553+
return respond.BadRequest(
554+
{ message: (error as Error).message },
555+
)
550556
}
551557
},
552558
input: OBJ({

api/sql.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ export async function runSQL(
2020
},
2121
body: JSON.stringify({ query, params }),
2222
})
23-
if (!res.ok) throw Error(`sql endpoint error ${res.status}`)
24-
const data = await res.json()
25-
26-
return data
23+
if (!res.ok) throw Error(await res.text())
24+
return await res.json()
2725
}
2826

2927
// Dialect detection attempts (run first successful)
@@ -60,7 +58,9 @@ const INTROSPECTION: Record<string, string> = {
6058

6159
async function fetchSchema(endpoint: string, token: string, dialect: string) {
6260
const sql = INTROSPECTION[dialect] ?? INTROSPECTION.unknown
63-
return await runSQL(endpoint, token, sql)
61+
try {
62+
return await runSQL(endpoint, token, sql)
63+
} catch { /* ignore */ }
6464
}
6565

6666
export type ColumnInfo = { name: string; type: string; ordinal: number }

api/user.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ export async function decodeSession(sessionCode?: string) {
4747
try {
4848
const id = await decryptMessage(sessionCode)
4949
return UsersCollection.find(({ userEmail }) => userEmail === id)
50-
} catch (err) {
51-
console.log('unable to decode session', { sessionCode })
50+
} catch {
51+
// Invalid session code
52+
return undefined
5253
}
5354
}
5455

tasks/seed.ts

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { insertLogs } from '/api/clickhouse-client.ts'
22
import {
3-
type Project,
4-
type Team,
5-
type User,
63
DeploymentsCollection,
4+
type Project,
75
ProjectsCollection,
6+
type Team,
87
TeamsCollection,
8+
type User,
99
UsersCollection,
1010
} from '/api/schema.ts'
1111

@@ -28,14 +28,25 @@ const users: User[] = [
2828
userPicture: undefined,
2929
isAdmin: false,
3030
},
31+
{
32+
userEmail: '[email protected]',
33+
userFullName: 'Clement',
34+
userPicture: undefined,
35+
isAdmin: true,
36+
},
37+
{
38+
userEmail: '[email protected]',
39+
userFullName: 'Abdou Top',
40+
userPicture: undefined,
41+
isAdmin: true,
42+
},
3143
]
3244

3345
const teams: Team[] = [
3446
{
3547
teamId: 'frontend-devs',
3648
teamName: 'Frontend Devs',
37-
teamMembers: ['[email protected]',
38-
49+
3950
},
4051
{
4152
teamId: 'backend-devs',
@@ -107,7 +118,7 @@ async function seed() {
107118

108119
// Seed projects
109120
console.log('Seeding projects...')
110-
for (const [i, project] of projects.entries()) {
121+
for (const [_, project] of projects.entries()) {
111122
await ProjectsCollection.insert(project)
112123
const url = `${project.slug}.com`
113124
const deployement = await DeploymentsCollection.insert({
@@ -121,16 +132,19 @@ async function seed() {
121132
})
122133
const service_instance_id = crypto.randomUUID()
123134
const now = Date.now() / 1000
124-
insertLogs(deployement.url, [...Array(100).keys()].map(n => ({
125-
attributes: { a: 'str', bool: true, num: n },
126-
event_name: `test-log-${n}`,
127-
severity_number: Math.floor(Math.random() * 24),
128-
service_instance_id,
129-
span_id: (now - n) + Math.random(),
130-
trace_id: (now - n) + Math.random(),
131-
service_version: 'v2',
132-
timestamp: (now - n) * 1000,
133-
})))
135+
insertLogs(
136+
deployement.url,
137+
[...Array(100).keys()].map((n) => ({
138+
attributes: { a: 'str', bool: true, num: n },
139+
event_name: `test-log-${n}`,
140+
severity_number: Math.floor(Math.random() * 24),
141+
service_instance_id,
142+
span_id: (now - n) + Math.random(),
143+
trace_id: (now - n) + Math.random(),
144+
service_version: 'v2',
145+
timestamp: (now - n) * 1000,
146+
})),
147+
)
134148
}
135149
console.log('Projects seeded.')
136150

web/components/QueryHistory.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
import { ChevronRight, Clock, Play, Search, Trash2 } from 'lucide-preact'
22
import { A, navigate, url } from '../lib/router.tsx'
3-
import { onRun, queriesHistory } from '../pages/DeploymentPage.tsx'
4-
5-
export type QueryHistoryItem = {
6-
query: string
7-
timestamp: string
8-
columns?: number
9-
rows?: number
10-
}
3+
import { onRun, queriesHistory } from '../lib/shared.tsx'
114

125
const deleteQuery = (hash: string) => {
136
const updatedHistory = { ...queriesHistory.value }

web/lib/shared.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { HardDrive, ListTodo } from 'lucide-preact'
2+
import { api } from './api.ts'
3+
import { DeploymentPage } from '../pages/DeploymentPage.tsx'
4+
import { SidebarItem } from '../components/SideBar.tsx'
5+
import { url } from './router.tsx'
6+
import { Signal } from '@preact/signals'
7+
8+
// export
9+
export type QueryHistoryItem = {
10+
query: string
11+
timestamp: string
12+
columns?: number
13+
rows?: number
14+
}
15+
16+
// Sidebar items for project page
17+
export const sidebarItems: Record<string, SidebarItem> = {
18+
'deployment': {
19+
icon: HardDrive,
20+
label: 'Deployment',
21+
component: DeploymentPage,
22+
},
23+
'tasks': { icon: ListTodo, label: 'Tasks', component: DeploymentPage },
24+
} as const
25+
26+
// API signal for deployment queries
27+
export const querier = api['GET/api/deployment/query'].signal()
28+
29+
// API signal for project deployments
30+
export const deployments = api['GET/api/project/deployments'].signal()
31+
32+
// API signal for current project
33+
export const project = api['GET/api/project'].signal()
34+
35+
export const onRun = (query: string) => {
36+
if (querier.pending) return
37+
const { dep, tab } = url.params
38+
if (dep && tab === 'queries' && query) {
39+
querier.fetch({ deployment: dep, sql: query })
40+
}
41+
}
42+
43+
export const queriesHistory = new Signal<Record<string, QueryHistoryItem>>(
44+
JSON.parse(localStorage.getItem('saved_queries') || '{}'),
45+
)
46+
queriesHistory.subscribe((val) => {
47+
localStorage.setItem('saved_queries', JSON.stringify(val))
48+
})

0 commit comments

Comments
 (0)