Skip to content

Commit

Permalink
python panel icon support
Browse files Browse the repository at this point in the history
  • Loading branch information
imanjra committed May 8, 2024
1 parent e3602e6 commit cebb04f
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 23 deletions.
33 changes: 27 additions & 6 deletions app/packages/operators/src/OperatorIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { usePluginDefinition } from "@fiftyone/plugins";
import { useColorScheme } from "@mui/material";
import { IconProps, useColorScheme } from "@mui/material";
import { resolveServerPath } from "./utils";
import { MuiIconFont } from "@fiftyone/components";

export default function OperatorIcon(props: CustomIconPropsType) {
const {
Expand All @@ -11,26 +12,43 @@ export default function OperatorIcon(props: CustomIconPropsType) {
_builtIn,
Fallback,
canExecute,
iconProps,
} = props;
const { mode } = useColorScheme();
const iconPath = mode === "dark" && darkIcon ? darkIcon : lightIcon || icon;

if (isIconFont(iconPath)) {
return <MuiIconFont {...(iconProps as IconProps)} name={iconPath} />;
}

if (!iconPath || !canExecute) return Fallback ? <Fallback /> : null;
if (_builtIn) return <ImageIcon src={iconPath} />;
return <CustomOperatorIcon pluginName={pluginName} iconPath={iconPath} />;
return (
<CustomOperatorIcon
pluginName={pluginName}
iconPath={iconPath}
iconProps={iconProps as JSX.IntrinsicElements["img"]}
/>
);
}

function CustomOperatorIcon(props: CustomOperatorIconPropsType) {
const { pluginName, iconPath } = props;
const { pluginName, iconPath, iconProps } = props;
const plugin = usePluginDefinition(pluginName);
const assetPath = resolveServerPath(plugin);
const resolvedIconPath = assetPath + iconPath;
return <ImageIcon src={resolvedIconPath} />;
return <ImageIcon src={resolvedIconPath} iconProps={iconProps} />;
}

function ImageIcon(props: ImageIconPropsType) {
const { src } = props;
return <img src={src} height={21} width={21} />;
const { src, iconProps } = props;
return <img {...iconProps} src={src} height={21} width={21} />;
}

function isIconFont(path: string) {
return (
typeof path === "string" && !path?.includes("/") && !path?.includes(".")
);
}

export type CustomIconPropsType = {
Expand All @@ -41,13 +59,16 @@ export type CustomIconPropsType = {
_builtIn?: boolean;
Fallback?: React.ComponentType;
canExecute?: boolean;
iconProps?: IconProps | JSX.IntrinsicElements["img"];
};

type CustomOperatorIconPropsType = {
pluginName?: string;
iconPath?: string;
iconProps?: JSX.IntrinsicElements["img"];
};

type ImageIconPropsType = {
src: string;
iconProps?: JSX.IntrinsicElements["img"];
};
26 changes: 26 additions & 0 deletions app/packages/operators/src/Panel/register.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { PluginComponentType, registerComponent } from "@fiftyone/plugins";
import { defineCustomPanel } from "../CustomPanel";
import OperatorIcon from "../OperatorIcon";

export default function registerPanel(ctx) {
registerComponent({
type: PluginComponentType.Panel,
name: ctx.params.panel_name,
component: defineCustomPanel(ctx.params),
label: ctx.params.panel_label,
activator: () => true,
Icon: () => {
return (
<OperatorIcon
icon={ctx.params.icon || "extension"}
darkIcon={ctx.params.dark_icon}
lightIcon={ctx.params.light_icon}
iconProps={{ sx: { fontSize: 14, mr: "0.5rem" } }}
/>
);
},
panelOptions: {
allowDuplicates: ctx.params.allow_duplicates,
},
});
}
19 changes: 4 additions & 15 deletions app/packages/operators/src/built-in-operators.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
Layout,
SpaceNode,
usePanel,
usePanelState,
usePanels,
useSetPanelStateById,
Expand All @@ -13,9 +12,11 @@ import * as types from "./types";

import { toSlug } from "@fiftyone/utilities";
import copyToClipboard from "copy-to-clipboard";
import { merge } from "lodash";
import { useSetRecoilState } from "recoil";
import { useOperatorExecutor } from ".";
import useRefetchableSavedViews from "../../core/src/hooks/useRefetchableSavedViews";
import registerPanel from "./Panel/register";
import {
ExecutionContext,
Operator,
Expand All @@ -25,10 +26,7 @@ import {
executeOperator,
listLocalAndRemoteOperators,
} from "./operators";
import { usePromptOperatorInput, useShowOperatorIO } from "./state";
import { merge } from "lodash";
import { PluginComponentType, registerComponent } from "@fiftyone/plugins";
import CustomPanel, { defineCustomPanel } from "./CustomPanel";
import { useShowOperatorIO } from "./state";
import usePanelEvent from "./usePanelEvent";

//
Expand Down Expand Up @@ -982,16 +980,7 @@ class RegisterPanel extends Operator {
return new types.Property(inputs);
}
async execute(ctx: ExecutionContext): Promise<void> {
registerComponent({
type: PluginComponentType.Panel,
name: ctx.params.panel_name,
component: defineCustomPanel(ctx.params),
label: ctx.params.panel_label,
activator: () => true,
panelOptions: {
allowDuplicates: ctx.params.allow_duplicates,
},
});
registerPanel(ctx);
}
}

Expand Down
1 change: 0 additions & 1 deletion app/packages/operators/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,3 @@ export enum OPERATOR_PROMPT_AREAS {
DRAWER_LEFT = "operator_prompt_area_drawer_left",
DRAWER_RIGHT = "operator_prompt_area_drawer_right",
}
export const PANEL_LOAD_TIMEOUT = 5000;
10 changes: 10 additions & 0 deletions fiftyone/operators/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
| `voxel51.com <https://voxel51.com/>`_
|
"""

import json

from bson import json_util
Expand Down Expand Up @@ -265,6 +266,9 @@ def register_panel(
self,
name,
label,
icon=None,
dark_icon=None,
light_icon=None,
on_load=None,
on_unload=None,
on_change=None,
Expand All @@ -275,6 +279,9 @@ def register_panel(
Args:
name: the name of the panel to register
icon (None): the icon to display in the panel tab
dark_icon (None): the icon to display in the panel tab in dark mode of app
light_icon (None): the icon to display in the panel tab in light mode of app
on_load (None): an operator to invoke when the panel is loaded
on_unload (None): an operator to invoke when the panel is unloaded
on_change (None): an operator to invoke when the panel state changes
Expand All @@ -283,6 +290,9 @@ def register_panel(
params = {
"panel_name": name,
"panel_label": label,
"icon": icon,
"dark_icon": dark_icon,
"light_icon": light_icon,
"on_load": on_load,
"on_unload": on_unload,
"on_change": on_change,
Expand Down
18 changes: 17 additions & 1 deletion fiftyone/operators/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,22 @@
class PanelOperatorConfig(OperatorConfig):
"""A configuration for a panel operator."""

def __init__(self, name, label, icon=None, allow_multiple=False, **kwargs):
def __init__(
self,
name,
label,
icon=None,
dark_icon=None,
light_icon=None,
allow_multiple=False,
**kwargs
):
super().__init__(name)
self.name = name
self.label = label
self.icon = icon
self.dark_icon = dark_icon
self.light_icon = light_icon
self.allow_multiple = allow_multiple
self.unlisted = True
self.on_startup = True
Expand All @@ -30,6 +41,8 @@ def to_json(self):
"name": self.name,
"label": self.label,
"icon": self.icon,
"dark_icon": self.dark_icon,
"light_icon": self.light_icon,
"allow_multiple": self.allow_multiple,
}

Expand All @@ -53,6 +66,9 @@ def on_startup(self, ctx):
"name": self.config.name,
"label": self.config.label,
"allow_duplicates": self.config.allow_multiple,
"icon": self.config.icon,
"dark_icon": self.config.dark_icon,
"light_icon": self.config.light_icon,
}
methods = ["on_load", "on_unload", "on_change", "on_view_change"]
for method in methods:
Expand Down

0 comments on commit cebb04f

Please sign in to comment.