Skip to content

Commit

Permalink
Merge branch 'panel' of github.com:voxel51/fiftyone into panel
Browse files Browse the repository at this point in the history
  • Loading branch information
Br2850 committed Oct 22, 2024
2 parents 6f81d66 + 4972cbc commit dfb8681
Show file tree
Hide file tree
Showing 78 changed files with 2,675 additions and 344 deletions.
41 changes: 41 additions & 0 deletions app/packages/components/src/components/Toast/Toast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { useState } from "react";
import { Snackbar, Button, SnackbarContent } from "@mui/material";
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import BoltIcon from '@mui/icons-material/Bolt'; // Icon for the lightning bolt

// Define types for the props
interface ToastProps {
action: React.ReactNode; // Accepts any valid React component, element, or JSX
message: React.ReactNode; // Accepts any valid React component, element, or JSX
duration?: number; // Optional duration, with a default value
}

const Toast: React.FC<ToastProps> = ({ action, message, duration = 5000 }) => {
const [open, setOpen] = useState(true);

const handleClose = (event, reason) => {
if (reason === "clickaway") {
return;
}
setOpen(false);
};

return (
<Snackbar
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
open={open}
onClose={handleClose}
autoHideDuration={duration}
sx={{ height: 5 }}
>
<SnackbarContent
message={message}
action={action}
style={{ backgroundColor: "#333", color: "#fff" }}
/>
</Snackbar>
);
}

export default Toast;
1 change: 1 addition & 0 deletions app/packages/components/src/components/Toast/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {default as Toast} from "./Toast";
1 change: 1 addition & 0 deletions app/packages/components/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ export { default as TabOption } from "./TabOption";
export { default as TextField } from "./TextField";
export { default as ThemeProvider, useFont, useTheme } from "./ThemeProvider";
export { default as Tooltip } from "./Tooltip";
export { Toast } from "./Toast";

export * from "./types";
19 changes: 11 additions & 8 deletions app/packages/core/src/components/Actions/Options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
useResetRecoilState,
useSetRecoilState,
} from "recoil";
import { LIGHTNING_MODE, SIDEBAR_MODE } from "../../utils/links";
import { QP_MODE, SIDEBAR_MODE } from "../../utils/links";
import Checkbox from "../Common/Checkbox";
import RadioGroup from "../Common/RadioGroup";
import { Button } from "../utils";
Expand Down Expand Up @@ -216,19 +216,22 @@ const DynamicGroupsViewMode = ({ modal }: { modal: boolean }) => {
);
};

const Lightning = () => {
const QueryPerformance = () => {
const [threshold, setThreshold] = useRecoilState(fos.lightningThreshold);
const config = useRecoilValue(fos.lightningThresholdConfig);
const reset = useResetRecoilState(fos.lightningThreshold);
const count = useRecoilValue(fos.datasetSampleCount);
const theme = useTheme();
const enableQueryPerformanceConfig = useRecoilValue(fos.enableQueryPerformanceConfig);
const defaultQueryPerformanceConfig = useRecoilValue(fos.defaultQueryPerformanceConfig);
const enableQpMode = enableQueryPerformanceConfig && defaultQueryPerformanceConfig;

return (
if (enableQpMode) return (
<>
<ActionOption
id="lightning-mode"
id="qp-mode"
text="Query Performance mode"
href={LIGHTNING_MODE}
href={QP_MODE}
title={"More on Query Performance mode"}
style={{
background: "unset",
Expand All @@ -239,11 +242,11 @@ const Lightning = () => {
svgStyles={{ height: "1rem", marginTop: 7.5 }}
/>
<TabOption
active={threshold === null ? "disable" : "enable"}
active={(threshold === null) ? "disable" : "enable"}
options={["disable", "enable"].map((value) => ({
text: value,
title: value,
dataCy: `lightning-mode-${value}`,
dataCy: `qp-mode-${value}`,
onClick: () =>
setThreshold(value === "disable" ? null : config ?? count),
}))}
Expand Down Expand Up @@ -372,7 +375,7 @@ const Options = ({ modal, anchorRef }: OptionsProps) => {
{isGroup && !isDynamicGroup && <GroupStatistics modal={modal} />}
<MediaFields modal={modal} />
<Patches modal={modal} />
{!view?.length && <Lightning />}
{!view?.length && <QueryPerformance />}
{!modal && <SidebarMode />}
<SortFilterResults modal={modal} />
</Popout>
Expand Down
4 changes: 2 additions & 2 deletions app/packages/core/src/components/FieldLabelAndInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
} from "recoil";
import styled from "styled-components";
import { ExternalLink } from "../../utils/generic";
import { LIGHTNING_MODE } from "../../utils/links";
import { QP_MODE } from "../../utils/links";
import { activeColorEntry } from "../ColorModal/state";

const selectedFieldInfo = atom<string | null>({
Expand Down Expand Up @@ -345,7 +345,7 @@ const Lightning: React.FunctionComponent<LightningProp> = ({ color, path }) => {
<ContentValue>
<ExternalLink
style={{ color: theme.text.primary }}
href={LIGHTNING_MODE}
href={QP_MODE}
>
Lightning indexed
</ExternalLink>
Expand Down
2 changes: 1 addition & 1 deletion app/packages/core/src/components/Grid/useFontSize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useCallback } from "react";
import useThreshold from "./useThreshold";

const MAX = 32;
const MIN = 10;
const MIN = 14;
const SCALE_FACTOR = 0.09;

export default (id: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const DynamicGroupsFlashlightWrapper = React.memo(() => {
);

const createLooker = fos.useCreateLooker(
false,
true,
true,
{
...opts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const Column: React.FC = () => {
);

const createLooker = fos.useCreateLooker(
false,
true,
true,
{
...opts,
Expand Down
12 changes: 12 additions & 0 deletions app/packages/core/src/components/Modal/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { describe, expect, it } from "vitest";
import { shortcutToHelpItems } from "./utils";

describe("shortcut processing test", () => {
it("parses unique shortcuts", () => {
const results = shortcutToHelpItems({
one: { shortcut: "test" },
two: { shortcut: "test" },
});
expect(results).toStrictEqual([{ shortcut: "test" }]);
});
});
16 changes: 11 additions & 5 deletions app/packages/core/src/components/Modal/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
export function shortcutToHelpItems(SHORTCUTS) {
const result = {};
for (const k of SHORTCUTS) {
result[SHORTCUTS[k].shortcut] = SHORTCUTS[k];
interface ShortcutItem {
shortcut: string;
}

type Shortcuts = { [key: string]: ShortcutItem };

export function shortcutToHelpItems(SHORTCUTS: Shortcuts) {
const uniqueItems = {};
for (const item of Object.values(SHORTCUTS)) {
uniqueItems[item.shortcut] = item;
}
return Object.values(result);
return Object.values(uniqueItems);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { RecoilState, useRecoilState } from "recoil";
import { useTheme } from "styled-components";
import {
FRAME_FILTERING_DISABLED,
LIGHTNING_MODE,
QP_MODE,
} from "../../../../utils/links";
import DisabledReason from "./DisabledReason";

Expand Down Expand Up @@ -60,7 +60,7 @@ export default ({
if (unindexed && !unlocked) {
return (
<Tooltip
text={<DisabledReason text={"add an index"} href={LIGHTNING_MODE} />}
text={<DisabledReason text={"add an index"} href={QP_MODE} />}
placement="top-center"
>
{arrow}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Tune } from "@mui/icons-material";
import React from "react";
import type { RecoilState } from "recoil";
import { useSetRecoilState } from "recoil";
import { LIGHTNING_MODE } from "../../../../utils/links";
import { QP_MODE } from "../../../../utils/links";
import DisabledReason from "./DisabledReason";

export default ({
Expand Down Expand Up @@ -54,7 +54,7 @@ export default ({
if (disabled) {
return (
<Tooltip
text={<DisabledReason href={LIGHTNING_MODE} text={"add an index"} />}
text={<DisabledReason href={QP_MODE} text={"add an index"} />}
placement="top-center"
>
{children}
Expand Down
108 changes: 108 additions & 0 deletions app/packages/core/src/plugins/SchemaIO/components/ActionsMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { MuiIconFont } from "@fiftyone/components";
import { MoreVert } from "@mui/icons-material";
import {
Box,
Button,
IconButton,
ListItemIcon,
ListItemText,
Menu,
MenuItem,
Stack,
} from "@mui/material";
import React, { useCallback } from "react";

const DEFAULT_MAX_INLINE = 1;

export default function ActionsMenu(props: ActionsPropsType) {
const { actions, maxInline = DEFAULT_MAX_INLINE } = props;

if (actions.length === maxInline) {
return (
<Stack direction="row" spacing={0.5} justifyContent="flex-end">
{actions.map((action) => (
<Action {...action} key={action.name} mode="inline" />
))}
</Stack>
);
}

return <ActionsOverflowMenu actions={actions} />;
}

function ActionsOverflowMenu(props: ActionsPropsType) {
const { actions } = props;
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);

const handleClose = useCallback(() => {
setOpen(false);
}, []);

return (
<Box>
<IconButton
onClick={() => {
setOpen(!open);
}}
ref={anchorRef}
>
<MoreVert />
</IconButton>
<Menu open={open} onClose={handleClose} anchorEl={anchorRef.current}>
{actions.map((action) => {
const { name, onClick } = action;
return (
<Action
key={name}
{...action}
mode="menu"
onClick={(action, e) => {
handleClose();
onClick?.(action, e);
}}
/>
);
})}
</Menu>
</Box>
);
}

function Action(props: ActionPropsType) {
const { label, name, onClick, icon, variant, mode } = props;

const Icon = icon ? <MuiIconFont name={icon} /> : null;

const handleClick = useCallback(
(e: React.MouseEvent) => {
onClick?.(props, e);
},
[onClick, props]
);

return mode === "inline" ? (
<Button variant={variant} startIcon={Icon} onClick={handleClick}>
{label}
</Button>
) : (
<MenuItem onClick={handleClick}>
{Icon && <ListItemIcon>{Icon}</ListItemIcon>}
<ListItemText>{label || name}</ListItemText>
</MenuItem>
);
}

type ActionsPropsType = {
actions: Array<ActionPropsType>;
maxInline?: number;
};

type ActionPropsType = {
name: string;
label: string;
onClick: (action: ActionPropsType, e: React.MouseEvent) => void;
icon: string;
variant: string;
mode: "inline" | "menu";
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
overlayToSx,
} from "../utils";
import { ViewPropsType } from "../utils/types";
import { has } from "lodash";

export default function ContainerizedComponent(props: ContainerizedComponent) {
const { schema, children } = props;
Expand All @@ -22,7 +23,11 @@ export default function ContainerizedComponent(props: ContainerizedComponent) {
}

if (isCompositeView(schema)) {
const hasOverlay = !!schema?.view?.overlay;
const sxForOverlay = overlayToSx[schema?.view?.overlay] || {};
if (hasOverlay) {
sxForOverlay.zIndex = 999;
}
return (
<Box sx={{ position: "relative", ...sxForOverlay }}>
{containerizedChildren}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import React, { useEffect, useRef, useState } from "react";
import { ObjectSchemaType, ViewPropsType } from "../utils/types";
import {
DEFAULT_FRAME_NUMBER,
GLOBAL_TIMELINE_ID,
} from "@fiftyone/playback/src/lib/constants";
import { DEFAULT_FRAME_NUMBER } from "@fiftyone/playback/src/lib/constants";
import { BufferManager, BufferRange } from "@fiftyone/utilities";
import { usePanelEvent } from "@fiftyone/operators";
import { usePanelId, useSetPanelStateById } from "@fiftyone/spaces";
Expand All @@ -13,7 +10,7 @@ import _ from "lodash";
export default function FrameLoaderView(props: ViewPropsType) {
const { schema, path, data } = props;
const { view = {} } = schema;
const { on_load_range, timeline_id, target } = view;
const { on_load_range, target, timeline_name } = view;
const panelId = usePanelId();
const triggerEvent = usePanelEvent();
const setPanelState = useSetPanelStateById(true);
Expand Down Expand Up @@ -76,14 +73,14 @@ export default function FrameLoaderView(props: ViewPropsType) {
[data, setPanelState, panelId, target]
);

const { isTimelineInitialized, subscribe } = useTimeline();
const { isTimelineInitialized, subscribe } = useTimeline(timeline_name);
const [subscribed, setSubscribed] = useState(false);

React.useEffect(() => {
if (subscribed) return;
if (isTimelineInitialized) {
subscribe({
id: timeline_id || GLOBAL_TIMELINE_ID,
id: panelId,
loadRange,
renderFrame: myRenderFrame,
});
Expand Down
Loading

0 comments on commit dfb8681

Please sign in to comment.