-
Notifications
You must be signed in to change notification settings - Fork 409
WebUI: Support custom-object-renderers plugin #9374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 16 commits
3c16aeb
be8c86e
c0d5826
6a9e0b5
ade503b
ae797ec
0591a5a
d5cea3c
0da2db8
01db027
0787e65
184351c
eaf7fa3
8c223a6
b09cdd6
221745d
11506b9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { PluginCustomObjectRenderers } from "../pluginCustomObjectRenderers"; | ||
|
|
||
| const DefaultCustomObjectRenderersPlugin: PluginCustomObjectRenderers = { | ||
| init: () => { | ||
| }, | ||
| get: () => { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| export default DefaultCustomObjectRenderersPlugin; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import React from "react"; | ||
| import { RendererComponent } from "../../pages/repositories/repository/fileRenderers/types"; | ||
| import { ConfigType } from "../../lib/hooks/configProvider"; | ||
|
|
||
| export interface PluginCustomObjectRenderers { | ||
| init: (config?: ConfigType) => void; | ||
| get: (contentType?: string, fileExtension?: string) => React.FC<RendererComponent> | null; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,25 @@ | ||
| import { PluginRepoCreationForm } from "./pluginRepoCreationForm"; | ||
| import DefaultRepoCreationFormPlugin from "./impls/DefaultRepoCreationFormPlugin"; | ||
| import { PluginCustomObjectRenderers } from "./pluginCustomObjectRenderers"; | ||
| import DefaultCustomObjectRenderersPlugin from "./impls/DefaultCustomObjectRenderers"; | ||
|
|
||
| export class PluginManager { | ||
| private _repoCreationForm: PluginRepoCreationForm = DefaultRepoCreationFormPlugin; | ||
| private _customObjectRenderers: PluginCustomObjectRenderers = DefaultCustomObjectRenderersPlugin; | ||
|
|
||
| overridePluginRepoCreationForm(pluginRepoCreationForm: PluginRepoCreationForm): void { | ||
| this._repoCreationForm = pluginRepoCreationForm; | ||
| } | ||
|
|
||
| get repoCreationForm(): PluginRepoCreationForm | null { | ||
| get repoCreationForm(): PluginRepoCreationForm { | ||
| return this._repoCreationForm; | ||
| } | ||
|
|
||
| overridePluginCustomObjectRenderers(pluginCustomObjectRenderers: PluginCustomObjectRenderers): void { | ||
| this._customObjectRenderers = pluginCustomObjectRenderers; | ||
| } | ||
|
|
||
| get customObjectRenderers(): PluginCustomObjectRenderers { | ||
| return this._customObjectRenderers; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,7 @@ import React, { createContext, FC, useContext, useEffect, useState, } from "reac | |||||
|
|
||||||
| import { config } from "../api"; | ||||||
| import useUser from "./user"; | ||||||
| import { usePluginManager } from "../../extendable/plugins/pluginsContext"; | ||||||
|
|
||||||
| type ConfigContextType = { | ||||||
| error: Error | null; | ||||||
|
|
@@ -10,9 +11,10 @@ type ConfigContextType = { | |||||
| }; | ||||||
|
|
||||||
| type ConfigType = { | ||||||
| storages: StorageConfigType[] | null; | ||||||
| storages?: StorageConfigType[]; | ||||||
|
||||||
| uiConfig?: UIConfigType; | ||||||
| versionConfig?: VersionConfig; | ||||||
| } | ||||||
| }; | ||||||
|
|
||||||
| type StorageConfigType = { | ||||||
| blockstore_namespace_ValidityRegex: string | null; | ||||||
|
|
@@ -25,7 +27,19 @@ type StorageConfigType = { | |||||
| pre_sign_support_ui: boolean; | ||||||
| }; | ||||||
|
|
||||||
| type UIConfigType = { | ||||||
|
||||||
| type UIConfigType = { | |
| type UIConfig = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I'll also align StorageConfigType.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
| type CustomViewerConfig = { | |
| type CustomViewer = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we sometimes use use snake case and sometimes pascal case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The snake case is what's returned from the API as is,
The pascal case is constructed in the js code.
Since the ConfigType is built in the js (see getConfig()),
I kept it as pascal case.
If it's critical I can align, but this has some internal sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not related, but used in the code, so added here.
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I usually avoid file reformatting, but this one was just a little unformatted. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| import React, {FC} from "react"; | ||
| import React, { FC } from "react"; | ||
| import SyntaxHighlighter from "react-syntax-highlighter"; | ||
| import {FileType, RendererComponent} from "./types"; | ||
| import {DuckDBRenderer} from "./data"; | ||
| import { FileType, RendererComponent } from "./types"; | ||
| import { DuckDBRenderer } from "./data"; | ||
| import { | ||
| GeoJSONRenderer, | ||
| ImageRenderer, | ||
|
|
@@ -13,19 +13,20 @@ import { | |
| TextRenderer, | ||
| UnsupportedFileType | ||
| } from "./simple"; | ||
| import { usePluginManager } from "../../../../extendable/plugins/pluginsContext"; | ||
|
|
||
|
|
||
| const MAX_FILE_SIZE = 20971520; // 20MiB | ||
|
|
||
|
|
||
| export const Renderers: {[fileType in FileType] : FC<RendererComponent> } = { | ||
| export const Renderers: { [fileType in FileType]: FC<RendererComponent> } = { | ||
| [FileType.DATA]: props => ( | ||
| <DuckDBRenderer {...props}/> | ||
| ), | ||
| [FileType.MARKDOWN]: props => ( | ||
| <TextDownloader {...props} onReady={text => | ||
| <MarkdownRenderer {...props} text={text}/> | ||
| } /> | ||
| }/> | ||
| ), | ||
| [FileType.IPYNB]: props => ( | ||
| <TextDownloader {...props} onReady={text => | ||
|
|
@@ -52,11 +53,11 @@ export const Renderers: {[fileType in FileType] : FC<RendererComponent> } = { | |
| [FileType.GEOJSON]: props => ( | ||
| <TextDownloader {...props} onReady={text => | ||
| <GeoJSONRenderer {...props} text={text}/> | ||
| } /> | ||
| }/> | ||
| ), | ||
| } | ||
|
|
||
| export const guessLanguage = (extension: string | null, contentType: string | null) => { | ||
| export const guessLanguage = (extension: string | null, contentType: string | null) => { | ||
| switch (extension) { | ||
| case 'py': | ||
| extension = 'python' | ||
|
|
@@ -178,7 +179,14 @@ export function guessType(contentType: string | null, fileExtension: string | nu | |
| } | ||
|
|
||
| export const ObjectRenderer: FC<RendererComponent> = (props: RendererComponent) => { | ||
| const fileType = guessType(props.contentType, props.fileExtension) | ||
| const pluginManager = usePluginManager(); | ||
|
|
||
| const customRenderer = pluginManager.customObjectRenderers.get(props.contentType, props.fileExtension) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The signature of get is for contentType and fileExtension is string, while their type is
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, apparently even IntelliJ noted about this... Updated - |
||
| if (customRenderer) { | ||
| return customRenderer(props) | ||
| } | ||
|
|
||
| const fileType = guessType(props.contentType, props.fileExtension) | ||
| if (fileType !== FileType.DATA && props.sizeBytes > MAX_FILE_SIZE) | ||
| return Renderers[FileType.TOO_LARGE](props) | ||
| return Renderers[fileType](props) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not related, but should be done.