From 7d4edfe14c7805d05324acd3f12422f66324a59f Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Thu, 1 Jun 2023 12:12:22 -0700 Subject: [PATCH 01/80] Refactor schemaControls, use selectField() when searching, cleaner schema documentation selection mode is default now for filed visibility --- .../components/Schema/SchemaSearchHelp.tsx | 14 +- .../Schema/SchemaSelectControls.tsx | 131 +++++++++--------- .../src/components/Schema/SchemaSelection.tsx | 1 - .../src/components/Schema/SchemaSettings.tsx | 29 ++-- .../state/src/hooks/useSchemaSettings.ts | 16 +-- 5 files changed, 100 insertions(+), 91 deletions(-) diff --git a/app/packages/core/src/components/Schema/SchemaSearchHelp.tsx b/app/packages/core/src/components/Schema/SchemaSearchHelp.tsx index 16a8175b4e..f6e76464d6 100644 --- a/app/packages/core/src/components/Schema/SchemaSearchHelp.tsx +++ b/app/packages/core/src/components/Schema/SchemaSearchHelp.tsx @@ -17,15 +17,15 @@ const EXAMPLES = [ }, { title: - '# Search across name, description, and all info.* keys for string "foo"', + 'Search across name, description, and all info.* keys for string "foo"', code: "foo", }, { - title: '# Match fields whose name contains "ground_truth"', + title: 'Match fields whose name contains "ground_truth"', code: "name:ground_truth", }, { - title: "# Match fields whose owner contains “foo”", + title: "Match fields whose owner contains “foo”", code: "info.owner:foo", }, { @@ -42,7 +42,7 @@ export const SchemaSearchHelp = (props: Props) => { const theme = useTheme(); return ( - + {EXAMPLES.map(({ title, primaryTextColor, code }: Example) => ( { {code && ( - + )} diff --git a/app/packages/core/src/components/Schema/SchemaSelectControls.tsx b/app/packages/core/src/components/Schema/SchemaSelectControls.tsx index 29b54f2641..7da51f915e 100644 --- a/app/packages/core/src/components/Schema/SchemaSelectControls.tsx +++ b/app/packages/core/src/components/Schema/SchemaSelectControls.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useMemo } from "react"; import { Box, FormControlLabel, FormGroup, Switch } from "@mui/material"; import Checkbox from "@mui/material/Checkbox"; @@ -32,6 +32,48 @@ export const SchemaSelectionControls = (props: Props) => { setIncludeNestedFields, } = useSchemaSettings(); const isFilterRuleMode = selectedTab === TAB_OPTIONS_MAP.FILTER_RULE; + const showMetadataVisibile = !!!(isFilterRuleMode && !searchResults.length); + const includeNestedVisible = !!(isFilterRuleMode && searchResults.length); + + const controlList = useMemo(() => { + return [ + { + label: "Show metadata", + isVisible: showMetadataVisibile, + value: showMetadata, + checked: showMetadata, + onChange: () => setShowMetadata(!showMetadata), + }, + { + label: "Include nested fields", + isVisible: includeNestedVisible, + value: includeNestedFields, + checked: includeNestedFields, + onChange: () => setIncludeNestedFields(!includeNestedFields), + disabled: !searchResults.length, + }, + { + label: "Show nested fields", + isVisible: !isFilterRuleMode, + value: showNestedFields, + checked: showNestedFields, + onChange: () => setShowNestedFields(!showNestedFields), + }, + { + label: "Select all", + isVisible: !isFilterRuleMode, + value: allFieldsChecked, + checked: allFieldsChecked, + onChange: () => setAllFieldsChecked(!allFieldsChecked), + }, + ]; + }, [ + showMetadata, + showMetadataVisibile, + includeNestedFields, + showNestedFields, + allFieldsChecked, + ]); return ( { sx={{ position: "relative !important" }} > - {!!!(isFilterRuleMode && !searchResults.length) && ( - - - setShowMetadata(!showMetadata)} - /> - } - label="Show metadata" - /> - - - )} - {!!(isFilterRuleMode && searchResults.length) && ( - - - - setIncludeNestedFields(!includeNestedFields) - } - disabled={!searchResults.length} - /> - } - label="Include nested fields" - /> - - - )} - {!isFilterRuleMode && ( - - - setShowNestedFields(!showNestedFields)} - /> - } - label="Show nested fields" - /> - - - )} - {!isFilterRuleMode && ( - - - setAllFieldsChecked(!allFieldsChecked)} - /> - } - label="Select all" - /> - - - )} + {controlList + .filter(({ isVisible }) => isVisible) + .map(({ label, value, checked, onChange, disabled = false }) => ( + + + + } + label={label} + sx={{ letterSpacing: "0.05rem" }} + /> + + + ))} ); diff --git a/app/packages/core/src/components/Schema/SchemaSelection.tsx b/app/packages/core/src/components/Schema/SchemaSelection.tsx index 3777864d52..ac8cdfb51c 100644 --- a/app/packages/core/src/components/Schema/SchemaSelection.tsx +++ b/app/packages/core/src/components/Schema/SchemaSelection.tsx @@ -142,7 +142,6 @@ export const SchemaSelection = () => { marginTop: "1rem", overflow: "auto", color: "#232323", - border: `1px solid ${theme.primary.plainBorder}`, }} > {showSearchHelp && } diff --git a/app/packages/core/src/components/Schema/SchemaSettings.tsx b/app/packages/core/src/components/Schema/SchemaSettings.tsx index fe5e9113a7..dfb3a0ab08 100644 --- a/app/packages/core/src/components/Schema/SchemaSettings.tsx +++ b/app/packages/core/src/components/Schema/SchemaSettings.tsx @@ -72,6 +72,8 @@ const SchemaSettings = () => { setLastAppliedPaths, lastAppliedPaths, setExcludedPaths, + isFilterRuleActive, + searchMetaFilter, } = useSchemaSettings(); useOutsideClick(schemaModalRef, (_) => { @@ -197,16 +199,25 @@ const SchemaSettings = () => { onClick={() => { const initialFieldNames = [...excludedPaths[datasetName]]; - const stageKwargs = { - field_names: initialFieldNames, - _allow_missing: true, - }; + let stage; + if (isFilterRuleActive) { + stage = { + _cls: "fiftyone.core.stages.SelectFields", + kwargs: { + meta_filter: searchMetaFilter, + _allow_missing: true, + }, + }; + } else { + stage = { + _cls: "fiftyone.core.stages.ExcludeFields", + kwargs: { + field_names: initialFieldNames, + _allow_missing: true, + }, + }; + } - const stageCls = "fiftyone.core.stages.ExcludeFields"; - const stage = { - _cls: stageCls, - kwargs: stageKwargs, - }; try { setSelectedFieldsStage(stage); } catch (e) { diff --git a/app/packages/state/src/hooks/useSchemaSettings.ts b/app/packages/state/src/hooks/useSchemaSettings.ts index b15edcd1d2..eafc82678b 100644 --- a/app/packages/state/src/hooks/useSchemaSettings.ts +++ b/app/packages/state/src/hooks/useSchemaSettings.ts @@ -113,7 +113,7 @@ export const showNestedFieldsState = atom({ }); export const schemaSelectedSettingsTab = atom({ key: "schemaSelectedSettingsTab", - default: TAB_OPTIONS_MAP.FILTER_RULE, + default: TAB_OPTIONS_MAP.SELECTION, }); export const settingsModal = atom<{ open: boolean } | null>({ key: "settingsModal", @@ -404,7 +404,7 @@ export default function useSchemaSettings() { const [searchTerm, setSearchTerm] = useRecoilState(schemaSearchTerm); const [searchResults, setSearchResults] = useRecoilState(schemaSearchRestuls); - const [schema, setSchema] = useRecoilState(schemaState); + const setSchema = useSetRecoilState(schemaState); useEffect(() => { if (datasetName) { setSchema(dataset ? buildSchema(dataset, true) : null); @@ -476,6 +476,7 @@ export default function useSchemaSettings() { const [selectedTab, setSelectedTab] = useRecoilState( schemaSelectedSettingsTab ); + const filterRuleTab = selectedTab === TAB_OPTIONS_MAP.FILTER_RULE; const selectedPathState = selectedPathsState({}); const [selectedPaths, setSelectedPaths] = useRecoilState<{}>( @@ -531,7 +532,6 @@ export default function useSchemaSettings() { finalSchemaKeyByPath = !isEmpty(viewSchema) ? viewSchema : fieldSchema; } - const filterRuleTab = selectedTab === TAB_OPTIONS_MAP.FILTER_RULE; const resSchema = Object.keys(finalSchemaKeyByPath) .sort() .filter((path) => { @@ -838,10 +838,7 @@ export default function useSchemaSettings() { // updates the affected fields count useEffect(() => { if (finalSchema?.length && excludedPaths?.[datasetName]) { - if ( - selectedTab === TAB_OPTIONS_MAP.FILTER_RULE && - searchResults?.length - ) { + if (filterRuleTab && searchResults?.length) { setAffectedPathCount( Object.keys(bareFinalSchema)?.length - searchResults.length ); @@ -849,9 +846,11 @@ export default function useSchemaSettings() { setAffectedPathCount(excludedPaths[datasetName].size); } } - }, [selectedTab, searchResults, excludedPaths, datasetName]); + }, [filterRuleTab, searchResults, excludedPaths, datasetName]); return { + searchMetaFilter, + filterRuleTab, settingModal, setSettingsModal, searchTerm, @@ -887,5 +886,6 @@ export default function useSchemaSettings() { searchSchemaFields, setLastAppliedPaths, lastAppliedPaths, + isFilterRuleActive: filterRuleTab, }; } From 6e263ee27c318f7c1b92fb7a9d98986fd830e7a9 Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Thu, 1 Jun 2023 12:44:34 -0700 Subject: [PATCH 02/80] update count dependency to refelct when applying filter rules --- app/packages/state/src/hooks/useSchemaSettings.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/packages/state/src/hooks/useSchemaSettings.ts b/app/packages/state/src/hooks/useSchemaSettings.ts index eafc82678b..fa0b34bf32 100644 --- a/app/packages/state/src/hooks/useSchemaSettings.ts +++ b/app/packages/state/src/hooks/useSchemaSettings.ts @@ -846,7 +846,14 @@ export default function useSchemaSettings() { setAffectedPathCount(excludedPaths[datasetName].size); } } - }, [filterRuleTab, searchResults, excludedPaths, datasetName]); + }, [ + finalSchema, + filterRuleTab, + searchResults, + excludedPaths, + datasetName, + selectedPaths, + ]); return { searchMetaFilter, From 2305bd4e025662caa66e453c088d569e07cb3355 Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Thu, 1 Jun 2023 14:33:42 -0700 Subject: [PATCH 03/80] add documentation links --- .../src/components/ColorModal/ColorModal.tsx | 17 +++++++++++++++- .../src/components/Schema/SchemaSettings.tsx | 20 ++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/app/packages/core/src/components/ColorModal/ColorModal.tsx b/app/packages/core/src/components/ColorModal/ColorModal.tsx index 10b8e5794d..8c64f4dfc4 100644 --- a/app/packages/core/src/components/ColorModal/ColorModal.tsx +++ b/app/packages/core/src/components/ColorModal/ColorModal.tsx @@ -17,13 +17,16 @@ import { ModalWrapper, } from "./ShareStyledDiv"; -import { useTheme } from "@fiftyone/components"; +import { ExternalLink, InfoIcon, useTheme } from "@fiftyone/components"; import Typography from "@mui/material/Typography"; import { Resizable } from "re-resizable"; import { resizeHandle } from "./../Sidebar/Sidebar.module.css"; import SidebarList from "./SidebarList"; import { ACTIVE_FIELD } from "./utils"; +const CUSTOM_COLOR_DOCUMENTATION_LINK = + "https://docs.voxel51.com/user_guide/app.html#app-color-schemes"; + const ColorModal = () => { const theme = useTheme(); const field = useRecoilValue(fos.activeColorField); @@ -112,6 +115,18 @@ const ColorModal = () => { > Color scheme + + + setActiveColorModalField(null)} onMouseDown={(e) => e.stopPropagation()} diff --git a/app/packages/core/src/components/Schema/SchemaSettings.tsx b/app/packages/core/src/components/Schema/SchemaSettings.tsx index dfb3a0ab08..9a748f6969 100644 --- a/app/packages/core/src/components/Schema/SchemaSettings.tsx +++ b/app/packages/core/src/components/Schema/SchemaSettings.tsx @@ -6,7 +6,7 @@ import * as fos from "@fiftyone/state"; import CloseIcon from "@mui/icons-material/Close"; import { Box, Typography } from "@mui/material"; -import { Button, useTheme } from "@fiftyone/components"; +import { Button, ExternalLink, InfoIcon, useTheme } from "@fiftyone/components"; import { TabOption } from "../utils"; import useSchemaSettings, { @@ -49,6 +49,9 @@ const Container = styled.div` background: white; `; +const FIELD_VISIBILITY_DOCUMENTATION_LINK = + "https://docs.voxel51.com/user_guide/app.html#app-field-visibility"; + const SchemaSettings = () => { const theme = useTheme(); @@ -137,10 +140,24 @@ const SchemaSettings = () => { fontSize="1.5rem" style={{ width: "100%", + letterSpacing: "0.05rem", }} > Field visibility + + + { overflow: "hidden", width: "100%", paddingTop: "0.5rem", + letterSpacing: "0.05rem", }} > Date: Fri, 2 Jun 2023 16:17:53 -0700 Subject: [PATCH 04/80] better disable field handling - (un)select is broken - fixing next --- .../state/src/hooks/useSchemaSettings.ts | 75 ++++++++++++++----- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/app/packages/state/src/hooks/useSchemaSettings.ts b/app/packages/state/src/hooks/useSchemaSettings.ts index fa0b34bf32..f8f6775390 100644 --- a/app/packages/state/src/hooks/useSchemaSettings.ts +++ b/app/packages/state/src/hooks/useSchemaSettings.ts @@ -25,6 +25,7 @@ import { Schema, TEMPORAL_DETECTION_FIELD, UNSUPPORTED_FILTER_TYPES, + VALID_LABEL_TYPES, VECTOR_FIELD, } from "@fiftyone/utilities"; import { @@ -70,12 +71,15 @@ const disabledField = ( groupField?: string ) => { const currField = combinedSchema?.[path] || ({} as Field); - const { ftype } = currField; + const { ftype, embeddedDocType } = currField; const parentPath = path.substring(0, path.lastIndexOf(".")); const parentField = combinedSchema?.[parentPath]; const parentEmbeddedDocType = parentField?.embeddedDocType; + const embedSplit = embeddedDocType?.split("."); + const pathSplit = path.split("."); + return ( [ OBJECT_ID_FIELD, @@ -86,6 +90,45 @@ const disabledField = ( [path, parentPath].includes(groupField) || RESERVED_FIELD_KEYS.includes(path) || path.startsWith("metadata") || + ([ + TEMPORAL_DETECTION_FIELD, + DETECTION_FIELD, + DETECTIONS_FIELD, + CLASSIFICATION_FIELD, + CLASSIFICATIONS_FIELD, + KEYPOINT_FILED, + REGRESSION_FILED, + HEATMAP_FIELD, + SEGMENTATION_FIELD, + GEO_LOCATIONS_FIELD, + GEO_LOCATION_FIELD, + POLYLINE_FIELD, + POLYLINES_FIELD, + ].includes(parentEmbeddedDocType) && + [ + "id", + "tags", + "label", + "bounding_box", + "mask", + "confidence", + "index", + "points", + "closed", + "filled", + "logits", + "mask_path", + "map", + "map_path", + "Range", + "Confidence", + "support", + "point", + "line", + "Polygon", + "points", + "polygons", + ].includes(pathSplit[pathSplit.length - 1])) || [ TEMPORAL_DETECTION_FIELD, DETECTION_FIELD, @@ -100,7 +143,10 @@ const disabledField = ( GEO_LOCATION_FIELD, POLYLINE_FIELD, POLYLINES_FIELD, - ].includes(parentEmbeddedDocType) + ].includes(ftype) || + (parentPath && parentPath !== path && ftype === LIST_FIELD) || + (ftype === EMBEDDED_DOCUMENT_FIELD && + VALID_LABEL_TYPES.includes(embedSplit?.[embedSplit?.length - 1])) ); }; export const schemaSearchTerm = atom({ @@ -457,7 +503,6 @@ export default function useSchemaSettings() { data?.schemaForViewStages || {}; const viewSchema = keyBy(frameFieldSchema, "path"); const fieldSchema = keyBy(fieldSchemaRaw, "path"); - const vPaths = Object.keys(viewSchema); const allPaths = viewSchema && fieldSchema @@ -794,32 +839,26 @@ export default function useSchemaSettings() { // select/unselect all const setAllFieldsCheckedWrapper = useCallback( (val) => { - if (allPaths?.length) { - setAllFieldsChecked(val); - const allThePaths = finalSchema.map((ff) => ff.path); - const newSelectedPaths = new Set(val ? allThePaths : []); - setSelectedPaths({ [datasetName]: newSelectedPaths }); - } + if (!allPaths?.length) return; + + setAllFieldsChecked(val); if (val) { setExcludedPaths({ [datasetName]: new Set() }); + setSelectedPaths({ [datasetName]: allPaths }); } else { if (includeNestedFields && allPaths?.length) { setExcludedPaths({ [datasetName]: new Set(allPaths) }); } else { - const topLevelPaths = finalSchema - .map((ff) => ff.path) - .filter((path) => { - const rawPath = path?.startsWith("frames.") - ? path.replace("frames.", "") - : path; - return !rawPath.includes("."); - }); + const topLevelPaths = (allPaths || []).filter( + (path) => !path.replace("frames.", "").includes(".") + ); setExcludedPaths({ [datasetName]: new Set(topLevelPaths) }); } + setSelectedPaths({ [datasetName]: new Set() }); } }, - [finalSchema, allPaths, vPaths, datasetName] + [allPaths, datasetName] ); const bareFinalSchema = useMemo( From ca66b4b5e47b2d9609993e97c27f8d893dcae63d Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Sun, 4 Jun 2023 20:09:47 -0700 Subject: [PATCH 05/80] improve select all control --- .../Schema/SchemaSelectControls.tsx | 9 +- .../state/src/hooks/useSchemaSettings.ts | 127 ++++++++++++------ 2 files changed, 90 insertions(+), 46 deletions(-) diff --git a/app/packages/core/src/components/Schema/SchemaSelectControls.tsx b/app/packages/core/src/components/Schema/SchemaSelectControls.tsx index 7da51f915e..74162541ef 100644 --- a/app/packages/core/src/components/Schema/SchemaSelectControls.tsx +++ b/app/packages/core/src/components/Schema/SchemaSelectControls.tsx @@ -1,8 +1,6 @@ import React, { useMemo } from "react"; import { Box, FormControlLabel, FormGroup, Switch } from "@mui/material"; -import Checkbox from "@mui/material/Checkbox"; -import { useTheme } from "@fiftyone/components"; import { useSchemaSettings } from "@fiftyone/state"; import { TAB_OPTIONS_MAP } from "@fiftyone/state/src/hooks/useSchemaSettings"; import styled from "styled-components"; @@ -15,10 +13,7 @@ const ContainerBox = styled(Box)` padding: 0.35rem 1rem; `; -interface Props {} - -export const SchemaSelectionControls = (props: Props) => { - const theme = useTheme(); +export const SchemaSelectionControls = () => { const { showNestedFields, setShowNestedFields, @@ -85,7 +80,7 @@ export const SchemaSelectionControls = (props: Props) => { {controlList .filter(({ isVisible }) => isVisible) .map(({ label, value, checked, onChange, disabled = false }) => ( - + { const parentPath = path.substring(0, path.lastIndexOf(".")); @@ -76,9 +77,12 @@ const disabledField = ( const parentPath = path.substring(0, path.lastIndexOf(".")); const parentField = combinedSchema?.[parentPath]; const parentEmbeddedDocType = parentField?.embeddedDocType; - - const embedSplit = embeddedDocType?.split("."); const pathSplit = path.split("."); + const embeddedDocTypeSplit = embeddedDocType?.split("."); + const hasDynamicEmbeddedDocument = [ + DYNAMIC_EMBEDDED_DOCUMENT_FIELD, + DYNAMIC_EMBEDDED_DOCUMENT_FIELD_V2, + ].includes(embeddedDocType); return ( [ @@ -144,9 +148,15 @@ const disabledField = ( POLYLINE_FIELD, POLYLINES_FIELD, ].includes(ftype) || - (parentPath && parentPath !== path && ftype === LIST_FIELD) || - (ftype === EMBEDDED_DOCUMENT_FIELD && - VALID_LABEL_TYPES.includes(embedSplit?.[embedSplit?.length - 1])) + (parentPath && + parentPath !== path && + ftype === LIST_FIELD && + (hasDynamicEmbeddedDocument || + VALID_LABEL_TYPES.includes( + embeddedDocType?.includes(".") + ? embeddedDocTypeSplit[embeddedDocTypeSplit.length - 1] + : embeddedDocType + ))) ); }; export const schemaSearchTerm = atom({ @@ -200,17 +210,27 @@ export const schemaSearchRestuls = atom({ }, ], }); + +// tracks action and value - currently used for (un)select all action +export const lastActionToggleSelectionState = atom | null>({ + key: "lastActionToggleSelectionState", + default: null, +}); + export const selectedPathsState = atomFamily({ key: "selectedPathsState", default: (param: {}) => param, effects: [ ({ onSet, getPromise, setSelf }) => { onSet(async (newPathsMap) => { - const viewSchema = await getPromise(viewSchemaState); const dataset = await getPromise(fos.dataset); + const viewSchema = await getPromise(viewSchemaState); const fieldSchema = await getPromise(fieldSchemaState); - const combinedSchema = { ...fieldSchema, ...viewSchema }; + const mapping = {}; Object.keys(combinedSchema).forEach((path) => { if (dataset.mediaType === "image") { @@ -310,31 +330,49 @@ export const excludedPathsState = atomFamily({ } const shouldFilterTopLevelFields = showNestedField || isInSearchMode; - // embedded document could break an exclude_field() call finalGreenPaths = shouldFilterTopLevelFields - ? finalGreenPaths.filter( - (path) => - !( - // a top-level embedded document with dynamic embed type - ( - [EMBEDDED_DOCUMENT_FIELD, LIST_FIELD].includes( - combinedSchema[path]?.ftype - ) && - [ - DYNAMIC_EMBEDDED_DOCUMENT_FIELD, - DYNAMIC_EMBEDDED_DOCUMENT_FIELD_V2, - ].includes(combinedSchema[path]?.embeddedDocType) && - (isVideo - ? !( - path.split(".").length === 2 && - path.startsWith("frames.") - ) || !path.includes(".") - : !path.includes(".")) - ) - ) - ) + ? finalGreenPaths.filter((path) => { + const isEmbeddedOrListType = [ + EMBEDDED_DOCUMENT_FIELD, + LIST_FIELD, + ].includes(combinedSchema[path]?.ftype); + + // embedded document could break an exclude_field() call causing mongo query issue. + const hasDynamicEmbeddedDocument = [ + DYNAMIC_EMBEDDED_DOCUMENT_FIELD, + DYNAMIC_EMBEDDED_DOCUMENT_FIELD_V2, + ].includes(combinedSchema[path]?.embeddedDocType); + + const isTopLevelPath = isVideo + ? !( + path.split(".").length === 2 && path.startsWith("frames.") + ) || !path.includes(".") + : !path.includes("."); + + return !( + isEmbeddedOrListType && + hasDynamicEmbeddedDocument && + isTopLevelPath + ); + }) : finalGreenPaths; + // filter out subpaths if a parent (or higher) path is also in the list + const finalGreenPathsSet = new Set(finalGreenPaths); + if (showNestedField) { + finalGreenPaths = finalGreenPaths.filter((path) => { + let tmp = path; + while (tmp.indexOf(".") > 0) { + const parentPath = tmp.substring(0, tmp.lastIndexOf(".")); + if (finalGreenPathsSet.has(parentPath) || path === parentPath) { + return false; + } + tmp = parentPath; + } + return true; + }); + } + setSelf({ [dataset.name]: new Set(finalGreenPaths), }); @@ -477,6 +515,8 @@ export default function useSchemaSettings() { const [searchMetaFilter, setSearchMetaFilter] = useRecoilState( searchMetaFilterState ); + const [lastActionToggleSelection, setLastActionToggleSelection] = + useRecoilState(lastActionToggleSelectionState); const vStages = useRecoilValue(fos.view); const [data, refetch] = useRefetchableFragment< @@ -611,7 +651,9 @@ export default function useSchemaSettings() { const isInSearchResult = searchResults.includes(path); const isSelected = (filterRuleTab && isInSearchResult) || - (!filterRuleTab && selectedPaths?.[datasetName]?.has(fullPath)); + (!filterRuleTab && + selectedPaths?.[datasetName] && + selectedPaths[datasetName]?.has(fullPath)); return { path, @@ -836,18 +878,16 @@ export default function useSchemaSettings() { [selectedPaths, viewPaths, datasetName, excludedPaths] ); - // select/unselect all - const setAllFieldsCheckedWrapper = useCallback( - (val) => { - if (!allPaths?.length) return; - - setAllFieldsChecked(val); + useEffect(() => { + if (!allPaths?.length) return; + if (lastActionToggleSelection) { + const val = lastActionToggleSelection[SELECT_ALL]; if (val) { setExcludedPaths({ [datasetName]: new Set() }); - setSelectedPaths({ [datasetName]: allPaths }); + setSelectedPaths({ [datasetName]: new Set([...allPaths]) }); } else { - if (includeNestedFields && allPaths?.length) { + if (includeNestedFields && filterRuleTab) { setExcludedPaths({ [datasetName]: new Set(allPaths) }); } else { const topLevelPaths = (allPaths || []).filter( @@ -857,8 +897,17 @@ export default function useSchemaSettings() { } setSelectedPaths({ [datasetName]: new Set() }); } + + setLastActionToggleSelection(null); + } + }, [lastActionToggleSelection, allPaths]); + + const setAllFieldsCheckedWrapper = useCallback( + (val: boolean) => { + setAllFieldsChecked(val); + setLastActionToggleSelection({ SELECT_ALL: val }); }, - [allPaths, datasetName] + [finalSchema] ); const bareFinalSchema = useMemo( From e9c0c6a29849e3b0c0108e990f8782c0638aed36 Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Mon, 5 Jun 2023 15:10:08 -0700 Subject: [PATCH 06/80] uncheck subpaths even if they are disabled --- .../Schema/SchemaSelectControls.tsx | 16 +-- .../src/components/Schema/SchemaSelection.tsx | 8 +- .../src/components/Schema/SchemaSettings.tsx | 9 +- .../Sidebar/Entries/FilterEntry.tsx | 14 +- .../state/src/hooks/useSchemaSettings.ts | 133 +++++++++--------- 5 files changed, 88 insertions(+), 92 deletions(-) diff --git a/app/packages/core/src/components/Schema/SchemaSelectControls.tsx b/app/packages/core/src/components/Schema/SchemaSelectControls.tsx index 74162541ef..508b8891a0 100644 --- a/app/packages/core/src/components/Schema/SchemaSelectControls.tsx +++ b/app/packages/core/src/components/Schema/SchemaSelectControls.tsx @@ -2,7 +2,6 @@ import React, { useMemo } from "react"; import { Box, FormControlLabel, FormGroup, Switch } from "@mui/material"; import { useSchemaSettings } from "@fiftyone/state"; -import { TAB_OPTIONS_MAP } from "@fiftyone/state/src/hooks/useSchemaSettings"; import styled from "styled-components"; const ContainerBox = styled(Box)` @@ -19,22 +18,21 @@ export const SchemaSelectionControls = () => { setShowNestedFields, allFieldsChecked, setAllFieldsChecked, - selectedTab, + isFilterRuleActive, showMetadata, setShowMetadata, searchResults, includeNestedFields, setIncludeNestedFields, } = useSchemaSettings(); - const isFilterRuleMode = selectedTab === TAB_OPTIONS_MAP.FILTER_RULE; - const showMetadataVisibile = !!!(isFilterRuleMode && !searchResults.length); - const includeNestedVisible = !!(isFilterRuleMode && searchResults.length); + const showMetadataVisible = !!!(isFilterRuleActive && !searchResults.length); + const includeNestedVisible = !!(isFilterRuleActive && searchResults.length); const controlList = useMemo(() => { return [ { label: "Show metadata", - isVisible: showMetadataVisibile, + isVisible: showMetadataVisible, value: showMetadata, checked: showMetadata, onChange: () => setShowMetadata(!showMetadata), @@ -49,14 +47,14 @@ export const SchemaSelectionControls = () => { }, { label: "Show nested fields", - isVisible: !isFilterRuleMode, + isVisible: !isFilterRuleActive, value: showNestedFields, checked: showNestedFields, onChange: () => setShowNestedFields(!showNestedFields), }, { label: "Select all", - isVisible: !isFilterRuleMode, + isVisible: !isFilterRuleActive, value: allFieldsChecked, checked: allFieldsChecked, onChange: () => setAllFieldsChecked(!allFieldsChecked), @@ -64,7 +62,7 @@ export const SchemaSelectionControls = () => { ]; }, [ showMetadata, - showMetadataVisibile, + showMetadataVisible, includeNestedFields, showNestedFields, allFieldsChecked, diff --git a/app/packages/core/src/components/Schema/SchemaSelection.tsx b/app/packages/core/src/components/Schema/SchemaSelection.tsx index ac8cdfb51c..0546bbb5bc 100644 --- a/app/packages/core/src/components/Schema/SchemaSelection.tsx +++ b/app/packages/core/src/components/Schema/SchemaSelection.tsx @@ -7,7 +7,6 @@ import { useSchemaSettings } from "@fiftyone/state"; import { SchemaSelectionControls } from "./SchemaSelectControls"; import { SchemaSearchHelp } from "./SchemaSearchHelp"; import { ExpandMore } from "@mui/icons-material"; -import { TAB_OPTIONS_MAP } from "@fiftyone/state/src/hooks/useSchemaSettings"; import styled from "styled-components"; interface Props {} @@ -23,13 +22,12 @@ export const SchemaSelection = () => { toggleSelection, finalSchema, searchResults, - selectedTab, + isFilterRuleActive, showMetadata, finalSchemaKeyByPath, } = useSchemaSettings(); - const isFilterRuleMode = selectedTab === TAB_OPTIONS_MAP.FILTER_RULE; const [expandedPaths, setExpandedPaths] = useState({}); - const showSearchHelp = isFilterRuleMode && !searchResults?.length; + const showSearchHelp = isFilterRuleActive && !searchResults?.length; const showSelection = !showSearchHelp; const expandedPathsKeys = new Set(Object.keys(expandedPaths)); const [JSONifiedPaths, setJSONifiedPaths] = useState(new Set()); @@ -191,7 +189,7 @@ export const SchemaSelection = () => { { setSelectedFieldsStage, datasetName, excludedPaths, - selectedPaths, resetExcludedPaths, setSelectedPaths, setLastAppliedPaths, @@ -77,6 +75,7 @@ const SchemaSettings = () => { setExcludedPaths, isFilterRuleActive, searchMetaFilter, + enabledSelectedPaths, } = useSchemaSettings(); useOutsideClick(schemaModalRef, (_) => { @@ -189,13 +188,13 @@ const SchemaSettings = () => { })} /> - {selectedTab === TAB_OPTIONS_MAP.FILTER_RULE && ( + {isFilterRuleActive && ( )} - {selectedTab === TAB_OPTIONS_MAP.SELECTION && } + {!isFilterRuleActive && } { setSettingsModal({ open: false }); } setLastAppliedPaths({ - selected: selectedPaths[datasetName], + selected: enabledSelectedPaths[datasetName], excluded: excludedPaths[datasetName], }); }} diff --git a/app/packages/core/src/components/Sidebar/Entries/FilterEntry.tsx b/app/packages/core/src/components/Sidebar/Entries/FilterEntry.tsx index 7a56fe9442..445443777f 100644 --- a/app/packages/core/src/components/Sidebar/Entries/FilterEntry.tsx +++ b/app/packages/core/src/components/Sidebar/Entries/FilterEntry.tsx @@ -11,10 +11,7 @@ import { InputDiv } from "./utils"; import * as fos from "@fiftyone/state"; import { Settings, VisibilityOff } from "@mui/icons-material"; import { Box, Typography } from "@mui/material"; -import { - affectedPathCountState, - selectedFieldsStageState, -} from "@fiftyone/state/src/hooks/useSchemaSettings"; +import { selectedFieldsStageState } from "@fiftyone/state/src/hooks/useSchemaSettings"; import { Tooltip, useTheme } from "@fiftyone/components"; const Filter = ({ modal }: { modal: boolean }) => { @@ -26,10 +23,13 @@ const Filter = ({ modal }: { modal: boolean }) => { const resetSelectedFieldStages = useResetRecoilState( selectedFieldsStageState ); - const affectedPathCount = useRecoilValue(affectedPathCountState); - const { setSelectedFieldsStage, resetTextFilter, resetExcludedPaths } = - fos.useSchemaSettings(); + const { + setSelectedFieldsStage, + resetTextFilter, + resetExcludedPaths, + affectedPathCount, + } = fos.useSchemaSettings(); useDebounce( () => { diff --git a/app/packages/state/src/hooks/useSchemaSettings.ts b/app/packages/state/src/hooks/useSchemaSettings.ts index 22d3270742..87ca1a94ae 100644 --- a/app/packages/state/src/hooks/useSchemaSettings.ts +++ b/app/packages/state/src/hooks/useSchemaSettings.ts @@ -230,13 +230,15 @@ export const selectedPathsState = atomFamily({ const viewSchema = await getPromise(viewSchemaState); const fieldSchema = await getPromise(fieldSchemaState); const combinedSchema = { ...fieldSchema, ...viewSchema }; + const isImage = dataset.mediaType === "image"; + const isVideo = dataset.mediaType === "video"; const mapping = {}; Object.keys(combinedSchema).forEach((path) => { - if (dataset.mediaType === "image") { + if (isImage) { mapping[path] = path; } - if (dataset.mediaType === "video" && viewSchema) { + if (isVideo && viewSchema) { Object.keys(viewSchema).forEach((path) => { mapping[path] = `frames.${path}`; }); @@ -253,12 +255,7 @@ export const selectedPathsState = atomFamily({ fieldSchema?.[path]?.ftype, combinedSchema ); - const disable = disabledField( - path, - combinedSchema, - dataset?.groupField - ); - return !!path && !skip && !disable; + return !!path && !skip; }) .map((path) => mapping?.[path] || path); @@ -269,6 +266,7 @@ export const selectedPathsState = atomFamily({ }, ], }); + export const excludedPathsState = atomFamily({ key: "excludedPathsState", default: (param: {}) => param, @@ -444,6 +442,7 @@ export default function useSchemaSettings() { const router = useContext(fos.RouterContext); const [setView] = useMutation(foq.setView); const dataset = useRecoilValue(fos.dataset); + const isGroupDataset = dataset?.groupField; const resetTextFilter = useResetRecoilState(fos.textFilter(false)); const datasetName = useRecoilValue(fos.datasetName); @@ -487,6 +486,8 @@ export default function useSchemaSettings() { const setFieldSchema = useSetRecoilState(fieldSchemaState); const [searchTerm, setSearchTerm] = useRecoilState(schemaSearchTerm); const [searchResults, setSearchResults] = useRecoilState(schemaSearchRestuls); + const isVideo = dataset.mediaType === "video"; + const isImage = dataset.mediaType === "image"; const setSchema = useSetRecoilState(schemaState); useEffect(() => { @@ -541,13 +542,11 @@ export default function useSchemaSettings() { }, [vStages, datasetName]); const { fieldSchema: fieldSchemaRaw, frameFieldSchema } = data?.schemaForViewStages || {}; + const viewSchema = keyBy(frameFieldSchema, "path"); const fieldSchema = keyBy(fieldSchemaRaw, "path"); - - const allPaths = - viewSchema && fieldSchema - ? Object.keys({ ...viewSchema, ...fieldSchema }) - : []; + const combinedSchema = { ...viewSchema, ...fieldSchema }; + const allPaths = !isEmpty(combinedSchema) ? Object.keys(combinedSchema) : []; useEffect(() => { if (!isEmpty(viewSchema)) { @@ -567,6 +566,13 @@ export default function useSchemaSettings() { const [selectedPaths, setSelectedPaths] = useRecoilState<{}>( selectedPathState ); + // disabled paths are filtered + const datasetSelectedPaths = selectedPaths[datasetName] || []; + const enabledSelectedPaths = datasetSelectedPaths.length + ? datasetSelectedPaths?.filter( + ({ path }) => !disabledField(path, combinedSchema, isGroupDataset) + ) + : []; const excludePathsState = excludedPathsState({}); const [excludedPaths, setExcludedPaths] = useRecoilState<{}>( @@ -586,7 +592,7 @@ export default function useSchemaSettings() { } else { excludedPaths?.[datasetName]?.forEach((path) => { if ( - dataset.mediaType === "video" + isVideo ? (path.split(".").length === 2 && path.startsWith("frames.")) || !path.includes(".") : !path.includes(".") @@ -606,7 +612,7 @@ export default function useSchemaSettings() { if (!datasetName || !selectedPaths?.[datasetName] || isEmpty(fieldSchema)) return [[], {}]; let finalSchemaKeyByPath = {}; - if (dataset.mediaType === "video") { + if (isVideo) { Object.keys(viewSchema).forEach((fieldPath) => { finalSchemaKeyByPath[fieldPath] = viewSchema[fieldPath]; }); @@ -627,26 +633,23 @@ export default function useSchemaSettings() { const pathLabel = path.split("."); const hasFrames = path?.startsWith("frames."); const count = pathLabel?.length - (hasFrames ? 1 : 0); - const rawPath = hasFrames ? path.replace("frames.", "") : path; + const rawPath = path.replace("frames.", ""); const pathLabelFinal = searchResults.length - ? dataset.mediaType === "video" && viewSchema?.[rawPath] + ? isVideo && viewSchema?.[rawPath] ? `frames.${path}` : path - : dataset.mediaType === "video" && viewSchema?.[rawPath] + : isVideo && viewSchema?.[rawPath] ? `frames.${pathLabel[pathLabel.length - 1]}` : pathLabel[pathLabel.length - 1]; const ftype = finalSchemaKeyByPath[path].ftype; const skip = skipField(path, ftype, finalSchemaKeyByPath); - const isGroupField = dataset?.groupField; const disabled = - disabledField(path, finalSchemaKeyByPath, isGroupField) || + disabledField(path, finalSchemaKeyByPath, isGroupDataset) || filterRuleTab; const fullPath = - dataset.mediaType === "video" && viewSchema?.[path] - ? `frames.${path}` - : path; + isVideo && viewSchema?.[path] ? `frames.${path}` : path; const isInSearchResult = searchResults.includes(path); const isSelected = @@ -658,7 +661,7 @@ export default function useSchemaSettings() { return { path, count, - isSelected: filterRuleTab ? isSelected : isSelected || disabled, + isSelected, pathLabelFinal, skip, disabled, @@ -800,17 +803,17 @@ export default function useSchemaSettings() { const subPaths = new Set(); subPaths.add(getPath(path)); Object.keys(mergedSchema).forEach((currPath: string) => { + const ftype = mergedSchema?.[currPath]?.ftype; if ( currPath.startsWith(path + ".") && - !skipField(currPath, mergedSchema?.[currPath]?.ftype, mergedSchema) && - !disabledField(currPath, mergedSchema, dataset?.groupField) + !skipField(currPath, ftype, mergedSchema) ) { subPaths.add(getPath(currPath)); } }); return subPaths; }, - [mergedSchema, datasetName] + [mergedSchema, datasetName, isGroupDataset] ); useEffect(() => { @@ -834,12 +837,9 @@ export default function useSchemaSettings() { } }, [viewSchema, fieldSchema]); - // toggle field selection const toggleSelection = useCallback( (rawPath: string, checked: boolean) => { if (!selectedPaths || !rawPath || !datasetName) return; - // improve this by unifying with similar patterns - // const path = dataset.mediaType === 'video' ? `frames.${rawPath}` : rawPath; const pathAndSubPaths = getSubPaths(rawPath); if (!pathAndSubPaths.size) { return; @@ -890,8 +890,10 @@ export default function useSchemaSettings() { if (includeNestedFields && filterRuleTab) { setExcludedPaths({ [datasetName]: new Set(allPaths) }); } else { - const topLevelPaths = (allPaths || []).filter( - (path) => !path.replace("frames.", "").includes(".") + const topLevelPaths = (allPaths || []).filter((path) => + path.startsWith("frames.") + ? !path.replace("frames.", "").includes(".") + : !path.includes(".") ); setExcludedPaths({ [datasetName]: new Set(topLevelPaths) }); } @@ -915,12 +917,12 @@ export default function useSchemaSettings() { mergedSchema ? finalSchema.filter((field) => { return ( - !disabledField(field.path, mergedSchema, dataset?.groupField) && + !disabledField(field.path, mergedSchema, isGroupDataset) && !skipField(field.path, mergedSchema?.[field.path], mergedSchema) ); }) : finalSchema, - [mergedSchema, finalSchema] + [mergedSchema, finalSchema, isGroupDataset] ); // updates the affected fields count @@ -944,43 +946,42 @@ export default function useSchemaSettings() { ]); return { - searchMetaFilter, - filterRuleTab, - settingModal, - setSettingsModal, - searchTerm, - setSearchTerm, - showNestedFields, - setShowNestedFields, - selectedTab, - setSelectedTab, - toggleSelection, - finalSchema, - selectedPaths, - setSelectedPaths, - allFieldsChecked, - setAllFieldsChecked: setAllFieldsCheckedWrapper, - searchResults, - setSearchResults, - showMetadata, - setShowMetadata, - setSelectedFieldsStage, affectedPathCount, - mediatType: dataset.mediaType, - dataset, - resetTextFilter, + allFieldsChecked, datasetName, - includeNestedFields, - setIncludeNestedFields, - finalSchemaKeyByPath, + enabledSelectedPaths, excludedPaths, - resetSelectedPaths, - resetExcludedPaths, + filterRuleTab, + finalSchema, + finalSchemaKeyByPath, + includeNestedFields, + isFilterRuleActive: filterRuleTab, isVideo: dataset?.mediaType === "video", - setExcludedPaths, + lastAppliedPaths, + resetExcludedPaths, + resetSelectedPaths, + resetTextFilter, + searchMetaFilter, + searchResults, searchSchemaFields, + searchTerm, + selectedPaths, + selectedTab, + setAllFieldsChecked: setAllFieldsCheckedWrapper, + setExcludedPaths, + setIncludeNestedFields, setLastAppliedPaths, - lastAppliedPaths, - isFilterRuleActive: filterRuleTab, + setSearchResults, + setSearchTerm, + setSelectedFieldsStage, + setSelectedPaths, + setSelectedTab, + setSettingsModal, + setShowMetadata, + setShowNestedFields, + settingModal, + showMetadata, + showNestedFields, + toggleSelection, }; } From bdf50f1105e7a527761a35e3390fbbe6359029bb Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Tue, 6 Jun 2023 13:19:15 -0700 Subject: [PATCH 07/80] show embedded document in selection mode --- .../src/components/Schema/SchemaSelection.tsx | 325 ++++++++++-------- 1 file changed, 176 insertions(+), 149 deletions(-) diff --git a/app/packages/core/src/components/Schema/SchemaSelection.tsx b/app/packages/core/src/components/Schema/SchemaSelection.tsx index 0546bbb5bc..925d9082fd 100644 --- a/app/packages/core/src/components/Schema/SchemaSelection.tsx +++ b/app/packages/core/src/components/Schema/SchemaSelection.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useState } from "react"; -import { Box } from "@mui/material"; +import { Box, Typography } from "@mui/material"; import Checkbox from "@mui/material/Checkbox"; import { CodeBlock, JSONIcon, useTheme } from "@fiftyone/components"; @@ -8,14 +8,26 @@ import { SchemaSelectionControls } from "./SchemaSelectControls"; import { SchemaSearchHelp } from "./SchemaSearchHelp"; import { ExpandMore } from "@mui/icons-material"; import styled from "styled-components"; - -interface Props {} +import { EMBEDDED_DOCUMENT_FIELD } from "@fiftyone/utilities"; const InfoCell = styled(Box)` display: flex; padding: 0 0.25rem; `; +const MetaInfoBlock = styled(Box)` + display: flex; + padding-left: 2rem; + font-size: 0.9rem; + color: ${({ theme }) => theme.text.secondary}; +`; +const MetaInfoKey = styled(Typography)` + color: ${({ theme }) => theme.text.secondary}; + padding-right: 0.25rem; + font-weight: bold !important; + font-size: 1rem; +`; + export const SchemaSelection = () => { const theme = useTheme(); const { @@ -51,30 +63,17 @@ export const SchemaSelection = () => { if (fInfo) { switch (typeof fInfo) { case "number": - return ( - - ); + const value = Number.isInteger(fInfo) ? fInfo : fInfo.toFixed(3); + return {value}; case "string": return ( - + + {fInfo.length ? fInfo : '""'} + ); case "boolean": - ; + const boolLabel: string = fInfo ? "True" : "False"; + {boolLabel}; case "object": try { const obj = fInfo; @@ -83,24 +82,20 @@ export const SchemaSelection = () => { return {key}; }); } else { - const res = Object.keys(obj) - .map((key) => { - const val = obj[key] || ""; - return `${key}: ${ - JSONifiedPaths.has(path) + return Object.keys(obj).map((key) => { + const val = obj[key] || ""; + return ( + + + {`${key}:`} + {` `} + + {JSONifiedPaths.has(path) ? JSON.stringify(val, null, 1) - : JSON.stringify(val) - }`; - }) - .join("\n"); - return ( - - ); + : JSON.stringify(val)} + + ); + }); } } catch (e) { return {fInfo}; @@ -144,126 +139,158 @@ export const SchemaSelection = () => { > {showSearchHelp && } {showSelection && - finalSchema?.map((item) => { - const { path, count, isSelected, pathLabelFinal, skip, disabled } = - item; + finalSchema?.map( + ({ path, count, isSelected, pathLabelFinal, skip, disabled }) => { + if (skip) return null; - if (skip) return null; + const field = finalSchemaKeyByPath[path]; + const fInfo = field?.info; + const fDesc = field?.description; + const ftype: string = field?.ftype || ""; + const embedDocType = field?.embeddedDocType; + let docTypeLabel = ftype.substring( + ftype.lastIndexOf(".") + 1, + ftype.length + ); + docTypeLabel = + ftype === EMBEDDED_DOCUMENT_FIELD + ? embedDocType.substring( + embedDocType.lastIndexOf(".") + 1, + embedDocType.length + ) + : docTypeLabel; + const isExpandable = fInfo || fDesc; - const field = finalSchemaKeyByPath[path]; - const fInfo = field?.info; - const fDesc = field?.description; - const isExpandable = fInfo || fDesc; + return ( + + + + + { + toggleSelection(path, isSelected); + }} + style={{ + padding: 0, + }} + disabled={disabled} + /> + + + + {pathLabelFinal} + + + ({docTypeLabel}) + + + + {isExpandable && ( + { + if (expandedPathsKeys.has(path)) { + const newPaths = Object.assign({}, expandedPaths); + delete newPaths[path]; + setExpandedPaths(newPaths); + } else { + const newPaths = Object.assign({}, expandedPaths); + const element = finalSchema.filter( + (sc) => sc.path === path + )?.[0]; - return ( - - - - - { - toggleSelection(path, isSelected); - }} - style={{ - padding: 0, + newPaths[path] = { + info: element?.info || "None", + description: element?.description || "None", + name: element?.name || "None", + }; + setExpandedPaths(newPaths); + } }} - disabled={disabled} - /> - - - {pathLabelFinal} - + > + + + )} - {isExpandable && ( - { - if (expandedPathsKeys.has(path)) { - const newPaths = Object.assign({}, expandedPaths); - delete newPaths[path]; - setExpandedPaths(newPaths); - } else { - const newPaths = Object.assign({}, expandedPaths); - const element = finalSchema.filter( - (sc) => sc.path === path - )?.[0]; - - newPaths[path] = { - info: element?.info || "None", - description: element?.description || "None", - name: element?.name || "None", - }; - setExpandedPaths(newPaths); - } - }} - > - - - )} - - - {expandedPathsKeys.has(path) && ( - - {renderInfo(fInfo, path)} - {fDesc && ( - - )} + + {expandedPathsKeys.has(path) && ( handleJSONify(path)} + maxHeight="200px" + overflow="auto" + position="relative" > - + Description: + {fDesc} + + )} + theme.typography.body2, - fontSize: "1rem", + position: "absolute", + right: "0.5rem", + bottom: "20%", + cursor: "pointer", }} - /> + onClick={() => handleJSONify(path)} + > + theme.typography.body2, + fontSize: "1rem", + }} + /> + - - )} + )} + - - ); - })} + ); + } + )} ); From 33554bd8c2a9736ba7b10855e255c4385e97481d Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Tue, 6 Jun 2023 21:25:58 -0700 Subject: [PATCH 08/80] field doc type using tertiary text color --- app/packages/core/src/components/Schema/SchemaSelection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/packages/core/src/components/Schema/SchemaSelection.tsx b/app/packages/core/src/components/Schema/SchemaSelection.tsx index 925d9082fd..2ff1358e33 100644 --- a/app/packages/core/src/components/Schema/SchemaSelection.tsx +++ b/app/packages/core/src/components/Schema/SchemaSelection.tsx @@ -215,7 +215,7 @@ export const SchemaSelection = () => { paddingLeft: "0.5rem", color: disabled ? theme.text.tertiary - : theme.text.secondary, + : theme.text.tertiary, fontSize: "0.8rem", alignItems: "center", }} From 05a87628591b292d93cfca1ae03175ff6c83c8d7 Mon Sep 17 00:00:00 2001 From: Lanny W Date: Wed, 7 Jun 2023 12:49:53 -0500 Subject: [PATCH 09/80] minor tweaks in color modal title style --- app/packages/core/src/components/ColorModal/ColorModal.tsx | 3 ++- app/packages/core/src/components/ColorModal/ShareStyledDiv.ts | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/packages/core/src/components/ColorModal/ColorModal.tsx b/app/packages/core/src/components/ColorModal/ColorModal.tsx index 8c64f4dfc4..b41778d673 100644 --- a/app/packages/core/src/components/ColorModal/ColorModal.tsx +++ b/app/packages/core/src/components/ColorModal/ColorModal.tsx @@ -121,6 +121,7 @@ const ColorModal = () => { height: "30px", display: "flex", alignItems: "center", + margin: "auto 4px", }} title="Documentation" href={CUSTOM_COLOR_DOCUMENTATION_LINK} @@ -130,7 +131,7 @@ const ColorModal = () => { setActiveColorModalField(null)} onMouseDown={(e) => e.stopPropagation()} - style={{ margin: "4px", cursor: "pointer" }} + style={{ margin: "auto 4px", cursor: "pointer" }} /> diff --git a/app/packages/core/src/components/ColorModal/ShareStyledDiv.ts b/app/packages/core/src/components/ColorModal/ShareStyledDiv.ts index 120d31be39..6d71cb8c97 100644 --- a/app/packages/core/src/components/ColorModal/ShareStyledDiv.ts +++ b/app/packages/core/src/components/ColorModal/ShareStyledDiv.ts @@ -33,6 +33,7 @@ export const Container = styled.div` export const DraggableContent = styled.div` height: ${(props) => `calc(${props.height}px - 6.5rem)`}; + border-top: 1px solid ${({ theme }) => theme.primary.plainBorder}; width: 100%; display: flex; flex-direction: row; @@ -51,7 +52,8 @@ export const DraggableModalTitle = styled.div` justify-content: space-between; width: 100%; height: 3rem; - padding: 0.75rem; + padding-left: 0.75rem; + padding-right: 0.75rem; background-color: ${({ theme }) => theme.background.level2}; cursor: move; font-weight: 600; From f1df4e57d1c279828231de50251ed0fe91fd5641 Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Thu, 8 Jun 2023 12:09:50 -0700 Subject: [PATCH 10/80] review comments and fix include nested fields selection view --- .../Schema/SchemaSelectControls.tsx | 11 +- .../src/components/Schema/SchemaSelection.tsx | 246 ++---------------- .../components/Schema/SchemaSelectionRow.tsx | 214 +++++++++++++++ .../src/components/Schema/SchemaSettings.tsx | 5 +- .../Sidebar/Entries/FilterEntry.tsx | 2 + .../state/src/hooks/useSchemaSettings.ts | 41 ++- 6 files changed, 282 insertions(+), 237 deletions(-) create mode 100644 app/packages/core/src/components/Schema/SchemaSelectionRow.tsx diff --git a/app/packages/core/src/components/Schema/SchemaSelectControls.tsx b/app/packages/core/src/components/Schema/SchemaSelectControls.tsx index 508b8891a0..0a32782b90 100644 --- a/app/packages/core/src/components/Schema/SchemaSelectControls.tsx +++ b/app/packages/core/src/components/Schema/SchemaSelectControls.tsx @@ -25,7 +25,7 @@ export const SchemaSelectionControls = () => { includeNestedFields, setIncludeNestedFields, } = useSchemaSettings(); - const showMetadataVisible = !!!(isFilterRuleActive && !searchResults.length); + const showMetadataVisible = !(isFilterRuleActive && !searchResults.length); const includeNestedVisible = !!(isFilterRuleActive && searchResults.length); const controlList = useMemo(() => { @@ -61,11 +61,18 @@ export const SchemaSelectionControls = () => { }, ]; }, [ - showMetadata, showMetadataVisible, + showMetadata, + includeNestedVisible, includeNestedFields, + searchResults.length, + isFilterRuleActive, showNestedFields, allFieldsChecked, + setShowMetadata, + setIncludeNestedFields, + setShowNestedFields, + setAllFieldsChecked, ]); return ( diff --git a/app/packages/core/src/components/Schema/SchemaSelection.tsx b/app/packages/core/src/components/Schema/SchemaSelection.tsx index 2ff1358e33..5db16e76e9 100644 --- a/app/packages/core/src/components/Schema/SchemaSelection.tsx +++ b/app/packages/core/src/components/Schema/SchemaSelection.tsx @@ -1,125 +1,38 @@ -import React, { useCallback, useEffect, useState } from "react"; -import { Box, Typography } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import { Box } from "@mui/material"; -import Checkbox from "@mui/material/Checkbox"; -import { CodeBlock, JSONIcon, useTheme } from "@fiftyone/components"; import { useSchemaSettings } from "@fiftyone/state"; import { SchemaSelectionControls } from "./SchemaSelectControls"; import { SchemaSearchHelp } from "./SchemaSearchHelp"; -import { ExpandMore } from "@mui/icons-material"; -import styled from "styled-components"; import { EMBEDDED_DOCUMENT_FIELD } from "@fiftyone/utilities"; - -const InfoCell = styled(Box)` - display: flex; - padding: 0 0.25rem; -`; - -const MetaInfoBlock = styled(Box)` - display: flex; - padding-left: 2rem; - font-size: 0.9rem; - color: ${({ theme }) => theme.text.secondary}; -`; -const MetaInfoKey = styled(Typography)` - color: ${({ theme }) => theme.text.secondary}; - padding-right: 0.25rem; - font-weight: bold !important; - font-size: 1rem; -`; +import { SchemaSelectionRow } from "./SchemaSelectionRow"; export const SchemaSelection = () => { - const theme = useTheme(); const { - toggleSelection, finalSchema, searchResults, isFilterRuleActive, showMetadata, finalSchemaKeyByPath, + setExpandedPaths, + expandedPaths, } = useSchemaSettings(); - const [expandedPaths, setExpandedPaths] = useState({}); const showSearchHelp = isFilterRuleActive && !searchResults?.length; const showSelection = !showSearchHelp; - const expandedPathsKeys = new Set(Object.keys(expandedPaths)); - const [JSONifiedPaths, setJSONifiedPaths] = useState(new Set()); useEffect(() => { - if (showMetadata) { + if (showMetadata && finalSchema && !expandedPaths) { const res = {}; - finalSchema?.forEach((entry) => { + finalSchema.forEach((entry) => { if (entry?.info || entry?.description) { res[entry.path] = entry; } }); setExpandedPaths(res); - } else { - setExpandedPaths({}); + } else if (!showMetadata && !!expandedPaths) { + setExpandedPaths(null); } - }, [showMetadata]); - - const renderInfo = useCallback( - (fInfo, path: string) => { - if (fInfo) { - switch (typeof fInfo) { - case "number": - const value = Number.isInteger(fInfo) ? fInfo : fInfo.toFixed(3); - return {value}; - case "string": - return ( - - {fInfo.length ? fInfo : '""'} - - ); - case "boolean": - const boolLabel: string = fInfo ? "True" : "False"; - {boolLabel}; - case "object": - try { - const obj = fInfo; - if (Array.isArray(obj)) { - return obj.map((key) => { - return {key}; - }); - } else { - return Object.keys(obj).map((key) => { - const val = obj[key] || ""; - return ( - - - {`${key}:`} - {` `} - - {JSONifiedPaths.has(path) - ? JSON.stringify(val, null, 1) - : JSON.stringify(val)} - - ); - }); - } - } catch (e) { - return {fInfo}; - } - default: - return None; - } - } - }, - [JSONifiedPaths] - ); - - const handleJSONify = useCallback( - (path: string) => { - const newJSONifiedPaths = new Set([...JSONifiedPaths]); - if (JSONifiedPaths.has(path)) { - newJSONifiedPaths.delete(path); - } else { - newJSONifiedPaths.add(path); - } - setJSONifiedPaths(newJSONifiedPaths); - }, - [JSONifiedPaths] - ); + }, [expandedPaths, finalSchema, setExpandedPaths, showMetadata]); return ( { {showSearchHelp && } {showSelection && finalSchema?.map( - ({ path, count, isSelected, pathLabelFinal, skip, disabled }) => { + ({ path, count, pathLabelFinal, skip, disabled, isSelected }) => { if (skip) return null; const field = finalSchemaKeyByPath[path]; @@ -159,135 +72,20 @@ export const SchemaSelection = () => { embedDocType.length ) : docTypeLabel; - const isExpandable = fInfo || fDesc; return ( - - - - - { - toggleSelection(path, isSelected); - }} - style={{ - padding: 0, - }} - disabled={disabled} - /> - - - - {pathLabelFinal} - - - ({docTypeLabel}) - - - - {isExpandable && ( - { - if (expandedPathsKeys.has(path)) { - const newPaths = Object.assign({}, expandedPaths); - delete newPaths[path]; - setExpandedPaths(newPaths); - } else { - const newPaths = Object.assign({}, expandedPaths); - const element = finalSchema.filter( - (sc) => sc.path === path - )?.[0]; - - newPaths[path] = { - info: element?.info || "None", - description: element?.description || "None", - name: element?.name || "None", - }; - setExpandedPaths(newPaths); - } - }} - > - - - )} - - - {expandedPathsKeys.has(path) && ( - - {renderInfo(fInfo, path)} - {fDesc && ( - - Description: - {fDesc} - - )} - handleJSONify(path)} - > - theme.typography.body2, - fontSize: "1rem", - }} - /> - - - )} - - + path={path} + isSelected={isSelected} + count={count} + disabled={disabled} + pathLabelFinal={pathLabelFinal} + docTypeLabel={docTypeLabel} + isExpandable={fInfo || fDesc} + info={fInfo} + description={fDesc} + /> ); } )} diff --git a/app/packages/core/src/components/Schema/SchemaSelectionRow.tsx b/app/packages/core/src/components/Schema/SchemaSelectionRow.tsx new file mode 100644 index 0000000000..d6809d2113 --- /dev/null +++ b/app/packages/core/src/components/Schema/SchemaSelectionRow.tsx @@ -0,0 +1,214 @@ +import React, { useCallback } from "react"; +import { Box, Typography } from "@mui/material"; + +import Checkbox from "@mui/material/Checkbox"; +import { useTheme } from "@fiftyone/components"; +import { useSchemaSettings } from "@fiftyone/state"; +import { ExpandMore } from "@mui/icons-material"; +import styled from "styled-components"; + +const InfoCell = styled(Box)` + display: flex; + padding: 0 0.25rem; +`; + +const MetaInfoBlock = styled(Box)` + display: flex; + padding-left: 2rem; + font-size: 0.9rem; + color: ${({ theme }) => theme.text.secondary}; +`; + +const MetaInfoKey = styled(Typography)` + color: ${({ theme }) => theme.text.secondary}; + padding-right: 0.25rem; + font-weight: bold !important; + font-size: 1rem; +`; + +const MAX_ROW_HEIGHT = "200px"; + +interface Props { + path: string; + isSelected: boolean; + count: number; + disabled: boolean; + pathLabelFinal: string; + docTypeLabel: string; + isExpandable: boolean; + info: any; + description: string; +} + +export const SchemaSelectionRow = (props: Props) => { + const { + path, + isSelected, + count, + disabled, + pathLabelFinal, + docTypeLabel, + isExpandable, + info, + description, + } = props; + const theme = useTheme(); + const { + toggleSelection, + finalSchema, + isFilterRuleActive, + expandedPaths = {}, + setExpandedPaths, + } = useSchemaSettings(); + const expandedPathsKeys = new Set(Object.keys(expandedPaths || {})); + + const renderInfo = useCallback(() => { + if (info) { + const infoType = typeof info; + if (infoType === "number") { + const value = Number.isInteger(info) ? info : info.toFixed(3); + return {value}; + } + if (infoType === "string") { + return ( + {info.length ? info : '""'} + ); + } + if (infoType === "boolean") { + const boolLabel: string = info ? "True" : "False"; + return ( + {boolLabel} + ); + } + if (infoType === "object") { + try { + const obj = info; + if (Array.isArray(obj)) { + return obj.map((key) => { + return {key}; + }); + } else { + return Object.keys(obj).map((key) => { + const val = obj[key] || ""; + return ( + + + {`${key}:`} + {` `} + + {JSON.stringify(val)} + + ); + }); + } + } catch (e) { + return {info}; + } + } + return None; + } + }, [info, path]); + + return ( + + + + + { + toggleSelection(path, isSelected); + }} + style={{ + padding: 0, + }} + disabled={disabled} + /> + + + + {pathLabelFinal} + + + ({docTypeLabel}) + + + + {isExpandable && ( + { + if (expandedPathsKeys && expandedPathsKeys.has(path)) { + const newPaths = Object.assign({}, expandedPaths); + delete newPaths[path]; + setExpandedPaths(newPaths); + } else { + const newPaths = Object.assign({}, expandedPaths); + const element = finalSchema.filter( + (sc) => sc.path === path + )?.[0]; + + newPaths[path] = { + info: element?.info || "None", + description: element?.description || "None", + name: element?.name || "None", + }; + setExpandedPaths(newPaths); + } + }} + > + + + )} + + + {expandedPathsKeys.has(path) && ( + + {renderInfo(info, path)} + {description && ( + + Description: + {description} + + )} + + )} + + + ); +}; diff --git a/app/packages/core/src/components/Schema/SchemaSettings.tsx b/app/packages/core/src/components/Schema/SchemaSettings.tsx index 4a0a597ead..dc0a8fbe95 100644 --- a/app/packages/core/src/components/Schema/SchemaSettings.tsx +++ b/app/packages/core/src/components/Schema/SchemaSettings.tsx @@ -76,6 +76,8 @@ const SchemaSettings = () => { isFilterRuleActive, searchMetaFilter, enabledSelectedPaths, + setShowNestedFields, + setIncludeNestedFields, } = useSchemaSettings(); useOutsideClick(schemaModalRef, (_) => { @@ -131,6 +133,7 @@ const SchemaSettings = () => { position: "relative", display: "flex", justifyContent: "space-between", + alignItems: "center", }} > { { title: `Fiele ${value}`, onClick: () => { setSelectedTab(value); + setShowNestedFields(false); }, }; })} diff --git a/app/packages/core/src/components/Sidebar/Entries/FilterEntry.tsx b/app/packages/core/src/components/Sidebar/Entries/FilterEntry.tsx index 445443777f..35762f33b0 100644 --- a/app/packages/core/src/components/Sidebar/Entries/FilterEntry.tsx +++ b/app/packages/core/src/components/Sidebar/Entries/FilterEntry.tsx @@ -29,6 +29,7 @@ const Filter = ({ modal }: { modal: boolean }) => { resetTextFilter, resetExcludedPaths, affectedPathCount, + setSearchResults, } = fos.useSchemaSettings(); useDebounce( @@ -69,6 +70,7 @@ const Filter = ({ modal }: { modal: boolean }) => { resetSelectedFieldStages(); setSelectedFieldsStage(undefined); resetExcludedPaths(); + setSearchResults([]); }} > {affectedPathCount > 0 && ( diff --git a/app/packages/state/src/hooks/useSchemaSettings.ts b/app/packages/state/src/hooks/useSchemaSettings.ts index 87ca1a94ae..520af247e2 100644 --- a/app/packages/state/src/hooks/useSchemaSettings.ts +++ b/app/packages/state/src/hooks/useSchemaSettings.ts @@ -159,29 +159,39 @@ const disabledField = ( ))) ); }; + export const schemaSearchTerm = atom({ key: "schemaSearchTerm", default: "", }); + export const showNestedFieldsState = atom({ key: "showNestedFieldsState", default: false, }); + export const schemaSelectedSettingsTab = atom({ key: "schemaSelectedSettingsTab", default: TAB_OPTIONS_MAP.SELECTION, }); + export const settingsModal = atom<{ open: boolean } | null>({ key: "settingsModal", default: { open: false, }, }); + export const allFieldsCheckedState = atom({ key: "allFieldsCheckedState", default: true, }); +export const expandedPathsState = atom<{} | null>({ + key: "expandedPathsState", + default: null, +}); + export const schemaSearchRestuls = atom({ key: "schemaSearchRestuls", default: [], @@ -487,7 +497,6 @@ export default function useSchemaSettings() { const [searchTerm, setSearchTerm] = useRecoilState(schemaSearchTerm); const [searchResults, setSearchResults] = useRecoilState(schemaSearchRestuls); const isVideo = dataset.mediaType === "video"; - const isImage = dataset.mediaType === "image"; const setSchema = useSetRecoilState(schemaState); useEffect(() => { @@ -499,6 +508,7 @@ export default function useSchemaSettings() { const [allFieldsChecked, setAllFieldsChecked] = useRecoilState( allFieldsCheckedState ); + const [includeNestedFields, setIncludeNestedFieldsRaw] = useRecoilState( includeNestedFieldsState ); @@ -506,6 +516,7 @@ export default function useSchemaSettings() { const [affectedPathCount, setAffectedPathCount] = useRecoilState( affectedPathCountState ); + const [lastAppliedPaths, setLastAppliedPaths] = useRecoilState( lastAppliedPathsState ); @@ -513,9 +524,13 @@ export default function useSchemaSettings() { const [showNestedFields, setShowNestedFieldsRaw] = useRecoilState( showNestedFieldsState ); + const [searchMetaFilter, setSearchMetaFilter] = useRecoilState( searchMetaFilterState ); + + const [expandedPaths, setExpandedPaths] = useRecoilState(expandedPathsState); + const [lastActionToggleSelection, setLastActionToggleSelection] = useRecoilState(lastActionToggleSelectionState); @@ -540,6 +555,7 @@ export default function useSchemaSettings() { ); } }, [vStages, datasetName]); + const { fieldSchema: fieldSchemaRaw, frameFieldSchema } = data?.schemaForViewStages || {}; @@ -549,10 +565,10 @@ export default function useSchemaSettings() { const allPaths = !isEmpty(combinedSchema) ? Object.keys(combinedSchema) : []; useEffect(() => { - if (!isEmpty(viewSchema)) { + if (viewSchema && !isEmpty(viewSchema)) { setViewSchema(viewSchema); } - if (!isEmpty(fieldSchema)) { + if (fieldSchema && !isEmpty(fieldSchema)) { setFieldSchema(fieldSchema); } }, [viewSchema, fieldSchema]); @@ -568,7 +584,7 @@ export default function useSchemaSettings() { ); // disabled paths are filtered const datasetSelectedPaths = selectedPaths[datasetName] || []; - const enabledSelectedPaths = datasetSelectedPaths.length + const enabledSelectedPaths = datasetSelectedPaths?.length ? datasetSelectedPaths?.filter( ({ path }) => !disabledField(path, combinedSchema, isGroupDataset) ) @@ -581,7 +597,7 @@ export default function useSchemaSettings() { const setShowNestedFields = useCallback( (val: boolean) => { - let newExcludePaths = new Set(); + const newExcludePaths = new Set(); if (val) { excludedPaths?.[datasetName]?.forEach((path) => { const subPaths = [...getSubPaths(path)]; @@ -593,7 +609,7 @@ export default function useSchemaSettings() { excludedPaths?.[datasetName]?.forEach((path) => { if ( isVideo - ? (path.split(".").length === 2 && path.startsWith("frames.")) || + ? (path.split(".")?.length === 2 && path.startsWith("frames.")) || !path.includes(".") : !path.includes(".") ) { @@ -674,7 +690,8 @@ export default function useSchemaSettings() { const rawPath = val.path?.startsWith("frames.") ? val.path.replace("frames.", "") : val.path; - return showNestedFields || (filterRuleTab && searchResults.length) + return showNestedFields || + (filterRuleTab && searchResults.length && includeNestedFields) ? true : !rawPath.includes("."); }) @@ -705,6 +722,7 @@ export default function useSchemaSettings() { searchResults, datasetName, fieldSchema, + includeNestedFields, ]); const [searchSchemaFieldsRaw] = useMutation( @@ -916,9 +934,10 @@ export default function useSchemaSettings() { () => mergedSchema ? finalSchema.filter((field) => { - return ( - !disabledField(field.path, mergedSchema, isGroupDataset) && - !skipField(field.path, mergedSchema?.[field.path], mergedSchema) + return !skipField( + field.path, + mergedSchema?.[field.path], + mergedSchema ); }) : finalSchema, @@ -951,6 +970,7 @@ export default function useSchemaSettings() { datasetName, enabledSelectedPaths, excludedPaths, + expandedPaths, filterRuleTab, finalSchema, finalSchemaKeyByPath, @@ -969,6 +989,7 @@ export default function useSchemaSettings() { selectedTab, setAllFieldsChecked: setAllFieldsCheckedWrapper, setExcludedPaths, + setExpandedPaths, setIncludeNestedFields, setLastAppliedPaths, setSearchResults, From 6d33e2be8935994cfa9be83af918e7a74dae512d Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Thu, 8 Jun 2023 13:57:08 -0700 Subject: [PATCH 11/80] review comments, refactor selection row, and count fix --- .../src/components/Schema/SchemaSettings.tsx | 7 +- .../state/src/hooks/useSchemaSettings.ts | 72 ++++++++++++------- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/app/packages/core/src/components/Schema/SchemaSettings.tsx b/app/packages/core/src/components/Schema/SchemaSettings.tsx index dc0a8fbe95..62f0d32645 100644 --- a/app/packages/core/src/components/Schema/SchemaSettings.tsx +++ b/app/packages/core/src/components/Schema/SchemaSettings.tsx @@ -77,7 +77,6 @@ const SchemaSettings = () => { searchMetaFilter, enabledSelectedPaths, setShowNestedFields, - setIncludeNestedFields, } = useSchemaSettings(); useOutsideClick(schemaModalRef, (_) => { @@ -186,6 +185,12 @@ const SchemaSettings = () => { onClick: () => { setSelectedTab(value); setShowNestedFields(false); + setSelectedPaths({ + [datasetName]: new Set(lastAppliedPaths.selected), + }); + setExcludedPaths({ + [datasetName]: new Set(lastAppliedPaths.excluded), + }); }, }; })} diff --git a/app/packages/state/src/hooks/useSchemaSettings.ts b/app/packages/state/src/hooks/useSchemaSettings.ts index 520af247e2..1e5d21124a 100644 --- a/app/packages/state/src/hooks/useSchemaSettings.ts +++ b/app/packages/state/src/hooks/useSchemaSettings.ts @@ -73,7 +73,6 @@ const disabledField = ( ) => { const currField = combinedSchema?.[path] || ({} as Field); const { ftype, embeddedDocType } = currField; - const parentPath = path.substring(0, path.lastIndexOf(".")); const parentField = combinedSchema?.[parentPath]; const parentEmbeddedDocType = parentField?.embeddedDocType; @@ -583,12 +582,14 @@ export default function useSchemaSettings() { selectedPathState ); // disabled paths are filtered - const datasetSelectedPaths = selectedPaths[datasetName] || []; - const enabledSelectedPaths = datasetSelectedPaths?.length - ? datasetSelectedPaths?.filter( - ({ path }) => !disabledField(path, combinedSchema, isGroupDataset) - ) - : []; + const datasetSelectedPaths = selectedPaths[datasetName] || new Set(); + const enabledSelectedPaths = + datasetSelectedPaths?.size && combinedSchema + ? [...datasetSelectedPaths]?.filter( + ({ path }) => + path && !disabledField(path, combinedSchema, isGroupDataset) + ) + : []; const excludePathsState = excludedPathsState({}); const [excludedPaths, setExcludedPaths] = useRecoilState<{}>( @@ -672,6 +673,7 @@ export default function useSchemaSettings() { (filterRuleTab && isInSearchResult) || (!filterRuleTab && selectedPaths?.[datasetName] && + selectedPaths[datasetName] instanceof Set && selectedPaths[datasetName]?.has(fullPath)); return { @@ -690,7 +692,7 @@ export default function useSchemaSettings() { const rawPath = val.path?.startsWith("frames.") ? val.path.replace("frames.", "") : val.path; - return showNestedFields || + return (!filterRuleTab && showNestedFields) || (filterRuleTab && searchResults.length && includeNestedFields) ? true : !rawPath.includes("."); @@ -844,8 +846,8 @@ export default function useSchemaSettings() { [datasetName]: combinedSchema, })); if ( - !lastAppliedPaths.selected.length && - !lastAppliedPaths.excluded.length + !lastAppliedPaths.selected?.length && + !lastAppliedPaths.excluded?.length ) { setLastAppliedPaths({ selected: [...combinedSchema], @@ -896,8 +898,22 @@ export default function useSchemaSettings() { [selectedPaths, viewPaths, datasetName, excludedPaths] ); + const bareFinalSchema = useMemo( + () => + mergedSchema + ? finalSchema.filter((field) => { + return !skipField( + field.path, + mergedSchema?.[field.path], + mergedSchema + ); + }) + : finalSchema, + [mergedSchema, finalSchema, isGroupDataset] + ); + useEffect(() => { - if (!allPaths?.length) return; + if (!allPaths?.length || !combinedSchema) return; if (lastActionToggleSelection) { const val = lastActionToggleSelection[SELECT_ALL]; @@ -915,12 +931,28 @@ export default function useSchemaSettings() { ); setExcludedPaths({ [datasetName]: new Set(topLevelPaths) }); } - setSelectedPaths({ [datasetName]: new Set() }); + const res = Object.values(combinedSchema) + .filter((f) => disabledField(f.path, combinedSchema, isGroupDataset)) + .map((f) => f.path); + + setSelectedPaths({ + [datasetName]: new Set(res), + }); } setLastActionToggleSelection(null); } - }, [lastActionToggleSelection, allPaths]); + }, [ + lastActionToggleSelection, + allPaths, + setLastActionToggleSelection, + setExcludedPaths, + datasetName, + setSelectedPaths, + includeNestedFields, + filterRuleTab, + combinedSchema, + ]); const setAllFieldsCheckedWrapper = useCallback( (val: boolean) => { @@ -930,20 +962,6 @@ export default function useSchemaSettings() { [finalSchema] ); - const bareFinalSchema = useMemo( - () => - mergedSchema - ? finalSchema.filter((field) => { - return !skipField( - field.path, - mergedSchema?.[field.path], - mergedSchema - ); - }) - : finalSchema, - [mergedSchema, finalSchema, isGroupDataset] - ); - // updates the affected fields count useEffect(() => { if (finalSchema?.length && excludedPaths?.[datasetName]) { From 75e732fab927336bce5915ab995d6ba53987a146 Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Thu, 8 Jun 2023 15:38:24 -0700 Subject: [PATCH 12/80] add first vitest for visibility, upgrade vitest packages --- app/package.json | 8 +- .../state/src/hooks/useSchemaSettings.test.ts | 32 ++ .../state/src/hooks/useSchemaSettings.ts | 7 +- app/yarn.lock | 469 +++++++++++++++++- 4 files changed, 492 insertions(+), 24 deletions(-) create mode 100644 app/packages/state/src/hooks/useSchemaSettings.test.ts diff --git a/app/package.json b/app/package.json index fe0e8c9bad..b4e9d76cd0 100644 --- a/app/package.json +++ b/app/package.json @@ -15,7 +15,8 @@ "postinstall": "patch-package", "start": "yarn workspace @fiftyone/app start", "start-desktop": "yarn workspace FiftyOne start-desktop", - "test": "yarn vitest run", + "test": "yarn vitest run --coverage", + "test-ui": "yarn vitest --ui", "gen:schema": "strawberry export-schema fiftyone.server.app:schema > schema.graphql" }, "devDependencies": { @@ -23,7 +24,8 @@ "@testing-library/react-hooks": "latest", "@typescript-eslint/eslint-plugin": "^5.44.0", "@typescript-eslint/parser": "^5.44.0", - "@vitest/coverage-c8": "^0.25.2", + "@vitest/coverage-v8": "^0.32.0", + "@vitest/ui": "^0.32.0", "concurrently": "^7.2.1", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", @@ -42,7 +44,7 @@ "vite": "^3.0.0", "vite-plugin-eslint": "^1.8.1", "vite-plugin-relay": "^2.0.0", - "vitest": "^0.25.2" + "vitest": "^0.32.0" }, "workspaces": [ "packages/*" diff --git a/app/packages/state/src/hooks/useSchemaSettings.test.ts b/app/packages/state/src/hooks/useSchemaSettings.test.ts new file mode 100644 index 0000000000..73042d930d --- /dev/null +++ b/app/packages/state/src/hooks/useSchemaSettings.test.ts @@ -0,0 +1,32 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; +import { disabledField } from "./useSchemaSettings"; +import { OBJECT_ID_FIELD } from "@fiftyone/utilities"; + +const FIELDS = { + ID_FIELD: { + path: "id", + embeddedDocType: null, + ftype: OBJECT_ID_FIELD, + description: null, + info: null, + name: null, + fields: null, + dbField: null, + subfield: null, + visible: false, + }, +}; + +describe("Disabled schema fields", () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("id path is disabled across all fields", () => { + const path = "id"; + const field_1 = FIELDS.ID_FIELD; + const schema = { id: field_1 }; + const isGroupDataset = "group"; + expect(disabledField(path, schema, isGroupDataset)).toBe(true); + }); +}); diff --git a/app/packages/state/src/hooks/useSchemaSettings.ts b/app/packages/state/src/hooks/useSchemaSettings.ts index 1e5d21124a..6e78867c17 100644 --- a/app/packages/state/src/hooks/useSchemaSettings.ts +++ b/app/packages/state/src/hooks/useSchemaSettings.ts @@ -66,11 +66,12 @@ const skipField = (path: string, ftype: string, schema: {}) => { path.endsWith(".index") ); }; -const disabledField = ( + +export const disabledField = ( path: string, - combinedSchema: Schema, + combinedSchema: Record, groupField?: string -) => { +): boolean => { const currField = combinedSchema?.[path] || ({} as Field); const { ftype, embeddedDocType } = currField; const parentPath = path.substring(0, path.lastIndexOf(".")); diff --git a/app/yarn.lock b/app/yarn.lock index 77cc94fe22..fe3a851d28 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -22,6 +22,16 @@ __metadata: languageName: node linkType: hard +"@ampproject/remapping@npm:^2.2.1": + version: 2.2.1 + resolution: "@ampproject/remapping@npm:2.2.1" + dependencies: + "@jridgewell/gen-mapping": ^0.3.0 + "@jridgewell/trace-mapping": ^0.3.9 + checksum: 03c04fd526acc64a1f4df22651186f3e5ef0a9d6d6530ce4482ec9841269cf7a11dbb8af79237c282d721c5312024ff17529cd72cc4768c11e999b58e2302079 + languageName: node + linkType: hard + "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.7": version: 7.16.7 resolution: "@babel/code-frame@npm:7.16.7" @@ -4454,7 +4464,8 @@ __metadata: "@testing-library/react-hooks": latest "@typescript-eslint/eslint-plugin": ^5.44.0 "@typescript-eslint/parser": ^5.44.0 - "@vitest/coverage-c8": ^0.25.2 + "@vitest/coverage-v8": ^0.32.0 + "@vitest/ui": ^0.32.0 concurrently: ^7.2.1 eslint: ^8.28.0 eslint-config-prettier: ^8.5.0 @@ -4474,7 +4485,7 @@ __metadata: vite: ^3.0.0 vite-plugin-eslint: ^1.8.1 vite-plugin-relay: ^2.0.0 - vitest: ^0.25.2 + vitest: ^0.32.0 languageName: unknown linkType: soft @@ -5132,6 +5143,23 @@ __metadata: languageName: node linkType: hard +"@jridgewell/sourcemap-codec@npm:^1.4.13": + version: 1.4.15 + resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" + checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.12": + version: 0.3.18 + resolution: "@jridgewell/trace-mapping@npm:0.3.18" + dependencies: + "@jridgewell/resolve-uri": 3.1.0 + "@jridgewell/sourcemap-codec": 1.4.14 + checksum: 0572669f855260808c16fe8f78f5f1b4356463b11d3f2c7c0b5580c8ba1cbf4ae53efe9f627595830856e57dbac2325ac17eb0c3dd0ec42102e6f227cc289c02 + languageName: node + linkType: hard + "@jridgewell/trace-mapping@npm:^0.3.14": version: 0.3.17 resolution: "@jridgewell/trace-mapping@npm:0.3.17" @@ -7934,6 +7962,13 @@ __metadata: languageName: node linkType: hard +"@types/chai@npm:^4.3.5": + version: 4.3.5 + resolution: "@types/chai@npm:4.3.5" + checksum: c8f26a88c6b5b53a3275c7f5ff8f107028e3cbb9ff26795fff5f3d9dea07106a54ce9e2dce5e40347f7c4cc35657900aaf0c83934a25a1ae12e61e0f5516e431 + languageName: node + linkType: hard + "@types/color-string@npm:^1.5.0": version: 1.5.2 resolution: "@types/color-string@npm:1.5.2" @@ -8932,13 +8967,67 @@ __metadata: languageName: node linkType: hard -"@vitest/coverage-c8@npm:^0.25.2": - version: 0.25.8 - resolution: "@vitest/coverage-c8@npm:0.25.8" +"@vitest/coverage-v8@npm:^0.32.0": + version: 0.32.0 + resolution: "@vitest/coverage-v8@npm:0.32.0" + dependencies: + "@ampproject/remapping": ^2.2.1 + "@bcoe/v8-coverage": ^0.2.3 + istanbul-lib-coverage: ^3.2.0 + istanbul-lib-report: ^3.0.0 + istanbul-lib-source-maps: ^4.0.1 + istanbul-reports: ^3.1.5 + magic-string: ^0.30.0 + picocolors: ^1.0.0 + std-env: ^3.3.2 + test-exclude: ^6.0.0 + v8-to-istanbul: ^9.1.0 + peerDependencies: + vitest: ">=0.32.0 <1" + checksum: 6f025b5a74397c91bab988c58a763ad9d4e9a3ebb20c928e3732e409358be656d0f3753e114970bce1f2a53cd09f3bab0f0a947cc0c7683469fd66a5c74a337c + languageName: node + linkType: hard + +"@vitest/expect@npm:0.32.0": + version: 0.32.0 + resolution: "@vitest/expect@npm:0.32.0" + dependencies: + "@vitest/spy": 0.32.0 + "@vitest/utils": 0.32.0 + chai: ^4.3.7 + checksum: 0f5740057faf1a45be00b7e06ad8dd7e5b37d9f436e29701a8577d42bdff930ce958bc9a7732eb88fb71a3ab5009a72f2ed11c02b2095a4173fa69f69897e7b4 + languageName: node + linkType: hard + +"@vitest/runner@npm:0.32.0": + version: 0.32.0 + resolution: "@vitest/runner@npm:0.32.0" + dependencies: + "@vitest/utils": 0.32.0 + concordance: ^5.0.4 + p-limit: ^4.0.0 + pathe: ^1.1.0 + checksum: d7a63a9a80d90a48e706fcf8bc1c2171ee0395f60241c1f0bb67854d246b68a472805d6abe33ce9a7250768c0b27af882e4beb7a5ba9eea2b3e085a54ed978e0 + languageName: node + linkType: hard + +"@vitest/snapshot@npm:0.32.0": + version: 0.32.0 + resolution: "@vitest/snapshot@npm:0.32.0" + dependencies: + magic-string: ^0.30.0 + pathe: ^1.1.0 + pretty-format: ^27.5.1 + checksum: 2017d461b8492ae16b15f4f3725e1e3dc7bd18e24f1db788f151f9435af620ee711114edc4bd6ad88ba047f47dc4104b7db87d7f7b29363537272c0353ceb71d + languageName: node + linkType: hard + +"@vitest/spy@npm:0.32.0": + version: 0.32.0 + resolution: "@vitest/spy@npm:0.32.0" dependencies: - c8: ^7.12.0 - vitest: 0.25.8 - checksum: 189a7d8df0e4185d7f016184c70a65fc40bf661294de340b7c63991ffb494acf09769ce1bc4817d879f13b5b5e462ab4052ca35fa8315ca2723b69f9fce61a28 + tinyspy: ^2.1.0 + checksum: 1c418f4064f4357e972e99d20e2b7b65b8cde3a8280a8e06a41fa81517efe335ca176c21a6644a6f490b565fb0ed6df0ed4ab8097813be3d0f4ec625b7fd3451 languageName: node linkType: hard @@ -8951,6 +9040,34 @@ __metadata: languageName: node linkType: hard +"@vitest/ui@npm:^0.32.0": + version: 0.32.0 + resolution: "@vitest/ui@npm:0.32.0" + dependencies: + "@vitest/utils": 0.32.0 + fast-glob: ^3.2.12 + fflate: ^0.7.4 + flatted: ^3.2.7 + pathe: ^1.1.0 + picocolors: ^1.0.0 + sirv: ^2.0.3 + peerDependencies: + vitest: ">=0.30.1 <1" + checksum: 0a0ac067ef667dfdd60e89c8a554cd2056cd5c39874940a0ed13cd4b27e04755aa2df56bbb19dcbf8eff7c458d84b7832ce9e817a5671319bb46019d3473c98d + languageName: node + linkType: hard + +"@vitest/utils@npm:0.32.0": + version: 0.32.0 + resolution: "@vitest/utils@npm:0.32.0" + dependencies: + concordance: ^5.0.4 + loupe: ^2.3.6 + pretty-format: ^27.5.1 + checksum: f27df1e7066a310cd43a7261f2b1f668e32b7443f9b90af4a6e49575ee2d65b019192833ddbd0f51eb5690130b5b1bd2459cb83397860941308eeb122983427a + languageName: node + linkType: hard + "@webassemblyjs/ast@npm:1.11.1": version: 1.11.1 resolution: "@webassemblyjs/ast@npm:1.11.1" @@ -9488,6 +9605,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^8.8.2": + version: 8.8.2 + resolution: "acorn@npm:8.8.2" + bin: + acorn: bin/acorn + checksum: f790b99a1bf63ef160c967e23c46feea7787e531292bb827126334612c234ed489a0dc2c7ba33156416f0ffa8d25bf2b0fdb7f35c2ba60eb3e960572bece4001 + languageName: node + linkType: hard + "address@npm:^1.0.1": version: 1.2.1 resolution: "address@npm:1.2.1" @@ -10624,6 +10750,13 @@ __metadata: languageName: node linkType: hard +"blueimp-md5@npm:^2.10.0": + version: 2.19.0 + resolution: "blueimp-md5@npm:2.19.0" + checksum: 28095dcbd2c67152a2938006e8d7c74c3406ba6556071298f872505432feb2c13241b0476644160ee0a5220383ba94cb8ccdac0053b51f68d168728f9c382530 + languageName: node + linkType: hard + "bn.js@npm:^4.0.0, bn.js@npm:^4.1.0, bn.js@npm:^4.11.9": version: 4.12.0 resolution: "bn.js@npm:4.12.0" @@ -11015,7 +11148,7 @@ __metadata: languageName: node linkType: hard -"c8@npm:^7.12.0, c8@npm:^7.6.0": +"c8@npm:^7.6.0": version: 7.12.0 resolution: "c8@npm:7.12.0" dependencies: @@ -11037,6 +11170,13 @@ __metadata: languageName: node linkType: hard +"cac@npm:^6.7.14": + version: 6.7.14 + resolution: "cac@npm:6.7.14" + checksum: 45a2496a9443abbe7f52a49b22fbe51b1905eff46e03fd5e6c98e3f85077be3f8949685a1849b1a9cd2bc3e5567dfebcf64f01ce01847baf918f1b37c839791a + languageName: node + linkType: hard + "cacache@npm:^12.0.2": version: 12.0.4 resolution: "cacache@npm:12.0.4" @@ -11981,6 +12121,22 @@ __metadata: languageName: node linkType: hard +"concordance@npm:^5.0.4": + version: 5.0.4 + resolution: "concordance@npm:5.0.4" + dependencies: + date-time: ^3.1.0 + esutils: ^2.0.3 + fast-diff: ^1.2.0 + js-string-escape: ^1.0.1 + lodash: ^4.17.15 + md5-hex: ^3.0.1 + semver: ^7.3.2 + well-known-symbols: ^2.0.0 + checksum: 749153ba711492feb7c3d2f5bb04c107157440b3e39509bd5dd19ee7b3ac751d1e4cd75796d9f702e0a713312dbc661421c68aa4a2c34d5f6d91f47e3a1c64a6 + languageName: node + linkType: hard + "concurrently@npm:^7.2.1": version: 7.2.1 resolution: "concurrently@npm:7.2.1" @@ -12922,6 +13078,15 @@ __metadata: languageName: node linkType: hard +"date-time@npm:^3.1.0": + version: 3.1.0 + resolution: "date-time@npm:3.1.0" + dependencies: + time-zone: ^1.0.0 + checksum: f9cfcd1b15dfeabab15c0b9d18eb9e4e2d9d4371713564178d46a8f91ad577a290b5178b80050718d02d9c0cf646f8a875011e12d1ed05871e9f72c72c8a8fe6 + languageName: node + linkType: hard + "debounce@npm:^1.2.1": version: 1.2.1 resolution: "debounce@npm:1.2.1" @@ -14720,7 +14885,7 @@ __metadata: languageName: node linkType: hard -"esutils@npm:^2.0.2": +"esutils@npm:^2.0.2, esutils@npm:^2.0.3": version: 2.0.3 resolution: "esutils@npm:2.0.3" checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87 @@ -14968,6 +15133,13 @@ __metadata: languageName: node linkType: hard +"fast-diff@npm:^1.2.0": + version: 1.3.0 + resolution: "fast-diff@npm:1.3.0" + checksum: d22d371b994fdc8cce9ff510d7b8dc4da70ac327bcba20df607dd5b9cae9f908f4d1028f5fe467650f058d1e7270235ae0b8230809a262b4df587a3b3aa216c3 + languageName: node + linkType: hard + "fast-equals@npm:^2.0.0": version: 2.0.4 resolution: "fast-equals@npm:2.0.4" @@ -14989,7 +15161,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.9": +"fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9": version: 3.2.12 resolution: "fast-glob@npm:3.2.12" dependencies: @@ -15169,6 +15341,13 @@ __metadata: languageName: node linkType: hard +"fflate@npm:^0.7.4": + version: 0.7.4 + resolution: "fflate@npm:0.7.4" + checksum: b812ab26047432db70ff4c73eb45ad53bd0774575b4818b9c61c2921e89ec65d1259f06ec1618f2ac55e6a2f2e29b6dc09173d213b46580bc69efae5344bf8f1 + languageName: node + linkType: hard + "figgy-pudding@npm:^3.5.1": version: 3.5.2 resolution: "figgy-pudding@npm:3.5.2" @@ -15346,7 +15525,7 @@ __metadata: languageName: node linkType: hard -"flatted@npm:^3.1.0": +"flatted@npm:^3.1.0, flatted@npm:^3.2.7": version: 3.2.7 resolution: "flatted@npm:3.2.7" checksum: 427633049d55bdb80201c68f7eb1cbd533e03eac541f97d3aecab8c5526f12a20ccecaeede08b57503e772c769e7f8680b37e8d482d1e5f8d7e2194687f9ea35 @@ -18100,7 +18279,7 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-source-maps@npm:^4.0.0": +"istanbul-lib-source-maps@npm:^4.0.0, istanbul-lib-source-maps@npm:^4.0.1": version: 4.0.1 resolution: "istanbul-lib-source-maps@npm:4.0.1" dependencies: @@ -18121,7 +18300,7 @@ __metadata: languageName: node linkType: hard -"istanbul-reports@npm:^3.1.4": +"istanbul-reports@npm:^3.1.4, istanbul-reports@npm:^3.1.5": version: 3.1.5 resolution: "istanbul-reports@npm:3.1.5" dependencies: @@ -18891,7 +19070,7 @@ __metadata: languageName: node linkType: hard -"jsonc-parser@npm:^3.0.0": +"jsonc-parser@npm:^3.0.0, jsonc-parser@npm:^3.2.0": version: 3.2.0 resolution: "jsonc-parser@npm:3.2.0" checksum: 946dd9a5f326b745aa326d48a7257e3f4a4b62c5e98ec8e49fa2bdd8d96cef7e6febf1399f5c7016114fd1f68a1c62c6138826d5d90bc650448e3cf0951c53c7 @@ -19305,6 +19484,13 @@ __metadata: languageName: node linkType: hard +"local-pkg@npm:^0.4.3": + version: 0.4.3 + resolution: "local-pkg@npm:0.4.3" + checksum: 7825aca531dd6afa3a3712a0208697aa4a5cd009065f32e3fb732aafcc42ed11f277b5ac67229222e96f4def55197171cdf3d5522d0381b489d2e5547b407d55 + languageName: node + linkType: hard + "locate-path@npm:^3.0.0": version: 3.0.0 resolution: "locate-path@npm:3.0.0" @@ -19445,7 +19631,7 @@ __metadata: languageName: node linkType: hard -"loupe@npm:^2.3.1": +"loupe@npm:^2.3.1, loupe@npm:^2.3.6": version: 2.3.6 resolution: "loupe@npm:2.3.6" dependencies: @@ -19546,6 +19732,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.30.0": + version: 0.30.0 + resolution: "magic-string@npm:0.30.0" + dependencies: + "@jridgewell/sourcemap-codec": ^1.4.13 + checksum: 7bdf22e27334d8a393858a16f5f840af63a7c05848c000fd714da5aa5eefa09a1bc01d8469362f25cc5c4a14ec01b46557b7fff8751365522acddf21e57c488d + languageName: node + linkType: hard + "make-dir@npm:^2.0.0, make-dir@npm:^2.1.0": version: 2.1.0 resolution: "make-dir@npm:2.1.0" @@ -19737,6 +19932,15 @@ __metadata: languageName: node linkType: hard +"md5-hex@npm:^3.0.1": + version: 3.0.1 + resolution: "md5-hex@npm:3.0.1" + dependencies: + blueimp-md5: ^2.10.0 + checksum: 6799a19e8bdd3e0c2861b94c1d4d858a89220488d7885c1fa236797e367d0c2e5f2b789e05309307083503f85be3603a9686a5915568a473137d6b4117419cc2 + languageName: node + linkType: hard + "md5.js@npm:^1.3.4": version: 1.3.5 resolution: "md5.js@npm:1.3.5" @@ -20501,6 +20705,18 @@ __metadata: languageName: node linkType: hard +"mlly@npm:^1.2.0": + version: 1.3.0 + resolution: "mlly@npm:1.3.0" + dependencies: + acorn: ^8.8.2 + pathe: ^1.1.0 + pkg-types: ^1.0.3 + ufo: ^1.1.2 + checksum: aea2a99131b1a1f02a733219317b6466156e150473e0a2f490802eaf2dc66940a21bb68e0ddd5c003360263e674e7dd0bd02da6520c740e6d16fa0edf5efa46e + languageName: node + linkType: hard + "mmd-parser@npm:^1.0.4": version: 1.0.4 resolution: "mmd-parser@npm:1.0.4" @@ -21414,6 +21630,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^4.0.0": + version: 4.0.0 + resolution: "p-limit@npm:4.0.0" + dependencies: + yocto-queue: ^1.0.0 + checksum: 01d9d70695187788f984226e16c903475ec6a947ee7b21948d6f597bed788e3112cc7ec2e171c1d37125057a5f45f3da21d8653e04a3a793589e12e9e80e756b + languageName: node + linkType: hard + "p-locate@npm:^3.0.0": version: 3.0.0 resolution: "p-locate@npm:3.0.0" @@ -21802,6 +22027,13 @@ __metadata: languageName: node linkType: hard +"pathe@npm:^1.1.0": + version: 1.1.1 + resolution: "pathe@npm:1.1.1" + checksum: 34ab3da2e5aa832ebc6a330ffe3f73d7ba8aec6e899b53b8ec4f4018de08e40742802deb12cf5add9c73b7bf719b62c0778246bd376ca62b0fb23e0dde44b759 + languageName: node + linkType: hard + "pathval@npm:^1.1.1": version: 1.1.1 resolution: "pathval@npm:1.1.1" @@ -21947,6 +22179,17 @@ __metadata: languageName: node linkType: hard +"pkg-types@npm:^1.0.3": + version: 1.0.3 + resolution: "pkg-types@npm:1.0.3" + dependencies: + jsonc-parser: ^3.2.0 + mlly: ^1.2.0 + pathe: ^1.1.0 + checksum: 4b305c834b912ddcc8a0fe77530c0b0321fe340396f84cbb87aecdbc126606f47f2178f23b8639e71a4870f9631c7217aef52ffed0ae17ea2dbbe7e43d116a6e + languageName: node + linkType: hard + "plist@npm:^3.0.1, plist@npm:^3.0.4": version: 3.0.5 resolution: "plist@npm:3.0.5" @@ -22350,7 +22593,7 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^27.0.2": +"pretty-format@npm:^27.0.2, pretty-format@npm:^27.5.1": version: 27.5.1 resolution: "pretty-format@npm:27.5.1" dependencies: @@ -24932,6 +25175,13 @@ __metadata: languageName: node linkType: hard +"siginfo@npm:^2.0.0": + version: 2.0.0 + resolution: "siginfo@npm:2.0.0" + checksum: 8aa5a98640ca09fe00d74416eca97551b3e42991614a3d1b824b115fc1401543650914f651ab1311518177e4d297e80b953f4cd4cd7ea1eabe824e8f2091de01 + languageName: node + linkType: hard + "signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" @@ -24975,6 +25225,17 @@ __metadata: languageName: node linkType: hard +"sirv@npm:^2.0.3": + version: 2.0.3 + resolution: "sirv@npm:2.0.3" + dependencies: + "@polka/url": ^1.0.0-next.20 + mrmime: ^1.0.0 + totalist: ^3.0.0 + checksum: e2dfd4c97735a6ad6d842d0eec2cd9e3919ff0e46f0d228248c5753ad4b70b832711e77e1259c031c439cdb08303cc54d923685c92b0e890145cc733af7c5568 + languageName: node + linkType: hard + "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -25304,6 +25565,13 @@ __metadata: languageName: node linkType: hard +"stackback@npm:0.0.2": + version: 0.0.2 + resolution: "stackback@npm:0.0.2" + checksum: 2d4dc4e64e2db796de4a3c856d5943daccdfa3dd092e452a1ce059c81e9a9c29e0b9badba91b43ef0d5ff5c04ee62feb3bcc559a804e16faf447bac2d883aa99 + languageName: node + linkType: hard + "stackframe@npm:^1.1.1": version: 1.2.1 resolution: "stackframe@npm:1.2.1" @@ -25386,6 +25654,13 @@ __metadata: languageName: node linkType: hard +"std-env@npm:^3.3.2": + version: 3.3.3 + resolution: "std-env@npm:3.3.3" + checksum: 6665f6d8bd63aae432d3eb9abbd7322847ad0d902603e6dce1e8051b4f42ceeb4f7f96a4faf70bb05ce65ceee2dc982502b701575c8a58b1bfad29f3dbb19f81 + languageName: node + linkType: hard + "store2@npm:^2.12.0": version: 2.14.2 resolution: "store2@npm:2.14.2" @@ -25672,6 +25947,15 @@ __metadata: languageName: node linkType: hard +"strip-literal@npm:^1.0.1": + version: 1.0.1 + resolution: "strip-literal@npm:1.0.1" + dependencies: + acorn: ^8.8.2 + checksum: ab40496820f02220390d95cdd620a997168efb69d5bd7d180bc4ef83ca562a95447843d8c7c88b8284879a29cf4eedc89d8001d1e098c1a1e23d12a9c755dff4 + languageName: node + linkType: hard + "strongly-connected-components@npm:^1.0.1": version: 1.0.1 resolution: "strongly-connected-components@npm:1.0.1" @@ -26180,6 +26464,13 @@ __metadata: languageName: node linkType: hard +"time-zone@npm:^1.0.0": + version: 1.0.0 + resolution: "time-zone@npm:1.0.0" + checksum: e46f5a69b8c236dcd8e91e29d40d4e7a3495ed4f59888c3f84ce1d9678e20461421a6ba41233509d47dd94bc18f1a4377764838b21b584663f942b3426dcbce8 + languageName: node + linkType: hard + "timers-browserify@npm:^2.0.4": version: 2.0.12 resolution: "timers-browserify@npm:2.0.12" @@ -26217,6 +26508,13 @@ __metadata: languageName: node linkType: hard +"tinybench@npm:^2.5.0": + version: 2.5.0 + resolution: "tinybench@npm:2.5.0" + checksum: 284bb9428f197ec8b869c543181315e65e41ccfdad3c4b6c916bb1fdae1b5c6785661b0d90cf135b48d833b03cb84dc5357b2d33ec65a1f5971fae0ab2023821 + languageName: node + linkType: hard + "tinycolor2@npm:^1.4.1": version: 1.6.0 resolution: "tinycolor2@npm:1.6.0" @@ -26238,6 +26536,13 @@ __metadata: languageName: node linkType: hard +"tinypool@npm:^0.5.0": + version: 0.5.0 + resolution: "tinypool@npm:0.5.0" + checksum: 4e0dfd8f28666d541c1d92304222edc4613f05d74fe2243c8520d466a2cc6596011a7072c1c41a7de7522351b82fda07e8038198e8f43673d8d69401c5903f8c + languageName: node + linkType: hard + "tinyqueue@npm:^2.0.3": version: 2.0.3 resolution: "tinyqueue@npm:2.0.3" @@ -26252,6 +26557,13 @@ __metadata: languageName: node linkType: hard +"tinyspy@npm:^2.1.0": + version: 2.1.1 + resolution: "tinyspy@npm:2.1.1" + checksum: cfe669803a7f11ca912742b84c18dcc4ceecaa7661c69bc5eb608a8a802d541c48aba220df8929f6c8cd09892ad37cb5ba5958ddbbb57940e91d04681d3cee73 + languageName: node + linkType: hard + "tmp-promise@npm:^3.0.2": version: 3.0.3 resolution: "tmp-promise@npm:3.0.3" @@ -26851,6 +27163,13 @@ __metadata: languageName: node linkType: hard +"ufo@npm:^1.1.2": + version: 1.1.2 + resolution: "ufo@npm:1.1.2" + checksum: 83c940a6a23b6d4fc0cd116265bb5dcf88ab34a408ad9196e413270ca607a4781c09b547dc518f43caee128a096f20fe80b5a0e62b4bcc0a868619896106d048 + languageName: node + linkType: hard + "uglify-js@npm:^3.1.4": version: 3.17.4 resolution: "uglify-js@npm:3.17.4" @@ -27563,6 +27882,17 @@ __metadata: languageName: node linkType: hard +"v8-to-istanbul@npm:^9.1.0": + version: 9.1.0 + resolution: "v8-to-istanbul@npm:9.1.0" + dependencies: + "@jridgewell/trace-mapping": ^0.3.12 + "@types/istanbul-lib-coverage": ^2.0.1 + convert-source-map: ^1.6.0 + checksum: 2069d59ee46cf8d83b4adfd8a5c1a90834caffa9f675e4360f1157ffc8578ef0f763c8f32d128334424159bb6b01f3876acd39cd13297b2769405a9da241f8d1 + languageName: node + linkType: hard + "validate-npm-package-license@npm:^3.0.1": version: 3.0.4 resolution: "validate-npm-package-license@npm:3.0.4" @@ -27737,6 +28067,22 @@ __metadata: languageName: node linkType: hard +"vite-node@npm:0.32.0": + version: 0.32.0 + resolution: "vite-node@npm:0.32.0" + dependencies: + cac: ^6.7.14 + debug: ^4.3.4 + mlly: ^1.2.0 + pathe: ^1.1.0 + picocolors: ^1.0.0 + vite: ^3.0.0 || ^4.0.0 + bin: + vite-node: vite-node.mjs + checksum: ce1c45e7d903afc001a08b3bc3159d268e8422e28ec7ffa8e4a4f99d18c9f4e447db989a6e0a8e168d3a4f4e6eb0b954f2b51ef1a85f29cc3f7f561045ff0bbe + languageName: node + linkType: hard + "vite-plugin-eslint@npm:^1.8.1": version: 1.8.1 resolution: "vite-plugin-eslint@npm:1.8.1" @@ -27920,7 +28266,7 @@ __metadata: languageName: node linkType: hard -"vitest@npm:0.25.8, vitest@npm:^0.25.2": +"vitest@npm:^0.25.2": version: 0.25.8 resolution: "vitest@npm:0.25.8" dependencies: @@ -27961,6 +28307,67 @@ __metadata: languageName: node linkType: hard +"vitest@npm:^0.32.0": + version: 0.32.0 + resolution: "vitest@npm:0.32.0" + dependencies: + "@types/chai": ^4.3.5 + "@types/chai-subset": ^1.3.3 + "@types/node": "*" + "@vitest/expect": 0.32.0 + "@vitest/runner": 0.32.0 + "@vitest/snapshot": 0.32.0 + "@vitest/spy": 0.32.0 + "@vitest/utils": 0.32.0 + acorn: ^8.8.2 + acorn-walk: ^8.2.0 + cac: ^6.7.14 + chai: ^4.3.7 + concordance: ^5.0.4 + debug: ^4.3.4 + local-pkg: ^0.4.3 + magic-string: ^0.30.0 + pathe: ^1.1.0 + picocolors: ^1.0.0 + std-env: ^3.3.2 + strip-literal: ^1.0.1 + tinybench: ^2.5.0 + tinypool: ^0.5.0 + vite: ^3.0.0 || ^4.0.0 + vite-node: 0.32.0 + why-is-node-running: ^2.2.2 + peerDependencies: + "@edge-runtime/vm": "*" + "@vitest/browser": "*" + "@vitest/ui": "*" + happy-dom: "*" + jsdom: "*" + playwright: "*" + safaridriver: "*" + webdriverio: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@vitest/browser": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + playwright: + optional: true + safaridriver: + optional: true + webdriverio: + optional: true + bin: + vitest: vitest.mjs + checksum: a752f7a2290e08cc4033936b1b9e1fe6adcb156bccff6404d4950b4f913c01a8015768f8dbd35267752331311dc55e218d56c5271c56e5ca9c848a36a5dc5b55 + languageName: node + linkType: hard + "vm-browserify@npm:^1.0.1": version: 1.1.2 resolution: "vm-browserify@npm:1.1.2" @@ -28244,6 +28651,13 @@ __metadata: languageName: node linkType: hard +"well-known-symbols@npm:^2.0.0": + version: 2.0.0 + resolution: "well-known-symbols@npm:2.0.0" + checksum: 4f54bbc3012371cb4d228f436891b8e7536d34ac61a57541890257e96788608e096231e0121ac24d08ef2f908b3eb2dc0adba35023eaeb2a7df655da91415402 + languageName: node + linkType: hard + "wgs84@npm:0.0.0": version: 0.0.0 resolution: "wgs84@npm:0.0.0" @@ -28362,6 +28776,18 @@ __metadata: languageName: node linkType: hard +"why-is-node-running@npm:^2.2.2": + version: 2.2.2 + resolution: "why-is-node-running@npm:2.2.2" + dependencies: + siginfo: ^2.0.0 + stackback: 0.0.2 + bin: + why-is-node-running: cli.js + checksum: 50820428f6a82dfc3cbce661570bcae9b658723217359b6037b67e495255409b4c8bc7931745f5c175df71210450464517cab32b2f7458ac9c40b4925065200a + languageName: node + linkType: hard + "wide-align@npm:^1.1.2, wide-align@npm:^1.1.5": version: 1.1.5 resolution: "wide-align@npm:1.1.5" @@ -28664,6 +29090,13 @@ __metadata: languageName: node linkType: hard +"yocto-queue@npm:^1.0.0": + version: 1.0.0 + resolution: "yocto-queue@npm:1.0.0" + checksum: 2cac84540f65c64ccc1683c267edce396b26b1e931aa429660aefac8fbe0188167b7aee815a3c22fa59a28a58d898d1a2b1825048f834d8d629f4c2a5d443801 + languageName: node + linkType: hard + "zstddec@npm:^0.0.2": version: 0.0.2 resolution: "zstddec@npm:0.0.2" From f298e09140b235667af30af61ba126e37877ad36 Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Thu, 8 Jun 2023 16:24:35 -0700 Subject: [PATCH 13/80] add basic test and refactor more --- .../state/src/hooks/useSchemaSettings.test.ts | 9 +- .../state/src/hooks/useSchemaSettings.ts | 118 +----------------- .../src/hooks/useSchemaSettings.utils.ts | 117 +++++++++++++++++ app/vite.config.ts | 8 ++ 4 files changed, 133 insertions(+), 119 deletions(-) create mode 100644 app/packages/state/src/hooks/useSchemaSettings.utils.ts diff --git a/app/packages/state/src/hooks/useSchemaSettings.test.ts b/app/packages/state/src/hooks/useSchemaSettings.test.ts index 73042d930d..493c1e761c 100644 --- a/app/packages/state/src/hooks/useSchemaSettings.test.ts +++ b/app/packages/state/src/hooks/useSchemaSettings.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { disabledField } from "./useSchemaSettings"; +import { disabledField } from "./useSchemaSettings.utils"; import { OBJECT_ID_FIELD } from "@fiftyone/utilities"; const FIELDS = { @@ -17,6 +17,9 @@ const FIELDS = { }, }; +const GROUP_DATASET = "group"; +const NOT_GROUP_DATASET = ""; + describe("Disabled schema fields", () => { afterEach(() => { vi.restoreAllMocks(); @@ -26,7 +29,7 @@ describe("Disabled schema fields", () => { const path = "id"; const field_1 = FIELDS.ID_FIELD; const schema = { id: field_1 }; - const isGroupDataset = "group"; - expect(disabledField(path, schema, isGroupDataset)).toBe(true); + + expect(disabledField(path, schema, NOT_GROUP_DATASET)).toBe(true); }); }); diff --git a/app/packages/state/src/hooks/useSchemaSettings.ts b/app/packages/state/src/hooks/useSchemaSettings.ts index 6e78867c17..b206090a95 100644 --- a/app/packages/state/src/hooks/useSchemaSettings.ts +++ b/app/packages/state/src/hooks/useSchemaSettings.ts @@ -2,37 +2,15 @@ import * as foq from "@fiftyone/relay"; import * as fos from "@fiftyone/state"; import { buildSchema } from "@fiftyone/state"; import { - CLASSIFICATIONS_FIELD, - CLASSIFICATION_FIELD, - DETECTIONS_FIELD, - DETECTION_FIELD, DETECTION_FILED, DYNAMIC_EMBEDDED_DOCUMENT_FIELD, DYNAMIC_EMBEDDED_DOCUMENT_FIELD_V2, EMBEDDED_DOCUMENT_FIELD, - FRAME_SUPPORT_FIELD, - Field, - GEO_LOCATIONS_FIELD, - GEO_LOCATION_FIELD, - HEATMAP_FIELD, - KEYPOINT_FILED, LIST_FIELD, - POLYLINES_FIELD, - POLYLINE_FIELD, - REGRESSION_FILED, - RESERVED_FIELD_KEYS, - SEGMENTATION_FIELD, Schema, - TEMPORAL_DETECTION_FIELD, UNSUPPORTED_FILTER_TYPES, - VALID_LABEL_TYPES, - VECTOR_FIELD, -} from "@fiftyone/utilities"; -import { - FRAME_NUMBER_FIELD, - JUST_FIELD, - OBJECT_ID_FIELD, } from "@fiftyone/utilities"; +import { JUST_FIELD } from "@fiftyone/utilities"; import { isEmpty, keyBy } from "lodash"; import { useCallback, useContext, useEffect, useMemo } from "react"; import { useMutation, useRefetchableFragment } from "react-relay"; @@ -45,6 +23,7 @@ import { useResetRecoilState, useSetRecoilState, } from "recoil"; +import { disabledField } from "./useSchemaSettings.utils"; export const TAB_OPTIONS_MAP = { SELECTION: "Selection", @@ -67,99 +46,6 @@ const skipField = (path: string, ftype: string, schema: {}) => { ); }; -export const disabledField = ( - path: string, - combinedSchema: Record, - groupField?: string -): boolean => { - const currField = combinedSchema?.[path] || ({} as Field); - const { ftype, embeddedDocType } = currField; - const parentPath = path.substring(0, path.lastIndexOf(".")); - const parentField = combinedSchema?.[parentPath]; - const parentEmbeddedDocType = parentField?.embeddedDocType; - const pathSplit = path.split("."); - const embeddedDocTypeSplit = embeddedDocType?.split("."); - const hasDynamicEmbeddedDocument = [ - DYNAMIC_EMBEDDED_DOCUMENT_FIELD, - DYNAMIC_EMBEDDED_DOCUMENT_FIELD_V2, - ].includes(embeddedDocType); - - return ( - [ - OBJECT_ID_FIELD, - FRAME_NUMBER_FIELD, - FRAME_SUPPORT_FIELD, - VECTOR_FIELD, - ].includes(ftype) || - [path, parentPath].includes(groupField) || - RESERVED_FIELD_KEYS.includes(path) || - path.startsWith("metadata") || - ([ - TEMPORAL_DETECTION_FIELD, - DETECTION_FIELD, - DETECTIONS_FIELD, - CLASSIFICATION_FIELD, - CLASSIFICATIONS_FIELD, - KEYPOINT_FILED, - REGRESSION_FILED, - HEATMAP_FIELD, - SEGMENTATION_FIELD, - GEO_LOCATIONS_FIELD, - GEO_LOCATION_FIELD, - POLYLINE_FIELD, - POLYLINES_FIELD, - ].includes(parentEmbeddedDocType) && - [ - "id", - "tags", - "label", - "bounding_box", - "mask", - "confidence", - "index", - "points", - "closed", - "filled", - "logits", - "mask_path", - "map", - "map_path", - "Range", - "Confidence", - "support", - "point", - "line", - "Polygon", - "points", - "polygons", - ].includes(pathSplit[pathSplit.length - 1])) || - [ - TEMPORAL_DETECTION_FIELD, - DETECTION_FIELD, - DETECTIONS_FIELD, - CLASSIFICATION_FIELD, - CLASSIFICATIONS_FIELD, - KEYPOINT_FILED, - REGRESSION_FILED, - HEATMAP_FIELD, - SEGMENTATION_FIELD, - GEO_LOCATIONS_FIELD, - GEO_LOCATION_FIELD, - POLYLINE_FIELD, - POLYLINES_FIELD, - ].includes(ftype) || - (parentPath && - parentPath !== path && - ftype === LIST_FIELD && - (hasDynamicEmbeddedDocument || - VALID_LABEL_TYPES.includes( - embeddedDocType?.includes(".") - ? embeddedDocTypeSplit[embeddedDocTypeSplit.length - 1] - : embeddedDocType - ))) - ); -}; - export const schemaSearchTerm = atom({ key: "schemaSearchTerm", default: "", diff --git a/app/packages/state/src/hooks/useSchemaSettings.utils.ts b/app/packages/state/src/hooks/useSchemaSettings.utils.ts new file mode 100644 index 0000000000..bbb736da44 --- /dev/null +++ b/app/packages/state/src/hooks/useSchemaSettings.utils.ts @@ -0,0 +1,117 @@ +import { + CLASSIFICATIONS_FIELD, + CLASSIFICATION_FIELD, + DETECTIONS_FIELD, + DETECTION_FIELD, + DYNAMIC_EMBEDDED_DOCUMENT_FIELD, + DYNAMIC_EMBEDDED_DOCUMENT_FIELD_V2, + FRAME_SUPPORT_FIELD, + Field, + GEO_LOCATIONS_FIELD, + GEO_LOCATION_FIELD, + HEATMAP_FIELD, + KEYPOINT_FILED, + LIST_FIELD, + POLYLINES_FIELD, + POLYLINE_FIELD, + REGRESSION_FILED, + RESERVED_FIELD_KEYS, + SEGMENTATION_FIELD, + TEMPORAL_DETECTION_FIELD, + VALID_LABEL_TYPES, + VECTOR_FIELD, +} from "@fiftyone/utilities"; +import { FRAME_NUMBER_FIELD, OBJECT_ID_FIELD } from "@fiftyone/utilities"; + +export const disabledField = ( + path: string, + combinedSchema: Record, + groupField?: string +): boolean => { + const currField = combinedSchema?.[path] || ({} as Field); + const { ftype, embeddedDocType } = currField; + const parentPath = path.substring(0, path.lastIndexOf(".")); + const parentField = combinedSchema?.[parentPath]; + const parentEmbeddedDocType = parentField?.embeddedDocType; + const pathSplit = path.split("."); + const embeddedDocTypeSplit = embeddedDocType?.split("."); + const hasDynamicEmbeddedDocument = [ + DYNAMIC_EMBEDDED_DOCUMENT_FIELD, + DYNAMIC_EMBEDDED_DOCUMENT_FIELD_V2, + ].includes(embeddedDocType); + + return ( + [ + OBJECT_ID_FIELD, + FRAME_NUMBER_FIELD, + FRAME_SUPPORT_FIELD, + VECTOR_FIELD, + ].includes(ftype) || + [path, parentPath].includes(groupField) || + RESERVED_FIELD_KEYS.includes(path) || + path.startsWith("metadata") || + ([ + TEMPORAL_DETECTION_FIELD, + DETECTION_FIELD, + DETECTIONS_FIELD, + CLASSIFICATION_FIELD, + CLASSIFICATIONS_FIELD, + KEYPOINT_FILED, + REGRESSION_FILED, + HEATMAP_FIELD, + SEGMENTATION_FIELD, + GEO_LOCATIONS_FIELD, + GEO_LOCATION_FIELD, + POLYLINE_FIELD, + POLYLINES_FIELD, + ].includes(parentEmbeddedDocType) && + [ + "id", + "tags", + "label", + "bounding_box", + "mask", + "confidence", + "index", + "points", + "closed", + "filled", + "logits", + "mask_path", + "map", + "map_path", + "Range", + "Confidence", + "support", + "point", + "line", + "Polygon", + "points", + "polygons", + ].includes(pathSplit[pathSplit.length - 1])) || + [ + TEMPORAL_DETECTION_FIELD, + DETECTION_FIELD, + DETECTIONS_FIELD, + CLASSIFICATION_FIELD, + CLASSIFICATIONS_FIELD, + KEYPOINT_FILED, + REGRESSION_FILED, + HEATMAP_FIELD, + SEGMENTATION_FIELD, + GEO_LOCATIONS_FIELD, + GEO_LOCATION_FIELD, + POLYLINE_FIELD, + POLYLINES_FIELD, + ].includes(ftype) || + (parentPath && + parentPath !== path && + ftype === LIST_FIELD && + (hasDynamicEmbeddedDocument || + VALID_LABEL_TYPES.includes( + embeddedDocType?.includes(".") + ? embeddedDocTypeSplit[embeddedDocTypeSplit.length - 1] + : embeddedDocType + ))) + ); +}; diff --git a/app/vite.config.ts b/app/vite.config.ts index a8193ce398..4d7bab4989 100644 --- a/app/vite.config.ts +++ b/app/vite.config.ts @@ -8,6 +8,14 @@ export default defineConfig({ coverage: { reporter: ["json", "lcov"], reportsDirectory: "./coverage", + enabled: true, + all: true, + exclude: [ + "**/__generated__/**", + "**/__generated__", + "**/.yarn/**", + "**/.storybook/**", + ], }, }, plugins: [relay], From b52b7b788482931e733cd82eae36393e9a020f66 Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Fri, 9 Jun 2023 06:12:23 -0700 Subject: [PATCH 14/80] keep one embed doc field --- app/packages/state/src/hooks/useSchemaSettings.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/packages/state/src/hooks/useSchemaSettings.ts b/app/packages/state/src/hooks/useSchemaSettings.ts index b206090a95..f24c126e2e 100644 --- a/app/packages/state/src/hooks/useSchemaSettings.ts +++ b/app/packages/state/src/hooks/useSchemaSettings.ts @@ -3,7 +3,6 @@ import * as fos from "@fiftyone/state"; import { buildSchema } from "@fiftyone/state"; import { DETECTION_FILED, - DYNAMIC_EMBEDDED_DOCUMENT_FIELD, DYNAMIC_EMBEDDED_DOCUMENT_FIELD_V2, EMBEDDED_DOCUMENT_FIELD, LIST_FIELD, @@ -233,7 +232,6 @@ export const excludedPathsState = atomFamily({ // embedded document could break an exclude_field() call causing mongo query issue. const hasDynamicEmbeddedDocument = [ - DYNAMIC_EMBEDDED_DOCUMENT_FIELD, DYNAMIC_EMBEDDED_DOCUMENT_FIELD_V2, ].includes(combinedSchema[path]?.embeddedDocType); From 423c01b857314156b4cf1c2f4fa6095bf54483c6 Mon Sep 17 00:00:00 2001 From: manivoxel51 Date: Fri, 9 Jun 2023 12:16:25 -0700 Subject: [PATCH 15/80] no coverage when yarn test --- app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/package.json b/app/package.json index b4e9d76cd0..96018190d4 100644 --- a/app/package.json +++ b/app/package.json @@ -15,7 +15,7 @@ "postinstall": "patch-package", "start": "yarn workspace @fiftyone/app start", "start-desktop": "yarn workspace FiftyOne start-desktop", - "test": "yarn vitest run --coverage", + "test": "yarn vitest run", "test-ui": "yarn vitest --ui", "gen:schema": "strawberry export-schema fiftyone.server.app:schema > schema.graphql" }, From bf61ef3c247638ee8882eab2e4b2c9828a0a0c1a Mon Sep 17 00:00:00 2001 From: imanjra Date: Mon, 12 Jun 2023 12:19:53 -0400 Subject: [PATCH 16/80] add support for multi-select with string type --- .../SchemaIO/components/DropdownView.tsx | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/app/packages/core/src/plugins/SchemaIO/components/DropdownView.tsx b/app/packages/core/src/plugins/SchemaIO/components/DropdownView.tsx index b13461f9ea..602d899b01 100644 --- a/app/packages/core/src/plugins/SchemaIO/components/DropdownView.tsx +++ b/app/packages/core/src/plugins/SchemaIO/components/DropdownView.tsx @@ -3,13 +3,38 @@ import { Box, Typography, Select, MenuItem, ListItemText } from "@mui/material"; import FieldWrapper from "./FieldWrapper"; import autoFocus from "../utils/auto-focus"; import { getComponentProps } from "../utils"; +import AlertView from "./AlertView"; + +const MULTI_SELECT_TYPES = ["string", "array"]; export default function DropdownView(props) { const { onChange, schema, path, data } = props; - const { view = {}, type } = schema; - const { choices } = view; + const { default: defaultValue, view = {}, type } = schema; + const { choices, multiple: multiSelect, separator = "," } = view; + + if (multiSelect && !MULTI_SELECT_TYPES.includes(type)) + return ( + + ); - const multiple = type === "array"; + const isArrayType = type === "array"; + const multiple = multiSelect || isArrayType; + const fallbackDefaultValue = multiple ? [] : ""; + const rawDefaultValue = data ?? defaultValue ?? fallbackDefaultValue; + const computedDefaultValue = + multiple && !Array.isArray(rawDefaultValue) + ? rawDefaultValue.toString().split(separator) + : rawDefaultValue; const choiceLabels = choices.reduce((labels, choice) => { labels[choice.value] = choice.label; @@ -20,7 +45,7 @@ export default function DropdownView(props) {