Skip to content

Commit

Permalink
Remove suspend from 3D viewer during modal navigation (voxel51#4253)
Browse files Browse the repository at this point in the history
* add none fields filter in modal to sidebar entries

* reuse sample parsing

* add sidebar sample parsing tests

* add hiddenNoneGroups tests

* add multi-slice cases
  • Loading branch information
benjaminpkane authored Apr 16, 2024
1 parent abfe0f7 commit deaf08c
Show file tree
Hide file tree
Showing 7 changed files with 353 additions and 102 deletions.
11 changes: 1 addition & 10 deletions app/packages/core/src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ const SampleModal = () => {
const isGroup = useRecoilValue(fos.isGroup);
const isPcd = useRecoilValue(fos.isPointcloudDataset);
const is3D = useRecoilValue(fos.is3DDataset);
const sampleId = useRecoilValue(fos.currentSampleId);

const clearModal = fos.useClearModal();
const { jsonPanel, helpPanel, onNavigate } = usePanels();
const tooltip = fos.useTooltip();
Expand Down Expand Up @@ -111,9 +109,6 @@ const SampleModal = () => {
[tooltipEventHandler]
);

const noneValuedPaths = useRecoilValue(fos.noneValuedPaths)?.[sampleId];
const hideNoneFields = useRecoilValue(fos.hideNoneValuedFields);

const renderEntry = useCallback(
(
key: string,
Expand All @@ -135,10 +130,6 @@ const SampleModal = () => {
const isFieldPrimitive =
!isLabelTag && !isLabel && !isOther && !(isTag && mode === "group");

if (hideNoneFields && noneValuedPaths?.has(entry?.path)) {
return { children: null };
}

return {
children: (
<>
Expand Down Expand Up @@ -208,7 +199,7 @@ const SampleModal = () => {
throw new Error("invalid entry");
}
},
[disabled, hideNoneFields, labelPaths, mode, noneValuedPaths]
[disabled, labelPaths, mode]
);

useEffect(() => {
Expand Down
94 changes: 16 additions & 78 deletions app/packages/core/src/components/Sidebar/Entries/PathValueEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,14 @@ import * as fos from "@fiftyone/state";
import {
DATE_FIELD,
DATE_TIME_FIELD,
DYNAMIC_EMBEDDED_DOCUMENT_FIELD,
EMBEDDED_DOCUMENT_FIELD,
formatDate,
formatDateTime,
FRAME_SUPPORT_FIELD,
} from "@fiftyone/utilities";
import { KeyboardArrowDown, KeyboardArrowUp } from "@mui/icons-material";
import { useSpring } from "@react-spring/core";
import React, { Suspense, useMemo, useState } from "react";
import {
selectorFamily,
useRecoilState,
useRecoilValue,
useRecoilValueLoadable,
} from "recoil";
import { selectorFamily, useRecoilValue, useRecoilValueLoadable } from "recoil";
import styled from "styled-components";
import LoadingDots from "../../../../../components/src/components/Loading/LoadingDots";
import { prettify } from "../../../utils/generic";
Expand Down Expand Up @@ -314,7 +307,7 @@ const SlicesLoadable = ({ path }: { path: string }) => {
);
};

const useSlicesData = <T extends unknown>(path: string) => {
const useSlicesData = <T,>(path: string) => {
const keys = path.split(".");
const loadable = useRecoilValueLoadable(fos.activePcdSlicesToSampleMap);
const slices = Array.from(useRecoilValue(fos.activePcdSlices) || []).sort();
Expand All @@ -328,28 +321,20 @@ const useSlicesData = <T extends unknown>(path: string) => {
}

if (!slices.every((slice) => loadable.contents[slice])) {
throw new Promise(() => {});
throw new Promise(() => null);
}

const data = { ...loadable.contents };
const data = { ...loadable.contents } as object;

const target = useRecoilValue(fos.field(keys[0]));
const target = fos.useAssertedRecoilValue(fos.field(keys[0]));
const isList = useRecoilValue(fos.isOfDocumentFieldList(path));
slices.forEach((slice) => {
let sliceData = data[slice].sample;
let field = target;

for (let index = 0; index < keys.length; index++) {
if (!sliceData) {
break;
}
const key = keys[index];
sliceData = sliceData[field?.dbField || key];

if (keys[index + 1]) {
field = field?.fields[keys[index + 1]];
}
}
data[slice] = sliceData;
data[slice] = fos.pullSidebarValue(
target,
keys,
data[slice].sample,
isList
);
});

return data as { [slice: string]: T };
Expand All @@ -374,73 +359,26 @@ const Loadable = ({ path }: { path: string }) => {
);
};

const isOfDocumentFieldList = selectorFamily({
key: "isOfDocumentField",
get:
(path: string) =>
({ get }) => {
const field = get(fos.field(path.split(".")[0]));

return [
DYNAMIC_EMBEDDED_DOCUMENT_FIELD,
EMBEDDED_DOCUMENT_FIELD,
].includes(field?.subfield || "");
},
});

const useData = <T,>(path: string): T => {
const keys = path.split(".");
const loadable = useRecoilValueLoadable(fos.activeModalSidebarSample);
const [noneValuedPaths, setNoneValued] = useRecoilState(fos.noneValuedPaths);
const sampleId = useRecoilValue(fos.currentSampleId);

if (loadable.state === "loading") {
throw loadable.contents;
}

if (loadable.state === "hasError") {
if (loadable.contents instanceof fos.SampleNotFound) {
throw new Promise(() => {});
throw new Promise(() => null);
}

throw loadable.contents;
}

let data = loadable.contents;
let field = useRecoilValue(fos.field(keys[0]));

if (useRecoilValue(isOfDocumentFieldList(path))) {
data = data?.[field?.dbField || keys[0]]?.map((d) => d[keys[1]]);
} else {
for (let index = 0; index < keys.length; index++) {
if (!data) {
break;
}
const key = keys[index];
data = data[field?.dbField || key];

if (keys[index + 1]) {
field = field?.fields?.[keys[index + 1]] || null;
}
}
}

const noneValued = noneValuedPaths?.[sampleId];
if (
(data === undefined || data === null) &&
path &&
!noneValued?.has(path) &&
sampleId
) {
const newNoneValued = noneValued
? new Set([...noneValued]).add(path)
: new Set([path]);
if (newNoneValued) {
setNoneValued({ [sampleId]: new Set([...newNoneValued, path]) });
}
}
const field = fos.useAssertedRecoilValue(fos.field(keys[0]));
const isList = useRecoilValue(fos.isOfDocumentFieldList(path));

return data as T;
return fos.pullSidebarValue(field, keys, loadable.contents, isList) as T;
};

const isScalarValue = selectorFamily({
Expand Down
2 changes: 1 addition & 1 deletion app/packages/core/src/components/Sidebar/Entries/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import Filter from "./FilterEntry";
import { PathGroupEntry as PathGroup } from "./GroupEntries";
import PathValue from "./PathValueEntry";

export { AddGroup, Empty, FilterablePath, Filter, PathGroup, PathValue };
export { AddGroup, Empty, Filter, FilterablePath, PathGroup, PathValue };
19 changes: 10 additions & 9 deletions app/packages/core/src/components/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,12 @@ const measureGroups = (
data: { top: number; height: number; key: string }[];
activeHeight: number;
} => {
const data = [];
let current = {
top: -MARGIN,
height: 0,
key: getEntryKey(items[order[0]].entry),
};
const data: typeof current[] = [];
let activeHeight = -MARGIN;

for (let i = 0; i < order.length; i++) {
Expand Down Expand Up @@ -264,32 +264,33 @@ const isDisabledEntry = (
};

const getAfterKey = (
activeKey: string,
activeKey: string | null,
items: InteractiveItems,
order: string[],
direction: Direction,
disabled: Set<string>
): string | null => {
if (!items[activeKey]) {
return;
if (activeKey === null || !items[activeKey]) {
return null;
}

const up = direction === Direction.UP;
const baseTop = items[order[0]].el.parentElement.getBoundingClientRect().y;
const baseTop =
items[order[0]].el.parentElement?.getBoundingClientRect().y || 0;
const isGroup = items[activeKey].entry.kind === fos.EntryKind.GROUP;
let { data, activeHeight } = isGroup
const measurement = isGroup
? measureGroups(activeKey, items, order)
: measureEntries(activeKey, items, order);

data = data.filter(
const data = measurement.data.filter(
({ key }) => !isDisabledEntry(items[key].entry, disabled, !isGroup)
);

const { top } = items[activeKey].el.getBoundingClientRect();
let y = top - baseTop;

if (!up) {
y += activeHeight;
y += measurement.activeHeight;
}

let filtered = data
Expand Down Expand Up @@ -435,7 +436,7 @@ const InteractiveSidebar = ({
throw entries;
}

let group = null;
let group: string | null = null;
order.current = [...entries].map((entry) => getEntryKey(entry));
for (const entry of entries) {
const key = getEntryKey(entry);
Expand Down
18 changes: 16 additions & 2 deletions app/packages/state/src/recoil/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ import {
LABEL_LISTS,
LABEL_LISTS_MAP,
LIST_FIELD,
meetsFieldType,
OBJECT_ID_FIELD,
STRING_FIELD,
Schema,
StrictField,
STRING_FIELD,
VALID_NUMERIC_TYPES,
VALID_PRIMITIVE_TYPES,
meetsFieldType,
withPath,
} from "@fiftyone/utilities";
import { RecoilState, selector, selectorFamily } from "recoil";
Expand Down Expand Up @@ -780,3 +780,17 @@ export const parentField = selectorFamily({
return get(field(parent));
},
});

export const isOfDocumentFieldList = selectorFamily({
key: "isOfDocumentFieldList",
get:
(path: string) =>
({ get }) => {
const f = get(field(path.split(".")[0]));

return [
DYNAMIC_EMBEDDED_DOCUMENT_FIELD,
EMBEDDED_DOCUMENT_FIELD,
].includes(f.subfield || "");
},
});
Loading

0 comments on commit deaf08c

Please sign in to comment.