create-file-viewer
Create a custom file viewer for Datagrok file share browser
SKILL.md.claude/skills/create-file-viewer/SKILL.md
GitHubCreate File Viewer
Create a custom file viewer that is used by the Datagrok file share browser to display files with specific extensions.
Usage
/create-file-viewer [extensions] [package-path]
Instructions
When this skill is invoked, help the user create a custom file viewer for one or more file extensions. Use the /ui skill for building the UI if necessary.
Step 1: Create the viewer function
Add a function to package.ts (or a separate file imported by it) with the correct annotations. The function must:
- Accept a single
fileinput - Return a
view - Have the
fileViewertag plus afileViewer-<ext>tag for each supported extension
//name: myFileViewer
//tags: fileViewer, fileViewer-xyz, fileViewer-abc
//input: file file
//output: view v
export function myFileViewer(file: DG.FileInfo) {
let view = DG.View.create();
// Read file content and render it
file.readAsString().then((content) => {
let host = ui.div([]);
// Process and display content
host.innerText = content;
view.append(host);
});
return view;
}
Step 2: Handle file content
Choose the appropriate method to read file content:
file.readAsString()- for text-based files (returnsPromise<string>)file.readAsBytes()- for binary files (returnsPromise<Uint8Array>)
Example for binary files:
//tags: fileViewer
//input: file file
//output: view v
//meta.fileViewer: mol, sdf, cif
export function structureViewer(file: DG.FileInfo) {
let view = DG.View.create();
let host = ui.div([], 'd4-ngl-viewer');
file
.readAsBytes()
.then(bytes => {
// Process binary content
let blob = new Blob([bytes]);
// Render blob...
});
view.append(host);
return view;
}
Key points
- The function runs when a user clicks on a file with a matching extension in the file share browser
- The view is displayed in the file preview panel
- Return the view synchronously; load file content asynchronously inside it
meta.fileViewercan take multiple extensions
For extensions that are efficiently DataFrames
- Return a
DG.TableViewdirectly — do not wrap a grid in a customDG.View - Transfer all source metadata to tags (table-level and column-level) so it survives round-trips through the platform
// Good — file viewer for a single-table format
static async previewFoo(file: DG.FileInfo): Promise<DG.View> {
const bytes = await file.readAsBytes();
const data = await parseFoo(bytes);
const df = toDataFrame(data);
const view = DG.TableView.create(df, false);
view.name = file.name;
return view;
}
- Set
df.setTag('source.format', '...')to record where the data came from - Preserve column-level metadata (description, format, categories) as tags
- Use a namespace prefix for format-specific tags (e.g.,
minitab.version,prism.sheetId) - Use the standard
descriptiontag for column descriptions
For extensions that contain multiple dataframes
- Use custom
DG.View - Show global file metadata on top
- 'Open all' big button on the ribbon
- Tab control with pane per dataframe
Behavior
- Ask the user which file extension(s) they want to support if not specified
- Determine whether the file is text-based or binary to choose
readAsStringvsreadAsBytes - Create the viewer function with correct tags for all specified extensions
- Add rendering logic appropriate for the file type