Skip to content

Commit 884eb11

Browse files
committed
feat(template): generate template dynamically for specific enabled plugins
1 parent 884ae23 commit 884eb11

16 files changed

Lines changed: 577 additions & 182 deletions

File tree

template/.env.example.tmpl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
DATABRICKS_HOST=https://...
2-
{{- if .dotenv_example}}
3-
{{.dotenv_example}}
2+
{{- if .dotEnv.example}}
3+
{{.dotEnv.example}}
4+
{{- end}}
5+
{{- if .plugins.lakebase}}
6+
PGHOST=your-lakebase-host.databricks.com
7+
PGDATABASE=databricks_postgres
8+
# Run: databricks postgres list-endpoints projects/{project-id}/branches/{branch-id}
9+
LAKEBASE_ENDPOINT=projects/<project-id>/branches/<branch-id>/endpoints/<endpoint-id>
10+
# PGUSER=your_user # optional, defaults to DATABRICKS_CLIENT_ID
11+
PGSSLMODE=require
412
{{- end}}
513
DATABRICKS_APP_PORT=8000
6-
DATABRICKS_APP_NAME={{.project_name}}
14+
DATABRICKS_APP_NAME={{.projectName}}
715
FLASK_RUN_HOST=0.0.0.0

template/.env.tmpl

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1-
{{if ne .profile ""}}DATABRICKS_CONFIG_PROFILE={{.profile}}{{else}}DATABRICKS_HOST={{.workspace_host}}{{end}}
2-
{{- if .dotenv}}
3-
{{.dotenv}}
1+
{{- if ne .profile ""}}
2+
DATABRICKS_CONFIG_PROFILE={{.profile}}
3+
{{- else}}
4+
DATABRICKS_HOST={{.workspaceHost}}
5+
{{- end}}
6+
{{- if .dotEnv.content}}
7+
{{.dotEnv.content}}
8+
{{- end}}
9+
{{- if .plugins.lakebase}}
10+
PGHOST='' # Copy from the Lakebase Postgres UI
11+
PGDATABASE='databricks_postgres' # Copy from the Lakebase Postgres UI
12+
LAKEBASE_ENDPOINT='' # Run: databricks postgres list-endpoints projects/{project-id}/branches/{branch-id}
13+
# PGUSER='' # optional, defaults to DATABRICKS_CLIENT_ID
14+
PGSSLMODE=require
415
{{- end}}
516
DATABRICKS_APP_PORT=8000
6-
DATABRICKS_APP_NAME={{.project_name}}
17+
DATABRICKS_APP_NAME={{.projectName}}
718
FLASK_RUN_HOST=0.0.0.0

template/app.yaml.tmpl

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
command: ['npm', 'run', 'start']
2-
{{- if .app_env}}
32
env:
4-
{{.app_env}}
3+
{{- if .plugins.analytics}}
4+
- name: DATABRICKS_WAREHOUSE_ID
5+
valueFrom: sql-warehouse
56
{{- end}}
7+
{{- if .plugins.lakebase}}
8+
- name: PGHOST
9+
value: "" # Copy from the Lakebase Postgres UI
10+
- name: PGDATABASE
11+
value: "databricks_postgres" # Copy from the Lakebase Postgres UI
12+
- name: LAKEBASE_ENDPOINT
13+
value: "" # Run: databricks postgres list-endpoints projects/{project-id}/branches/{branch-id}
14+
- name: PGSSLMODE
15+
value: "require"
16+
# - name: PGUSER
17+
# value: "" # optional, defaults to DATABRICKS_CLIENT_ID
18+
{{- end}}

template/appkit.plugins.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@
2626
"optional": []
2727
}
2828
},
29+
"lakebase": {
30+
"name": "lakebase",
31+
"displayName": "Lakebase",
32+
"description": "SQL query execution against Databricks Lakebase Autoscaling",
33+
"package": "@databricks/appkit",
34+
"onSetupMessage": "Configure environment variables before running or deploying the app.\nSee: https://databricks.github.io/appkit/docs/plugins#lakebase-plugin",
35+
"resources": {
36+
"required": [],
37+
"optional": []
38+
}
39+
},
2940
"server": {
3041
"name": "server",
3142
"displayName": "Server Plugin",

template/client/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
1010
<link rel="manifest" href="/site.webmanifest" />
1111
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
12-
<title>{{.project_name}}</title>
12+
<title>{{.projectName}}</title>
1313
</head>
1414
<body>
1515
<div id="root"></div>

template/client/public/site.webmanifest

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "{{.project_name}}",
3-
"short_name": "{{.project_name}}",
2+
"name": "{{.projectName}}",
3+
"short_name": "{{.projectName}}",
44
"icons": [
55
{
66
"src": "/favicon-192x192.png",

template/client/src/App.tsx

Lines changed: 96 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,167 +1,114 @@
1-
/**
2-
* ⚠️ BEFORE MODIFYING THIS FILE:
3-
*
4-
* 1. Create SQL files in config/queries/
5-
* 2. Run `npm run typegen` to generate query types
6-
* 3. Check appKitTypes.d.ts for available types
7-
*
8-
* Common Mistakes:
9-
* - DataTable does NOT accept `data` or `columns` props
10-
* - Charts use `xKey` and `yKey`, NOT `seriesKey`/`nameKey`/`valueKey`
11-
* - useAnalyticsQuery has no `enabled` option - use conditional rendering
12-
*/
1+
import { createBrowserRouter, RouterProvider, NavLink, Outlet } from 'react-router';
132
import {
14-
useAnalyticsQuery,
15-
AreaChart,
16-
LineChart,
17-
RadarChart,
183
Card,
194
CardContent,
205
CardHeader,
216
CardTitle,
22-
Skeleton,
23-
Label,
24-
Select,
25-
SelectContent,
26-
SelectItem,
27-
SelectTrigger,
28-
SelectValue,
297
} from '@databricks/appkit-ui/react';
30-
import { sql } from "@databricks/appkit-ui/js";
31-
import { useState, useEffect } from 'react';
8+
{{- if .plugins.analytics}}
9+
import { AnalyticsPage } from './pages/analytics/AnalyticsPage';
10+
{{- end}}
11+
{{- if .plugins.lakebase}}
12+
import { LakebasePage } from './pages/lakebase/LakebasePage';
13+
{{- end}}
3214

33-
function App() {
34-
const { data, loading, error } = useAnalyticsQuery('hello_world', {
35-
message: sql.string('hello world'),
36-
});
15+
const navLinkClass = ({ isActive }: { isActive: boolean }) =>
16+
`px-3 py-1.5 rounded-md text-sm font-medium transition-colors ${
17+
isActive
18+
? 'bg-primary text-primary-foreground'
19+
: 'text-muted-foreground hover:bg-muted hover:text-foreground'
20+
}`;
3721

38-
const [health, setHealth] = useState<{
39-
status: string;
40-
timestamp: string;
41-
} | null>(null);
42-
const [healthError, setHealthError] = useState<string | null>(null);
22+
function Layout() {
23+
return (
24+
<div className="min-h-screen bg-background flex flex-col">
25+
<header className="border-b px-6 py-3 flex items-center gap-4">
26+
<h1 className="text-lg font-semibold text-foreground">{{.projectName}}</h1>
27+
<nav className="flex gap-1">
28+
<NavLink to="/" end className={navLinkClass}>
29+
Home
30+
</NavLink>
31+
{{- if .plugins.analytics}}
32+
<NavLink to="/analytics" className={navLinkClass}>
33+
Analytics
34+
</NavLink>
35+
{{- end}}
36+
{{- if .plugins.lakebase}}
37+
<NavLink to="/lakebase" className={navLinkClass}>
38+
Lakebase
39+
</NavLink>
40+
{{- end}}
41+
</nav>
42+
</header>
4343

44-
useEffect(() => {
45-
fetch('/health')
46-
.then((response) => response.json())
47-
.then((data: { status: string }) => setHealth({ ...data, timestamp: new Date().toISOString() }))
48-
.catch((error: { message: string }) => setHealthError(error.message));
49-
}, []);
44+
<main className="flex-1 p-6">
45+
<Outlet />
46+
</main>
47+
</div>
48+
);
49+
}
5050

51-
const [maxMonthNum, setMaxMonthNum] = useState<number>(12);
51+
const router = createBrowserRouter([
52+
{
53+
element: <Layout />,
54+
children: [
55+
{ path: '/', element: <HomePage /> },
56+
{{- if .plugins.analytics}}
57+
{ path: '/analytics', element: <AnalyticsPage /> },
58+
{{- end}}
59+
{{- if .plugins.lakebase}}
60+
{ path: '/lakebase', element: <LakebasePage /> },
61+
{{- end}}
62+
],
63+
},
64+
]);
5265

53-
const salesParameters = { max_month_num: sql.number(maxMonthNum) };
66+
export default function App() {
67+
return <RouterProvider router={router} />;
68+
}
5469

70+
function HomePage() {
5571
return (
56-
<div className="min-h-screen bg-background flex flex-col items-center justify-center p-4 w-full">
57-
<div className="mb-8 text-center">
58-
<h1 className="text-4xl font-bold mb-2 text-foreground">Minimal Databricks App</h1>
59-
<p className="text-lg text-muted-foreground max-w-md">A minimal Databricks App powered by Databricks AppKit</p>
72+
<div className="max-w-2xl mx-auto space-y-6 mt-8">
73+
<div className="text-center">
74+
<h2 className="text-3xl font-bold mb-2 text-foreground">
75+
Welcome to your Databricks App
76+
</h2>
77+
<p className="text-lg text-muted-foreground">
78+
Powered by Databricks AppKit
79+
</p>
6080
</div>
6181

62-
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 w-full max-w-7xl">
63-
<Card className="shadow-lg">
64-
<CardHeader>
65-
<CardTitle>SQL Query Result</CardTitle>
66-
</CardHeader>
67-
<CardContent>
68-
{loading && (
69-
<div className="space-y-2">
70-
<Skeleton className="h-4 w-3/4" />
71-
<Skeleton className="h-8 w-1/2" />
72-
</div>
73-
)}
74-
{error && <div className="text-destructive bg-destructive/10 p-3 rounded-md">Error: {error}</div>}
75-
{data && data.length > 0 && (
76-
<div className="space-y-2">
77-
<div className="text-sm text-muted-foreground">Query: SELECT :message AS value</div>
78-
<div className="text-2xl font-bold text-primary">{data[0].value}</div>
79-
</div>
80-
)}
81-
{data && data.length === 0 && <div className="text-muted-foreground">No results</div>}
82-
</CardContent>
83-
</Card>
84-
85-
<Card className="shadow-lg md:col-span-2">
86-
<CardHeader>
87-
<CardTitle>Health Check</CardTitle>
88-
</CardHeader>
89-
<CardContent>
90-
{!health && !healthError && (
91-
<div className="space-y-2">
92-
<Skeleton className="h-6 w-24" />
93-
<Skeleton className="h-4 w-48" />
94-
</div>
95-
)}
96-
{healthError && (
97-
<div className="text-destructive bg-destructive/10 p-3 rounded-md">Error: {healthError}</div>
98-
)}
99-
{health && (
100-
<div className="space-y-2">
101-
<div className="flex items-center gap-2">
102-
<div className="w-2 h-2 rounded-full bg-success animate-pulse"></div>
103-
<div className="text-lg font-semibold text-success">{health.status.toUpperCase()}</div>
104-
</div>
105-
<div className="text-sm text-muted-foreground">
106-
Last checked: {new Date(health.timestamp).toLocaleString()}
107-
</div>
108-
</div>
109-
)}
110-
</CardContent>
111-
</Card>
112-
113-
<Card className="shadow-lg md:col-span-3">
114-
<CardHeader>
115-
<CardTitle>Sales Data Filter</CardTitle>
116-
</CardHeader>
117-
<CardContent>
118-
<div className="max-w-md">
119-
<div className="space-y-2">
120-
<Label htmlFor="max-month">Show data up to month</Label>
121-
<Select value={maxMonthNum.toString()} onValueChange={(value) => setMaxMonthNum(parseInt(value))}>
122-
<SelectTrigger id="max-month">
123-
<SelectValue placeholder="All months" />
124-
</SelectTrigger>
125-
<SelectContent>
126-
{Array.from({ length: 12 }, (_, i) => (
127-
<SelectItem key={`month-${i + 1}`} value={(i + 1).toString()}>
128-
{i + 1 === 12 ? 'All months (12)' : `Month ${i + 1}`}
129-
</SelectItem>
130-
))}
131-
</SelectContent>
132-
</Select>
133-
</div>
134-
</div>
135-
</CardContent>
136-
</Card>
137-
138-
<Card className="shadow-lg flex min-w-0">
139-
<CardHeader>
140-
<CardTitle>Sales Trend Area Chart</CardTitle>
141-
</CardHeader>
142-
<CardContent>
143-
<AreaChart queryKey="mocked_sales" parameters={salesParameters} />
144-
</CardContent>
145-
</Card>
146-
<Card className="shadow-lg flex min-w-0">
147-
<CardHeader>
148-
<CardTitle>Sales Trend Custom Line Chart</CardTitle>
149-
</CardHeader>
150-
<CardContent>
151-
<LineChart queryKey="mocked_sales" parameters={salesParameters} />
152-
</CardContent>
153-
</Card>
154-
<Card className="shadow-lg flex min-w-0">
155-
<CardHeader>
156-
<CardTitle>Sales Trend Radar Chart</CardTitle>
157-
</CardHeader>
158-
<CardContent>
159-
<RadarChart queryKey="mocked_sales" parameters={salesParameters} />
160-
</CardContent>
161-
</Card>
162-
</div>
82+
<Card className="shadow-lg">
83+
<CardHeader>
84+
<CardTitle>Getting Started</CardTitle>
85+
</CardHeader>
86+
<CardContent className="space-y-3">
87+
<p className="text-sm text-muted-foreground">Your app is ready. Explore the resources below to continue building.</p>
88+
<ul className="space-y-2 text-sm">
89+
<li>
90+
<a
91+
href="https://github.com/databricks/appkit"
92+
target="_blank"
93+
rel="noopener noreferrer"
94+
className="text-primary underline underline-offset-4 hover:text-primary/80"
95+
>
96+
AppKit on GitHub →
97+
</a>
98+
</li>
99+
<li>
100+
<a
101+
href="https://databricks.github.io/appkit/"
102+
target="_blank"
103+
rel="noopener noreferrer"
104+
className="text-primary underline underline-offset-4 hover:text-primary/80"
105+
>
106+
AppKit documentation →
107+
</a>
108+
</li>
109+
</ul>
110+
</CardContent>
111+
</Card>
163112
</div>
164113
);
165114
}
166-
167-
export default App;

0 commit comments

Comments
 (0)