From 27c3bf8682a50ae13e8a193f517ff8c554e189b9 Mon Sep 17 00:00:00 2001 From: Br2850 Date: Wed, 23 Oct 2024 00:43:18 -0600 Subject: [PATCH 1/5] add toastView to python panels --- .../components/src/components/Toast/Toast.tsx | 73 +++++++++++++------ .../plugins/SchemaIO/components/ToastView.tsx | 18 +++++ .../src/plugins/SchemaIO/components/index.ts | 1 + app/packages/operators/src/types.ts | 15 ++++ fiftyone/operators/types.py | 15 ++++ fiftyone/server/main.py | 8 +- 6 files changed, 105 insertions(+), 25 deletions(-) create mode 100644 app/packages/core/src/plugins/SchemaIO/components/ToastView.tsx diff --git a/app/packages/components/src/components/Toast/Toast.tsx b/app/packages/components/src/components/Toast/Toast.tsx index c16c7ec733..29c799650b 100644 --- a/app/packages/components/src/components/Toast/Toast.tsx +++ b/app/packages/components/src/components/Toast/Toast.tsx @@ -2,12 +2,22 @@ import React from "react"; import { atom, useRecoilState } from "recoil"; import { Box, Snackbar, SnackbarContent } from "@mui/material"; -// Define types for the props interface ToastProps { message: React.ReactNode; - primary: (setOpen: React.Dispatch>) => React.ReactNode; - secondary: (setOpen: React.Dispatch>) => React.ReactNode; - duration?: number; // Optional duration, with a default value + primary: ( + setOpen: React.Dispatch> + ) => React.ReactNode; + secondary: ( + setOpen: React.Dispatch> + ) => React.ReactNode; + duration?: number; + layout?: { + vertical?: "top" | "bottom"; + horizontal?: "left" | "center" | "right"; + height?: number | string; + backgroundColor?: string; + color?: string; + }; } const toastStateAtom = atom({ @@ -15,41 +25,56 @@ const toastStateAtom = atom({ default: true, }); -const Toast: React.FC = ({message, primary, secondary, duration = 5000 }) => { - - const [open, setOpen] = useRecoilState(toastStateAtom); // State management for toast visibility +const Toast: React.FC = ({ + message, + primary, + secondary, + duration = 5000, + layout = {}, +}) => { + const [open, setOpen] = useRecoilState(toastStateAtom); - const handleClose = (event, reason) => { - if (reason === "clickaway") { - return; - } - setOpen(false); - }; + const handleClose = React.useCallback( + (event, reason) => { + if (reason === "clickaway") return; + setOpen(false); + }, + [setOpen] + ); - const action = ( -
- - {primary(setOpen)} {/* Pass setOpen to primary button */} - {secondary(setOpen)} {/* Pass setOpen to secondary button */} - -
+ const action = React.useMemo( + () => ( +
+ + {primary(setOpen)} + {secondary(setOpen)} + +
+ ), + [primary, secondary, setOpen] ); return ( ); -} +}; export default Toast; diff --git a/app/packages/core/src/plugins/SchemaIO/components/ToastView.tsx b/app/packages/core/src/plugins/SchemaIO/components/ToastView.tsx new file mode 100644 index 0000000000..52458d2d06 --- /dev/null +++ b/app/packages/core/src/plugins/SchemaIO/components/ToastView.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import { Toast } from "@fiftyone/components"; + +export default function ToastView(props) { + const { schema } = props; + const { view = {} } = schema; + const { message, primary, secondary, duration, layout } = view; + + return ( + + ); +} diff --git a/app/packages/core/src/plugins/SchemaIO/components/index.ts b/app/packages/core/src/plugins/SchemaIO/components/index.ts index ed79e70f65..6e2e35e567 100644 --- a/app/packages/core/src/plugins/SchemaIO/components/index.ts +++ b/app/packages/core/src/plugins/SchemaIO/components/index.ts @@ -50,5 +50,6 @@ export { default as TabsView } from "./TabsView"; export { default as TagsView } from "./TagsView"; export { default as TextView } from "./TextView"; export { default as TextFieldView } from "./TextFieldView"; +export { default as ToastView } from "./ToastView"; export { default as TupleView } from "./TupleView"; export { default as UnsupportedView } from "./UnsupportedView"; diff --git a/app/packages/operators/src/types.ts b/app/packages/operators/src/types.ts index 1f8d1b414c..1051765ff2 100644 --- a/app/packages/operators/src/types.ts +++ b/app/packages/operators/src/types.ts @@ -1196,6 +1196,20 @@ export class ModalView extends Button { } } +/** + * Operator class for describing a ToastView {@link View} for an + * operator type. + */ +export class ToastView extends View { + constructor(options: ViewProps) { + super(options); + this.name = "ToastView"; + } + static fromJSON(json) { + return new ToastView(json); + } +} + /** * Places where you can have your operator placement rendered. */ @@ -1267,6 +1281,7 @@ const VIEWS = { LazyFieldView, PillBadgeView, ModalView, + ToastView, }; export function typeFromJSON({ name, ...rest }): ANY_TYPE { diff --git a/fiftyone/operators/types.py b/fiftyone/operators/types.py index a0205ca1b7..5931dce8e8 100644 --- a/fiftyone/operators/types.py +++ b/fiftyone/operators/types.py @@ -1813,6 +1813,21 @@ def to_json(self): return {**super().to_json(), "severity": self.severity} +class ToastView(View): + """Displays a snackbar style toast element. + + Args: + message: the message to display + primary (None): the primary button text + secondary (None): the secondary button text + duration (None): the duration to stay on screen in milliseconds + layout (None): the layout of the toast + """ + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + class CheckboxView(View): """Displays a checkbox. diff --git a/fiftyone/server/main.py b/fiftyone/server/main.py index 13bd357d5e..4fbc65a1cb 100644 --- a/fiftyone/server/main.py +++ b/fiftyone/server/main.py @@ -21,10 +21,12 @@ import fiftyone as fo import fiftyone.constants as foc +import fiftyone.zoo as foz from fiftyone.server.app import app from fiftyone.server.events import set_port + DEBUG_LOGGING = fo.config.logging_level == "DEBUG" if DEBUG_LOGGING: @@ -47,4 +49,8 @@ if args.clean_start: fo.delete_datasets("*") - asyncio.run(serve(app, config), debug=DEBUG_LOGGING) + dataset_directory = "." + dataset = foz.load_zoo_dataset("quickstart") + + +asyncio.run(serve(app, config), debug=DEBUG_LOGGING) From a37b4f802a28532029d82f0ec07cb4f279faa463 Mon Sep 17 00:00:00 2001 From: Br2850 Date: Wed, 23 Oct 2024 01:54:23 -0600 Subject: [PATCH 2/5] top and bottom positioning --- .../components/src/components/Toast/Toast.tsx | 76 ++++++++++++------- .../plugins/SchemaIO/components/ToastView.tsx | 12 +-- fiftyone/operators/types.py | 16 +++- 3 files changed, 63 insertions(+), 41 deletions(-) diff --git a/app/packages/components/src/components/Toast/Toast.tsx b/app/packages/components/src/components/Toast/Toast.tsx index 29c799650b..ca5f509a49 100644 --- a/app/packages/components/src/components/Toast/Toast.tsx +++ b/app/packages/components/src/components/Toast/Toast.tsx @@ -4,17 +4,15 @@ import { Box, Snackbar, SnackbarContent } from "@mui/material"; interface ToastProps { message: React.ReactNode; - primary: ( - setOpen: React.Dispatch> - ) => React.ReactNode; - secondary: ( - setOpen: React.Dispatch> - ) => React.ReactNode; + primary?: any; + secondary?: any; duration?: number; layout?: { vertical?: "top" | "bottom"; horizontal?: "left" | "center" | "right"; height?: number | string; + top?: number | string; + bottom?: number | string; backgroundColor?: string; color?: string; }; @@ -32,45 +30,65 @@ const Toast: React.FC = ({ duration = 5000, layout = {}, }) => { - const [open, setOpen] = useRecoilState(toastStateAtom); + const snackbarStyle = { + height: layout?.height || 5, + ...(layout?.top && { + top: { + xs: layout.top, + sm: layout.top, + md: layout.top, + lg: layout.top, + xl: layout.top, + }, + }), + ...(layout?.bottom && { + bottom: { + xs: layout.bottom, + sm: layout.bottom, + md: layout.bottom, + lg: layout.bottom, + xl: layout.bottom, + }, + }), + }; - const handleClose = React.useCallback( - (event, reason) => { - if (reason === "clickaway") return; - setOpen(false); - }, - [setOpen] - ); + const [open, setOpen] = useRecoilState(toastStateAtom); // State management for toast visibility + + const handleClose = (event, reason) => { + if (reason === "clickaway") { + return; + } + setOpen(false); + }; - const action = React.useMemo( - () => ( -
- - {primary(setOpen)} - {secondary(setOpen)} - -
- ), - [primary, secondary, setOpen] + const action = ( +
+ + {/* note: Not implemented within Python Panels context */} + {primary && primary(setOpen)} {/* Pass setOpen to primary button */} + {secondary && secondary(setOpen)}{" "} + {/* Pass setOpen to secondary button */} + +
); return ( diff --git a/app/packages/core/src/plugins/SchemaIO/components/ToastView.tsx b/app/packages/core/src/plugins/SchemaIO/components/ToastView.tsx index 52458d2d06..b5a8708cd5 100644 --- a/app/packages/core/src/plugins/SchemaIO/components/ToastView.tsx +++ b/app/packages/core/src/plugins/SchemaIO/components/ToastView.tsx @@ -4,15 +4,7 @@ import { Toast } from "@fiftyone/components"; export default function ToastView(props) { const { schema } = props; const { view = {} } = schema; - const { message, primary, secondary, duration, layout } = view; + const { message, duration, layout } = view; - return ( - - ); + return ; } diff --git a/fiftyone/operators/types.py b/fiftyone/operators/types.py index 5931dce8e8..407e9956ff 100644 --- a/fiftyone/operators/types.py +++ b/fiftyone/operators/types.py @@ -1816,10 +1816,22 @@ def to_json(self): class ToastView(View): """Displays a snackbar style toast element. + Examples:: + + schema = { + "message": "Test", + "duration": 30000, + "layout": { + "vertical": "top", + "horizontal": "center", + "top": "200px" + }, + } + snackbar = types.ToastView(**schema) + panel.obj("toast", view=snackbar) + Args: message: the message to display - primary (None): the primary button text - secondary (None): the secondary button text duration (None): the duration to stay on screen in milliseconds layout (None): the layout of the toast """ From 57711116f0959dc92b4bb55cdee3338af44fa4df Mon Sep 17 00:00:00 2001 From: Br2850 Date: Wed, 23 Oct 2024 01:57:53 -0600 Subject: [PATCH 3/5] cleanup --- app/packages/components/src/components/Toast/Toast.tsx | 2 +- fiftyone/server/main.py | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/app/packages/components/src/components/Toast/Toast.tsx b/app/packages/components/src/components/Toast/Toast.tsx index ca5f509a49..04d0b93f7a 100644 --- a/app/packages/components/src/components/Toast/Toast.tsx +++ b/app/packages/components/src/components/Toast/Toast.tsx @@ -75,7 +75,7 @@ const Toast: React.FC = ({ return ( Date: Wed, 23 Oct 2024 02:29:28 -0600 Subject: [PATCH 4/5] Update Toast.tsx --- app/packages/components/src/components/Toast/Toast.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/packages/components/src/components/Toast/Toast.tsx b/app/packages/components/src/components/Toast/Toast.tsx index 04d0b93f7a..5048016eb6 100644 --- a/app/packages/components/src/components/Toast/Toast.tsx +++ b/app/packages/components/src/components/Toast/Toast.tsx @@ -86,7 +86,7 @@ const Toast: React.FC = ({ Date: Wed, 23 Oct 2024 02:43:27 -0600 Subject: [PATCH 5/5] font styling --- app/packages/components/src/components/Toast/Toast.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/packages/components/src/components/Toast/Toast.tsx b/app/packages/components/src/components/Toast/Toast.tsx index 04d0b93f7a..d429e6476c 100644 --- a/app/packages/components/src/components/Toast/Toast.tsx +++ b/app/packages/components/src/components/Toast/Toast.tsx @@ -15,6 +15,8 @@ interface ToastProps { bottom?: number | string; backgroundColor?: string; color?: string; + fontSize?: string; + textAlign?: string; }; } @@ -86,9 +88,12 @@ const Toast: React.FC = ({