From 8685bae2827cb9759e6ecc33a158861593dce159 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 17 Sep 2024 16:30:04 +0530 Subject: [PATCH 1/5] Introduce --- .../components/PhotoViewer/FileInfo/index.tsx | 2 +- .../new/photos/components/PeopleList.tsx | 7 ++++++- web/packages/new/photos/components/SearchBar.tsx | 16 +++++++++++++--- web/packages/new/photos/services/ml/index.ts | 7 ++++--- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx b/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx index 21675c36a8..d996b72020 100644 --- a/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx +++ b/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx @@ -270,7 +270,7 @@ export const FileInfo: React.FC = ({ {isMLEnabled() && ( <> - {/* */} + {/* TODO-Cluster */} )} diff --git a/web/packages/new/photos/components/PeopleList.tsx b/web/packages/new/photos/components/PeopleList.tsx index 6de6dadd1b..edfb813fcf 100644 --- a/web/packages/new/photos/components/PeopleList.tsx +++ b/web/packages/new/photos/components/PeopleList.tsx @@ -6,11 +6,16 @@ import { t } from "i18next"; import React, { useEffect, useState } from "react"; export interface PeopleListProps { + /** The list of {@link Person} entities to show. */ people: Person[]; + /** Limit to display to whatever fits within {@link maxRows} rows. */ maxRows: number; + /** Optional callback invoked when a particular person is selected. */ onSelect?: (person: Person, index: number) => void; } - +/** + * Shows a list of {@link Person} (named cluster groups). + */ export const PeopleList: React.FC = ({ people, maxRows, diff --git a/web/packages/new/photos/components/SearchBar.tsx b/web/packages/new/photos/components/SearchBar.tsx index 276dff408b..d2b9f4ac03 100644 --- a/web/packages/new/photos/components/SearchBar.tsx +++ b/web/packages/new/photos/components/SearchBar.tsx @@ -5,6 +5,8 @@ import { isMLSupported, mlStatusSnapshot, mlStatusSubscribe, + peopleSnapshot, + peopleSubscribe, } from "@/new/photos/services/ml"; import { searchOptionsForString } from "@/new/photos/services/search"; import type { SearchOption } from "@/new/photos/services/search/types"; @@ -37,6 +39,7 @@ import { type StylesConfig, } from "react-select"; import AsyncSelect from "react-select/async"; +import { PeopleList } from "./PeopleList"; export interface SearchBarProps { /** @@ -358,7 +361,9 @@ interface EmptyStateProps { */ const EmptyState: React.FC = () => { const mlStatus = useSyncExternalStore(mlStatusSubscribe, mlStatusSnapshot); + const people = useSyncExternalStore(peopleSubscribe, peopleSnapshot); + // TODO-Cluster if (!mlStatus || mlStatus.phase == "disabled") { assertionFailed(); return <>; @@ -383,11 +388,16 @@ const EmptyState: React.FC = () => { break; } - // TODO-Cluster this is where it'll go. - // const people = wipPersons(); - return ( + {people && ( + console.log(args)} + /> + )} {label} diff --git a/web/packages/new/photos/services/ml/index.ts b/web/packages/new/photos/services/ml/index.ts index a36bdc02a1..a57bb2c03f 100644 --- a/web/packages/new/photos/services/ml/index.ts +++ b/web/packages/new/photos/services/ml/index.ts @@ -440,6 +440,7 @@ export const wipClusterDebugPageContents = async ( _wip_isClustering = false; _wip_people = people; triggerStatusUpdate(); + triggerPeopleUpdate(); return { clusters, @@ -654,7 +655,7 @@ export const peopleSubscribe = (onChange: () => void): (() => void) => { export const peopleSnapshot = (): Person[] | undefined => { const result = _state.peopleSnapshot; // We don't have it yet, trigger an update. - if (!result) triggerPeopleUpdate(); + // if (!result) triggerPeopleUpdate(); return result; }; @@ -678,9 +679,9 @@ const setPeopleSnapshot = (snapshot: Person[] | undefined) => { * people might be updated in a push based manner. */ const getPeople = async (): Promise => { - if (!_state.isMLEnabled) return undefined; + if (!_state.isMLEnabled) return []; // TODO-Cluster additional check for now as it is heavily WIP. - if (!process.env.NEXT_PUBLIC_ENTE_WIP_CL) return undefined; + if (!process.env.NEXT_PUBLIC_ENTE_WIP_CL) return []; if (!(await wipClusterEnable())) return []; return _wip_people; }; From 0431493736c28e133db778d15b90fbbce9c23245 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 17 Sep 2024 17:24:40 +0530 Subject: [PATCH 2/5] Fix sizing on mobile screens and long search texts --- web/packages/new/photos/components/SearchBar.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/packages/new/photos/components/SearchBar.tsx b/web/packages/new/photos/components/SearchBar.tsx index d2b9f4ac03..d163fb5536 100644 --- a/web/packages/new/photos/components/SearchBar.tsx +++ b/web/packages/new/photos/components/SearchBar.tsx @@ -246,7 +246,11 @@ const createSelectStyles = ({ cursor: "text", }, }), - input: (styles) => ({ ...styles, color: colors.text.base }), + input: (styles) => ({ + ...styles, + color: colors.text.base, + overflowX: "hidden", + }), menu: (style) => ({ ...style, // Suppress the default margin at the top. @@ -271,6 +275,7 @@ const createSelectStyles = ({ ...style, color: colors.text.muted, whiteSpace: "nowrap", + overflowX: "hidden", }), // Hide some things we don't need. dropdownIndicator: (style) => ({ ...style, display: "none" }), From bcd1fd0cc853d379d4575789982b464b30e72fe4 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 17 Sep 2024 17:49:51 +0530 Subject: [PATCH 3/5] People list - 1 --- .../new/photos/components/PeopleList.tsx | 38 ++++++++++++++++--- .../new/photos/components/SearchBar.tsx | 25 ++++++------ 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/web/packages/new/photos/components/PeopleList.tsx b/web/packages/new/photos/components/PeopleList.tsx index edfb813fcf..161539a52a 100644 --- a/web/packages/new/photos/components/PeopleList.tsx +++ b/web/packages/new/photos/components/PeopleList.tsx @@ -1,3 +1,4 @@ +import { useIsMobileWidth } from "@/base/hooks"; import type { Person } from "@/new/photos/services/ml"; import { faceCrop, unidentifiedFaceIDs } from "@/new/photos/services/ml"; import type { EnteFile } from "@/new/photos/types/file"; @@ -21,24 +22,49 @@ export const PeopleList: React.FC = ({ maxRows, onSelect, }) => { + const isMobileWidth = useIsMobileWidth(); + // TODO-Cluster: FaceCropImageView has hardcoded placeholder dimensions return ( - - {people.map((person, index) => ( - + {people.slice(0, isMobileWidth ? 6 : 7).map((person, index) => ( + onSelect && onSelect(person, index)} > - + ))} - + ); }; +const SearchFaceChipContainer = styled("div")` + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + gap: 5px; + margin-block: 16px; + /* On very small (~ < 375px) mobile screens 6 faces won't fit in 2 rows. + Clip the third one. */ + overflow: hidden; +`; + +const SearchFaceChip = styled("div")` + width: 87px; + height: 87px; + border-radius: 50%; + overflow: hidden; + cursor: "pointer"; + & > img { + width: 100%; + height: 100%; + } +`; + const FaceChipContainer = styled("div")` display: flex; flex-wrap: wrap; diff --git a/web/packages/new/photos/components/SearchBar.tsx b/web/packages/new/photos/components/SearchBar.tsx index d163fb5536..c0817cc5e8 100644 --- a/web/packages/new/photos/components/SearchBar.tsx +++ b/web/packages/new/photos/components/SearchBar.tsx @@ -394,18 +394,21 @@ const EmptyState: React.FC = () => { } return ( - - {people && ( - console.log(args)} - /> + + {people && people.length > 0 && ( + <> + + {t("people")} + + console.log(args)} + /> + )} - - {label} - + {label} ); From c03b3fd203087f104c58f88a7c79cd563bcc2684 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 17 Sep 2024 20:13:50 +0530 Subject: [PATCH 4/5] Clickable --- .../new/photos/components/SearchBar.tsx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/web/packages/new/photos/components/SearchBar.tsx b/web/packages/new/photos/components/SearchBar.tsx index c0817cc5e8..725a8004cf 100644 --- a/web/packages/new/photos/components/SearchBar.tsx +++ b/web/packages/new/photos/components/SearchBar.tsx @@ -12,6 +12,7 @@ import { searchOptionsForString } from "@/new/photos/services/search"; import type { SearchOption } from "@/new/photos/services/search/types"; import { nullToUndefined } from "@/utils/transform"; import CalendarIcon from "@mui/icons-material/CalendarMonth"; +import ChevronRightIcon from "@mui/icons-material/ChevronRight"; import CloseIcon from "@mui/icons-material/Close"; import ImageIcon from "@mui/icons-material/Image"; import LocationIcon from "@mui/icons-material/LocationOn"; @@ -397,9 +398,7 @@ const EmptyState: React.FC = () => { {people && people.length > 0 && ( <> - - {t("people")} - + = () => { // ); }; +const PeopleHeader: React.FC = () => { + const handleClick = () => console.log("click"); + return ( + + + {t("people")} + + + + ); +}; + // TODO-Cluster // const Legend = styled("span")` // font-size: 20px; From 18a7fce5236514c74eaadaffe0e4796d6af8004e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Tue, 17 Sep 2024 20:23:52 +0530 Subject: [PATCH 5/5] Cleanup --- .../new/photos/components/SearchBar.tsx | 93 +------------------ web/packages/shared/components/Container.tsx | 19 ---- 2 files changed, 2 insertions(+), 110 deletions(-) diff --git a/web/packages/new/photos/components/SearchBar.tsx b/web/packages/new/photos/components/SearchBar.tsx index 725a8004cf..8d67c0a37a 100644 --- a/web/packages/new/photos/components/SearchBar.tsx +++ b/web/packages/new/photos/components/SearchBar.tsx @@ -1,5 +1,6 @@ import { assertionFailed } from "@/base/assert"; import { useIsMobileWidth } from "@/base/hooks"; +import log from "@/base/log"; import { ItemCard, ResultPreviewTile } from "@/new/photos/components/ItemCards"; import { isMLSupported, @@ -369,6 +370,7 @@ const EmptyState: React.FC = () => { const mlStatus = useSyncExternalStore(mlStatusSubscribe, mlStatusSnapshot); const people = useSyncExternalStore(peopleSubscribe, peopleSnapshot); + log.debug(() => ["EmptyState", { mlStatus, people }]); // TODO-Cluster if (!mlStatus || mlStatus.phase == "disabled") { assertionFailed(); @@ -410,44 +412,6 @@ const EmptyState: React.FC = () => { {label} ); - - // TODO-Cluster - // const options = props.selectProps.options as SearchOption[]; - // const peopleSuggestions = options.filter( - // (o) => o.type === SuggestionType.PERSON, - // ); - // const people = peopleSuggestions.map((o) => o.value as Person); - // return ( - // - // - // {isMLEnabled() && - // indexStatus && - // (people && people.length > 0 ? ( - // - // {t("people")} - // - // ) : ( - // - // ))} - // {isMLEnabled() && indexStatus && ( - // - // {indexStatusSuggestion.label} - // - // )} - // {people && people.length > 0 && ( - // // "@ente/shared/components/Container" - // { - // }} - // /> - // - // )} - // - // {props.children} - // - // ); }; const PeopleHeader: React.FC = () => { @@ -462,59 +426,6 @@ const PeopleHeader: React.FC = () => { ); }; -// TODO-Cluster -// const Legend = styled("span")` -// font-size: 20px; -// color: #ddd; -// display: inline; -// padding: 0px 12px; -// `; - -/* -TODO: Cluster - -export async function getAllPeopleSuggestion(): Promise> { - try { - const people = await getAllPeople(200); - return people.map((person) => ({ - label: person.name, - type: SuggestionType.PERSON, - value: person, - hide: true, - })); - } catch (e) { - log.error("getAllPeopleSuggestion failed", e); - return []; - } -} - -async function getAllPeople(limit: number = undefined) { - return (await wipPersons()).slice(0, limit); - // TODO-Clustetr - // if (done) return []; - - // done = true; - // if (process.env.NEXT_PUBLIC_ENTE_WIP_CL_FETCH) { - // await syncCGroups(); - // const people = await clusterGroups(); - // log.debug(() => ["people", { people }]); - // } - - // let people: Array = []; // await mlIDbStorage.getAllPeople(); - // people = await wipCluster(); - // // await mlPeopleStore.iterate((person) => { - // // people.push(person); - // // }); - // people = people ?? []; - // const result = people - // .sort((p1, p2) => p2.files.length - p1.files.length) - // .slice(0, limit); - // // log.debug(() => ["getAllPeople", result]); - - // return result; -} -*/ - const Option: React.FC> = (props) => ( diff --git a/web/packages/shared/components/Container.tsx b/web/packages/shared/components/Container.tsx index cd0dca4914..d275837db8 100644 --- a/web/packages/shared/components/Container.tsx +++ b/web/packages/shared/components/Container.tsx @@ -10,21 +10,6 @@ export const VerticallyCentered = styled(Box)` overflow: auto; `; -export const Row = styled("div")` - min-height: 32px; - display: flex; - align-items: center; - margin-bottom: ${({ theme }) => theme.spacing(2)}; - flex: 1; -`; - -export const Value = styled("div")<{ width?: string }>` - display: flex; - justify-content: flex-start; - align-items: center; - width: ${(props) => props.width ?? "30%"}; -`; - export const FlexWrapper = styled(Box)` display: flex; width: 100%; @@ -59,10 +44,6 @@ export const HorizontalFlex = styled(Box)({ display: "flex", }); -export const VerticalFlex = styled(HorizontalFlex)({ - flexDirection: "column", -}); - export const VerticallyCenteredFlex = styled(HorizontalFlex)({ alignItems: "center", display: "flex",