@databricks/appkit-ui 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +9 -1
- package/dist/cli/commands/plugin/create/scaffold.js +2 -8
- package/dist/cli/commands/plugin/create/scaffold.js.map +1 -1
- package/dist/react/charts/base.js +3 -2
- package/dist/react/charts/base.js.map +1 -1
- package/dist/react/charts/normalize.d.ts.map +1 -1
- package/dist/react/charts/normalize.js +3 -1
- package/dist/react/charts/normalize.js.map +1 -1
- package/dist/react/charts/options.d.ts +1 -0
- package/dist/react/charts/options.d.ts.map +1 -1
- package/dist/react/charts/options.js +13 -8
- package/dist/react/charts/options.js.map +1 -1
- package/dist/react/charts/utils.d.ts.map +1 -1
- package/dist/react/charts/utils.js +23 -1
- package/dist/react/charts/utils.js.map +1 -1
- package/dist/react/file-browser/directory-list.d.ts +54 -0
- package/dist/react/file-browser/directory-list.d.ts.map +1 -0
- package/dist/react/file-browser/directory-list.js +74 -0
- package/dist/react/file-browser/directory-list.js.map +1 -0
- package/dist/react/file-browser/file-breadcrumb.d.ts +25 -0
- package/dist/react/file-browser/file-breadcrumb.d.ts.map +1 -0
- package/dist/react/file-browser/file-breadcrumb.js +27 -0
- package/dist/react/file-browser/file-breadcrumb.js.map +1 -0
- package/dist/react/file-browser/file-entry.d.ts +27 -0
- package/dist/react/file-browser/file-entry.d.ts.map +1 -0
- package/dist/react/file-browser/file-entry.js +31 -0
- package/dist/react/file-browser/file-entry.js.map +1 -0
- package/dist/react/file-browser/file-preview-panel.d.ts +42 -0
- package/dist/react/file-browser/file-preview-panel.d.ts.map +1 -0
- package/dist/react/file-browser/file-preview-panel.js +135 -0
- package/dist/react/file-browser/file-preview-panel.js.map +1 -0
- package/dist/react/file-browser/index.d.ts +7 -0
- package/dist/react/file-browser/index.js +6 -0
- package/dist/react/file-browser/new-folder-input.d.ts +36 -0
- package/dist/react/file-browser/new-folder-input.d.ts.map +1 -0
- package/dist/react/file-browser/new-folder-input.js +52 -0
- package/dist/react/file-browser/new-folder-input.js.map +1 -0
- package/dist/react/file-browser/types.d.ts +52 -0
- package/dist/react/file-browser/types.d.ts.map +1 -0
- package/dist/react/genie/genie-chart-inference.d.ts +17 -0
- package/dist/react/genie/genie-chart-inference.d.ts.map +1 -0
- package/dist/react/genie/genie-chart-inference.js +75 -0
- package/dist/react/genie/genie-chart-inference.js.map +1 -0
- package/dist/react/genie/genie-chat-message-list.js +1 -1
- package/dist/react/genie/genie-chat-message.d.ts.map +1 -1
- package/dist/react/genie/genie-chat-message.js +27 -16
- package/dist/react/genie/genie-chat-message.js.map +1 -1
- package/dist/react/genie/genie-query-transform.d.ts +31 -0
- package/dist/react/genie/genie-query-transform.d.ts.map +1 -0
- package/dist/react/genie/genie-query-transform.js +79 -0
- package/dist/react/genie/genie-query-transform.js.map +1 -0
- package/dist/react/genie/genie-query-visualization.d.ts +25 -0
- package/dist/react/genie/genie-query-visualization.d.ts.map +1 -0
- package/dist/react/genie/genie-query-visualization.js +79 -0
- package/dist/react/genie/genie-query-visualization.js.map +1 -0
- package/dist/react/genie/index.d.ts +4 -1
- package/dist/react/genie/index.js +3 -0
- package/dist/react/genie/types.d.ts +2 -2
- package/dist/react/genie/types.d.ts.map +1 -1
- package/dist/react/index.d.ts +13 -2
- package/dist/react/index.js +16 -6
- package/dist/react/lib/format.d.ts +14 -0
- package/dist/react/lib/format.d.ts.map +1 -0
- package/dist/react/lib/format.js +17 -1
- package/dist/react/lib/format.js.map +1 -1
- package/dist/react/table/data-table.js +2 -2
- package/dist/react/table/table-wrapper.js +1 -1
- package/dist/react/ui/breadcrumb.js +1 -1
- package/dist/react/ui/index.js +5 -5
- package/dist/react/ui/navigation-menu.js +1 -1
- package/dist/react/ui/sidebar.js +1 -1
- package/dist/shared/src/genie.d.ts +16 -2
- package/dist/shared/src/genie.d.ts.map +1 -1
- package/dist/shared/src/index.d.ts +1 -1
- package/docs/api/appkit/Class.Plugin.md +60 -12
- package/docs/api/appkit/Class.ResourceRegistry.md +3 -3
- package/docs/api/appkit/Function.createApp.md +3 -3
- package/docs/api/appkit/Interface.PluginManifest.md +9 -3
- package/docs/api/appkit/TypeAlias.PluginData.md +45 -0
- package/docs/api/appkit/TypeAlias.ToPlugin.md +1 -1
- package/docs/api/appkit-ui/files/DirectoryList.md +36 -0
- package/docs/api/appkit-ui/files/FileBreadcrumb.md +27 -0
- package/docs/api/appkit-ui/files/FileEntry.md +27 -0
- package/docs/api/appkit-ui/files/FilePreviewPanel.md +32 -0
- package/docs/api/appkit-ui/files/NewFolderInput.md +30 -0
- package/docs/api/appkit-ui/genie/GenieQueryVisualization.md +29 -0
- package/docs/api/appkit.md +1 -0
- package/docs/configuration.md +15 -0
- package/docs/plugins/custom-plugins.md +4 -13
- package/docs/plugins/files.md +350 -0
- package/docs/plugins.md +2 -1
- package/llms.txt +9 -1
- package/package.json +1 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# FileEntry
|
|
2
|
+
|
|
3
|
+
Single file or directory row with icon, name, size, and selection state
|
|
4
|
+
|
|
5
|
+
## FileEntry[](#fileentry-1 "Direct link to FileEntry")
|
|
6
|
+
|
|
7
|
+
Single file or directory row with icon, name, size, and selection state
|
|
8
|
+
|
|
9
|
+
**Source:** [`packages/appkit-ui/src/react/file-browser/file-entry.tsx`](https://github.com/databricks/appkit/blob/main/packages/appkit-ui/src/react/file-browser/file-entry.tsx)
|
|
10
|
+
|
|
11
|
+
### Props[](#props "Direct link to Props")
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Required | Default | Description |
|
|
14
|
+
| ------------ | ----------------------------- | -------- | ------- | ------------------------------------------------------- |
|
|
15
|
+
| `entry` | `DirectoryEntry` | ✓ | - | The directory entry to render |
|
|
16
|
+
| `entryPath` | `string` | ✓ | - | Resolved full path for this entry |
|
|
17
|
+
| `isSelected` | `boolean` | | - | Whether this entry is currently selected |
|
|
18
|
+
| `formatSize` | `((bytes: number) => string)` | | - | Custom file size formatter (defaults to formatFileSize) |
|
|
19
|
+
|
|
20
|
+
### Usage[](#usage "Direct link to Usage")
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { FileEntry } from '@databricks/appkit-ui';
|
|
24
|
+
|
|
25
|
+
<FileEntry /* props */ />
|
|
26
|
+
|
|
27
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# FilePreviewPanel
|
|
2
|
+
|
|
3
|
+
Preview panel displaying file metadata, image/text preview, and download/delete actions
|
|
4
|
+
|
|
5
|
+
## FilePreviewPanel[](#filepreviewpanel-1 "Direct link to FilePreviewPanel")
|
|
6
|
+
|
|
7
|
+
Preview panel displaying file metadata, image/text preview, and download/delete actions
|
|
8
|
+
|
|
9
|
+
**Source:** [`packages/appkit-ui/src/react/file-browser/file-preview-panel.tsx`](https://github.com/databricks/appkit/blob/main/packages/appkit-ui/src/react/file-browser/file-preview-panel.tsx)
|
|
10
|
+
|
|
11
|
+
### Props[](#props "Direct link to Props")
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Required | Default | Description |
|
|
14
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------- | ------------------------------------------------------------------------- |
|
|
15
|
+
| `selectedFile` | `string \| null` | ✓ | - | Full path of the selected file (null when nothing is selected) |
|
|
16
|
+
| `preview` | `FilePreview \| null` | ✓ | - | Preview data for the selected file |
|
|
17
|
+
| `previewLoading` | `boolean` | | - | Whether the preview is loading |
|
|
18
|
+
| `onDownload` | `((filePath: string) => void)` | | - | Called when the download button is clicked |
|
|
19
|
+
| `onDelete` | `((filePath: string) => void)` | | - | Called when the delete button is clicked |
|
|
20
|
+
| `deleting` | `boolean` | | - | Whether a delete operation is in progress |
|
|
21
|
+
| `imagePreviewSrc` | `string \| ((filePath: string) => string)` | | - | Image preview source — string URL or function that receives the file path |
|
|
22
|
+
| `formatSize` | `((bytes: number) => string)` | | - | Custom file size formatter (defaults to formatFileSize) |
|
|
23
|
+
| `labels` | `Pick<FileBrowserLabels, "type" \| "download" \| "size" \| "selectFilePrompt" \| "previewNotAvailable" \| "previewFailed" \| "modified" \| "unknown">` | | - | Customizable labels |
|
|
24
|
+
|
|
25
|
+
### Usage[](#usage "Direct link to Usage")
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { FilePreviewPanel } from '@databricks/appkit-ui';
|
|
29
|
+
|
|
30
|
+
<FilePreviewPanel /* props */ />
|
|
31
|
+
|
|
32
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# NewFolderInput
|
|
2
|
+
|
|
3
|
+
Inline folder-name input with create/cancel actions
|
|
4
|
+
|
|
5
|
+
## NewFolderInput[](#newfolderinput-1 "Direct link to NewFolderInput")
|
|
6
|
+
|
|
7
|
+
Inline folder-name input with create/cancel actions
|
|
8
|
+
|
|
9
|
+
**Source:** [`packages/appkit-ui/src/react/file-browser/new-folder-input.tsx`](https://github.com/databricks/appkit/blob/main/packages/appkit-ui/src/react/file-browser/new-folder-input.tsx)
|
|
10
|
+
|
|
11
|
+
### Props[](#props "Direct link to Props")
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Required | Default | Description |
|
|
14
|
+
| ----------- | -------------------------------------------------------------- | -------- | ------- | -------------------------------------- |
|
|
15
|
+
| `value` | `string` | ✓ | - | Current folder name value |
|
|
16
|
+
| `onChange` | `(value: string) => void` | ✓ | - | Called when folder name changes |
|
|
17
|
+
| `onCreate` | `() => void` | ✓ | - | Called when the user confirms creation |
|
|
18
|
+
| `onCancel` | `() => void` | ✓ | - | Called when the user cancels |
|
|
19
|
+
| `creating` | `boolean` | | - | Whether folder creation is in progress |
|
|
20
|
+
| `autoFocus` | `boolean` | | `true` | Auto-focus the input on mount |
|
|
21
|
+
| `labels` | `Pick<FileBrowserLabels, "create" \| "folderNamePlaceholder">` | | - | Customizable labels |
|
|
22
|
+
|
|
23
|
+
### Usage[](#usage "Direct link to Usage")
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { NewFolderInput } from '@databricks/appkit-ui';
|
|
27
|
+
|
|
28
|
+
<NewFolderInput /* props */ />
|
|
29
|
+
|
|
30
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# GenieQueryVisualization
|
|
2
|
+
|
|
3
|
+
Renders a chart + data table for a Genie query result.
|
|
4
|
+
|
|
5
|
+
## GenieQueryVisualization[](#geniequeryvisualization-1 "Direct link to GenieQueryVisualization")
|
|
6
|
+
|
|
7
|
+
Renders a chart + data table for a Genie query result.
|
|
8
|
+
|
|
9
|
+
* When a chart type can be inferred: shows Tabs with "Chart" (default) and "Table"
|
|
10
|
+
* When no chart fits: shows only the data table
|
|
11
|
+
* When data is empty/malformed: renders nothing
|
|
12
|
+
|
|
13
|
+
**Source:** [`packages/appkit-ui/src/react/genie/genie-query-visualization.tsx`](https://github.com/databricks/appkit/blob/main/packages/appkit-ui/src/react/genie/genie-query-visualization.tsx)
|
|
14
|
+
|
|
15
|
+
### Props[](#props "Direct link to Props")
|
|
16
|
+
|
|
17
|
+
| Prop | Type | Required | Default | Description |
|
|
18
|
+
| ----------- | ------------------------ | -------- | ------- | ------------------------------------------ |
|
|
19
|
+
| `data` | `GenieStatementResponse` | ✓ | - | Raw statement\_response from the Genie API |
|
|
20
|
+
| `className` | `string` | | - | Additional CSS classes |
|
|
21
|
+
|
|
22
|
+
### Usage[](#usage "Direct link to Usage")
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { GenieQueryVisualization } from '@databricks/appkit-ui';
|
|
26
|
+
|
|
27
|
+
<GenieQueryVisualization /* props */ />
|
|
28
|
+
|
|
29
|
+
```
|
package/docs/api/appkit.md
CHANGED
|
@@ -51,6 +51,7 @@ Core library for building Databricks applications with type-safe SQL queries, pl
|
|
|
51
51
|
| ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
52
52
|
| [ConfigSchema](./docs/api/appkit/TypeAlias.ConfigSchema.md) | Configuration schema definition for plugin config. Re-exported from the standard JSON Schema Draft 7 types. |
|
|
53
53
|
| [IAppRouter](./docs/api/appkit/TypeAlias.IAppRouter.md) | Express router type for plugin route registration |
|
|
54
|
+
| [PluginData](./docs/api/appkit/TypeAlias.PluginData.md) | - |
|
|
54
55
|
| [ResourcePermission](./docs/api/appkit/TypeAlias.ResourcePermission.md) | Union of all possible permission levels across all resource types. |
|
|
55
56
|
| [ToPlugin](./docs/api/appkit/TypeAlias.ToPlugin.md) | - |
|
|
56
57
|
|
package/docs/configuration.md
CHANGED
|
@@ -46,6 +46,21 @@ env:
|
|
|
46
46
|
|
|
47
47
|
This makes the warehouse ID available to your app at runtime. The `valueFrom: sql-warehouse` directive tells Databricks Apps to inject the configured warehouse ID.
|
|
48
48
|
|
|
49
|
+
### Binding Unity Catalog volumes (files plugin)[](#binding-unity-catalog-volumes-files-plugin "Direct link to Binding Unity Catalog volumes (files plugin)")
|
|
50
|
+
|
|
51
|
+
The files plugin uses named volumes. Each volume key maps to an environment variable `DATABRICKS_VOLUME_{KEY_UPPERCASE}`:
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
env:
|
|
55
|
+
- name: DATABRICKS_VOLUME_UPLOADS
|
|
56
|
+
valueFrom: volume
|
|
57
|
+
- name: DATABRICKS_VOLUME_EXPORTS
|
|
58
|
+
valueFrom: volume
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
See the [Files plugin](./docs/plugins/files.md) documentation for details.
|
|
63
|
+
|
|
49
64
|
For advanced configuration options (authorization, networking, resource limits), see the [Databricks Apps Configuration](https://docs.databricks.com/aws/en/dev-tools/databricks-apps/configuration) documentation.
|
|
50
65
|
|
|
51
66
|
## Environment variables[](#environment-variables "Direct link to Environment variables")
|
|
@@ -14,13 +14,10 @@ For a deeper understanding of the plugin structure, read on.
|
|
|
14
14
|
Extend the [`Plugin`](./docs/api/appkit/Class.Plugin.md) class and export with `toPlugin()`:
|
|
15
15
|
|
|
16
16
|
```typescript
|
|
17
|
-
import { Plugin, toPlugin } from "@databricks/appkit";
|
|
17
|
+
import { Plugin, toPlugin, type PluginManifest } from "@databricks/appkit";
|
|
18
18
|
import type express from "express";
|
|
19
19
|
|
|
20
20
|
class MyPlugin extends Plugin {
|
|
21
|
-
name = "myPlugin";
|
|
22
|
-
|
|
23
|
-
// Define resource requirements in the static manifest
|
|
24
21
|
static manifest = {
|
|
25
22
|
name: "myPlugin",
|
|
26
23
|
displayName: "My Plugin",
|
|
@@ -41,7 +38,7 @@ class MyPlugin extends Plugin {
|
|
|
41
38
|
],
|
|
42
39
|
optional: []
|
|
43
40
|
}
|
|
44
|
-
}
|
|
41
|
+
} satisfies PluginManifest<"myPlugin">;
|
|
45
42
|
|
|
46
43
|
async setup() {
|
|
47
44
|
// Initialize your plugin
|
|
@@ -56,17 +53,13 @@ class MyPlugin extends Plugin {
|
|
|
56
53
|
}
|
|
57
54
|
|
|
58
55
|
exports() {
|
|
59
|
-
// an object with the methods from this plugin to expose
|
|
60
56
|
return {
|
|
61
57
|
myCustomMethod: this.myCustomMethod
|
|
62
58
|
}
|
|
63
59
|
}
|
|
64
60
|
}
|
|
65
61
|
|
|
66
|
-
export const myPlugin = toPlugin
|
|
67
|
-
MyPlugin,
|
|
68
|
-
"myPlugin",
|
|
69
|
-
);
|
|
62
|
+
export const myPlugin = toPlugin(MyPlugin);
|
|
70
63
|
|
|
71
64
|
```
|
|
72
65
|
|
|
@@ -80,8 +73,6 @@ interface MyPluginConfig extends BasePluginConfig {
|
|
|
80
73
|
}
|
|
81
74
|
|
|
82
75
|
class MyPlugin extends Plugin<MyPluginConfig> {
|
|
83
|
-
name = "myPlugin";
|
|
84
|
-
|
|
85
76
|
static manifest = {
|
|
86
77
|
name: "myPlugin",
|
|
87
78
|
displayName: "My Plugin",
|
|
@@ -95,7 +86,7 @@ class MyPlugin extends Plugin<MyPluginConfig> {
|
|
|
95
86
|
{ type: "database", alias: "cache", resourceKey: "cache", description: "Query result caching (if enabled)", permission: "CAN_CONNECT_AND_CREATE", fields: { instance_name: { env: "DATABRICKS_CACHE_INSTANCE" }, database_name: { env: "DATABRICKS_CACHE_DB" } } }
|
|
96
87
|
]
|
|
97
88
|
}
|
|
98
|
-
}
|
|
89
|
+
} satisfies PluginManifest<"myPlugin">;
|
|
99
90
|
|
|
100
91
|
// Runtime: Convert optional resources to required based on config
|
|
101
92
|
static getResourceRequirements(config: MyPluginConfig) {
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# Files plugin
|
|
2
|
+
|
|
3
|
+
File operations against Databricks Unity Catalog Volumes. Supports listing, reading, downloading, uploading, deleting, and previewing files with built-in caching, retry, and timeout handling via the execution interceptor pipeline.
|
|
4
|
+
|
|
5
|
+
**Key features:**
|
|
6
|
+
|
|
7
|
+
* **Multi-volume**: Define named volumes (e.g. `uploads`, `exports`) and access them independently
|
|
8
|
+
* CRUD operations on Unity Catalog Volume files
|
|
9
|
+
* Streaming downloads with content-type resolution
|
|
10
|
+
* Inline raw serving with XSS-safe content type enforcement
|
|
11
|
+
* Upload size limits with streaming enforcement
|
|
12
|
+
* Automatic cache invalidation on write operations
|
|
13
|
+
* Custom content type mappings
|
|
14
|
+
* Per-user execution context (OBO)
|
|
15
|
+
|
|
16
|
+
## Basic usage[](#basic-usage "Direct link to Basic usage")
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { createApp, files, server } from "@databricks/appkit";
|
|
20
|
+
|
|
21
|
+
await createApp({
|
|
22
|
+
plugins: [
|
|
23
|
+
server(),
|
|
24
|
+
files(),
|
|
25
|
+
],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Set `DATABRICKS_VOLUME_*` environment variables in your `app.yaml` (or `.env`). The plugin auto-discovers them at startup:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
DATABRICKS_VOLUME_UPLOADS=/Volumes/catalog/schema/uploads
|
|
34
|
+
DATABRICKS_VOLUME_EXPORTS=/Volumes/catalog/schema/exports
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
That's it — no `volumes` config needed. The env var suffix becomes the volume key (lowercased):
|
|
39
|
+
|
|
40
|
+
| Environment variable | Volume key |
|
|
41
|
+
| --------------------------- | ---------- |
|
|
42
|
+
| `DATABRICKS_VOLUME_UPLOADS` | `uploads` |
|
|
43
|
+
| `DATABRICKS_VOLUME_EXPORTS` | `exports` |
|
|
44
|
+
|
|
45
|
+
## Auto-discovery[](#auto-discovery "Direct link to Auto-discovery")
|
|
46
|
+
|
|
47
|
+
The plugin scans `process.env` for keys matching `DATABRICKS_VOLUME_*` and registers each as a volume with default `{}` config. Env vars with an empty value or the bare `DATABRICKS_VOLUME_` prefix (no suffix) are skipped.
|
|
48
|
+
|
|
49
|
+
**Merge semantics:** auto-discovered volumes are always merged with explicitly configured ones. Explicit config wins for per-volume overrides (e.g., `maxUploadSize`), while discovered-only volumes get default settings.
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// Explicit overrides for uploads; exports is auto-discovered from env
|
|
53
|
+
files({
|
|
54
|
+
volumes: {
|
|
55
|
+
uploads: { maxUploadSize: 100_000_000 },
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
This produces two volumes (`uploads` with a 100 MB limit, `exports` with defaults), assuming both `DATABRICKS_VOLUME_UPLOADS` and `DATABRICKS_VOLUME_EXPORTS` are set.
|
|
62
|
+
|
|
63
|
+
## Configuration[](#configuration "Direct link to Configuration")
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
interface IFilesConfig {
|
|
67
|
+
/** Named volumes to expose. Each key becomes a volume accessor. */
|
|
68
|
+
volumes?: Record<string, VolumeConfig>;
|
|
69
|
+
/** Operation timeout in milliseconds. Overrides the per-tier defaults. */
|
|
70
|
+
timeout?: number;
|
|
71
|
+
/** Map of file extensions to MIME types (priority over built-in map). Inherited by all volumes. */
|
|
72
|
+
customContentTypes?: Record<string, string>;
|
|
73
|
+
/** Maximum upload size in bytes. Defaults to 5 GB. Inherited by all volumes. */
|
|
74
|
+
maxUploadSize?: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface VolumeConfig {
|
|
78
|
+
/** Maximum upload size in bytes for this volume. Overrides plugin-level default. */
|
|
79
|
+
maxUploadSize?: number;
|
|
80
|
+
/** Map of file extensions to MIME types for this volume. Overrides plugin-level default. */
|
|
81
|
+
customContentTypes?: Record<string, string>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Per-volume overrides[](#per-volume-overrides "Direct link to Per-volume overrides")
|
|
87
|
+
|
|
88
|
+
Each volume inherits the plugin-level `maxUploadSize` and `customContentTypes` unless overridden:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
files({
|
|
92
|
+
maxUploadSize: 5_000_000_000, // 5 GB default for all volumes
|
|
93
|
+
customContentTypes: { ".avro": "application/avro" },
|
|
94
|
+
volumes: {
|
|
95
|
+
uploads: { maxUploadSize: 100_000_000 }, // 100 MB limit for uploads only
|
|
96
|
+
exports: {}, // uses plugin-level defaults
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Custom content types[](#custom-content-types "Direct link to Custom content types")
|
|
103
|
+
|
|
104
|
+
Override or extend the built-in extension → MIME map:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
files({
|
|
108
|
+
volumes: { data: {} },
|
|
109
|
+
customContentTypes: {
|
|
110
|
+
".avro": "application/avro",
|
|
111
|
+
".ndjson": "application/x-ndjson",
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Dangerous MIME types (`text/html`, `text/javascript`, `application/javascript`, `application/xhtml+xml`, `image/svg+xml`) are blocked to prevent stored-XSS when files are served inline via `/raw`.
|
|
118
|
+
|
|
119
|
+
## HTTP routes[](#http-routes "Direct link to HTTP routes")
|
|
120
|
+
|
|
121
|
+
Routes are mounted at `/api/files/*`. All routes except `/volumes` execute in user context via `asUser(req)`.
|
|
122
|
+
|
|
123
|
+
| Method | Path | Query / Body | Response |
|
|
124
|
+
| ------ | ---------------------- | ---------------------------- | ------------------------------------------------------------ |
|
|
125
|
+
| GET | `/volumes` | — | `{ volumes: string[] }` |
|
|
126
|
+
| GET | `/:volumeKey/list` | `?path` (optional) | `DirectoryEntry[]` |
|
|
127
|
+
| GET | `/:volumeKey/read` | `?path` (required) | `text/plain` body |
|
|
128
|
+
| GET | `/:volumeKey/download` | `?path` (required) | Binary stream (`Content-Disposition: attachment`) |
|
|
129
|
+
| GET | `/:volumeKey/raw` | `?path` (required) | Binary stream (inline for safe types, attachment for unsafe) |
|
|
130
|
+
| GET | `/:volumeKey/exists` | `?path` (required) | `{ exists: boolean }` |
|
|
131
|
+
| GET | `/:volumeKey/metadata` | `?path` (required) | `FileMetadata` |
|
|
132
|
+
| GET | `/:volumeKey/preview` | `?path` (required) | `FilePreview` |
|
|
133
|
+
| POST | `/:volumeKey/upload` | `?path` (required), raw body | `{ success: true }` |
|
|
134
|
+
| POST | `/:volumeKey/mkdir` | `body.path` (required) | `{ success: true }` |
|
|
135
|
+
| DELETE | `/:volumeKey` | `?path` (required) | `{ success: true }` |
|
|
136
|
+
|
|
137
|
+
The `:volumeKey` parameter must match one of the configured volume keys. Unknown volume keys return a `404` with the list of available volumes.
|
|
138
|
+
|
|
139
|
+
### Path validation[](#path-validation "Direct link to Path validation")
|
|
140
|
+
|
|
141
|
+
All endpoints that accept a `path` parameter enforce:
|
|
142
|
+
|
|
143
|
+
* Path is required (non-empty)
|
|
144
|
+
* Maximum 4096 characters
|
|
145
|
+
* No null bytes
|
|
146
|
+
|
|
147
|
+
### Raw endpoint security[](#raw-endpoint-security "Direct link to Raw endpoint security")
|
|
148
|
+
|
|
149
|
+
The `/:volumeKey/raw` endpoint serves files inline for browser display but applies security headers:
|
|
150
|
+
|
|
151
|
+
* `X-Content-Type-Options: nosniff`
|
|
152
|
+
* `Content-Security-Policy: sandbox`
|
|
153
|
+
* Unsafe content types (HTML, JS, SVG) are forced to download via `Content-Disposition: attachment`
|
|
154
|
+
|
|
155
|
+
## Execution defaults[](#execution-defaults "Direct link to Execution defaults")
|
|
156
|
+
|
|
157
|
+
Every operation runs through the interceptor pipeline with tier-specific defaults:
|
|
158
|
+
|
|
159
|
+
| Tier | Cache | Retry | Timeout | Operations |
|
|
160
|
+
| ------------ | ----- | ----- | ------- | ------------------------------------- |
|
|
161
|
+
| **Read** | 60 s | 3x | 30 s | list, read, exists, metadata, preview |
|
|
162
|
+
| **Download** | none | 3x | 30 s | download, raw |
|
|
163
|
+
| **Write** | none | none | 600 s | upload, mkdir, delete |
|
|
164
|
+
|
|
165
|
+
Retry uses exponential backoff with a 1 s initial delay.
|
|
166
|
+
|
|
167
|
+
The download timeout applies to the stream start, not the full transfer.
|
|
168
|
+
|
|
169
|
+
## Cache isolation[](#cache-isolation "Direct link to Cache isolation")
|
|
170
|
+
|
|
171
|
+
Cache keys include the volume key, ensuring volumes have independent caches. For example, `uploads:list` and `exports:list` are cached separately.
|
|
172
|
+
|
|
173
|
+
Write operations (`upload`, `mkdir`, `delete`) automatically invalidate the cached `list` entry for the parent directory of the affected volume.
|
|
174
|
+
|
|
175
|
+
## Programmatic API[](#programmatic-api "Direct link to Programmatic API")
|
|
176
|
+
|
|
177
|
+
The `exports()` API is a callable that accepts a volume key and returns a `VolumeHandle`. The handle exposes all `VolumeAPI` methods directly (service principal, logs a warning) and an `asUser(req)` method for OBO access (recommended).
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
// OBO access (recommended)
|
|
181
|
+
const entries = await appkit.files("uploads").asUser(req).list();
|
|
182
|
+
const content = await appkit.files("exports").asUser(req).read("report.csv");
|
|
183
|
+
|
|
184
|
+
// Service principal access (logs a warning encouraging OBO)
|
|
185
|
+
const entries = await appkit.files("uploads").list();
|
|
186
|
+
|
|
187
|
+
// Named accessor
|
|
188
|
+
const vol = appkit.files.volume("uploads");
|
|
189
|
+
await vol.asUser(req).list();
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### VolumeAPI methods[](#volumeapi-methods "Direct link to VolumeAPI methods")
|
|
194
|
+
|
|
195
|
+
| Method | Signature | Returns |
|
|
196
|
+
| ----------------- | ----------------------------------------------------------------------------------------------------- | ------------------ |
|
|
197
|
+
| `list` | `(directoryPath?: string)` | `DirectoryEntry[]` |
|
|
198
|
+
| `read` | `(filePath: string, options?: { maxSize?: number })` | `string` |
|
|
199
|
+
| `download` | `(filePath: string)` | `DownloadResponse` |
|
|
200
|
+
| `exists` | `(filePath: string)` | `boolean` |
|
|
201
|
+
| `metadata` | `(filePath: string)` | `FileMetadata` |
|
|
202
|
+
| `upload` | `(filePath: string, contents: ReadableStream \| Buffer \| string, options?: { overwrite?: boolean })` | `void` |
|
|
203
|
+
| `createDirectory` | `(directoryPath: string)` | `void` |
|
|
204
|
+
| `delete` | `(filePath: string)` | `void` |
|
|
205
|
+
| `preview` | `(filePath: string)` | `FilePreview` |
|
|
206
|
+
|
|
207
|
+
> `read()` loads the entire file into memory as a string. Files larger than 10 MB (default) are rejected — use `download()` for large files, or pass `{ maxSize: <bytes> }` to override.
|
|
208
|
+
|
|
209
|
+
## Path resolution[](#path-resolution "Direct link to Path resolution")
|
|
210
|
+
|
|
211
|
+
Paths can be **absolute** or **relative**:
|
|
212
|
+
|
|
213
|
+
* **Absolute** — starts with `/`, must begin with `/Volumes/` (e.g. `/Volumes/catalog/schema/vol/data.csv`)
|
|
214
|
+
* **Relative** — prepended with the volume path resolved from the environment variable (e.g. `data.csv` → `/Volumes/catalog/schema/uploads/data.csv`)
|
|
215
|
+
|
|
216
|
+
Path traversal (`../`) is rejected. If a relative path is used and the volume's environment variable is not set, an error is thrown.
|
|
217
|
+
|
|
218
|
+
The `list()` method with no arguments lists the volume root.
|
|
219
|
+
|
|
220
|
+
## Types[](#types "Direct link to Types")
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
// Re-exported from @databricks/sdk-experimental
|
|
224
|
+
type DirectoryEntry = files.DirectoryEntry;
|
|
225
|
+
type DownloadResponse = files.DownloadResponse;
|
|
226
|
+
|
|
227
|
+
interface FileMetadata {
|
|
228
|
+
/** File size in bytes. */
|
|
229
|
+
contentLength: number | undefined;
|
|
230
|
+
/** MIME content type of the file. */
|
|
231
|
+
contentType: string | undefined;
|
|
232
|
+
/** ISO 8601 timestamp of the last modification. */
|
|
233
|
+
lastModified: string | undefined;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
interface FilePreview extends FileMetadata {
|
|
237
|
+
/** First portion of text content, or null for non-text files. */
|
|
238
|
+
textPreview: string | null;
|
|
239
|
+
/** Whether the file is detected as a text format. */
|
|
240
|
+
isText: boolean;
|
|
241
|
+
/** Whether the file is detected as an image format. */
|
|
242
|
+
isImage: boolean;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
interface VolumeConfig {
|
|
246
|
+
/** Maximum upload size in bytes for this volume. */
|
|
247
|
+
maxUploadSize?: number;
|
|
248
|
+
/** Map of file extensions to MIME types for this volume. */
|
|
249
|
+
customContentTypes?: Record<string, string>;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
interface VolumeAPI {
|
|
253
|
+
list(directoryPath?: string): Promise<DirectoryEntry[]>;
|
|
254
|
+
read(filePath: string, options?: { maxSize?: number }): Promise<string>;
|
|
255
|
+
download(filePath: string): Promise<DownloadResponse>;
|
|
256
|
+
exists(filePath: string): Promise<boolean>;
|
|
257
|
+
metadata(filePath: string): Promise<FileMetadata>;
|
|
258
|
+
upload(filePath: string, contents: ReadableStream | Buffer | string, options?: { overwrite?: boolean }): Promise<void>;
|
|
259
|
+
createDirectory(directoryPath: string): Promise<void>;
|
|
260
|
+
delete(filePath: string): Promise<void>;
|
|
261
|
+
preview(filePath: string): Promise<FilePreview>;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Volume handle: all VolumeAPI methods (service principal) + asUser() for OBO. */
|
|
265
|
+
type VolumeHandle = VolumeAPI & {
|
|
266
|
+
asUser: (req: Request) => VolumeAPI;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Content-type resolution[](#content-type-resolution "Direct link to Content-type resolution")
|
|
272
|
+
|
|
273
|
+
`contentTypeFromPath(filePath, reported?, customTypes?)` resolves a file's MIME type:
|
|
274
|
+
|
|
275
|
+
1. Check `customContentTypes` map first (if configured).
|
|
276
|
+
2. Match the file extension against the built-in map.
|
|
277
|
+
3. Fall back to the server-reported type, or `application/octet-stream`.
|
|
278
|
+
|
|
279
|
+
Built-in extensions: `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.svg`, `.bmp`, `.ico`, `.html`, `.css`, `.js`, `.ts`, `.py`, `.txt`, `.md`, `.csv`, `.json`, `.jsonl`, `.xml`, `.yaml`, `.yml`, `.sql`, `.pdf`, `.ipynb`, `.parquet`, `.zip`, `.gz`.
|
|
280
|
+
|
|
281
|
+
## User context[](#user-context "Direct link to User context")
|
|
282
|
+
|
|
283
|
+
Routes use `this.asUser(req)` so operations execute with the requesting user's Databricks credentials (on-behalf-of / OBO). The `/volumes` route is the only exception since it only reads plugin config.
|
|
284
|
+
|
|
285
|
+
The programmatic API returns a `VolumeHandle` that exposes all `VolumeAPI` methods directly (service principal) and an `asUser(req)` method for OBO access. Calling any method without `asUser()` logs a warning encouraging OBO usage but does not throw. OBO access is strongly recommended for production use.
|
|
286
|
+
|
|
287
|
+
## Resource requirements[](#resource-requirements "Direct link to Resource requirements")
|
|
288
|
+
|
|
289
|
+
Volume resources are declared **dynamically** via `getResourceRequirements(config)` based on discovered + configured volumes. Each volume key generates a required resource with `WRITE_VOLUME` permission and a `DATABRICKS_VOLUME_{KEY_UPPERCASE}` environment variable.
|
|
290
|
+
|
|
291
|
+
For example, if `DATABRICKS_VOLUME_UPLOADS` and `DATABRICKS_VOLUME_EXPORTS` are set, calling `files()` generates two required volume resources validated at startup — no explicit `volumes` config needed.
|
|
292
|
+
|
|
293
|
+
## Error responses[](#error-responses "Direct link to Error responses")
|
|
294
|
+
|
|
295
|
+
All errors return JSON:
|
|
296
|
+
|
|
297
|
+
```json
|
|
298
|
+
{
|
|
299
|
+
"error": "Human-readable message",
|
|
300
|
+
"plugin": "files"
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
| Status | Description |
|
|
306
|
+
| ------ | ------------------------------------------------------------- |
|
|
307
|
+
| 400 | Missing or invalid `path` parameter |
|
|
308
|
+
| 404 | Unknown volume key |
|
|
309
|
+
| 413 | Upload exceeds `maxUploadSize` |
|
|
310
|
+
| 500 | Operation failed (SDK, network, upstream, or unhandled error) |
|
|
311
|
+
|
|
312
|
+
## Frontend components[](#frontend-components "Direct link to Frontend components")
|
|
313
|
+
|
|
314
|
+
The `@databricks/appkit-ui` package provides ready-to-use React components for building a file browser:
|
|
315
|
+
|
|
316
|
+
### FileBrowser[](#filebrowser "Direct link to FileBrowser")
|
|
317
|
+
|
|
318
|
+
A composable set of components for browsing, previewing, and managing files in a Unity Catalog Volume:
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
import {
|
|
322
|
+
DirectoryList,
|
|
323
|
+
FileBreadcrumb,
|
|
324
|
+
FilePreviewPanel,
|
|
325
|
+
} from "@databricks/appkit-ui/react";
|
|
326
|
+
|
|
327
|
+
function FileBrowserPage() {
|
|
328
|
+
return (
|
|
329
|
+
<div style={{ display: "flex", gap: 16 }}>
|
|
330
|
+
<div style={{ flex: 1 }}>
|
|
331
|
+
<FileBreadcrumb
|
|
332
|
+
rootLabel="uploads"
|
|
333
|
+
segments={["data"]}
|
|
334
|
+
onNavigateToRoot={() => {}}
|
|
335
|
+
onNavigateToSegment={() => {}}
|
|
336
|
+
/>
|
|
337
|
+
<DirectoryList
|
|
338
|
+
entries={[]}
|
|
339
|
+
onEntryClick={() => {}}
|
|
340
|
+
resolveEntryPath={(entry) => entry.path ?? ""}
|
|
341
|
+
/>
|
|
342
|
+
</div>
|
|
343
|
+
<FilePreviewPanel selectedFile={null} preview={null} />
|
|
344
|
+
</div>
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
See the [Files (UC) components](./docs/api/appkit-ui/files/DirectoryList.md) reference for the full props API.
|
package/docs/plugins.md
CHANGED
|
@@ -9,13 +9,14 @@ For complete API documentation, see the [`Plugin`](./docs/api/appkit/Class.Plugi
|
|
|
9
9
|
Configure plugins when creating your AppKit instance:
|
|
10
10
|
|
|
11
11
|
```typescript
|
|
12
|
-
import { createApp, server, analytics, genie } from "@databricks/appkit";
|
|
12
|
+
import { createApp, server, analytics, genie, files } from "@databricks/appkit";
|
|
13
13
|
|
|
14
14
|
const AppKit = await createApp({
|
|
15
15
|
plugins: [
|
|
16
16
|
server({ port: 8000 }),
|
|
17
17
|
analytics(),
|
|
18
18
|
genie(),
|
|
19
|
+
files(),
|
|
19
20
|
],
|
|
20
21
|
});
|
|
21
22
|
|
package/llms.txt
CHANGED
|
@@ -44,6 +44,7 @@ npx @databricks/appkit docs <query>
|
|
|
44
44
|
- [Caching](./docs/plugins/caching.md): AppKit provides both global and plugin-level caching capabilities.
|
|
45
45
|
- [Creating custom plugins](./docs/plugins/custom-plugins.md): If you need custom API routes or background logic, implement an AppKit plugin. The fastest way is to use the CLI:
|
|
46
46
|
- [Execution context](./docs/plugins/execution-context.md): AppKit manages Databricks authentication via two contexts:
|
|
47
|
+
- [Files plugin](./docs/plugins/files.md): File operations against Databricks Unity Catalog Volumes. Supports listing, reading, downloading, uploading, deleting, and previewing files with built-in caching, retry, and timeout handling via the execution interceptor pipeline.
|
|
47
48
|
- [Genie plugin](./docs/plugins/genie.md): Integrates Databricks AI/BI Genie spaces into your AppKit application, enabling natural language data queries via a conversational interface.
|
|
48
49
|
- [Lakebase plugin](./docs/plugins/lakebase.md): Currently, the Lakebase plugin currently requires a one-time manual setup to connect your Databricks App with your Lakebase database. An automated setup process is planned for an upcoming future release.
|
|
49
50
|
- [Plugin management](./docs/plugins/plugin-management.md): AppKit includes a CLI for managing plugins. All commands are available under npx @databricks/appkit plugin.
|
|
@@ -83,7 +84,7 @@ npx @databricks/appkit docs <query>
|
|
|
83
84
|
- [Interface: GenerateDatabaseCredentialRequest](./docs/api/appkit/Interface.GenerateDatabaseCredentialRequest.md): Request parameters for generating database OAuth credentials
|
|
84
85
|
- [Interface: ITelemetry](./docs/api/appkit/Interface.ITelemetry.md): Plugin-facing interface for OpenTelemetry instrumentation.
|
|
85
86
|
- [Interface: LakebasePoolConfig](./docs/api/appkit/Interface.LakebasePoolConfig.md): Configuration for creating a Lakebase connection pool
|
|
86
|
-
- [Interface: PluginManifest](./docs/api/appkit/Interface.PluginManifest.md): Plugin manifest that declares metadata and resource requirements.
|
|
87
|
+
- [Interface: PluginManifest<TName>](./docs/api/appkit/Interface.PluginManifest.md): Plugin manifest that declares metadata and resource requirements.
|
|
87
88
|
- [Interface: RequestedClaims](./docs/api/appkit/Interface.RequestedClaims.md): Optional claims for fine-grained Unity Catalog table permissions
|
|
88
89
|
- [Interface: RequestedResource](./docs/api/appkit/Interface.RequestedResource.md): Resource to request permissions for in Unity Catalog
|
|
89
90
|
- [Interface: ResourceEntry](./docs/api/appkit/Interface.ResourceEntry.md): Internal representation of a resource in the registry.
|
|
@@ -94,6 +95,7 @@ npx @databricks/appkit docs <query>
|
|
|
94
95
|
- [Interface: ValidationResult](./docs/api/appkit/Interface.ValidationResult.md): Result of validating all registered resources against the environment.
|
|
95
96
|
- [Type Alias: ConfigSchema](./docs/api/appkit/TypeAlias.ConfigSchema.md): Configuration schema definition for plugin config.
|
|
96
97
|
- [Type Alias: IAppRouter](./docs/api/appkit/TypeAlias.IAppRouter.md): Express router type for plugin route registration
|
|
98
|
+
- [Type Alias: PluginData<T, U, N>](./docs/api/appkit/TypeAlias.PluginData.md): Type Parameters
|
|
97
99
|
- [Type Alias: ResourcePermission](./docs/api/appkit/TypeAlias.ResourcePermission.md): Union of all possible permission levels across all resource types.
|
|
98
100
|
- [Type Alias: ToPlugin()<T, U, N>](./docs/api/appkit/TypeAlias.ToPlugin.md): Type Parameters
|
|
99
101
|
- [Variable: sql](./docs/api/appkit/Variable.sql.md): SQL helper namespace
|
|
@@ -110,10 +112,16 @@ npx @databricks/appkit docs <query>
|
|
|
110
112
|
- [PieChart](./docs/api/appkit-ui/data/PieChart.md): Pie Chart component for proportional data visualization.
|
|
111
113
|
- [RadarChart](./docs/api/appkit-ui/data/RadarChart.md): Radar Chart component for multi-dimensional data comparison.
|
|
112
114
|
- [ScatterChart](./docs/api/appkit-ui/data/ScatterChart.md): Scatter Chart component for correlation and distribution visualization.
|
|
115
|
+
- [DirectoryList](./docs/api/appkit-ui/files/DirectoryList.md): Card-wrapped directory listing with loading, error, and empty states
|
|
116
|
+
- [FileBreadcrumb](./docs/api/appkit-ui/files/FileBreadcrumb.md): Path-aware breadcrumb navigation built on top of Breadcrumb primitives
|
|
117
|
+
- [FileEntry](./docs/api/appkit-ui/files/FileEntry.md): Single file or directory row with icon, name, size, and selection state
|
|
118
|
+
- [FilePreviewPanel](./docs/api/appkit-ui/files/FilePreviewPanel.md): Preview panel displaying file metadata, image/text preview, and download/delete actions
|
|
119
|
+
- [NewFolderInput](./docs/api/appkit-ui/files/NewFolderInput.md): Inline folder-name input with create/cancel actions
|
|
113
120
|
- [GenieChat](./docs/api/appkit-ui/genie/GenieChat.md): Full-featured chat interface for a single Databricks AI/BI Genie space. Handles message streaming, conversation history, and auto-reconnection via SSE.
|
|
114
121
|
- [GenieChatInput](./docs/api/appkit-ui/genie/GenieChatInput.md): Auto-expanding textarea input with a send button for chat messages. Submits on Enter (Shift+Enter for newline).
|
|
115
122
|
- [GenieChatMessage](./docs/api/appkit-ui/genie/GenieChatMessage.md): Renders a single Genie message bubble with optional expandable SQL query attachments.
|
|
116
123
|
- [GenieChatMessageList](./docs/api/appkit-ui/genie/GenieChatMessageList.md): Scrollable message list that renders Genie chat messages with auto-scroll, skeleton loaders, and a streaming indicator.
|
|
124
|
+
- [GenieQueryVisualization](./docs/api/appkit-ui/genie/GenieQueryVisualization.md): Renders a chart + data table for a Genie query result.
|
|
117
125
|
- [Styling](./docs/api/appkit-ui/styling.md): This guide covers how to style AppKit UI components using CSS variables and theming.
|
|
118
126
|
- [Accordion](./docs/api/appkit-ui/ui/Accordion.md): Collapsible content sections organized in a vertical stack
|
|
119
127
|
- [Alert](./docs/api/appkit-ui/ui/Alert.md): Displays important information with optional icon and multiple variants
|