From 17c17dd9019198c01142302cd26e6f534e6ff307 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 11:44:30 +0530 Subject: [PATCH 01/19] Hook --- web/apps/photos/src/components/SearchBar.tsx | 97 ++++++++++---------- 1 file changed, 51 insertions(+), 46 deletions(-) diff --git a/web/apps/photos/src/components/SearchBar.tsx b/web/apps/photos/src/components/SearchBar.tsx index dc1a444a4a..422a4ba3b9 100644 --- a/web/apps/photos/src/components/SearchBar.tsx +++ b/web/apps/photos/src/components/SearchBar.tsx @@ -139,6 +139,8 @@ const SearchInput: React.FC = ({ // The contents of the input field associated with the select. const [inputValue, setInputValue] = useState(""); + const styles = useSelectStyles(); + useEffect(() => { search(value); }, [value]); @@ -242,6 +244,7 @@ const SearchInput: React.FC = ({ ref={selectRef} value={value} components={components} + styles={styles} placeholder={t("search_hint")} loadOptions={getOptions} onChange={handleChange} @@ -250,7 +253,6 @@ const SearchInput: React.FC = ({ escapeClearsValue inputValue={inputValue} onInputChange={handleInputChange} - styles={SelectStyles} noOptionsMessage={({ inputValue }) => shouldShowEmptyState(inputValue) ? ( @@ -277,51 +279,54 @@ const SearchInputWrapper = styled(Box)` margin: auto; `; -const SelectStyles: StylesConfig = { - container: (style) => ({ ...style, flex: 1 }), - control: (style, { isFocused }) => ({ - ...style, - // Give a solid background color. - backgroundColor: "rgb(26, 26, 26)", - borderColor: isFocused ? "#1DB954" : "transparent", - boxShadow: "none", - ":hover": { - borderColor: "#01DE4D", - cursor: "text", - }, - }), - input: (styles) => ({ ...styles, color: "#fff" }), - menu: (style) => ({ - ...style, - // Suppress the default margin at the top. - marginTop: "1px", - // Same background color as the control (must be solid, otherwise the - // content behind the menu shows through). - backgroundColor: "rgb(26, 26, 26)", - }), - option: (style, { isFocused }) => ({ - ...style, - padding: 0, - backgroundColor: "transparent !important", - "& :hover": { - cursor: "pointer", - }, - "& .main": { - backgroundColor: isFocused && "#202020", - }, - "&:last-child .MuiDivider-root": { - display: "none", - }, - }), - placeholder: (style) => ({ - ...style, - color: "rgba(255, 255, 255, 0.7)", - whiteSpace: "nowrap", - }), - // Hide some things we don't need. - dropdownIndicator: (style) => ({ ...style, display: "none" }), - indicatorSeparator: (style) => ({ ...style, display: "none" }), - clearIndicator: (style) => ({ ...style, display: "none" }), +const useSelectStyles = (): StylesConfig => { + console.log("useSelectStyles"); + return { + container: (style) => ({ ...style, flex: 1 }), + control: (style, { isFocused }) => ({ + ...style, + // Give a solid background color. + backgroundColor: "rgb(26, 26, 26)", + borderColor: isFocused ? "#1DB954" : "transparent", + boxShadow: "none", + ":hover": { + borderColor: "#01DE4D", + cursor: "text", + }, + }), + input: (styles) => ({ ...styles, color: "#fff" }), + menu: (style) => ({ + ...style, + // Suppress the default margin at the top. + marginTop: "1px", + // Same background color as the control (must be solid, otherwise the + // content behind the menu shows through). + backgroundColor: "rgb(26, 26, 26)", + }), + option: (style, { isFocused }) => ({ + ...style, + padding: 0, + backgroundColor: "transparent !important", + "& :hover": { + cursor: "pointer", + }, + "& .main": { + backgroundColor: isFocused && "#202020", + }, + "&:last-child .MuiDivider-root": { + display: "none", + }, + }), + placeholder: (style) => ({ + ...style, + color: "rgba(255, 255, 255, 0.7)", + whiteSpace: "nowrap", + }), + // Hide some things we don't need. + dropdownIndicator: (style) => ({ ...style, display: "none" }), + indicatorSeparator: (style) => ({ ...style, display: "none" }), + clearIndicator: (style) => ({ ...style, display: "none" }), + }; }; const Control = ({ children, ...props }: ControlProps) => ( From 985ebc2f7791537ff239d666823eb363780f289e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 11:48:31 +0530 Subject: [PATCH 02/19] Theme + memo --- web/apps/photos/src/components/SearchBar.tsx | 9 ++++++--- web/apps/photos/src/components/pages/gallery/Avatar.tsx | 3 +-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/web/apps/photos/src/components/SearchBar.tsx b/web/apps/photos/src/components/SearchBar.tsx index 422a4ba3b9..91cea16887 100644 --- a/web/apps/photos/src/components/SearchBar.tsx +++ b/web/apps/photos/src/components/SearchBar.tsx @@ -1,6 +1,7 @@ import { assertionFailed } from "@/base/assert"; import { useIsMobileWidth } from "@/base/hooks"; import { FileType } from "@/media/file-type"; +import { useTheme, type Theme } from "@mui/material"; import { isMLSupported, mlStatusSnapshot, @@ -139,7 +140,9 @@ const SearchInput: React.FC = ({ // The contents of the input field associated with the select. const [inputValue, setInputValue] = useState(""); - const styles = useSelectStyles(); + const theme = useTheme(); + + const styles = useMemo(() => useSelectStyles(theme), [theme]); useEffect(() => { search(value); @@ -279,8 +282,8 @@ const SearchInputWrapper = styled(Box)` margin: auto; `; -const useSelectStyles = (): StylesConfig => { - console.log("useSelectStyles"); +const useSelectStyles = (theme: Theme): StylesConfig => { + console.log("useSelectStyles", theme); return { container: (style) => ({ ...style, flex: 1 }), control: (style, { isFocused }) => ({ diff --git a/web/apps/photos/src/components/pages/gallery/Avatar.tsx b/web/apps/photos/src/components/pages/gallery/Avatar.tsx index 7ee9e2f7b5..5d7d5ea8fc 100644 --- a/web/apps/photos/src/components/pages/gallery/Avatar.tsx +++ b/web/apps/photos/src/components/pages/gallery/Avatar.tsx @@ -1,7 +1,6 @@ import log from "@/base/log"; import { EnteFile } from "@/new/photos/types/file"; -import { styled } from "@mui/material"; -import { useTheme } from "@mui/material/styles"; +import { styled, useTheme } from "@mui/material"; import { GalleryContext } from "pages/gallery"; import React, { useContext, useLayoutEffect, useState } from "react"; From 71d77a62fdd9053b7eb56e84197d78afa5037ca3 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 12:03:18 +0530 Subject: [PATCH 03/19] Use colors from theme --- web/apps/photos/src/components/SearchBar.tsx | 23 ++++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/web/apps/photos/src/components/SearchBar.tsx b/web/apps/photos/src/components/SearchBar.tsx index 91cea16887..c03d3b9e7c 100644 --- a/web/apps/photos/src/components/SearchBar.tsx +++ b/web/apps/photos/src/components/SearchBar.tsx @@ -1,7 +1,6 @@ import { assertionFailed } from "@/base/assert"; import { useIsMobileWidth } from "@/base/hooks"; import { FileType } from "@/media/file-type"; -import { useTheme, type Theme } from "@mui/material"; import { isMLSupported, mlStatusSnapshot, @@ -39,6 +38,8 @@ import { Stack, styled, Typography, + useTheme, + type Theme, } from "@mui/material"; import CollectionCard from "components/Collections/CollectionCard"; import { ResultPreviewTile } from "components/Collections/styledComponents"; @@ -282,29 +283,27 @@ const SearchInputWrapper = styled(Box)` margin: auto; `; -const useSelectStyles = (theme: Theme): StylesConfig => { - console.log("useSelectStyles", theme); +const useSelectStyles = ({ + colors, +}: Theme): StylesConfig => { return { container: (style) => ({ ...style, flex: 1 }), control: (style, { isFocused }) => ({ ...style, - // Give a solid background color. - backgroundColor: "rgb(26, 26, 26)", - borderColor: isFocused ? "#1DB954" : "transparent", + backgroundColor: colors.background.elevated, + borderColor: isFocused ? colors.accent.A500 : "transparent", boxShadow: "none", ":hover": { - borderColor: "#01DE4D", + borderColor: colors.accent.A300, cursor: "text", }, }), - input: (styles) => ({ ...styles, color: "#fff" }), + input: (styles) => ({ ...styles, color: colors.text.base }), menu: (style) => ({ ...style, // Suppress the default margin at the top. marginTop: "1px", - // Same background color as the control (must be solid, otherwise the - // content behind the menu shows through). - backgroundColor: "rgb(26, 26, 26)", + backgroundColor: colors.background.elevated, }), option: (style, { isFocused }) => ({ ...style, @@ -322,7 +321,7 @@ const useSelectStyles = (theme: Theme): StylesConfig => { }), placeholder: (style) => ({ ...style, - color: "rgba(255, 255, 255, 0.7)", + color: colors.text.muted, whiteSpace: "nowrap", }), // Hide some things we don't need. From 1d239d409f184e2918704e8eb42a58058115975a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 12:19:45 +0530 Subject: [PATCH 04/19] Fin --- web/apps/photos/src/components/SearchBar.tsx | 90 ++++++++++---------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/web/apps/photos/src/components/SearchBar.tsx b/web/apps/photos/src/components/SearchBar.tsx index c03d3b9e7c..f322cf2892 100644 --- a/web/apps/photos/src/components/SearchBar.tsx +++ b/web/apps/photos/src/components/SearchBar.tsx @@ -65,7 +65,7 @@ import { } from "react-select"; import AsyncSelect from "react-select/async"; import { getAutoCompleteSuggestions } from "services/searchService"; -import { Collection } from "types/collection"; +import { type Collection } from "types/collection"; interface SearchBarProps { isInSearchMode: boolean; @@ -285,51 +285,49 @@ const SearchInputWrapper = styled(Box)` const useSelectStyles = ({ colors, -}: Theme): StylesConfig => { - return { - container: (style) => ({ ...style, flex: 1 }), - control: (style, { isFocused }) => ({ - ...style, - backgroundColor: colors.background.elevated, - borderColor: isFocused ? colors.accent.A500 : "transparent", - boxShadow: "none", - ":hover": { - borderColor: colors.accent.A300, - cursor: "text", - }, - }), - input: (styles) => ({ ...styles, color: colors.text.base }), - menu: (style) => ({ - ...style, - // Suppress the default margin at the top. - marginTop: "1px", - backgroundColor: colors.background.elevated, - }), - option: (style, { isFocused }) => ({ - ...style, - padding: 0, - backgroundColor: "transparent !important", - "& :hover": { - cursor: "pointer", - }, - "& .main": { - backgroundColor: isFocused && "#202020", - }, - "&:last-child .MuiDivider-root": { - display: "none", - }, - }), - placeholder: (style) => ({ - ...style, - color: colors.text.muted, - whiteSpace: "nowrap", - }), - // Hide some things we don't need. - dropdownIndicator: (style) => ({ ...style, display: "none" }), - indicatorSeparator: (style) => ({ ...style, display: "none" }), - clearIndicator: (style) => ({ ...style, display: "none" }), - }; -}; +}: Theme): StylesConfig => ({ + container: (style) => ({ ...style, flex: 1 }), + control: (style, { isFocused }) => ({ + ...style, + backgroundColor: colors.background.elevated, + borderColor: isFocused ? colors.accent.A500 : "transparent", + boxShadow: "none", + ":hover": { + borderColor: colors.accent.A300, + cursor: "text", + }, + }), + input: (styles) => ({ ...styles, color: colors.text.base }), + menu: (style) => ({ + ...style, + // Suppress the default margin at the top. + marginTop: "1px", + backgroundColor: colors.background.elevated, + }), + option: (style, { isFocused }) => ({ + ...style, + padding: 0, + backgroundColor: "transparent !important", + "& :hover": { + cursor: "pointer", + }, + "& .main": { + backgroundColor: isFocused && colors.background.elevated2, + }, + "&:last-child .MuiDivider-root": { + display: "none", + }, + }), + placeholder: (style) => ({ + ...style, + color: colors.text.muted, + whiteSpace: "nowrap", + }), + // Hide some things we don't need. + dropdownIndicator: (style) => ({ ...style, display: "none" }), + indicatorSeparator: (style) => ({ ...style, display: "none" }), + clearIndicator: (style) => ({ ...style, display: "none" }), +}); const Control = ({ children, ...props }: ControlProps) => ( From cc3caf2e5d7c17038b7221db0c564b07ca75050e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 16:57:49 +0530 Subject: [PATCH 05/19] doc --- web/apps/photos/src/components/SearchBar.tsx | 19 +++++++++++++++++++ .../new/photos/services/search/types.ts | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/web/apps/photos/src/components/SearchBar.tsx b/web/apps/photos/src/components/SearchBar.tsx index f322cf2892..3369ae9ea2 100644 --- a/web/apps/photos/src/components/SearchBar.tsx +++ b/web/apps/photos/src/components/SearchBar.tsx @@ -68,7 +68,12 @@ import { getAutoCompleteSuggestions } from "services/searchService"; import { type Collection } from "types/collection"; interface SearchBarProps { + /** + * `true` if the search bar is being shown when the gallery is already in + * "search mode". + */ isInSearchMode: boolean; + /** Enter or exit search mode. */ setIsInSearchMode: (v: boolean) => void; updateSearch: UpdateSearch; collections: Collection[]; @@ -80,6 +85,20 @@ export type UpdateSearch = ( summary: SearchResultSummary, ) => void; +/** + * The search bar is a styled "select" element that allow the user to type in + * the attached input field, and shows a list of matching options in a dropdown. + * + * When the search input is empty, it shows some general information in the + * dropdown instead (e.g. the ML indexing status). + * + * When the search input is not empty, it shows various {@link SearchOption}s, + * each of which is a possible suggestion for a search that the user might've + * intended. Each suggestion shows a count of matching files, and some previews. + * + * Selecting one of the these options causes the gallery to enter a "search + * mode", where it shows a filtered list of files that match that option. + */ export const SearchBar: React.FC = ({ setIsInSearchMode, isInSearchMode, diff --git a/web/packages/new/photos/services/search/types.ts b/web/packages/new/photos/services/search/types.ts index 4f5915d87e..baddbfbb28 100644 --- a/web/packages/new/photos/services/search/types.ts +++ b/web/packages/new/photos/services/search/types.ts @@ -142,6 +142,10 @@ export interface SearchResultSummary { /** * An option shown in the the search bar's select dropdown. + * + * The option includes essential data that is necessary to show a corresponding + * entry in the dropdown. If the user selects the option, then we will re-run + * the search, using the data to filter the list of files shown to the user. */ export interface SearchOption extends Suggestion { fileCount: number; From 012a79689408f3ec66bc42727e26db95b4ace316 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 17:05:28 +0530 Subject: [PATCH 06/19] New type --- web/apps/photos/src/services/searchService.ts | 4 ++-- web/packages/new/photos/services/search/types.ts | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/web/apps/photos/src/services/searchService.ts b/web/apps/photos/src/services/searchService.ts index 47b6b27a2a..f10f9e95a3 100644 --- a/web/apps/photos/src/services/searchService.ts +++ b/web/apps/photos/src/services/searchService.ts @@ -14,8 +14,8 @@ import { SuggestionType, } from "@/new/photos/services/search/types"; import type { LocationTag } from "@/new/photos/services/user-entity"; -import { EnteFile } from "@/new/photos/types/file"; -import { Collection } from "types/collection"; +import { type EnteFile } from "@/new/photos/types/file"; +import { type Collection } from "types/collection"; import { getUniqueFiles } from "utils/file"; // Suggestions shown in the search dropdown when the user has typed something. diff --git a/web/packages/new/photos/services/search/types.ts b/web/packages/new/photos/services/search/types.ts index baddbfbb28..b375c05aeb 100644 --- a/web/packages/new/photos/services/search/types.ts +++ b/web/packages/new/photos/services/search/types.ts @@ -140,6 +140,17 @@ export interface SearchResultSummary { fileCount: number; } +export type SearchSuggestion = { label: string } & ( + | { type: "collection"; collectionID: number } + | { type: "files"; fileIDs: number[] } + | { type: "fileType"; fileType: FileType } + | { type: "date"; dateComponents: SearchDateComponents } + | { type: "location"; locationTag: LocationTag } + | { type: "city"; city: City } + | { type: "clip"; clipScoreForFileID: Map } + | { type: "cgroup"; cgroup: SearchPerson } +); + /** * An option shown in the the search bar's select dropdown. * From 87e31965e5a4c27cd6b3720f21927fc4432c21cb Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 17:11:53 +0530 Subject: [PATCH 07/19] Move up --- web/apps/photos/src/pages/gallery.tsx | 5 +++-- web/apps/photos/src/services/searchService.ts | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx index 7a2a096b15..e882ea4196 100644 --- a/web/apps/photos/src/pages/gallery.tsx +++ b/web/apps/photos/src/pages/gallery.tsx @@ -407,7 +407,8 @@ export default function Gallery() { }; }, []); - useEffect(() => setSearchableFiles(files), [files]); + // TODO: Is this uniquing necessary? Doesn't seem like. + useEffect(() => setSearchableFiles(getUniqueFiles(files)), [files]); useEffect(() => { if (!user || !files || !collections || !hiddenFiles || !trashedFiles) { @@ -526,7 +527,7 @@ export default function Gallery() { let filteredFiles: EnteFile[] = []; if (isInSearchMode) { - filteredFiles = getUniqueFiles(await search(searchQuery)); + filteredFiles = await search(searchQuery); } else { filteredFiles = getUniqueFiles( (isInHiddenSection ? hiddenFiles : files).filter((item) => { diff --git a/web/apps/photos/src/services/searchService.ts b/web/apps/photos/src/services/searchService.ts index f10f9e95a3..7dd3e289c2 100644 --- a/web/apps/photos/src/services/searchService.ts +++ b/web/apps/photos/src/services/searchService.ts @@ -16,7 +16,6 @@ import { import type { LocationTag } from "@/new/photos/services/user-entity"; import { type EnteFile } from "@/new/photos/types/file"; import { type Collection } from "types/collection"; -import { getUniqueFiles } from "utils/file"; // Suggestions shown in the search dropdown when the user has typed something. export const getAutoCompleteSuggestions = @@ -53,7 +52,7 @@ async function convertSuggestionsToOptions( const previewImageAppendedOptions: SearchOption[] = []; for (const suggestion of suggestions) { const searchQuery = convertSuggestionToSearchQuery(suggestion); - const resultFiles = getUniqueFiles(await search(searchQuery)); + const resultFiles = await search(searchQuery); if (searchQuery?.clip) { resultFiles.sort((a, b) => { const aScore = searchQuery.clip.get(a.id); From a4a2623074f8a9f8fd804a61cf345e7a614da470 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 17:17:06 +0530 Subject: [PATCH 08/19] Move --- .../Collections/CollectionInfoWithOptions.tsx | 8 ++++-- .../CollectionListBar/CollectionCard.tsx | 3 +-- .../QuickOptions/DownloadQuickOption.tsx | 2 +- .../QuickOptions/ShareQuickOption.tsx | 2 +- .../CollectionOptions/QuickOptions/index.tsx | 2 +- .../Collections/CollectionOptions/index.tsx | 3 +-- .../Collections/CollectionSelector/index.tsx | 2 +- .../Collections/CollectionShare/index.tsx | 7 +++-- .../CollectionShare/sharingDetails.tsx | 3 +-- web/apps/photos/src/pages/gallery.tsx | 7 +++-- .../photos/src/services/collectionService.ts | 4 +-- web/apps/photos/src/types/collection/index.ts | 26 ++++++++++++++++++- web/apps/photos/src/utils/collection.ts | 24 ----------------- 13 files changed, 50 insertions(+), 43 deletions(-) diff --git a/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx b/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx index e960ab87fe..5ddc03b26c 100644 --- a/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx +++ b/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx @@ -6,9 +6,13 @@ import PeopleIcon from "@mui/icons-material/People"; import { SetCollectionNamerAttributes } from "components/Collections/CollectionNamer"; import CollectionOptions from "components/Collections/CollectionOptions"; import type { Dispatch, SetStateAction } from "react"; -import { Collection, CollectionSummary } from "types/collection"; +import { + Collection, + CollectionSummary, + CollectionSummaryType, +} from "types/collection"; import { SetFilesDownloadProgressAttributesCreator } from "types/gallery"; -import { CollectionSummaryType, shouldShowOptions } from "utils/collection"; +import { shouldShowOptions } from "utils/collection"; import { CollectionInfo } from "./CollectionInfo"; import { CollectionInfoBarWrapper } from "./styledComponents"; diff --git a/web/apps/photos/src/components/Collections/CollectionListBar/CollectionCard.tsx b/web/apps/photos/src/components/Collections/CollectionListBar/CollectionCard.tsx index 50b4378929..efbf3510fd 100644 --- a/web/apps/photos/src/components/Collections/CollectionListBar/CollectionCard.tsx +++ b/web/apps/photos/src/components/Collections/CollectionListBar/CollectionCard.tsx @@ -5,8 +5,7 @@ import PeopleIcon from "@mui/icons-material/People"; import PushPin from "@mui/icons-material/PushPin"; import { Box, Typography, styled } from "@mui/material"; import Tooltip from "@mui/material/Tooltip"; -import { CollectionSummary } from "types/collection"; -import { CollectionSummaryType } from "utils/collection"; +import { CollectionSummary, CollectionSummaryType } from "types/collection"; import CollectionCard from "../CollectionCard"; import { ActiveIndicator, diff --git a/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/DownloadQuickOption.tsx b/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/DownloadQuickOption.tsx index 06b7fcfe0d..7b26342ac8 100644 --- a/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/DownloadQuickOption.tsx +++ b/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/DownloadQuickOption.tsx @@ -1,7 +1,7 @@ import FileDownloadOutlinedIcon from "@mui/icons-material/FileDownloadOutlined"; import { IconButton, Tooltip } from "@mui/material"; import { t } from "i18next"; -import { CollectionSummaryType } from "utils/collection"; +import { CollectionSummaryType } from "types/collection"; import { CollectionActions } from ".."; interface Iprops { handleCollectionAction: ( diff --git a/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/ShareQuickOption.tsx b/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/ShareQuickOption.tsx index 9532f94df6..4d9565c32a 100644 --- a/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/ShareQuickOption.tsx +++ b/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/ShareQuickOption.tsx @@ -1,7 +1,7 @@ import PeopleIcon from "@mui/icons-material/People"; import { IconButton, Tooltip } from "@mui/material"; import { t } from "i18next"; -import { CollectionSummaryType } from "utils/collection"; +import { CollectionSummaryType } from "types/collection"; import { CollectionActions } from ".."; interface Iprops { diff --git a/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/index.tsx b/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/index.tsx index 1087c83ab5..eac6046631 100644 --- a/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionOptions/QuickOptions/index.tsx @@ -1,7 +1,7 @@ import { FlexWrapper } from "@ente/shared/components/Container"; import EnteSpinner from "@ente/shared/components/EnteSpinner"; +import { CollectionSummaryType } from "types/collection"; import { - CollectionSummaryType, showDownloadQuickOption, showEmptyTrashQuickOption, showShareQuickOption, diff --git a/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx b/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx index 65b3a0f3cf..f43bed216d 100644 --- a/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx @@ -12,14 +12,13 @@ import { useContext, useRef, useState } from "react"; import { Trans } from "react-i18next"; import * as CollectionAPI from "services/collectionService"; import * as TrashService from "services/trashService"; -import { Collection } from "types/collection"; +import { Collection, CollectionSummaryType } from "types/collection"; import { SetFilesDownloadProgressAttributesCreator } from "types/gallery"; import { ALL_SECTION, changeCollectionOrder, changeCollectionSortOrder, changeCollectionVisibility, - CollectionSummaryType, downloadCollectionHelper, downloadDefaultHiddenCollectionHelper, HIDDEN_ITEMS_SECTION, diff --git a/web/apps/photos/src/components/Collections/CollectionSelector/index.tsx b/web/apps/photos/src/components/Collections/CollectionSelector/index.tsx index fd9a8525bd..cdbc901b2e 100644 --- a/web/apps/photos/src/components/Collections/CollectionSelector/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionSelector/index.tsx @@ -9,11 +9,11 @@ import { Collection, CollectionSummaries, CollectionSummary, + CollectionSummaryType, } from "types/collection"; import { CollectionSelectorIntent } from "types/gallery"; import { COLLECTION_SORT_ORDER, - CollectionSummaryType, DUMMY_UNCATEGORIZED_COLLECTION, isAddToAllowedCollection, isMoveToAllowedCollection, diff --git a/web/apps/photos/src/components/Collections/CollectionShare/index.tsx b/web/apps/photos/src/components/Collections/CollectionShare/index.tsx index 1cc063b6d0..e9a709566a 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/index.tsx @@ -2,8 +2,11 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; import { Titlebar } from "@/base/components/Titlebar"; import { DialogProps, Stack } from "@mui/material"; import { t } from "i18next"; -import { Collection, CollectionSummary } from "types/collection"; -import { CollectionSummaryType } from "utils/collection"; +import { + Collection, + CollectionSummary, + CollectionSummaryType, +} from "types/collection"; import EmailShare from "./emailShare"; import PublicShare from "./publicShare"; import SharingDetails from "./sharingDetails"; diff --git a/web/apps/photos/src/components/Collections/CollectionShare/sharingDetails.tsx b/web/apps/photos/src/components/Collections/CollectionShare/sharingDetails.tsx index 889dc4084f..c314a5aa05 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/sharingDetails.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/sharingDetails.tsx @@ -12,8 +12,7 @@ import Avatar from "components/pages/gallery/Avatar"; import { t } from "i18next"; import { GalleryContext } from "pages/gallery"; import { useContext } from "react"; -import { COLLECTION_ROLE } from "types/collection"; -import { CollectionSummaryType } from "utils/collection"; +import { COLLECTION_ROLE, CollectionSummaryType } from "types/collection"; export default function SharingDetails({ collection, type }) { const galleryContext = useContext(GalleryContext); diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx index e882ea4196..7f40003f76 100644 --- a/web/apps/photos/src/pages/gallery.tsx +++ b/web/apps/photos/src/pages/gallery.tsx @@ -105,7 +105,11 @@ import { sync, triggerPreFileInfoSync } from "services/sync"; import { syncTrash } from "services/trashService"; import uploadManager from "services/upload/uploadManager"; import { isTokenValid } from "services/userService"; -import { Collection, CollectionSummaries } from "types/collection"; +import { + Collection, + CollectionSummaries, + CollectionSummaryType, +} from "types/collection"; import { GalleryContextType, SelectedState, @@ -118,7 +122,6 @@ import { ALL_SECTION, ARCHIVE_SECTION, COLLECTION_OPS_TYPE, - CollectionSummaryType, HIDDEN_ITEMS_SECTION, TRASH_SECTION, constructCollectionNameMap, diff --git a/web/apps/photos/src/services/collectionService.ts b/web/apps/photos/src/services/collectionService.ts index 669d6cea15..db5ce4bec5 100644 --- a/web/apps/photos/src/services/collectionService.ts +++ b/web/apps/photos/src/services/collectionService.ts @@ -28,7 +28,9 @@ import { CollectionShareeMagicMetadata, CollectionSummaries, CollectionSummary, + CollectionSummaryType, CollectionToFileMap, + CollectionType, CreatePublicAccessTokenRequest, EncryptedCollection, EncryptedFileKey, @@ -43,8 +45,6 @@ import { ARCHIVE_SECTION, COLLECTION_LIST_SORT_BY, COLLECTION_SORT_ORDER, - CollectionSummaryType, - CollectionType, DUMMY_UNCATEGORIZED_COLLECTION, HIDDEN_ITEMS_SECTION, TRASH_SECTION, diff --git a/web/apps/photos/src/types/collection/index.ts b/web/apps/photos/src/types/collection/index.ts index 5a2fcef3cc..0258b34a71 100644 --- a/web/apps/photos/src/types/collection/index.ts +++ b/web/apps/photos/src/types/collection/index.ts @@ -5,7 +5,31 @@ import { MagicMetadataCore, SUB_TYPE, } from "@/new/photos/types/magicMetadata"; -import { CollectionSummaryType, CollectionType } from "utils/collection"; + +export enum CollectionType { + folder = "folder", + favorites = "favorites", + album = "album", + uncategorized = "uncategorized", +} + +export enum CollectionSummaryType { + folder = "folder", + favorites = "favorites", + album = "album", + archive = "archive", + trash = "trash", + uncategorized = "uncategorized", + all = "all", + outgoingShare = "outgoingShare", + incomingShareViewer = "incomingShareViewer", + incomingShareCollaborator = "incomingShareCollaborator", + sharedOnlyViaLink = "sharedOnlyViaLink", + archived = "archived", + defaultHidden = "defaultHidden", + hiddenItems = "hiddenItems", + pinned = "pinned", +} export enum COLLECTION_ROLE { VIEWER = "VIEWER", diff --git a/web/apps/photos/src/utils/collection.ts b/web/apps/photos/src/utils/collection.ts index 32f2ff424e..3d1a1398ce 100644 --- a/web/apps/photos/src/utils/collection.ts +++ b/web/apps/photos/src/utils/collection.ts @@ -42,30 +42,6 @@ export const DUMMY_UNCATEGORIZED_COLLECTION = -3; export const HIDDEN_ITEMS_SECTION = -4; export const ALL_SECTION = 0; -export enum CollectionType { - folder = "folder", - favorites = "favorites", - album = "album", - uncategorized = "uncategorized", -} - -export enum CollectionSummaryType { - folder = "folder", - favorites = "favorites", - album = "album", - archive = "archive", - trash = "trash", - uncategorized = "uncategorized", - all = "all", - outgoingShare = "outgoingShare", - incomingShareViewer = "incomingShareViewer", - incomingShareCollaborator = "incomingShareCollaborator", - sharedOnlyViaLink = "sharedOnlyViaLink", - archived = "archived", - defaultHidden = "defaultHidden", - hiddenItems = "hiddenItems", - pinned = "pinned", -} export enum COLLECTION_LIST_SORT_BY { NAME, CREATION_TIME_ASCENDING, From c809d572f79528c951ae00b5871e3bfc891c9738 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 17:36:30 +0530 Subject: [PATCH 09/19] Move --- .../Collections/CollectionInfoWithOptions.tsx | 7 +--- .../CollectionOptions/AlbumCastDialog.tsx | 2 +- .../Collections/CollectionOptions/index.tsx | 3 +- .../Collections/CollectionSelector/index.tsx | 2 +- .../emailShare/AddParticipant.tsx | 2 +- .../emailShare/ManageEmailShare.tsx | 6 ++- .../emailShare/ManageParticipant.tsx | 2 +- .../CollectionShare/emailShare/index.tsx | 2 +- .../Collections/CollectionShare/index.tsx | 7 +--- .../publicShare/EnablePublicShareOptions.tsx | 2 +- .../CollectionShare/publicShare/index.tsx | 2 +- .../publicShare/manage/deviceLimit.tsx | 6 ++- .../publicShare/manage/downloadAccess.tsx | 6 ++- .../publicShare/manage/index.tsx | 6 ++- .../publicShare/manage/linkExpiry.tsx | 6 ++- .../publicShare/manage/linkPassword/index.tsx | 6 ++- .../publicShare/manage/publicCollect.tsx | 6 ++- .../publicShare/managePublicShare.tsx | 2 +- .../CollectionShare/sharingDetails.tsx | 3 +- .../src/components/Collections/index.tsx | 3 +- web/apps/photos/src/components/SearchBar.tsx | 2 +- .../photos/src/components/Upload/Uploader.tsx | 4 +- .../components/pages/gallery/AvatarGroup.tsx | 2 +- .../pages/gallery/SelectedFileOptions.tsx | 2 +- web/apps/photos/src/pages/gallery.tsx | 7 +--- web/apps/photos/src/pages/shared-albums.tsx | 2 +- .../photos/src/services/collectionService.ts | 32 ++++++++------- web/apps/photos/src/services/export/index.ts | 2 +- .../photos/src/services/export/migration.ts | 2 +- web/apps/photos/src/services/fileService.ts | 2 +- .../src/services/publicCollectionService.ts | 5 ++- web/apps/photos/src/services/searchService.ts | 2 +- web/apps/photos/src/services/trashService.ts | 2 +- .../src/services/upload/uploadManager.ts | 2 +- web/apps/photos/src/services/watch.ts | 2 +- web/apps/photos/src/types/collection.ts | 33 +++++++++++++++ web/apps/photos/src/types/gallery/index.ts | 2 +- .../src/types/publicCollection/index.ts | 2 +- web/apps/photos/src/utils/collection.ts | 15 +++---- .../photos/src/utils/magicMetadata/index.ts | 2 +- .../index.ts => packages/media/collection.ts} | 40 +++---------------- web/packages/media/types/file.ts | 0 42 files changed, 138 insertions(+), 107 deletions(-) create mode 100644 web/apps/photos/src/types/collection.ts rename web/{apps/photos/src/types/collection/index.ts => packages/media/collection.ts} (78%) delete mode 100644 web/packages/media/types/file.ts diff --git a/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx b/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx index 5ddc03b26c..7a2cbd2453 100644 --- a/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx +++ b/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx @@ -1,3 +1,4 @@ +import type { Collection } from "@/media/collection"; import { SpaceBetweenFlex } from "@ente/shared/components/Container"; import ArchiveOutlined from "@mui/icons-material/ArchiveOutlined"; import Favorite from "@mui/icons-material/FavoriteRounded"; @@ -6,11 +7,7 @@ import PeopleIcon from "@mui/icons-material/People"; import { SetCollectionNamerAttributes } from "components/Collections/CollectionNamer"; import CollectionOptions from "components/Collections/CollectionOptions"; import type { Dispatch, SetStateAction } from "react"; -import { - Collection, - CollectionSummary, - CollectionSummaryType, -} from "types/collection"; +import { CollectionSummary, CollectionSummaryType } from "types/collection"; import { SetFilesDownloadProgressAttributesCreator } from "types/gallery"; import { shouldShowOptions } from "utils/collection"; import { CollectionInfo } from "./CollectionInfo"; diff --git a/web/apps/photos/src/components/Collections/CollectionOptions/AlbumCastDialog.tsx b/web/apps/photos/src/components/Collections/CollectionOptions/AlbumCastDialog.tsx index 75ec3b4626..2bf59abf55 100644 --- a/web/apps/photos/src/components/Collections/CollectionOptions/AlbumCastDialog.tsx +++ b/web/apps/photos/src/components/Collections/CollectionOptions/AlbumCastDialog.tsx @@ -1,5 +1,6 @@ import { boxSeal } from "@/base/crypto/libsodium"; import log from "@/base/log"; +import type { Collection } from "@/media/collection"; import { VerticallyCentered } from "@ente/shared/components/Container"; import DialogBoxV2 from "@ente/shared/components/DialogBoxV2"; import EnteButton from "@ente/shared/components/EnteButton"; @@ -12,7 +13,6 @@ import { Link, Typography } from "@mui/material"; import { t } from "i18next"; import { useEffect, useState } from "react"; import { Trans } from "react-i18next"; -import { Collection } from "types/collection"; import { v4 as uuidv4 } from "uuid"; import { loadSender } from "../../../utils/useCastSender"; diff --git a/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx b/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx index f43bed216d..030f54ed18 100644 --- a/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx @@ -1,4 +1,5 @@ import log from "@/base/log"; +import type { Collection } from "@/media/collection"; import { ItemVisibility } from "@/media/file-metadata"; import { HorizontalFlex } from "@ente/shared/components/Container"; import OverflowMenu from "@ente/shared/components/OverflowMenu/menu"; @@ -12,7 +13,7 @@ import { useContext, useRef, useState } from "react"; import { Trans } from "react-i18next"; import * as CollectionAPI from "services/collectionService"; import * as TrashService from "services/trashService"; -import { Collection, CollectionSummaryType } from "types/collection"; +import { CollectionSummaryType } from "types/collection"; import { SetFilesDownloadProgressAttributesCreator } from "types/gallery"; import { ALL_SECTION, diff --git a/web/apps/photos/src/components/Collections/CollectionSelector/index.tsx b/web/apps/photos/src/components/Collections/CollectionSelector/index.tsx index cdbc901b2e..4132360aad 100644 --- a/web/apps/photos/src/components/Collections/CollectionSelector/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionSelector/index.tsx @@ -1,3 +1,4 @@ +import type { Collection } from "@/media/collection"; import { FlexWrapper } from "@ente/shared/components/Container"; import DialogTitleWithCloseButton from "@ente/shared/components/DialogBox/TitleWithCloseButton"; import { DialogContent, useMediaQuery } from "@mui/material"; @@ -6,7 +7,6 @@ import { t } from "i18next"; import { useEffect, useState } from "react"; import { createUnCategorizedCollection } from "services/collectionService"; import { - Collection, CollectionSummaries, CollectionSummary, CollectionSummaryType, diff --git a/web/apps/photos/src/components/Collections/CollectionShare/emailShare/AddParticipant.tsx b/web/apps/photos/src/components/Collections/CollectionShare/emailShare/AddParticipant.tsx index 080d1c667a..d42243a813 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/emailShare/AddParticipant.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/emailShare/AddParticipant.tsx @@ -1,8 +1,8 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; import { Titlebar } from "@/base/components/Titlebar"; +import { COLLECTION_ROLE, type Collection } from "@/media/collection"; import { DialogProps, Stack } from "@mui/material"; import { t } from "i18next"; -import { COLLECTION_ROLE, Collection } from "types/collection"; import { GalleryContext } from "pages/gallery"; import { useContext, useMemo } from "react"; diff --git a/web/apps/photos/src/components/Collections/CollectionShare/emailShare/ManageEmailShare.tsx b/web/apps/photos/src/components/Collections/CollectionShare/emailShare/ManageEmailShare.tsx index 9f7f407da4..6ebcfce510 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/emailShare/ManageEmailShare.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/emailShare/ManageEmailShare.tsx @@ -5,6 +5,11 @@ import { MenuSectionTitle, } from "@/base/components/Menu"; import { Titlebar } from "@/base/components/Titlebar"; +import { + COLLECTION_ROLE, + type Collection, + type CollectionUser, +} from "@/media/collection"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import Add from "@mui/icons-material/Add"; import AdminPanelSettingsIcon from "@mui/icons-material/AdminPanelSettings"; @@ -18,7 +23,6 @@ import { AppContext } from "pages/_app"; import { GalleryContext } from "pages/gallery"; import { useContext, useRef, useState } from "react"; import { unshareCollection } from "services/collectionService"; -import { COLLECTION_ROLE, Collection, CollectionUser } from "types/collection"; import AddParticipant from "./AddParticipant"; import ManageParticipant from "./ManageParticipant"; diff --git a/web/apps/photos/src/components/Collections/CollectionShare/emailShare/ManageParticipant.tsx b/web/apps/photos/src/components/Collections/CollectionShare/emailShare/ManageParticipant.tsx index 3c41f65533..f448af9102 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/emailShare/ManageParticipant.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/emailShare/ManageParticipant.tsx @@ -2,6 +2,7 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; import { MenuItemDivider, MenuItemGroup } from "@/base/components/Menu"; import { Titlebar } from "@/base/components/Titlebar"; import log from "@/base/log"; +import type { Collection, CollectionUser } from "@/media/collection"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import BlockIcon from "@mui/icons-material/Block"; import DoneIcon from "@mui/icons-material/Done"; @@ -14,7 +15,6 @@ import { GalleryContext } from "pages/gallery"; import { useContext } from "react"; import { Trans } from "react-i18next"; import { shareCollection } from "services/collectionService"; -import { Collection, CollectionUser } from "types/collection"; import { handleSharingErrors } from "utils/error/ui"; interface Iprops { diff --git a/web/apps/photos/src/components/Collections/CollectionShare/emailShare/index.tsx b/web/apps/photos/src/components/Collections/CollectionShare/emailShare/index.tsx index 3137bcc8aa..151b482c5c 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/emailShare/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/emailShare/index.tsx @@ -1,5 +1,5 @@ +import { COLLECTION_ROLE, type Collection } from "@/media/collection"; import { useRef, useState } from "react"; -import { COLLECTION_ROLE, Collection } from "types/collection"; import { MenuItemDivider, diff --git a/web/apps/photos/src/components/Collections/CollectionShare/index.tsx b/web/apps/photos/src/components/Collections/CollectionShare/index.tsx index e9a709566a..f970df0589 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/index.tsx @@ -1,12 +1,9 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; import { Titlebar } from "@/base/components/Titlebar"; +import type { Collection } from "@/media/collection"; import { DialogProps, Stack } from "@mui/material"; import { t } from "i18next"; -import { - Collection, - CollectionSummary, - CollectionSummaryType, -} from "types/collection"; +import { CollectionSummary, CollectionSummaryType } from "types/collection"; import EmailShare from "./emailShare"; import PublicShare from "./publicShare"; import SharingDetails from "./sharingDetails"; diff --git a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/EnablePublicShareOptions.tsx b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/EnablePublicShareOptions.tsx index 3a1cea2a29..e6b49845b2 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/EnablePublicShareOptions.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/EnablePublicShareOptions.tsx @@ -3,6 +3,7 @@ import { MenuItemGroup, MenuSectionTitle, } from "@/base/components/Menu"; +import type { Collection, PublicURL } from "@/media/collection"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import DownloadSharp from "@mui/icons-material/DownloadSharp"; import LinkIcon from "@mui/icons-material/Link"; @@ -15,7 +16,6 @@ import { createShareableURL, updateShareableURL, } from "services/collectionService"; -import { Collection, PublicURL } from "types/collection"; import { handleSharingErrors } from "utils/error/ui"; interface Iprops { collection: Collection; diff --git a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/index.tsx b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/index.tsx index e71f482cf6..805fb5d233 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/index.tsx @@ -1,5 +1,5 @@ +import type { Collection, PublicURL } from "@/media/collection"; import { useEffect, useState } from "react"; -import { Collection, PublicURL } from "types/collection"; import { appendCollectionKeyToShareURL } from "utils/collection"; import EnablePublicShareOptions from "./EnablePublicShareOptions"; import CopyLinkModal from "./copyLinkModal"; diff --git a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/deviceLimit.tsx b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/deviceLimit.tsx index 0e5b769056..99517c4cd2 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/deviceLimit.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/deviceLimit.tsx @@ -1,12 +1,16 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; import { MenuItemDivider, MenuItemGroup } from "@/base/components/Menu"; import { Titlebar } from "@/base/components/Titlebar"; +import type { + Collection, + PublicURL, + UpdatePublicURL, +} from "@/media/collection"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import ChevronRight from "@mui/icons-material/ChevronRight"; import { DialogProps, Stack } from "@mui/material"; import { t } from "i18next"; import { useMemo, useState } from "react"; -import { Collection, PublicURL, UpdatePublicURL } from "types/collection"; import { getDeviceLimitOptions } from "utils/collection"; interface Iprops { diff --git a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/downloadAccess.tsx b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/downloadAccess.tsx index 92008cc75a..a1b759a491 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/downloadAccess.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/downloadAccess.tsx @@ -1,9 +1,13 @@ +import type { + Collection, + PublicURL, + UpdatePublicURL, +} from "@/media/collection"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import { t } from "i18next"; import { AppContext } from "pages/_app"; import { useContext } from "react"; import { Trans } from "react-i18next"; -import { Collection, PublicURL, UpdatePublicURL } from "types/collection"; interface Iprops { publicShareProp: PublicURL; collection: Collection; diff --git a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/index.tsx b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/index.tsx index a8f2f96ca0..98a39646b4 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/index.tsx @@ -1,6 +1,11 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; import { MenuItemDivider, MenuItemGroup } from "@/base/components/Menu"; import { Titlebar } from "@/base/components/Titlebar"; +import type { + Collection, + PublicURL, + UpdatePublicURL, +} from "@/media/collection"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import ContentCopyIcon from "@mui/icons-material/ContentCopy"; import RemoveCircleOutline from "@mui/icons-material/RemoveCircleOutline"; @@ -12,7 +17,6 @@ import { deleteShareableURL, updateShareableURL, } from "services/collectionService"; -import { Collection, PublicURL, UpdatePublicURL } from "types/collection"; import { SetPublicShareProp } from "types/publicCollection"; import { handleSharingErrors } from "utils/error/ui"; import { ManageDeviceLimit } from "./deviceLimit"; diff --git a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/linkExpiry.tsx b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/linkExpiry.tsx index e2efaca504..8487240274 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/linkExpiry.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/linkExpiry.tsx @@ -1,13 +1,17 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; import { MenuItemDivider, MenuItemGroup } from "@/base/components/Menu"; import { Titlebar } from "@/base/components/Titlebar"; +import type { + Collection, + PublicURL, + UpdatePublicURL, +} from "@/media/collection"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import { formatDateTime } from "@ente/shared/time/format"; import ChevronRight from "@mui/icons-material/ChevronRight"; import { DialogProps, Stack } from "@mui/material"; import { t } from "i18next"; import { useMemo, useState } from "react"; -import { Collection, PublicURL, UpdatePublicURL } from "types/collection"; import { shareExpiryOptions } from "utils/collection"; import { isLinkExpired } from "../managePublicShare"; diff --git a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/linkPassword/index.tsx b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/linkPassword/index.tsx index 2c5890e9ab..5c9855bdee 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/linkPassword/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/linkPassword/index.tsx @@ -1,8 +1,12 @@ +import type { + Collection, + PublicURL, + UpdatePublicURL, +} from "@/media/collection"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import { t } from "i18next"; import { AppContext } from "pages/_app"; import { useContext, useState } from "react"; -import { Collection, PublicURL, UpdatePublicURL } from "types/collection"; import { PublicLinkSetPassword } from "./setPassword"; interface Iprops { diff --git a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/publicCollect.tsx b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/publicCollect.tsx index b97b6978c8..24f778ff26 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/publicCollect.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/manage/publicCollect.tsx @@ -1,8 +1,12 @@ import { MenuItemGroup, MenuSectionTitle } from "@/base/components/Menu"; +import type { + Collection, + PublicURL, + UpdatePublicURL, +} from "@/media/collection"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import { Stack } from "@mui/material"; import { t } from "i18next"; -import { Collection, PublicURL, UpdatePublicURL } from "types/collection"; interface Iprops { publicShareProp: PublicURL; diff --git a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/managePublicShare.tsx b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/managePublicShare.tsx index a5e7342c29..d06bbd87b1 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/publicShare/managePublicShare.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/publicShare/managePublicShare.tsx @@ -1,4 +1,5 @@ import { MenuItemDivider, MenuItemGroup } from "@/base/components/Menu"; +import type { Collection, PublicURL } from "@/media/collection"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import ChevronRightIcon from "@mui/icons-material/ChevronRight"; import ContentCopyIcon from "@mui/icons-material/ContentCopyOutlined"; @@ -8,7 +9,6 @@ import PublicIcon from "@mui/icons-material/Public"; import { Stack, Typography } from "@mui/material"; import { t } from "i18next"; import { useState } from "react"; -import { Collection, PublicURL } from "types/collection"; import { SetPublicShareProp } from "types/publicCollection"; import ManagePublicShareOptions from "./manage"; diff --git a/web/apps/photos/src/components/Collections/CollectionShare/sharingDetails.tsx b/web/apps/photos/src/components/Collections/CollectionShare/sharingDetails.tsx index c314a5aa05..4d557f211f 100644 --- a/web/apps/photos/src/components/Collections/CollectionShare/sharingDetails.tsx +++ b/web/apps/photos/src/components/Collections/CollectionShare/sharingDetails.tsx @@ -3,6 +3,7 @@ import { MenuItemGroup, MenuSectionTitle, } from "@/base/components/Menu"; +import { COLLECTION_ROLE } from "@/media/collection"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; import AdminPanelSettingsIcon from "@mui/icons-material/AdminPanelSettings"; import ModeEditIcon from "@mui/icons-material/ModeEdit"; @@ -12,7 +13,7 @@ import Avatar from "components/pages/gallery/Avatar"; import { t } from "i18next"; import { GalleryContext } from "pages/gallery"; import { useContext } from "react"; -import { COLLECTION_ROLE, CollectionSummaryType } from "types/collection"; +import { CollectionSummaryType } from "types/collection"; export default function SharingDetails({ collection, type }) { const galleryContext = useContext(GalleryContext); diff --git a/web/apps/photos/src/components/Collections/index.tsx b/web/apps/photos/src/components/Collections/index.tsx index 60519984da..03e75eaf87 100644 --- a/web/apps/photos/src/components/Collections/index.tsx +++ b/web/apps/photos/src/components/Collections/index.tsx @@ -1,3 +1,4 @@ +import type { Collection } from "@/media/collection"; import { useLocalState } from "@ente/shared/hooks/useLocalState"; import { LS_KEYS } from "@ente/shared/storage/localStorage"; import AllCollections from "components/Collections/AllCollections"; @@ -8,7 +9,7 @@ import CollectionShare from "components/Collections/CollectionShare"; import { ITEM_TYPE, TimeStampListItem } from "components/PhotoList"; import { useCallback, useEffect, useMemo, useState } from "react"; import { sortCollectionSummaries } from "services/collectionService"; -import { Collection, CollectionSummaries } from "types/collection"; +import { CollectionSummaries } from "types/collection"; import { SetFilesDownloadProgressAttributesCreator } from "types/gallery"; import { ALL_SECTION, diff --git a/web/apps/photos/src/components/SearchBar.tsx b/web/apps/photos/src/components/SearchBar.tsx index 3369ae9ea2..626ffc260a 100644 --- a/web/apps/photos/src/components/SearchBar.tsx +++ b/web/apps/photos/src/components/SearchBar.tsx @@ -1,5 +1,6 @@ import { assertionFailed } from "@/base/assert"; import { useIsMobileWidth } from "@/base/hooks"; +import type { Collection } from "@/media/collection"; import { FileType } from "@/media/file-type"; import { isMLSupported, @@ -65,7 +66,6 @@ import { } from "react-select"; import AsyncSelect from "react-select/async"; import { getAutoCompleteSuggestions } from "services/searchService"; -import { type Collection } from "types/collection"; interface SearchBarProps { /** diff --git a/web/apps/photos/src/components/Upload/Uploader.tsx b/web/apps/photos/src/components/Upload/Uploader.tsx index fc1977e392..c482364033 100644 --- a/web/apps/photos/src/components/Upload/Uploader.tsx +++ b/web/apps/photos/src/components/Upload/Uploader.tsx @@ -1,6 +1,7 @@ import { basename } from "@/base/file"; import log from "@/base/log"; import type { CollectionMapping, Electron, ZipItem } from "@/base/types/ipc"; +import type { Collection } from "@/media/collection"; import { exportMetadataDirectoryName } from "@/new/photos/services/export"; import type { FileAndPath, @@ -33,8 +34,6 @@ import type { } from "services/upload/uploadManager"; import uploadManager from "services/upload/uploadManager"; import watcher from "services/watch"; -import { NotificationAttributes } from "types/Notification"; -import { Collection } from "types/collection"; import { CollectionSelectorIntent, SetCollectionSelectorAttributes, @@ -42,6 +41,7 @@ import { SetFiles, SetLoading, } from "types/gallery"; +import { NotificationAttributes } from "types/Notification"; import { getOrCreateAlbum } from "utils/collection"; import { PublicCollectionGalleryContext } from "utils/publicCollectionGallery"; import { diff --git a/web/apps/photos/src/components/pages/gallery/AvatarGroup.tsx b/web/apps/photos/src/components/pages/gallery/AvatarGroup.tsx index df733fdded..a45bb6f771 100644 --- a/web/apps/photos/src/components/pages/gallery/AvatarGroup.tsx +++ b/web/apps/photos/src/components/pages/gallery/AvatarGroup.tsx @@ -1,6 +1,6 @@ +import type { Collection } from "@/media/collection"; import { styled } from "@mui/material"; import NumberAvatar from "@mui/material/Avatar"; -import { Collection } from "types/collection"; import Avatar from "./Avatar"; const AvatarContainer = styled("div")({ diff --git a/web/apps/photos/src/components/pages/gallery/SelectedFileOptions.tsx b/web/apps/photos/src/components/pages/gallery/SelectedFileOptions.tsx index 01182abfa9..29087e87c5 100644 --- a/web/apps/photos/src/components/pages/gallery/SelectedFileOptions.tsx +++ b/web/apps/photos/src/components/pages/gallery/SelectedFileOptions.tsx @@ -1,4 +1,5 @@ import { SelectionBar } from "@/base/components/Navbar"; +import type { Collection } from "@/media/collection"; import { FluidContainer } from "@ente/shared/components/Container"; import ClockIcon from "@mui/icons-material/AccessTime"; import AddIcon from "@mui/icons-material/Add"; @@ -16,7 +17,6 @@ import { Box, IconButton, Stack, Tooltip } from "@mui/material"; import { t } from "i18next"; import { AppContext } from "pages/_app"; import { useContext } from "react"; -import { Collection } from "types/collection"; import { CollectionSelectorIntent, SetCollectionSelectorAttributes, diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx index 7f40003f76..0b33378521 100644 --- a/web/apps/photos/src/pages/gallery.tsx +++ b/web/apps/photos/src/pages/gallery.tsx @@ -2,6 +2,7 @@ import { stashRedirect } from "@/accounts/services/redirect"; import { NavbarBase } from "@/base/components/Navbar"; import { useIsMobileWidth } from "@/base/hooks"; import log from "@/base/log"; +import type { Collection } from "@/media/collection"; import { WhatsNew } from "@/new/photos/components/WhatsNew"; import { shouldShowWhatsNew } from "@/new/photos/services/changelog"; import downloadManager from "@/new/photos/services/download"; @@ -105,11 +106,7 @@ import { sync, triggerPreFileInfoSync } from "services/sync"; import { syncTrash } from "services/trashService"; import uploadManager from "services/upload/uploadManager"; import { isTokenValid } from "services/userService"; -import { - Collection, - CollectionSummaries, - CollectionSummaryType, -} from "types/collection"; +import { CollectionSummaries, CollectionSummaryType } from "types/collection"; import { GalleryContextType, SelectedState, diff --git a/web/apps/photos/src/pages/shared-albums.tsx b/web/apps/photos/src/pages/shared-albums.tsx index c11e49fd80..3b843c8bd8 100644 --- a/web/apps/photos/src/pages/shared-albums.tsx +++ b/web/apps/photos/src/pages/shared-albums.tsx @@ -2,6 +2,7 @@ import { NavbarBase, SelectionBar } from "@/base/components/Navbar"; import { sharedCryptoWorker } from "@/base/crypto"; import { useIsMobileWidth, useIsTouchscreen } from "@/base/hooks"; import log from "@/base/log"; +import type { Collection } from "@/media/collection"; import downloadManager from "@/new/photos/services/download"; import { EnteFile } from "@/new/photos/types/file"; import { mergeMetadata } from "@/new/photos/utils/file"; @@ -63,7 +64,6 @@ import { verifyPublicCollectionPassword, } from "services/publicCollectionService"; import uploadManager from "services/upload/uploadManager"; -import { Collection } from "types/collection"; import { SelectedState, SetFilesDownloadProgressAttributes, diff --git a/web/apps/photos/src/services/collectionService.ts b/web/apps/photos/src/services/collectionService.ts index db5ce4bec5..80f7f741b4 100644 --- a/web/apps/photos/src/services/collectionService.ts +++ b/web/apps/photos/src/services/collectionService.ts @@ -1,6 +1,23 @@ import { encryptMetadataJSON, sharedCryptoWorker } from "@/base/crypto"; import log from "@/base/log"; import { apiURL } from "@/base/origins"; +import { + AddToCollectionRequest, + Collection, + CollectionMagicMetadata, + CollectionMagicMetadataProps, + CollectionPublicMagicMetadata, + CollectionShareeMagicMetadata, + CollectionToFileMap, + CollectionType, + CreatePublicAccessTokenRequest, + EncryptedCollection, + EncryptedFileKey, + MoveToCollectionRequest, + PublicURL, + RemoveFromCollectionRequest, + UpdatePublicURL, +} from "@/media/collection"; import { ItemVisibility } from "@/media/file-metadata"; import { getLocalFiles } from "@/new/photos/services/files"; import { EnteFile } from "@/new/photos/types/file"; @@ -19,25 +36,10 @@ import { getActualKey } from "@ente/shared/user"; import type { User } from "@ente/shared/user/types"; import { t } from "i18next"; import { - AddToCollectionRequest, - Collection, CollectionFilesCount, - CollectionMagicMetadata, - CollectionMagicMetadataProps, - CollectionPublicMagicMetadata, - CollectionShareeMagicMetadata, CollectionSummaries, CollectionSummary, CollectionSummaryType, - CollectionToFileMap, - CollectionType, - CreatePublicAccessTokenRequest, - EncryptedCollection, - EncryptedFileKey, - MoveToCollectionRequest, - PublicURL, - RemoveFromCollectionRequest, - UpdatePublicURL, } from "types/collection"; import { FamilyData } from "types/user"; import { diff --git a/web/apps/photos/src/services/export/index.ts b/web/apps/photos/src/services/export/index.ts index 84d48832a9..a130f9f729 100644 --- a/web/apps/photos/src/services/export/index.ts +++ b/web/apps/photos/src/services/export/index.ts @@ -1,5 +1,6 @@ import { ensureElectron } from "@/base/electron"; import log from "@/base/log"; +import type { Collection } from "@/media/collection"; import { fileCreationPhotoDate, fileLocation, @@ -27,7 +28,6 @@ import QueueProcessor, { RequestCanceller, } from "@ente/shared/utils/queueProcessor"; import i18n from "i18next"; -import { Collection } from "types/collection"; import { CollectionExportNames, ExportProgress, diff --git a/web/apps/photos/src/services/export/migration.ts b/web/apps/photos/src/services/export/migration.ts index 9c1c011e32..2116ca258c 100644 --- a/web/apps/photos/src/services/export/migration.ts +++ b/web/apps/photos/src/services/export/migration.ts @@ -1,6 +1,7 @@ import { ensureElectron } from "@/base/electron"; import { nameAndExtension } from "@/base/file"; import log from "@/base/log"; +import type { Collection } from "@/media/collection"; import { FileType } from "@/media/file-type"; import { decodeLivePhoto } from "@/media/live-photo"; import downloadManager from "@/new/photos/services/download"; @@ -17,7 +18,6 @@ import { wait } from "@/utils/promise"; import { LS_KEYS, getData } from "@ente/shared/storage/localStorage"; import type { User } from "@ente/shared/user/types"; import { getLocalCollections } from "services/collectionService"; -import { Collection } from "types/collection"; import { CollectionExportNames, ExportProgress, diff --git a/web/apps/photos/src/services/fileService.ts b/web/apps/photos/src/services/fileService.ts index 613e9bd85e..354bc04da7 100644 --- a/web/apps/photos/src/services/fileService.ts +++ b/web/apps/photos/src/services/fileService.ts @@ -1,6 +1,7 @@ import { encryptMetadataJSON } from "@/base/crypto"; import log from "@/base/log"; import { apiURL } from "@/base/origins"; +import type { Collection } from "@/media/collection"; import { clearCachedThumbnailsIfChanged, getLocalFiles, @@ -19,7 +20,6 @@ import { batch } from "@/utils/array"; import HTTPService from "@ente/shared/network/HTTPService"; import { getToken } from "@ente/shared/storage/localStorage/helpers"; import exportService from "services/export"; -import { Collection } from "types/collection"; import { SetFiles } from "types/gallery"; import { decryptFile, getLatestVersionFiles, sortFiles } from "utils/file"; import { diff --git a/web/apps/photos/src/services/publicCollectionService.ts b/web/apps/photos/src/services/publicCollectionService.ts index 8b1a522954..9deed90281 100644 --- a/web/apps/photos/src/services/publicCollectionService.ts +++ b/web/apps/photos/src/services/publicCollectionService.ts @@ -1,12 +1,15 @@ import { sharedCryptoWorker } from "@/base/crypto"; import log from "@/base/log"; import { apiURL } from "@/base/origins"; +import type { + Collection, + CollectionPublicMagicMetadata, +} from "@/media/collection"; import { EncryptedEnteFile, EnteFile } from "@/new/photos/types/file"; import { mergeMetadata } from "@/new/photos/utils/file"; import { CustomError, parseSharingErrorCodes } from "@ente/shared/error"; import HTTPService from "@ente/shared/network/HTTPService"; import localForage from "@ente/shared/storage/localForage"; -import { Collection, CollectionPublicMagicMetadata } from "types/collection"; import { LocalSavedPublicCollectionFiles } from "types/publicCollection"; import { decryptFile, sortFiles } from "utils/file"; diff --git a/web/apps/photos/src/services/searchService.ts b/web/apps/photos/src/services/searchService.ts index 7dd3e289c2..215b15c2e6 100644 --- a/web/apps/photos/src/services/searchService.ts +++ b/web/apps/photos/src/services/searchService.ts @@ -1,4 +1,5 @@ import log from "@/base/log"; +import type { Collection } from "@/media/collection"; import { FileType } from "@/media/file-type"; import { createSearchQuery, search } from "@/new/photos/services/search"; import type { @@ -15,7 +16,6 @@ import { } from "@/new/photos/services/search/types"; import type { LocationTag } from "@/new/photos/services/user-entity"; import { type EnteFile } from "@/new/photos/types/file"; -import { type Collection } from "types/collection"; // Suggestions shown in the search dropdown when the user has typed something. export const getAutoCompleteSuggestions = diff --git a/web/apps/photos/src/services/trashService.ts b/web/apps/photos/src/services/trashService.ts index 73d2f2a44f..fef3d4ee64 100644 --- a/web/apps/photos/src/services/trashService.ts +++ b/web/apps/photos/src/services/trashService.ts @@ -1,5 +1,6 @@ import log from "@/base/log"; import { apiURL } from "@/base/origins"; +import type { Collection } from "@/media/collection"; import { getLocalTrash, getTrashedFiles, @@ -9,7 +10,6 @@ import { EncryptedTrashItem, Trash } from "@/new/photos/types/file"; import HTTPService from "@ente/shared/network/HTTPService"; import localForage from "@ente/shared/storage/localForage"; import { getToken } from "@ente/shared/storage/localStorage/helpers"; -import { Collection } from "types/collection"; import { SetFiles } from "types/gallery"; import { decryptFile } from "utils/file"; import { getCollection } from "./collectionService"; diff --git a/web/apps/photos/src/services/upload/uploadManager.ts b/web/apps/photos/src/services/upload/uploadManager.ts index 1028f84aed..d6c32f6cf5 100644 --- a/web/apps/photos/src/services/upload/uploadManager.ts +++ b/web/apps/photos/src/services/upload/uploadManager.ts @@ -4,6 +4,7 @@ import { lowercaseExtension, nameAndExtension } from "@/base/file"; import log from "@/base/log"; import type { Electron } from "@/base/types/ipc"; import { ComlinkWorker } from "@/base/worker/comlink-worker"; +import type { Collection } from "@/media/collection"; import { FileType } from "@/media/file-type"; import { potentialFileTypeFromExtension } from "@/media/live-photo"; import { getLocalFiles } from "@/new/photos/services/files"; @@ -26,7 +27,6 @@ import { } from "services/publicCollectionService"; import { getDisableCFUploadProxyFlag } from "services/userService"; import watcher from "services/watch"; -import { Collection } from "types/collection"; import { SetFiles } from "types/gallery"; import { decryptFile, getUserOwnedFiles, sortFiles } from "utils/file"; import { diff --git a/web/apps/photos/src/services/watch.ts b/web/apps/photos/src/services/watch.ts index bbac30cae7..e17e054978 100644 --- a/web/apps/photos/src/services/watch.ts +++ b/web/apps/photos/src/services/watch.ts @@ -11,6 +11,7 @@ import type { FolderWatch, FolderWatchSyncedFile, } from "@/base/types/ipc"; +import type { Collection } from "@/media/collection"; import { getLocalFiles } from "@/new/photos/services/files"; import { UPLOAD_RESULT } from "@/new/photos/services/upload/types"; import { EncryptedEnteFile } from "@/new/photos/types/file"; @@ -19,7 +20,6 @@ import debounce from "debounce"; import uploadManager, { type UploadItemWithCollection, } from "services/upload/uploadManager"; -import { Collection } from "types/collection"; import { groupFilesBasedOnCollectionID } from "utils/file"; import { removeFromCollection } from "./collectionService"; diff --git a/web/apps/photos/src/types/collection.ts b/web/apps/photos/src/types/collection.ts new file mode 100644 index 0000000000..3442ff98e9 --- /dev/null +++ b/web/apps/photos/src/types/collection.ts @@ -0,0 +1,33 @@ +import type { EnteFile } from "@/new/photos/types/file"; + +export enum CollectionSummaryType { + folder = "folder", + favorites = "favorites", + album = "album", + archive = "archive", + trash = "trash", + uncategorized = "uncategorized", + all = "all", + outgoingShare = "outgoingShare", + incomingShareViewer = "incomingShareViewer", + incomingShareCollaborator = "incomingShareCollaborator", + sharedOnlyViaLink = "sharedOnlyViaLink", + archived = "archived", + defaultHidden = "defaultHidden", + hiddenItems = "hiddenItems", + pinned = "pinned", +} + +export interface CollectionSummary { + id: number; + name: string; + type: CollectionSummaryType; + coverFile: EnteFile; + latestFile: EnteFile; + fileCount: number; + updationTime: number; + order?: number; +} + +export type CollectionSummaries = Map; +export type CollectionFilesCount = Map; diff --git a/web/apps/photos/src/types/gallery/index.ts b/web/apps/photos/src/types/gallery/index.ts index 1f95e78a19..ce789d31a0 100644 --- a/web/apps/photos/src/types/gallery/index.ts +++ b/web/apps/photos/src/types/gallery/index.ts @@ -1,9 +1,9 @@ +import type { Collection } from "@/media/collection"; import { EnteFile } from "@/new/photos/types/file"; import type { User } from "@ente/shared/user/types"; import { CollectionSelectorAttributes } from "components/Collections/CollectionSelector"; import { FilesDownloadProgressAttributes } from "components/FilesDownloadProgress"; import { TimeStampListItem } from "components/PhotoList"; -import { Collection } from "types/collection"; export type SelectedState = { [k: number]: boolean; diff --git a/web/apps/photos/src/types/publicCollection/index.ts b/web/apps/photos/src/types/publicCollection/index.ts index 95c5607584..41039a67e5 100644 --- a/web/apps/photos/src/types/publicCollection/index.ts +++ b/web/apps/photos/src/types/publicCollection/index.ts @@ -1,6 +1,6 @@ +import type { PublicURL } from "@/media/collection"; import { EnteFile } from "@/new/photos/types/file"; import { TimeStampListItem } from "components/PhotoList"; -import { PublicURL } from "types/collection"; export interface PublicCollectionGalleryContextType { token: string; diff --git a/web/apps/photos/src/utils/collection.ts b/web/apps/photos/src/utils/collection.ts index 3d1a1398ce..084bbc97ea 100644 --- a/web/apps/photos/src/utils/collection.ts +++ b/web/apps/photos/src/utils/collection.ts @@ -1,5 +1,12 @@ import { ensureElectron } from "@/base/electron"; import log from "@/base/log"; +import { + COLLECTION_ROLE, + type Collection, + CollectionMagicMetadataProps, + CollectionPublicMagicMetadataProps, + CollectionType, +} from "@/media/collection"; import { ItemVisibility } from "@/media/file-metadata"; import { getAllLocalFiles, getLocalFiles } from "@/new/photos/services/files"; import { EnteFile } from "@/new/photos/types/file"; @@ -25,13 +32,7 @@ import { updatePublicCollectionMagicMetadata, updateSharedCollectionMagicMetadata, } from "services/collectionService"; -import { - COLLECTION_ROLE, - Collection, - CollectionMagicMetadataProps, - CollectionPublicMagicMetadataProps, - CollectionSummaries, -} from "types/collection"; +import { CollectionSummaries, CollectionSummaryType } from "types/collection"; import { SetFilesDownloadProgressAttributes } from "types/gallery"; import { downloadFilesWithProgress } from "utils/file"; import { isArchivedCollection, updateMagicMetadata } from "utils/magicMetadata"; diff --git a/web/apps/photos/src/utils/magicMetadata/index.ts b/web/apps/photos/src/utils/magicMetadata/index.ts index 3f2132f82d..467e3cf04c 100644 --- a/web/apps/photos/src/utils/magicMetadata/index.ts +++ b/web/apps/photos/src/utils/magicMetadata/index.ts @@ -1,8 +1,8 @@ import { sharedCryptoWorker } from "@/base/crypto"; +import type { Collection } from "@/media/collection"; import { ItemVisibility } from "@/media/file-metadata"; import { EnteFile } from "@/new/photos/types/file"; import { MagicMetadataCore } from "@/new/photos/types/magicMetadata"; -import { Collection } from "types/collection"; export function isArchivedFile(item: EnteFile): boolean { if (!item || !item.magicMetadata || !item.magicMetadata.data) { diff --git a/web/apps/photos/src/types/collection/index.ts b/web/packages/media/collection.ts similarity index 78% rename from web/apps/photos/src/types/collection/index.ts rename to web/packages/media/collection.ts index 0258b34a71..3e60bde054 100644 --- a/web/apps/photos/src/types/collection/index.ts +++ b/web/packages/media/collection.ts @@ -1,11 +1,13 @@ import { ItemVisibility } from "@/media/file-metadata"; -import { EnteFile } from "@/new/photos/types/file"; +import type { EnteFile } from "@/new/photos/types/file"; import { - EncryptedMagicMetadata, - MagicMetadataCore, + type EncryptedMagicMetadata, + type MagicMetadataCore, SUB_TYPE, } from "@/new/photos/types/magicMetadata"; +// TODO: Audit this file + export enum CollectionType { folder = "folder", favorites = "favorites", @@ -13,24 +15,6 @@ export enum CollectionType { uncategorized = "uncategorized", } -export enum CollectionSummaryType { - folder = "folder", - favorites = "favorites", - album = "album", - archive = "archive", - trash = "trash", - uncategorized = "uncategorized", - all = "all", - outgoingShare = "outgoingShare", - incomingShareViewer = "incomingShareViewer", - incomingShareCollaborator = "incomingShareCollaborator", - sharedOnlyViaLink = "sharedOnlyViaLink", - archived = "archived", - defaultHidden = "defaultHidden", - hiddenItems = "hiddenItems", - pinned = "pinned", -} - export enum COLLECTION_ROLE { VIEWER = "VIEWER", OWNER = "OWNER", @@ -164,17 +148,3 @@ export interface CollectionPublicMagicMetadataProps { export type CollectionPublicMagicMetadata = MagicMetadataCore; - -export interface CollectionSummary { - id: number; - name: string; - type: CollectionSummaryType; - coverFile: EnteFile; - latestFile: EnteFile; - fileCount: number; - updationTime: number; - order?: number; -} - -export type CollectionSummaries = Map; -export type CollectionFilesCount = Map; diff --git a/web/packages/media/types/file.ts b/web/packages/media/types/file.ts deleted file mode 100644 index e69de29bb2..0000000000 From ace2e5bb2783fa87f10730ebb89b05be7331c88d Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 18:08:48 +0530 Subject: [PATCH 10/19] Move --- web/apps/photos/src/components/SearchBar.tsx | 2 +- web/apps/photos/src/services/searchService.ts | 174 ------------------ .../new/photos/services/search/index.ts | 171 +++++++++++++++++ 3 files changed, 172 insertions(+), 175 deletions(-) delete mode 100644 web/apps/photos/src/services/searchService.ts diff --git a/web/apps/photos/src/components/SearchBar.tsx b/web/apps/photos/src/components/SearchBar.tsx index 626ffc260a..8d5fb0f063 100644 --- a/web/apps/photos/src/components/SearchBar.tsx +++ b/web/apps/photos/src/components/SearchBar.tsx @@ -7,6 +7,7 @@ import { mlStatusSnapshot, mlStatusSubscribe, } from "@/new/photos/services/ml"; +import { getAutoCompleteSuggestions } from "@/new/photos/services/search"; import type { City, SearchDateComponents, @@ -65,7 +66,6 @@ import { type StylesConfig, } from "react-select"; import AsyncSelect from "react-select/async"; -import { getAutoCompleteSuggestions } from "services/searchService"; interface SearchBarProps { /** diff --git a/web/apps/photos/src/services/searchService.ts b/web/apps/photos/src/services/searchService.ts deleted file mode 100644 index 215b15c2e6..0000000000 --- a/web/apps/photos/src/services/searchService.ts +++ /dev/null @@ -1,174 +0,0 @@ -import log from "@/base/log"; -import type { Collection } from "@/media/collection"; -import { FileType } from "@/media/file-type"; -import { createSearchQuery, search } from "@/new/photos/services/search"; -import type { - SearchDateComponents, - SearchPerson, -} from "@/new/photos/services/search/types"; -import { - City, - ClipSearchScores, - SearchOption, - SearchQuery, - Suggestion, - SuggestionType, -} from "@/new/photos/services/search/types"; -import type { LocationTag } from "@/new/photos/services/user-entity"; -import { type EnteFile } from "@/new/photos/types/file"; - -// Suggestions shown in the search dropdown when the user has typed something. -export const getAutoCompleteSuggestions = - (files: EnteFile[], collections: Collection[]) => - async (searchPhrase: string): Promise => { - log.debug(() => ["getAutoCompleteSuggestions", { searchPhrase }]); - try { - const searchPhrase2 = searchPhrase.trim().toLowerCase(); - if (!searchPhrase2?.length) { - return []; - } - const suggestions: Suggestion[] = [ - // The following functionality has moved to createSearchQuery - // - getClipSuggestion(searchPhrase) - // - getDateSuggestion(searchPhrase), - // - getLocationSuggestion(searchPhrase), - // - getFileTypeSuggestion(searchPhrase), - ...(await createSearchQuery(searchPhrase)), - ...getCollectionSuggestion(searchPhrase2, collections), - getFileNameSuggestion(searchPhrase2, files), - getFileCaptionSuggestion(searchPhrase2, files), - ].filter((suggestion) => !!suggestion); - - return convertSuggestionsToOptions(suggestions); - } catch (e) { - log.error("getAutoCompleteSuggestions failed", e); - return []; - } - }; - -async function convertSuggestionsToOptions( - suggestions: Suggestion[], -): Promise { - const previewImageAppendedOptions: SearchOption[] = []; - for (const suggestion of suggestions) { - const searchQuery = convertSuggestionToSearchQuery(suggestion); - const resultFiles = await search(searchQuery); - if (searchQuery?.clip) { - resultFiles.sort((a, b) => { - const aScore = searchQuery.clip.get(a.id); - const bScore = searchQuery.clip.get(b.id); - return bScore - aScore; - }); - } - if (resultFiles.length) { - previewImageAppendedOptions.push({ - ...suggestion, - fileCount: resultFiles.length, - previewFiles: resultFiles.slice(0, 3), - }); - } - } - return previewImageAppendedOptions; -} - -function getCollectionSuggestion( - searchPhrase: string, - collections: Collection[], -): Suggestion[] { - const collectionResults = searchCollection(searchPhrase, collections); - - return collectionResults.map( - (searchResult) => - ({ - type: SuggestionType.COLLECTION, - value: searchResult.id, - label: searchResult.name, - }) as Suggestion, - ); -} - -function getFileNameSuggestion( - searchPhrase: string, - files: EnteFile[], -): Suggestion { - const matchedFiles = searchFilesByName(searchPhrase, files); - return { - type: SuggestionType.FILE_NAME, - value: matchedFiles.map((file) => file.id), - label: searchPhrase, - }; -} - -function getFileCaptionSuggestion( - searchPhrase: string, - files: EnteFile[], -): Suggestion { - const matchedFiles = searchFilesByCaption(searchPhrase, files); - return { - type: SuggestionType.FILE_CAPTION, - value: matchedFiles.map((file) => file.id), - label: searchPhrase, - }; -} - -function searchCollection( - searchPhrase: string, - collections: Collection[], -): Collection[] { - return collections.filter((collection) => - collection.name.toLowerCase().includes(searchPhrase), - ); -} - -function searchFilesByName(searchPhrase: string, files: EnteFile[]) { - return files.filter( - (file) => - file.id.toString().includes(searchPhrase) || - file.metadata.title.toLowerCase().includes(searchPhrase), - ); -} - -function searchFilesByCaption(searchPhrase: string, files: EnteFile[]) { - return files.filter( - (file) => - file.pubMagicMetadata && - file.pubMagicMetadata.data.caption - ?.toLowerCase() - .includes(searchPhrase), - ); -} - -function convertSuggestionToSearchQuery(option: Suggestion): SearchQuery { - switch (option.type) { - case SuggestionType.DATE: - return { - date: option.value as SearchDateComponents, - }; - - case SuggestionType.LOCATION: - return { - location: option.value as LocationTag, - }; - - case SuggestionType.CITY: - return { city: option.value as City }; - - case SuggestionType.COLLECTION: - return { collection: option.value as number }; - - case SuggestionType.FILE_NAME: - return { files: option.value as number[] }; - - case SuggestionType.FILE_CAPTION: - return { files: option.value as number[] }; - - case SuggestionType.PERSON: - return { person: option.value as SearchPerson }; - - case SuggestionType.FILE_TYPE: - return { fileType: option.value as FileType }; - - case SuggestionType.CLIP: - return { clip: option.value as ClipSearchScores }; - } -} diff --git a/web/packages/new/photos/services/search/index.ts b/web/packages/new/photos/services/search/index.ts index cfd7a0ca21..9f90d3bd6b 100644 --- a/web/packages/new/photos/services/search/index.ts +++ b/web/packages/new/photos/services/search/index.ts @@ -1,16 +1,25 @@ import { isDesktop } from "@/base/app"; +import log from "@/base/log"; import { masterKeyFromSession } from "@/base/session-store"; import { ComlinkWorker } from "@/base/worker/comlink-worker"; +import type { Collection } from "@/media/collection"; import { FileType } from "@/media/file-type"; +import type { LocationTag } from "@/new/photos/services/user-entity"; import i18n, { t } from "i18next"; import type { EnteFile } from "../../types/file"; import { clipMatches, isMLEnabled } from "../ml"; import { SuggestionType, + type City, + type ClipSearchScores, type DateSearchResult, type LabelledFileType, type LocalizedSearchData, + type SearchDateComponents, + type SearchOption, + type SearchPerson, type SearchQuery, + type Suggestion, } from "./types"; import type { SearchWorker } from "./worker"; @@ -149,3 +158,165 @@ const labelledFileTypes = (): LabelledFileType[] => [ { fileType: FileType.video, label: t("VIDEO") }, { fileType: FileType.livePhoto, label: t("LIVE_PHOTO") }, ]; + +// TODO-Cluster -- AUDIT BELOW THIS + +// Suggestions shown in the search dropdown when the user has typed something. +export const getAutoCompleteSuggestions = + (files: EnteFile[], collections: Collection[]) => + async (searchPhrase: string): Promise => { + log.debug(() => ["getAutoCompleteSuggestions", { searchPhrase }]); + try { + const searchPhrase2 = searchPhrase.trim().toLowerCase(); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (!searchPhrase2?.length) { + return []; + } + const suggestions: Suggestion[] = [ + // The following functionality has moved to createSearchQuery + // - getClipSuggestion(searchPhrase) + // - getDateSuggestion(searchPhrase), + // - getLocationSuggestion(searchPhrase), + // - getFileTypeSuggestion(searchPhrase), + ...(await createSearchQuery(searchPhrase)), + ...getCollectionSuggestion(searchPhrase2, collections), + getFileNameSuggestion(searchPhrase2, files), + getFileCaptionSuggestion(searchPhrase2, files), + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + ].filter((suggestion) => !!suggestion); + + return convertSuggestionsToOptions(suggestions); + } catch (e) { + log.error("getAutoCompleteSuggestions failed", e); + return []; + } + }; + +async function convertSuggestionsToOptions( + suggestions: Suggestion[], +): Promise { + const previewImageAppendedOptions: SearchOption[] = []; + for (const suggestion of suggestions) { + const searchQuery = convertSuggestionToSearchQuery(suggestion); + const resultFiles = await search(searchQuery); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (searchQuery?.clip) { + resultFiles.sort((a, b) => { + const aScore = searchQuery.clip?.get(a.id) ?? 0; + const bScore = searchQuery.clip?.get(b.id) ?? 0; + return bScore - aScore; + }); + } + if (resultFiles.length) { + previewImageAppendedOptions.push({ + ...suggestion, + fileCount: resultFiles.length, + previewFiles: resultFiles.slice(0, 3), + }); + } + } + return previewImageAppendedOptions; +} + +function getCollectionSuggestion( + searchPhrase: string, + collections: Collection[], +): Suggestion[] { + const collectionResults = searchCollection(searchPhrase, collections); + + return collectionResults.map( + (searchResult) => + ({ + type: SuggestionType.COLLECTION, + value: searchResult.id, + label: searchResult.name, + }) as Suggestion, + ); +} + +function getFileNameSuggestion( + searchPhrase: string, + files: EnteFile[], +): Suggestion { + const matchedFiles = searchFilesByName(searchPhrase, files); + return { + type: SuggestionType.FILE_NAME, + value: matchedFiles.map((file) => file.id), + label: searchPhrase, + }; +} + +function getFileCaptionSuggestion( + searchPhrase: string, + files: EnteFile[], +): Suggestion { + const matchedFiles = searchFilesByCaption(searchPhrase, files); + return { + type: SuggestionType.FILE_CAPTION, + value: matchedFiles.map((file) => file.id), + label: searchPhrase, + }; +} + +function searchCollection( + searchPhrase: string, + collections: Collection[], +): Collection[] { + return collections.filter((collection) => + collection.name.toLowerCase().includes(searchPhrase), + ); +} + +function searchFilesByName(searchPhrase: string, files: EnteFile[]) { + return files.filter( + (file) => + file.id.toString().includes(searchPhrase) || + file.metadata.title.toLowerCase().includes(searchPhrase), + ); +} + +function searchFilesByCaption(searchPhrase: string, files: EnteFile[]) { + return files.filter( + (file) => + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain + file.pubMagicMetadata && + file.pubMagicMetadata.data.caption + ?.toLowerCase() + .includes(searchPhrase), + ); +} + +function convertSuggestionToSearchQuery(option: Suggestion): SearchQuery { + switch (option.type) { + case SuggestionType.DATE: + return { + date: option.value as SearchDateComponents, + }; + + case SuggestionType.LOCATION: + return { + location: option.value as LocationTag, + }; + + case SuggestionType.CITY: + return { city: option.value as City }; + + case SuggestionType.COLLECTION: + return { collection: option.value as number }; + + case SuggestionType.FILE_NAME: + return { files: option.value as number[] }; + + case SuggestionType.FILE_CAPTION: + return { files: option.value as number[] }; + + case SuggestionType.PERSON: + return { person: option.value as SearchPerson }; + + case SuggestionType.FILE_TYPE: + return { fileType: option.value as FileType }; + + case SuggestionType.CLIP: + return { clip: option.value as ClipSearchScores }; + } +} From bf001794b418a93901ba1cab8d5823e923f9ae1b Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 19:49:17 +0530 Subject: [PATCH 11/19] Also pass collections --- web/apps/photos/src/pages/gallery.tsx | 9 ++++-- .../new/photos/services/search/index.ts | 31 ++++++++++--------- .../new/photos/services/search/types.ts | 9 ++++++ .../new/photos/services/search/worker.ts | 13 +++++--- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx index 0b33378521..64405dd4ff 100644 --- a/web/apps/photos/src/pages/gallery.tsx +++ b/web/apps/photos/src/pages/gallery.tsx @@ -11,7 +11,7 @@ import { getLocalTrashedFiles, } from "@/new/photos/services/files"; import { wipHasSwitchedOnceCmpAndSet } from "@/new/photos/services/ml"; -import { search, setSearchableFiles } from "@/new/photos/services/search"; +import { search, setSearchableData } from "@/new/photos/services/search"; import { SearchQuery, SearchResultSummary, @@ -407,8 +407,11 @@ export default function Gallery() { }; }, []); - // TODO: Is this uniquing necessary? Doesn't seem like. - useEffect(() => setSearchableFiles(getUniqueFiles(files)), [files]); + useEffect( + // TODO: Try to set things up so that this uniquing is not needed. + () => setSearchableData({ collections, files: getUniqueFiles(files) }), + [collections, files], + ); useEffect(() => { if (!user || !files || !collections || !hiddenFiles || !trashedFiles) { diff --git a/web/packages/new/photos/services/search/index.ts b/web/packages/new/photos/services/search/index.ts index 9f90d3bd6b..25bdf5ce42 100644 --- a/web/packages/new/photos/services/search/index.ts +++ b/web/packages/new/photos/services/search/index.ts @@ -8,19 +8,20 @@ import type { LocationTag } from "@/new/photos/services/user-entity"; import i18n, { t } from "i18next"; import type { EnteFile } from "../../types/file"; import { clipMatches, isMLEnabled } from "../ml"; -import { - SuggestionType, - type City, - type ClipSearchScores, - type DateSearchResult, - type LabelledFileType, - type LocalizedSearchData, - type SearchDateComponents, - type SearchOption, - type SearchPerson, - type SearchQuery, - type Suggestion, +import type { + City, + ClipSearchScores, + DateSearchResult, + LabelledFileType, + LocalizedSearchData, + SearchableData, + SearchDateComponents, + SearchOption, + SearchPerson, + SearchQuery, + Suggestion, } from "./types"; +import { SuggestionType } from "./types"; import type { SearchWorker } from "./worker"; /** @@ -61,10 +62,10 @@ export const triggerSearchDataSync = () => void worker().then((w) => masterKeyFromSession().then((k) => w.sync(k))); /** - * Set the files over which we will search. + * Set the collections and files over which we should search. */ -export const setSearchableFiles = (enteFiles: EnteFile[]) => - void worker().then((w) => w.setEnteFiles(enteFiles)); +export const setSearchableData = (data: SearchableData) => + void worker().then((w) => w.setSearchableData(data)); /** * Convert a search string into a reusable "search query" that can be passed on diff --git a/web/packages/new/photos/services/search/types.ts b/web/packages/new/photos/services/search/types.ts index b375c05aeb..2ef199d736 100644 --- a/web/packages/new/photos/services/search/types.ts +++ b/web/packages/new/photos/services/search/types.ts @@ -4,10 +4,19 @@ */ import type { Location } from "@/base/types"; +import type { Collection } from "@/media/collection"; import { FileType } from "@/media/file-type"; import type { EnteFile } from "@/new/photos/types/file"; import type { LocationTag } from "../user-entity"; +/** + * The base data over which we should search. + */ +export interface SearchableData { + collections: Collection[]; + files: EnteFile[]; +} + export interface DateSearchResult { components: SearchDateComponents; label: string; diff --git a/web/packages/new/photos/services/search/worker.ts b/web/packages/new/photos/services/search/worker.ts index 735bd9c035..8b3c57dce9 100644 --- a/web/packages/new/photos/services/search/worker.ts +++ b/web/packages/new/photos/services/search/worker.ts @@ -19,6 +19,7 @@ import type { LabelledFileType, LocalizedSearchData, Searchable, + SearchableData, SearchDateComponents, SearchQuery, Suggestion, @@ -30,7 +31,7 @@ import { SuggestionType } from "./types"; * remains responsive. */ export class SearchWorker { - private enteFiles: EnteFile[] = []; + private searchableData: SearchableData = { collections: [], files: [] }; private locationTags: Searchable[] = []; private cities: Searchable[] = []; @@ -60,10 +61,10 @@ export class SearchWorker { } /** - * Set the files that we should search across. + * Set the data that we should search across. */ - setEnteFiles(enteFiles: EnteFile[]) { - this.enteFiles = enteFiles; + setSearchableData(data: SearchableData) { + this.searchableData = data; } /** @@ -82,7 +83,9 @@ export class SearchWorker { * Return {@link EnteFile}s that satisfy the given {@link searchQuery}. */ search(searchQuery: SearchQuery) { - return this.enteFiles.filter((f) => isMatchingFile(f, searchQuery)); + return this.searchableData.files.filter((f) => + isMatchingFile(f, searchQuery), + ); } } From 5b2be09a6a44987dd4cf3fee3a5ed8a75410a0e8 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 19:56:51 +0530 Subject: [PATCH 12/19] To new --- .../new/photos/services/search/index.ts | 22 ++++--------------- .../new/photos/services/search/worker.ts | 13 +++++++++++ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/web/packages/new/photos/services/search/index.ts b/web/packages/new/photos/services/search/index.ts index 25bdf5ce42..eb84ce3b33 100644 --- a/web/packages/new/photos/services/search/index.ts +++ b/web/packages/new/photos/services/search/index.ts @@ -166,7 +166,10 @@ const labelledFileTypes = (): LabelledFileType[] => [ export const getAutoCompleteSuggestions = (files: EnteFile[], collections: Collection[]) => async (searchPhrase: string): Promise => { - log.debug(() => ["getAutoCompleteSuggestions", { searchPhrase }]); + log.debug(() => [ + "getAutoCompleteSuggestions", + { searchPhrase, collections }, + ]); try { const searchPhrase2 = searchPhrase.trim().toLowerCase(); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition @@ -180,7 +183,6 @@ export const getAutoCompleteSuggestions = // - getLocationSuggestion(searchPhrase), // - getFileTypeSuggestion(searchPhrase), ...(await createSearchQuery(searchPhrase)), - ...getCollectionSuggestion(searchPhrase2, collections), getFileNameSuggestion(searchPhrase2, files), getFileCaptionSuggestion(searchPhrase2, files), // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition @@ -219,22 +221,6 @@ async function convertSuggestionsToOptions( return previewImageAppendedOptions; } -function getCollectionSuggestion( - searchPhrase: string, - collections: Collection[], -): Suggestion[] { - const collectionResults = searchCollection(searchPhrase, collections); - - return collectionResults.map( - (searchResult) => - ({ - type: SuggestionType.COLLECTION, - value: searchResult.id, - label: searchResult.name, - }) as Suggestion, - ); -} - function getFileNameSuggestion( searchPhrase: string, files: EnteFile[], diff --git a/web/packages/new/photos/services/search/worker.ts b/web/packages/new/photos/services/search/worker.ts index 8b3c57dce9..d45c85bf24 100644 --- a/web/packages/new/photos/services/search/worker.ts +++ b/web/packages/new/photos/services/search/worker.ts @@ -1,5 +1,6 @@ import { HTTPError } from "@/base/http"; import type { Location } from "@/base/types"; +import type { Collection } from "@/media/collection"; import { fileCreationPhotoDate, fileLocation } from "@/media/file-metadata"; import type { EnteFile } from "@/new/photos/types/file"; import { nullToUndefined } from "@/utils/transform"; @@ -73,6 +74,7 @@ export class SearchWorker { createSearchQuery(s: string, localizedSearchData: LocalizedSearchData) { return createSearchQuery( s, + this.searchableData, localizedSearchData, this.locationTags, this.cities, @@ -93,16 +95,27 @@ expose(SearchWorker); const createSearchQuery = ( s: string, + { collections }: SearchableData, { locale, holidays, labelledFileTypes }: LocalizedSearchData, locationTags: Searchable[], cities: Searchable[], ): Suggestion[] => [ + collectionSuggestions(s, collections), dateSuggestions(s, locale, holidays), locationSuggestions(s, locationTags, cities), fileTypeSuggestions(s, labelledFileTypes), ].flat(); +const collectionSuggestions = (s: string, collections: Collection[]) => + collections + .filter(({ name }) => name.toLowerCase().includes(s)) + .map(({ id, name }) => ({ + type: SuggestionType.COLLECTION, + value: id, + label: name, + })); + const dateSuggestions = ( s: string, locale: string, From 2f9bbbc84caf983f7a533ddca53f72f324dd18c6 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 20:06:23 +0530 Subject: [PATCH 13/19] Fix --- web/apps/photos/src/pages/gallery.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx index 64405dd4ff..75a5df7017 100644 --- a/web/apps/photos/src/pages/gallery.tsx +++ b/web/apps/photos/src/pages/gallery.tsx @@ -408,8 +408,11 @@ export default function Gallery() { }, []); useEffect( - // TODO: Try to set things up so that this uniquing is not needed. - () => setSearchableData({ collections, files: getUniqueFiles(files) }), + () => + setSearchableData({ + collections: collections ?? [], + files: getUniqueFiles(files ?? []), + }), [collections, files], ); From 57cf26c01ced04b1017a48a8412b99f125d42eed Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 20:18:23 +0530 Subject: [PATCH 14/19] fn --- .../new/photos/services/search/index.ts | 30 ------------------- .../new/photos/services/search/worker.ts | 23 ++++++++++++-- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/web/packages/new/photos/services/search/index.ts b/web/packages/new/photos/services/search/index.ts index eb84ce3b33..ab491e524d 100644 --- a/web/packages/new/photos/services/search/index.ts +++ b/web/packages/new/photos/services/search/index.ts @@ -183,7 +183,6 @@ export const getAutoCompleteSuggestions = // - getLocationSuggestion(searchPhrase), // - getFileTypeSuggestion(searchPhrase), ...(await createSearchQuery(searchPhrase)), - getFileNameSuggestion(searchPhrase2, files), getFileCaptionSuggestion(searchPhrase2, files), // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition ].filter((suggestion) => !!suggestion); @@ -221,18 +220,6 @@ async function convertSuggestionsToOptions( return previewImageAppendedOptions; } -function getFileNameSuggestion( - searchPhrase: string, - files: EnteFile[], -): Suggestion { - const matchedFiles = searchFilesByName(searchPhrase, files); - return { - type: SuggestionType.FILE_NAME, - value: matchedFiles.map((file) => file.id), - label: searchPhrase, - }; -} - function getFileCaptionSuggestion( searchPhrase: string, files: EnteFile[], @@ -245,23 +232,6 @@ function getFileCaptionSuggestion( }; } -function searchCollection( - searchPhrase: string, - collections: Collection[], -): Collection[] { - return collections.filter((collection) => - collection.name.toLowerCase().includes(searchPhrase), - ); -} - -function searchFilesByName(searchPhrase: string, files: EnteFile[]) { - return files.filter( - (file) => - file.id.toString().includes(searchPhrase) || - file.metadata.title.toLowerCase().includes(searchPhrase), - ); -} - function searchFilesByCaption(searchPhrase: string, files: EnteFile[]) { return files.filter( (file) => diff --git a/web/packages/new/photos/services/search/worker.ts b/web/packages/new/photos/services/search/worker.ts index d45c85bf24..5bd934b1eb 100644 --- a/web/packages/new/photos/services/search/worker.ts +++ b/web/packages/new/photos/services/search/worker.ts @@ -95,15 +95,16 @@ expose(SearchWorker); const createSearchQuery = ( s: string, - { collections }: SearchableData, + { collections, files }: SearchableData, { locale, holidays, labelledFileTypes }: LocalizedSearchData, locationTags: Searchable[], cities: Searchable[], ): Suggestion[] => [ - collectionSuggestions(s, collections), dateSuggestions(s, locale, holidays), locationSuggestions(s, locationTags, cities), + collectionSuggestions(s, collections), + fileNameSuggestions(s, files), fileTypeSuggestions(s, labelledFileTypes), ].flat(); @@ -116,6 +117,24 @@ const collectionSuggestions = (s: string, collections: Collection[]) => label: name, })); +const fileNameSuggestions = (s: string, files: EnteFile[]) => { + // Convert the search string to a number. This allows searching a file by + // its exact (integral) ID. + const sn = Number(s) || undefined; + + const matchingFiles = files.filter( + ({ id, metadata }) => + id === sn || metadata.title.toLowerCase().includes(s), + ); + return matchingFiles.length + ? { + type: SuggestionType.FILE_NAME, + value: matchingFiles.map((f) => f.id), + label: s, + } + : []; +}; + const dateSuggestions = ( s: string, locale: string, From 044e1b687f57856eac9ee875f4cae9aa2ec234a1 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 20:30:39 +0530 Subject: [PATCH 15/19] cap --- .../new/photos/services/search/index.ts | 43 ++----------------- .../new/photos/services/search/worker.ts | 17 +++++++- 2 files changed, 19 insertions(+), 41 deletions(-) diff --git a/web/packages/new/photos/services/search/index.ts b/web/packages/new/photos/services/search/index.ts index ab491e524d..b3b8e8896b 100644 --- a/web/packages/new/photos/services/search/index.ts +++ b/web/packages/new/photos/services/search/index.ts @@ -168,25 +168,11 @@ export const getAutoCompleteSuggestions = async (searchPhrase: string): Promise => { log.debug(() => [ "getAutoCompleteSuggestions", - { searchPhrase, collections }, + { searchPhrase, files, collections }, ]); try { - const searchPhrase2 = searchPhrase.trim().toLowerCase(); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (!searchPhrase2?.length) { - return []; - } - const suggestions: Suggestion[] = [ - // The following functionality has moved to createSearchQuery - // - getClipSuggestion(searchPhrase) - // - getDateSuggestion(searchPhrase), - // - getLocationSuggestion(searchPhrase), - // - getFileTypeSuggestion(searchPhrase), - ...(await createSearchQuery(searchPhrase)), - getFileCaptionSuggestion(searchPhrase2, files), - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - ].filter((suggestion) => !!suggestion); - + const suggestions: Suggestion[] = + await createSearchQuery(searchPhrase); return convertSuggestionsToOptions(suggestions); } catch (e) { log.error("getAutoCompleteSuggestions failed", e); @@ -220,29 +206,6 @@ async function convertSuggestionsToOptions( return previewImageAppendedOptions; } -function getFileCaptionSuggestion( - searchPhrase: string, - files: EnteFile[], -): Suggestion { - const matchedFiles = searchFilesByCaption(searchPhrase, files); - return { - type: SuggestionType.FILE_CAPTION, - value: matchedFiles.map((file) => file.id), - label: searchPhrase, - }; -} - -function searchFilesByCaption(searchPhrase: string, files: EnteFile[]) { - return files.filter( - (file) => - // eslint-disable-next-line @typescript-eslint/prefer-optional-chain - file.pubMagicMetadata && - file.pubMagicMetadata.data.caption - ?.toLowerCase() - .includes(searchPhrase), - ); -} - function convertSuggestionToSearchQuery(option: Suggestion): SearchQuery { switch (option.type) { case SuggestionType.DATE: diff --git a/web/packages/new/photos/services/search/worker.ts b/web/packages/new/photos/services/search/worker.ts index 5bd934b1eb..6bddf8be4a 100644 --- a/web/packages/new/photos/services/search/worker.ts +++ b/web/packages/new/photos/services/search/worker.ts @@ -101,11 +101,12 @@ const createSearchQuery = ( cities: Searchable[], ): Suggestion[] => [ + fileTypeSuggestions(s, labelledFileTypes), dateSuggestions(s, locale, holidays), locationSuggestions(s, locationTags, cities), collectionSuggestions(s, collections), fileNameSuggestions(s, files), - fileTypeSuggestions(s, labelledFileTypes), + fileCaptionSuggestions(s, files), ].flat(); const collectionSuggestions = (s: string, collections: Collection[]) => @@ -135,6 +136,20 @@ const fileNameSuggestions = (s: string, files: EnteFile[]) => { : []; }; +const fileCaptionSuggestions = (s: string, files: EnteFile[]) => { + const matchingFiles = files.filter((file) => + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + file.pubMagicMetadata?.data?.caption?.toLowerCase().includes(s), + ); + return matchingFiles.length + ? { + type: SuggestionType.FILE_CAPTION, + value: matchingFiles.map((f) => f.id), + label: s, + } + : []; +}; + const dateSuggestions = ( s: string, locale: string, From 1317791fed1fee9f97daf526ff8f03a697d87619 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 20:53:00 +0530 Subject: [PATCH 16/19] Ontology --- web/apps/photos/src/pages/gallery.tsx | 7 ++- .../new/photos/services/search/index.ts | 23 ++++---- .../new/photos/services/search/worker.ts | 53 ++++++++++--------- 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx index 75a5df7017..9f44530ffa 100644 --- a/web/apps/photos/src/pages/gallery.tsx +++ b/web/apps/photos/src/pages/gallery.tsx @@ -11,7 +11,10 @@ import { getLocalTrashedFiles, } from "@/new/photos/services/files"; import { wipHasSwitchedOnceCmpAndSet } from "@/new/photos/services/ml"; -import { search, setSearchableData } from "@/new/photos/services/search"; +import { + filterSearchableFiles, + setSearchableData, +} from "@/new/photos/services/search"; import { SearchQuery, SearchResultSummary, @@ -533,7 +536,7 @@ export default function Gallery() { let filteredFiles: EnteFile[] = []; if (isInSearchMode) { - filteredFiles = await search(searchQuery); + filteredFiles = await filterSearchableFiles(searchQuery); } else { filteredFiles = getUniqueFiles( (isInHiddenSection ? hiddenFiles : files).filter((item) => { diff --git a/web/packages/new/photos/services/search/index.ts b/web/packages/new/photos/services/search/index.ts index b3b8e8896b..4614bfb06d 100644 --- a/web/packages/new/photos/services/search/index.ts +++ b/web/packages/new/photos/services/search/index.ts @@ -19,6 +19,7 @@ import type { SearchOption, SearchPerson, SearchQuery, + SearchSuggestion, Suggestion, } from "./types"; import { SuggestionType } from "./types"; @@ -68,12 +69,12 @@ export const setSearchableData = (data: SearchableData) => void worker().then((w) => w.setSearchableData(data)); /** - * Convert a search string into a reusable "search query" that can be passed on - * to the {@link search} function. + * Convert a search string into a suggestions that can be shown in the search + * results, and can also be used filter the searchable files. * * @param searchString The string we want to search for. */ -export const createSearchQuery = async (searchString: string) => { +export const suggestionsForString = async (searchString: string) => { // Normalize it by trimming whitespace and converting to lowercase. const s = searchString.trim().toLowerCase(); if (s.length == 0) return []; @@ -83,7 +84,9 @@ export const createSearchQuery = async (searchString: string) => { // the search worker, then combine the two. const results = await Promise.all([ clipSuggestions(s, searchString).then((s) => s ?? []), - worker().then((w) => w.createSearchQuery(s, localizedSearchData())), + worker().then((w) => + w.suggestionsForString(s, searchString, localizedSearchData()), + ), ]); return results.flat(); }; @@ -102,11 +105,11 @@ const clipSuggestions = async (s: string, searchString: string) => { }; /** - * Search for and return the list of {@link EnteFile}s that match the given - * {@link search} query. + * Return the list of {@link EnteFile}s (from amongst the previously set + * {@link SearchableData}) that match the given search {@link suggestion}. */ -export const search = async (search: SearchQuery) => - worker().then((w) => w.search(search)); +export const filterSearchableFiles = async (suggestion: SearchSuggestion) => + worker().then((w) => w.filterSearchableFiles(suggestion)); /** * Cached value of {@link localizedSearchData}. @@ -172,7 +175,7 @@ export const getAutoCompleteSuggestions = ]); try { const suggestions: Suggestion[] = - await createSearchQuery(searchPhrase); + await suggestionsForString(searchPhrase); return convertSuggestionsToOptions(suggestions); } catch (e) { log.error("getAutoCompleteSuggestions failed", e); @@ -186,7 +189,7 @@ async function convertSuggestionsToOptions( const previewImageAppendedOptions: SearchOption[] = []; for (const suggestion of suggestions) { const searchQuery = convertSuggestionToSearchQuery(suggestion); - const resultFiles = await search(searchQuery); + const resultFiles = await filterSearchableFiles(searchQuery); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (searchQuery?.clip) { resultFiles.sort((a, b) => { diff --git a/web/packages/new/photos/services/search/worker.ts b/web/packages/new/photos/services/search/worker.ts index 6bddf8be4a..0cd349dc9e 100644 --- a/web/packages/new/photos/services/search/worker.ts +++ b/web/packages/new/photos/services/search/worker.ts @@ -23,6 +23,7 @@ import type { SearchableData, SearchDateComponents, SearchQuery, + SearchSuggestion, Suggestion, } from "./types"; import { SuggestionType } from "./types"; @@ -69,11 +70,16 @@ export class SearchWorker { } /** - * Convert a search string into a reusable query. + * Convert a search string into a list of {@link SearchSuggestion}s. */ - createSearchQuery(s: string, localizedSearchData: LocalizedSearchData) { - return createSearchQuery( + suggestionsForString( + s: string, + searchString: string, + localizedSearchData: LocalizedSearchData, + ) { + return suggestionsForString( s, + searchString, this.searchableData, localizedSearchData, this.locationTags, @@ -82,19 +88,24 @@ export class SearchWorker { } /** - * Return {@link EnteFile}s that satisfy the given {@link searchQuery}. + * Return {@link EnteFile}s that satisfy the given {@link suggestion}. */ - search(searchQuery: SearchQuery) { + filterSearchableFiles(suggestion: SearchSuggestion) { return this.searchableData.files.filter((f) => - isMatchingFile(f, searchQuery), + isMatchingFile(f, suggestion), ); } } expose(SearchWorker); -const createSearchQuery = ( +/** + * @param s The normalized form of {@link searchString}. + * @param searchString The original search string. + */ +const suggestionsForString = ( s: string, + searchString: string, { collections, files }: SearchableData, { locale, holidays, labelledFileTypes }: LocalizedSearchData, locationTags: Searchable[], @@ -105,8 +116,8 @@ const createSearchQuery = ( dateSuggestions(s, locale, holidays), locationSuggestions(s, locationTags, cities), collectionSuggestions(s, collections), - fileNameSuggestions(s, files), - fileCaptionSuggestions(s, files), + suggestionForFiles(fileNameMatches(s, files), searchString), + suggestionForFiles(fileCaptionMatches(s, files), searchString), ].flat(); const collectionSuggestions = (s: string, collections: Collection[]) => @@ -118,37 +129,31 @@ const collectionSuggestions = (s: string, collections: Collection[]) => label: name, })); -const fileNameSuggestions = (s: string, files: EnteFile[]) => { +const fileNameMatches = (s: string, files: EnteFile[]) => { // Convert the search string to a number. This allows searching a file by // its exact (integral) ID. const sn = Number(s) || undefined; - const matchingFiles = files.filter( + return files.filter( ({ id, metadata }) => id === sn || metadata.title.toLowerCase().includes(s), ); - return matchingFiles.length +}; + +const suggestionForFiles = (matchingFiles: EnteFile[], searchString: string) => + matchingFiles.length ? { type: SuggestionType.FILE_NAME, value: matchingFiles.map((f) => f.id), - label: s, + label: searchString, } : []; -}; -const fileCaptionSuggestions = (s: string, files: EnteFile[]) => { - const matchingFiles = files.filter((file) => +const fileCaptionMatches = (s: string, files: EnteFile[]) => + files.filter((file) => // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition file.pubMagicMetadata?.data?.caption?.toLowerCase().includes(s), ); - return matchingFiles.length - ? { - type: SuggestionType.FILE_CAPTION, - value: matchingFiles.map((f) => f.id), - label: s, - } - : []; -}; const dateSuggestions = ( s: string, From e0db18819578e4f84f4bc8bd1d6cdb5e07ff90ec Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 20:56:17 +0530 Subject: [PATCH 17/19] Temporary backtrack --- web/packages/new/photos/services/search/index.ts | 3 +-- web/packages/new/photos/services/search/types.ts | 1 + web/packages/new/photos/services/search/worker.ts | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/web/packages/new/photos/services/search/index.ts b/web/packages/new/photos/services/search/index.ts index 4614bfb06d..25e8b6c1d7 100644 --- a/web/packages/new/photos/services/search/index.ts +++ b/web/packages/new/photos/services/search/index.ts @@ -19,7 +19,6 @@ import type { SearchOption, SearchPerson, SearchQuery, - SearchSuggestion, Suggestion, } from "./types"; import { SuggestionType } from "./types"; @@ -108,7 +107,7 @@ const clipSuggestions = async (s: string, searchString: string) => { * Return the list of {@link EnteFile}s (from amongst the previously set * {@link SearchableData}) that match the given search {@link suggestion}. */ -export const filterSearchableFiles = async (suggestion: SearchSuggestion) => +export const filterSearchableFiles = async (suggestion: SearchQuery) => worker().then((w) => w.filterSearchableFiles(suggestion)); /** diff --git a/web/packages/new/photos/services/search/types.ts b/web/packages/new/photos/services/search/types.ts index 2ef199d736..7c91facf04 100644 --- a/web/packages/new/photos/services/search/types.ts +++ b/web/packages/new/photos/services/search/types.ts @@ -134,6 +134,7 @@ export interface Suggestion { } export interface SearchQuery { + suggestion?: SearchSuggestion; date?: SearchDateComponents; location?: LocationTag; city?: City; diff --git a/web/packages/new/photos/services/search/worker.ts b/web/packages/new/photos/services/search/worker.ts index 0cd349dc9e..aa31c7f16c 100644 --- a/web/packages/new/photos/services/search/worker.ts +++ b/web/packages/new/photos/services/search/worker.ts @@ -23,7 +23,6 @@ import type { SearchableData, SearchDateComponents, SearchQuery, - SearchSuggestion, Suggestion, } from "./types"; import { SuggestionType } from "./types"; @@ -90,7 +89,7 @@ export class SearchWorker { /** * Return {@link EnteFile}s that satisfy the given {@link suggestion}. */ - filterSearchableFiles(suggestion: SearchSuggestion) { + filterSearchableFiles(suggestion: SearchQuery) { return this.searchableData.files.filter((f) => isMatchingFile(f, suggestion), ); From c2ea68c39cabda5063d8db76c37ce22d2d07bf09 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 20:58:23 +0530 Subject: [PATCH 18/19] Prune --- web/apps/photos/src/components/SearchBar.tsx | 12 ++---------- web/apps/photos/src/pages/gallery.tsx | 8 -------- web/packages/new/photos/services/search/index.ts | 9 ++------- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/web/apps/photos/src/components/SearchBar.tsx b/web/apps/photos/src/components/SearchBar.tsx index 8d5fb0f063..e2649f661b 100644 --- a/web/apps/photos/src/components/SearchBar.tsx +++ b/web/apps/photos/src/components/SearchBar.tsx @@ -1,6 +1,5 @@ import { assertionFailed } from "@/base/assert"; import { useIsMobileWidth } from "@/base/hooks"; -import type { Collection } from "@/media/collection"; import { FileType } from "@/media/file-type"; import { isMLSupported, @@ -22,7 +21,6 @@ import { } from "@/new/photos/services/search/types"; import { labelForSuggestionType } from "@/new/photos/services/search/ui"; import type { LocationTag } from "@/new/photos/services/user-entity"; -import { EnteFile } from "@/new/photos/types/file"; import { FreeFlowText, SpaceBetweenFlex, @@ -76,8 +74,6 @@ interface SearchBarProps { /** Enter or exit search mode. */ setIsInSearchMode: (v: boolean) => void; updateSearch: UpdateSearch; - collections: Collection[]; - files: EnteFile[]; } export type UpdateSearch = ( @@ -140,16 +136,12 @@ interface SearchInputProps { isOpen: boolean; setIsOpen: (value: boolean) => void; updateSearch: UpdateSearch; - files: EnteFile[]; - collections: Collection[]; } const SearchInput: React.FC = ({ isOpen, setIsOpen, updateSearch, - files, - collections, }) => { const appContext = useContext(AppContext); @@ -199,8 +191,8 @@ const SearchInput: React.FC = ({ }; const getOptions = useCallback( - pDebounce(getAutoCompleteSuggestions(files, collections), 250), - [files, collections], + pDebounce(getAutoCompleteSuggestions(), 250), + [], ); const search = (selectedOption: SearchOption) => { diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx index 9f44530ffa..6e2dd613bd 100644 --- a/web/apps/photos/src/pages/gallery.tsx +++ b/web/apps/photos/src/pages/gallery.tsx @@ -1099,8 +1099,6 @@ export default function Gallery() { isInSearchMode={isInSearchMode} setIsInSearchMode={setIsInSearchMode} updateSearch={updateSearch} - collections={collections} - files={files} /> )} @@ -1279,8 +1277,6 @@ interface NormalNavbarContentsProps { isInSearchMode: boolean; setIsInSearchMode: (v: boolean) => void; updateSearch: UpdateSearch; - collections: Collection[]; - files: EnteFile[]; } const NormalNavbarContents: React.FC = ({ @@ -1289,8 +1285,6 @@ const NormalNavbarContents: React.FC = ({ isInSearchMode, setIsInSearchMode, updateSearch, - collections, - files, }) => ( <> {!isInSearchMode && } @@ -1298,8 +1292,6 @@ const NormalNavbarContents: React.FC = ({ isInSearchMode={isInSearchMode} setIsInSearchMode={setIsInSearchMode} updateSearch={updateSearch} - collections={collections} - files={files} /> {!isInSearchMode && } diff --git a/web/packages/new/photos/services/search/index.ts b/web/packages/new/photos/services/search/index.ts index 25e8b6c1d7..af0dca4a23 100644 --- a/web/packages/new/photos/services/search/index.ts +++ b/web/packages/new/photos/services/search/index.ts @@ -2,11 +2,9 @@ import { isDesktop } from "@/base/app"; import log from "@/base/log"; import { masterKeyFromSession } from "@/base/session-store"; import { ComlinkWorker } from "@/base/worker/comlink-worker"; -import type { Collection } from "@/media/collection"; import { FileType } from "@/media/file-type"; import type { LocationTag } from "@/new/photos/services/user-entity"; import i18n, { t } from "i18next"; -import type { EnteFile } from "../../types/file"; import { clipMatches, isMLEnabled } from "../ml"; import type { City, @@ -166,12 +164,9 @@ const labelledFileTypes = (): LabelledFileType[] => [ // Suggestions shown in the search dropdown when the user has typed something. export const getAutoCompleteSuggestions = - (files: EnteFile[], collections: Collection[]) => + () => async (searchPhrase: string): Promise => { - log.debug(() => [ - "getAutoCompleteSuggestions", - { searchPhrase, files, collections }, - ]); + log.debug(() => ["getAutoCompleteSuggestions"]); try { const suggestions: Suggestion[] = await suggestionsForString(searchPhrase); From 1fd9ea7a274c0595129a5818baac3809a04800f5 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 11 Sep 2024 21:17:45 +0530 Subject: [PATCH 19/19] Prune and doc --- web/apps/photos/src/components/SearchBar.tsx | 66 +++++++++----------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/web/apps/photos/src/components/SearchBar.tsx b/web/apps/photos/src/components/SearchBar.tsx index e2649f661b..37149b00a2 100644 --- a/web/apps/photos/src/components/SearchBar.tsx +++ b/web/apps/photos/src/components/SearchBar.tsx @@ -45,10 +45,8 @@ import CollectionCard from "components/Collections/CollectionCard"; import { ResultPreviewTile } from "components/Collections/styledComponents"; import { t } from "i18next"; import pDebounce from "p-debounce"; -import { AppContext } from "pages/_app"; import { useCallback, - useContext, useEffect, useMemo, useRef, @@ -67,11 +65,24 @@ import AsyncSelect from "react-select/async"; interface SearchBarProps { /** - * `true` if the search bar is being shown when the gallery is already in - * "search mode". + * [Note: "Search mode"] + * + * On mobile sized screens, normally the search input areas is not + * displayed. Clicking the search icon enters the "search mode", where we + * show the search input area. + * + * On other screens, the search input is always shown even if we are not in + * search mode. + * + * When we're in search mode, + * + * 1. Other icons from the navbar are hidden + * 2. Next to the search input there is a cancel button to exit search mode. */ isInSearchMode: boolean; - /** Enter or exit search mode. */ + /** + * Enter or exit "search mode". + */ setIsInSearchMode: (v: boolean) => void; updateSearch: UpdateSearch; } @@ -83,17 +94,18 @@ export type UpdateSearch = ( /** * The search bar is a styled "select" element that allow the user to type in - * the attached input field, and shows a list of matching options in a dropdown. + * the attached input field, and shows a list of matching suggestions in a + * dropdown. * * When the search input is empty, it shows some general information in the * dropdown instead (e.g. the ML indexing status). * - * When the search input is not empty, it shows various {@link SearchOption}s, - * each of which is a possible suggestion for a search that the user might've - * intended. Each suggestion shows a count of matching files, and some previews. + * When the search input is not empty, it shows these {@link SearchSuggestion}s. + * Alongside each suggestion is shows a count of matching files, and some + * previews. * - * Selecting one of the these options causes the gallery to enter a "search - * mode", where it shows a filtered list of files that match that option. + * Selecting one of the these suggestions causes the gallery to shows a filtered + * list of files that match that suggestion. */ export const SearchBar: React.FC = ({ setIsInSearchMode, @@ -109,11 +121,7 @@ export const SearchBar: React.FC = ({ {isMobileWidth && !isInSearchMode ? ( ) : ( - + )} ); @@ -133,18 +141,14 @@ const MobileSearchArea: React.FC = ({ onSearch }) => ( ); interface SearchInputProps { - isOpen: boolean; - setIsOpen: (value: boolean) => void; + isInSearchMode: boolean; updateSearch: UpdateSearch; } const SearchInput: React.FC = ({ - isOpen, - setIsOpen, + isInSearchMode, updateSearch, }) => { - const appContext = useContext(AppContext); - // A ref to the top level Select. const selectRef = useRef(null); // The currently selected option. @@ -178,16 +182,9 @@ const SearchInput: React.FC = ({ }; const resetSearch = () => { - if (isOpen) { - appContext.startLoading(); - updateSearch(null, null); - setTimeout(() => { - appContext.finishLoading(); - }, 10); - setIsOpen(false); - setValue(null); - setInputValue(""); - } + updateSearch(null, null); + setValue(null); + setInputValue(""); }; const getOptions = useCallback( @@ -205,19 +202,16 @@ const SearchInput: React.FC = ({ search = { date: selectedOption.value as SearchDateComponents, }; - setIsOpen(true); break; case SuggestionType.LOCATION: search = { location: selectedOption.value as LocationTag, }; - setIsOpen(true); break; case SuggestionType.CITY: search = { city: selectedOption.value as City, }; - setIsOpen(true); break; case SuggestionType.COLLECTION: search = { collection: selectedOption.value as number }; @@ -275,7 +269,7 @@ const SearchInput: React.FC = ({ } /> - {isOpen && ( + {isInSearchMode && ( resetSearch()} sx={{ ml: 1 }}>