diff --git a/src/main/webapp/ui/src/eln/gallery/__tests__/useGalleryActions.test.js b/src/main/webapp/ui/src/eln/gallery/__tests__/useGalleryActions.test.js index 0f2742a55..d42367f49 100644 --- a/src/main/webapp/ui/src/eln/gallery/__tests__/useGalleryActions.test.js +++ b/src/main/webapp/ui/src/eln/gallery/__tests__/useGalleryActions.test.js @@ -42,7 +42,6 @@ describe("useGalleryActions", () => { version: 1, size: 1024, path: [], - setPath: () => {}, thumbnailId: null, gallerySection: "Images", token: "", @@ -131,7 +130,6 @@ describe("useGalleryActions", () => { version: 1, size: 1024, path: [], - setPath: () => {}, thumbnailId: null, gallerySection: "Images", token: "", @@ -222,7 +220,6 @@ describe("useGalleryActions", () => { version: 1, size: 1024, path: [], - setPath: () => {}, thumbnailId: null, gallerySection: "Images", token: "", diff --git a/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js b/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js index ee5c48b94..598321e79 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js +++ b/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js @@ -56,6 +56,7 @@ import AlertContext, { mkAlert } from "../../../stores/contexts/Alert"; import CardMedia from "@mui/material/CardMedia"; import { useFolderOpen } from "./OpenFolderProvider"; import { type URL } from "../../../util/types"; +import AnalyticsContext from "../../../stores/contexts/Analytics"; /** * When tapped, the user is presented with their operating system's file @@ -88,6 +89,7 @@ const UploadNewVersionMenuItem = ({ folderId: FetchingData.Fetched, |}) => { const { uploadNewVersion } = useGalleryActions(); + const { trackEvent } = React.useContext(AnalyticsContext); const selection = useGallerySelection(); const newVersionInputRef = React.useRef(null); @@ -175,7 +177,12 @@ const UploadNewVersionMenuItem = ({ .elseThrow(); void uploadNewVersion(idOfFolderThatFileIsIn, file, newFile) - .then(onSuccess) + .then(() => { + onSuccess(); + trackEvent("user:uploads_new_version:file:gallery", { + version: file.version + 1, + }); + }) .catch(onError); }} type="file" @@ -196,6 +203,7 @@ const RenameDialog = ({ file: GalleryFile, |}) => { const [newName, setNewName] = React.useState(""); + const { trackEvent } = React.useContext(AnalyticsContext); const { rename } = useGalleryActions(); return ( { void rename(file, newName).then(() => { onClose(); + trackEvent("user:renames:file:gallery"); }); }} validationResult={ @@ -282,6 +291,7 @@ function ActionsMenu({ const selection = useGallerySelection(); const theme = useTheme(); const { addAlert } = React.useContext(AlertContext); + const { trackEvent } = React.useContext(AnalyticsContext); const canPreviewAsImage = useImagePreviewOfGalleryFile(); const canEditWithCollabora = useCollaboraEdit(); const canEditWithOfficeOnline = useOfficeOnlineEdit(); @@ -313,26 +323,27 @@ function ActionsMenu({ .only.toResult(() => new Error("Too many items selected.")) .flatMap< | {| key: "image", downloadHref: () => Promise |} - | {| key: "document", url: string |} + | {| key: "collabora", url: string |} + | {| key: "officeonline", url: string |} >((file) => { if (file.isImage && typeof file.downloadHref !== "undefined") return Result.Ok({ key: "image", downloadHref: file.downloadHref }); return canEditWithCollabora(file) - .orElseTry(() => canEditWithOfficeOnline(file)) - .map< - Result< + .map((url) => ({ + key: "collabora", + url, + })) + .orElseTry(() => + canEditWithOfficeOnline(file).map< | {| key: "image", downloadHref: () => Promise |} - | {| key: "document", url: string |} - > - >((url) => - Result.Ok({ - key: "document", + | {| key: "collabora", url: string |} + | {| key: "officeonline", url: string |} + >((url) => ({ + key: "officeonline", url, - }) + })) ) - .orElseGet(() => - Result.Error<_>([new Error("Cannot edit this item.")]) - ); + .mapError(() => new Error("Cannot edit this item.")); }) ); @@ -527,7 +538,14 @@ function ActionsMenu({ onClick={() => { editingAllowed.get().do( doNotAwait(async (action) => { - if (action.key === "document") window.open(action.url); + if (action.key === "officeonline") { + window.open(action.url); + trackEvent("user:opens:document:officeonline"); + } + if (action.key === "collabora") { + window.open(action.url); + trackEvent("user:opens:document:collabora"); + } if (action.key === "image") { try { const downloadHref = await action.downloadHref(); @@ -565,6 +583,7 @@ function ActionsMenu({ void duplicateFiles(selection.asSet()).then(() => { void refreshListing(); setActionsMenuAnchorEl(null); + trackEvent("user:duplicates:file:gallery"); }); }} compact @@ -648,6 +667,7 @@ function ActionsMenu({ onClick={() => { void download(selection.asSet()).then(() => { setActionsMenuAnchorEl(null); + trackEvent("user:downloads:file:gallery"); }); }} compact @@ -664,6 +684,9 @@ function ActionsMenu({ avatar={} onClick={() => { setExportOpen(true); + trackEvent("user:opens:export_dialog:gallery", { + count: selection.size, + }); }} compact disabled={exportAllowed.get().isError} @@ -770,6 +793,7 @@ function ActionsMenu({ .elseThrow(); await uploadFiles(idOfFolderThatFileIsIn, [newFile]); void refreshListing(); + trackEvent("user:edit:image:gallery"); } catch (e) { addAlert( mkAlert({ diff --git a/src/main/webapp/ui/src/eln/gallery/components/AppBar.js b/src/main/webapp/ui/src/eln/gallery/components/AppBar.js index 53c4f3dce..2f4c81aa1 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/AppBar.js +++ b/src/main/webapp/ui/src/eln/gallery/components/AppBar.js @@ -12,6 +12,8 @@ import AccessibilityTips from "../../../components/AccessibilityTips"; import HelpDocs from "../../../components/Help/HelpDocs"; import HelpIcon from "@mui/icons-material/Help"; import { observer } from "mobx-react-lite"; +import AnalyticsContext from "../../../stores/contexts/Analytics"; +import useViewportDimensions from "../../../util/useViewportDimensions"; type GalleryAppBarArgs = {| setDrawerOpen: (boolean) => void, @@ -24,6 +26,8 @@ function GalleryAppBar({ drawerOpen, sidebarId, }: GalleryAppBarArgs): Node { + const { trackEvent } = React.useContext(AnalyticsContext); + const { isViewportSmall } = useViewportDimensions(); return ( @@ -33,6 +37,10 @@ function GalleryAppBar({ aria-expanded={drawerOpen ? "true" : "false"} onClick={() => { setDrawerOpen(!drawerOpen); + if (!isViewportSmall) + trackEvent(`user:toggle:sidebar:gallery`, { + open: !drawerOpen, + }); }} > diff --git a/src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js b/src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js index fbdf23fa8..b9f13ae44 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js +++ b/src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js @@ -33,6 +33,7 @@ import { usePdfPreview } from "./CallablePdfPreview"; import { useAsposePreview } from "./CallableAsposePreview"; import { Optional } from "../../../util/optional"; import { useFolderOpen } from "./OpenFolderProvider"; +import AnalyticsContext from "../../../stores/contexts/Analytics"; /** * The height, in pixels, of the region that responds to touch/pointer events @@ -179,14 +180,17 @@ const Puller: ComponentType<{| const NameFieldForLargeViewports = styled( observer( ({ file, className }: {| file: GalleryFile, className: string |}) => { + const { trackEvent } = React.useContext(AnalyticsContext); const { rename } = useGalleryActions(); const [name, setName] = React.useState(file.name); const textField = React.useRef(null); function handleSubmit() { - void rename(file, name); - textField.current?.blur(); - setName(file.transformFilename(() => name)); + void rename(file, name).then(() => { + textField.current?.blur(); + setName(file.transformFilename(() => name)); + trackEvent("user:renames:file:gallery"); + }); } return ( @@ -678,6 +682,7 @@ export const InfoPanelForLargeViewports: ComponentType<{||}> = () => { const { openPdfPreview } = usePdfPreview(); const primaryAction = usePrimaryAction(); const { openFolder } = useFolderOpen(); + const { trackEvent } = React.useContext(AnalyticsContext); return ( <> @@ -771,6 +776,7 @@ export const InfoPanelForLargeViewports: ComponentType<{||}> = () => { { window.open(action.url); + trackEvent("user:opens:document:collabora"); }} label="Edit" sx={{ @@ -787,6 +793,7 @@ export const InfoPanelForLargeViewports: ComponentType<{||}> = () => { { window.open(action.url); + trackEvent("user:opens:document:officeonline"); }} label="Edit" sx={{ @@ -880,6 +887,7 @@ export const InfoPanelForSmallViewports: ComponentType<{| const selection = useGallerySelection(); const mobileInfoPanelId = React.useId(); const { openFolder } = useFolderOpen(); + const { trackEvent } = React.useContext(AnalyticsContext); return ( { setMobileInfoPanelOpen(true); + trackEvent("user:opens:mobileInfoPanel:gallery"); }} swipeAreaWidth={CLOSED_MOBILE_INFO_PANEL_HEIGHT} disableSwipeToOpen={false} diff --git a/src/main/webapp/ui/src/eln/gallery/components/LinkedDocumentsPanel.js b/src/main/webapp/ui/src/eln/gallery/components/LinkedDocumentsPanel.js index 5449e8333..aeb58c49a 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/LinkedDocumentsPanel.js +++ b/src/main/webapp/ui/src/eln/gallery/components/LinkedDocumentsPanel.js @@ -8,6 +8,7 @@ import useLinkedDocuments, { type Document } from "../useLinkedDocuments"; import { DataGrid, useGridApiRef } from "@mui/x-data-grid"; import { DataGridColumn } from "../../../util/table"; import GlobalId from "../../../components/GlobalId"; +import AnalyticsContext from "../../../stores/contexts/Analytics"; /** * This table lists all of the ELN documents that reference the passed @@ -25,6 +26,7 @@ export const LinkedDocumentsPanel: ComponentType<{| file: GalleryFile |}> = ({ }): Node => { const apiRef = useGridApiRef(); const linkedDocuments = useLinkedDocuments(file); + const { trackEvent } = React.useContext(AnalyticsContext); React.useEffect(() => { setTimeout(() => { @@ -60,7 +62,14 @@ export const LinkedDocumentsPanel: ComponentType<{| file: GalleryFile |}> = ({ flex: 0, resizable: true, sortable: false, - renderCell: ({ row }) => , + renderCell: ({ row }) => ( + { + trackEvent("user:click:globalId:galleryLinkedDocuments"); + }} + /> + ), }), ]} rows={linkedDocuments.documents} diff --git a/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js b/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js index 074f75516..3f480d642 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js +++ b/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js @@ -90,6 +90,7 @@ import InputAdornment from "@mui/material/InputAdornment"; import IconButtonWithTooltip from "../../../components/IconButtonWithTooltip"; import CloseIcon from "@mui/icons-material/Close"; import SearchIcon from "@mui/icons-material/Search"; +import AnalyticsContext from "../../../stores/contexts/Analytics"; function useIsBeingMoved(): ( file: GalleryFile, @@ -268,6 +269,7 @@ const BreadcrumbLink = React.forwardRef< const dndContext = useDndContext(); const dndInProgress = Boolean(dndContext.active); const { openFolder } = useFolderOpen(); + const { trackEvent } = React.useContext(AnalyticsContext); return ( { e.preventDefault(); e.stopPropagation(); + trackEvent("user:tapped:breadcrumb:gallery"); if (folder) { openFolder(folder); } else { @@ -407,10 +410,13 @@ const FileCard = styled( const dndContext = useDndContext(); const dndInProgress = Boolean(dndContext.active); + const { trackEvent } = React.useContext(AnalyticsContext); const { onDragEnter, onDragOver, onDragLeave, onDrop, over } = useFileImportDropZone({ onDrop: (files) => { - void uploadFiles(file.id, files); + void uploadFiles(file.id, files).then(() => { + trackEvent("user:drag_uploads:file:into_folder"); + }); /* * No need to refresh the listing as the uploaded file has been * placed inside a folder into which the user cannot currently see @@ -1281,6 +1287,7 @@ function GalleryMainPanel({ const viewportDimensions = useViewportDimensions(); const filestoresEnabled = useDeploymentProperty("netfilestores.enabled"); const { uploadFiles } = useGalleryActions(); + const { trackEvent } = React.useContext(AnalyticsContext); const { onDragEnter, onDragOver, onDragLeave, onDrop, over } = useFileImportDropZone({ onDrop: doNotAwait(async (files) => { @@ -1289,10 +1296,17 @@ function GalleryMainPanel({ }); await uploadFiles(fId, files); void refreshListing(); + if (path.length > 0) { + trackEvent("user:drag_uploads:file:into_current_folder"); + } else { + trackEvent("user:drag_uploads:file:section_root", { + section: selectedSection, + }); + } }), }); const [viewMenuAnchorEl, setViewMenuAnchorEl] = React.useState(null); - const [viewMode, setViewMode] = useUiPreference( + const [viewMode, _setViewMode] = useUiPreference( PREFERENCES.GALLERY_VIEW_MODE, { defaultValue: "grid", @@ -1322,6 +1336,14 @@ function GalleryMainPanel({ }); const keyboardSensor = useSensor(KeyboardSensor, {}); + const setViewMode = (newViewMode: "grid" | "tree" | "carousel") => { + _setViewMode(newViewMode); + setViewMenuAnchorEl(null); + trackEvent("user:change:view:gallery", { + view: newViewMode, + }); + }; + return FetchingData.match(filestoresEnabled, { loading: () => null, error: () => ( @@ -1391,6 +1413,9 @@ function GalleryMainPanel({ filesBeingMoved ).then(() => { void refreshListing(); + trackEvent("user:drags:file:gallery", { + count: filesBeingMoved.size, + }); }); }} > @@ -1452,7 +1477,6 @@ function GalleryMainPanel({ avatar={} onClick={() => { setViewMode("grid"); - setViewMenuAnchorEl(null); selection.clear(); }} /> @@ -1464,7 +1488,6 @@ function GalleryMainPanel({ avatar={} onClick={() => { setViewMode("tree"); - setViewMenuAnchorEl(null); selection.clear(); }} /> @@ -1476,7 +1499,6 @@ function GalleryMainPanel({ avatar={} onClick={() => { setViewMode("carousel"); - setViewMenuAnchorEl(null); /* * We don't clear the selection because we want * carousel view to default to the selected file, @@ -1536,16 +1558,15 @@ function GalleryMainPanel({ ])()} onClick={() => { setSortMenuAnchorEl(null); - if (orderBy === "name") { - if (sortOrder === "ASC") { - setSortOrder("DESC"); - } else { - setSortOrder("ASC"); - } - } else { - setOrderBy("name"); - setSortOrder("ASC"); - } + let newSortOrder = "ASC"; + if (orderBy === "name" && sortOrder === "ASC") + newSortOrder = "DESC"; + setSortOrder(newSortOrder); + setOrderBy("name"); + trackEvent("user:change:sorting:gallery", { + sortOrder: newSortOrder, + orderBy: "name", + }); }} /> { setSortMenuAnchorEl(null); - if (orderBy === "modificationDate") { - if (sortOrder === "ASC") { - setSortOrder("DESC"); - } else { - setSortOrder("ASC"); - } - } else { - setOrderBy("modificationDate"); - setSortOrder("ASC"); - } + let newSortOrder = "ASC"; + if ( + orderBy === "modificationDate" && + sortOrder === "ASC" + ) + newSortOrder = "DESC"; + setSortOrder(newSortOrder); + setOrderBy("modificationDate"); + trackEvent("user:change:sorting:gallery", { + sortOrder: newSortOrder, + orderBy: "modificationDate", + }); }} /> diff --git a/src/main/webapp/ui/src/eln/gallery/components/MoveDialog.js b/src/main/webapp/ui/src/eln/gallery/components/MoveDialog.js index 219806e07..b1c320219 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/MoveDialog.js +++ b/src/main/webapp/ui/src/eln/gallery/components/MoveDialog.js @@ -27,6 +27,7 @@ import { type GallerySection } from "../common"; import { observer } from "mobx-react-lite"; import PlaceholderLabel from "./PlaceholderLabel"; import { doNotAwait } from "../../../util/Util"; +import AnalyticsContext from "../../../stores/contexts/Analytics"; type MoveDialogArgs = {| open: boolean, @@ -51,6 +52,7 @@ const MoveDialog = observer( refreshListing, }: MoveDialogArgs): Node => { const { isViewportVerySmall } = useViewportDimensions(); + const { trackEvent } = React.useContext(AnalyticsContext); const { galleryListing, refreshListing: refreshListingInsideDialog } = useGalleryListing({ @@ -140,6 +142,9 @@ const MoveDialog = observer( await moveFiles(section, rootDestination(), selectedFiles); void refreshListing(); onClose(); + trackEvent("user:moved:files:gallery", { + count: selectedFiles.size, + }); } finally { setTopLevelLoading(false); } @@ -177,6 +182,9 @@ const MoveDialog = observer( ); void refreshListing(); onClose(); + trackEvent("user:moved:files:gallery", { + count: selectedFiles.size, + }); } finally { setSubmitLoading(false); } diff --git a/src/main/webapp/ui/src/eln/gallery/components/MoveToIrods.js b/src/main/webapp/ui/src/eln/gallery/components/MoveToIrods.js index 316610e55..ec27d128e 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/MoveToIrods.js +++ b/src/main/webapp/ui/src/eln/gallery/components/MoveToIrods.js @@ -34,6 +34,7 @@ import ValidatingSubmitButton from "../../../components/ValidatingSubmitButton"; import Result from "../../../util/result"; import AccessibilityTips from "../../../components/AccessibilityTips"; import docLinks from "../../../assets/DocLinks"; +import AnalyticsContext from "../../../stores/contexts/Analytics"; /** * The color scheme to match the iRODS branding. @@ -139,6 +140,7 @@ function MoveCopyDialog({ dialogOpen, setDialogOpen, }: MoveCopyDialogArgs) { + const { trackEvent } = React.useContext(AnalyticsContext); const irods = useIrods(selectedIds); const [locationsAnchorEl, setLocationsAnchorEl] = React.useState(null); const [selectedDestination, setSelectedDestination] = @@ -204,6 +206,7 @@ function MoveCopyDialog({ .then(() => { setDialogOpen(false); setShowUsernamePasswordForm(false); + trackEvent("user:copy:file:irods"); }) .finally(() => { setOperationInProgress(false); @@ -216,6 +219,7 @@ function MoveCopyDialog({ .then(() => { setDialogOpen(false); setShowUsernamePasswordForm(false); + trackEvent("user:move:file:irods"); }) .finally(() => { setOperationInProgress(false); diff --git a/src/main/webapp/ui/src/eln/gallery/components/Sidebar.js b/src/main/webapp/ui/src/eln/gallery/components/Sidebar.js index cffe4038e..f645e0368 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/Sidebar.js +++ b/src/main/webapp/ui/src/eln/gallery/components/Sidebar.js @@ -51,6 +51,7 @@ import useOauthToken from "../../../common/useOauthToken"; import * as Parsers from "../../../util/parsers"; import { useDeploymentProperty } from "../../useDeploymentProperty"; import AddFilestoreDialog from "./AddFilestoreDialog"; +import AnalyticsContext from "../../../stores/contexts/Analytics"; const StyledMenu = styled(Menu)(({ open }) => ({ "& .MuiPaper-root": { @@ -118,6 +119,7 @@ const UploadMenuItem = ({ |}) => { const { uploadFiles } = useGalleryActions(); const inputRef = React.useRef(null); + const { trackEvent } = React.useContext(AnalyticsContext); /* * This is necessary because React does not yet support the new cancel event @@ -160,6 +162,7 @@ const UploadMenuItem = ({ onChange={({ target: { files } }) => { void uploadFiles(fId, [...files]).then(() => { onUploadComplete(); + trackEvent("user:uploaded:file:gallery"); }); }} type="file" @@ -189,6 +192,7 @@ const NewFolderMenuItem = ({ const [name, setName] = React.useState(""); const { createFolder } = useGalleryActions(); const [submitting, setSubmitting] = React.useState(false); + const { trackEvent } = React.useContext(AnalyticsContext); return ( <> @@ -232,6 +236,7 @@ const NewFolderMenuItem = ({ void createFolder(fId, name) .then(() => { onDialogClose(true); + trackEvent("user:created:folder:gallery"); }) .finally(() => { setSubmitting(false); diff --git a/src/main/webapp/ui/src/eln/gallery/components/TreeView.js b/src/main/webapp/ui/src/eln/gallery/components/TreeView.js index bd1fdae35..58bbf9dd8 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/TreeView.js +++ b/src/main/webapp/ui/src/eln/gallery/components/TreeView.js @@ -36,6 +36,7 @@ import { usePdfPreview } from "./CallablePdfPreview"; import { useAsposePreview } from "./CallableAsposePreview"; import usePrimaryAction from "../primaryActionHooks"; import { useFolderOpen } from "./OpenFolderProvider"; +import AnalyticsContext from "../../../stores/contexts/Analytics"; const StyledTreeItem = styled(TreeItem)(({ theme }) => ({ [`.${treeItemClasses.content}`]: { @@ -213,11 +214,13 @@ const CustomTreeItem = observer( refeshing: boolean, |}) => { const { uploadFiles } = useGalleryActions(); + const { trackEvent } = React.useContext(AnalyticsContext); const { onDragEnter, onDragOver, onDragLeave, onDrop, over } = useFileImportDropZone({ onDrop: doNotAwait(async (files) => { await uploadFiles(file.id, files); void refreshListing(); + trackEvent("user:drag_uploads:file:into_folder"); }), disabled: !file.isFolder, }); diff --git a/src/main/webapp/ui/src/eln/gallery/index.js b/src/main/webapp/ui/src/eln/gallery/index.js index cec4a83d4..45ebb346e 100644 --- a/src/main/webapp/ui/src/eln/gallery/index.js +++ b/src/main/webapp/ui/src/eln/gallery/index.js @@ -31,6 +31,7 @@ import { CallableAsposePreview } from "./components/CallableAsposePreview"; import { useSearchParamState } from "../../util/useSearchParamState"; import { FilestoreLoginProvider } from "./components/FilestoreLoginDialog"; import OpenFolderProvider from "./components/OpenFolderProvider"; +import AnalyticsContext from "../../stores/contexts/Analytics"; const WholePage = styled(() => { const [searchParams, setSelectedSection] = useSearchParamState({ @@ -63,6 +64,14 @@ const WholePage = styled(() => { const [drawerOpen, setDrawerOpen] = React.useState(!isViewportSmall); const sidebarId = React.useId(); + const { trackEvent } = React.useContext(AnalyticsContext); + React.useEffect(() => { + trackEvent("user:load:page:gallery", { section: selectedSection }); + /* eslint-disable-next-line react-hooks/exhaustive-deps -- + * - selectedSection may change but we only care about on-mount + */ + }, []); + return ( @@ -83,6 +92,9 @@ const WholePage = styled(() => { setSelectedSection({ mediaType }); setPath([]); setAppliedSearchTerm(""); + trackEvent("user:change:section:gallery", { + section: mediaType, + }); }} drawerOpen={drawerOpen} setDrawerOpen={setDrawerOpen} @@ -112,7 +124,14 @@ const WholePage = styled(() => { setSortOrder={setSortOrder} setOrderBy={setOrderBy} appliedSearchTerm={appliedSearchTerm} - setAppliedSearchTerm={setAppliedSearchTerm} + setAppliedSearchTerm={(newTerm) => { + if (path.length > 0) { + trackEvent("user:search:folder:gallery"); + } else { + trackEvent("user:search:section:gallery"); + } + setAppliedSearchTerm(newTerm); + }} /> diff --git a/src/main/webapp/ui/src/eln/gallery/useGalleryActions.js b/src/main/webapp/ui/src/eln/gallery/useGalleryActions.js index d29f04a5a..7dea38d3f 100644 --- a/src/main/webapp/ui/src/eln/gallery/useGalleryActions.js +++ b/src/main/webapp/ui/src/eln/gallery/useGalleryActions.js @@ -18,6 +18,7 @@ import AlertContext, { mkAlert } from "../../stores/contexts/Alert"; import useOauthToken from "../../common/useOauthToken"; import { partitionAllSettled } from "../../util/Util"; import { type GallerySection } from "./common"; +import AnalyticsContext from "../../stores/contexts/Analytics"; const ONE_MINUTE_IN_MS = 60 * 60 * 1000; @@ -143,6 +144,7 @@ export function useGalleryActions(): {| |} { const { addAlert, removeAlert } = React.useContext(AlertContext); const { getToken } = useOauthToken(); + const { trackEvent } = React.useContext(AnalyticsContext); /* * We create these axios objects because the global axios object is polluted @@ -725,6 +727,8 @@ export function useGalleryActions(): {| }) ); + trackEvent("user:edit:description:gallery"); + setDescription(newDescription); } catch (e) { addAlert( diff --git a/src/main/webapp/ui/src/eln/gallery/useGalleryListing.js b/src/main/webapp/ui/src/eln/gallery/useGalleryListing.js index 76f0e0aad..db59e786f 100644 --- a/src/main/webapp/ui/src/eln/gallery/useGalleryListing.js +++ b/src/main/webapp/ui/src/eln/gallery/useGalleryListing.js @@ -255,7 +255,6 @@ export class LocalGalleryFile implements GalleryFile { +size: number; +version: number; +thumbnailId: number | null; - #open: () => void | void; downloadHref: void | (() => Promise); #cachedDownloadHref: UrlType | void; @@ -277,7 +276,6 @@ export class LocalGalleryFile implements GalleryFile { type, ownerName, path, - setPath, gallerySection, size, version, @@ -294,7 +292,6 @@ export class LocalGalleryFile implements GalleryFile { type: string, ownerName: string, path: $ReadOnlyArray, - setPath: ($ReadOnlyArray) => void, gallerySection: string, size: number, version: number, @@ -319,7 +316,6 @@ export class LocalGalleryFile implements GalleryFile { this.size = size; this.version = version; this.thumbnailId = thumbnailId; - this.#open = () => setPath([...path, this]); this.setName = action((newName) => { this.name = newName; }); @@ -469,7 +465,6 @@ export class Filestore implements GalleryFile { description: Description; +isFolder: boolean; +size: number; - #open: () => void; +path: $ReadOnlyArray; constructor({ @@ -477,7 +472,6 @@ export class Filestore implements GalleryFile { name, filesystemId, filesystemName, - setPath, path, }: {| id: Id, @@ -485,14 +479,12 @@ export class Filestore implements GalleryFile { filesystemId: number, filesystemName: string, path: $ReadOnlyArray, - setPath: ($ReadOnlyArray) => void, |}) { this.id = id; this.name = name; this.description = Description.Missing(); this.isFolder = true; this.size = 0; - this.#open = () => setPath([...path, this]); this.filesystemId = filesystemId; this.filesystemName = filesystemName; this.path = path; @@ -582,7 +574,6 @@ class RemoteFile implements GalleryFile { +isFolder: boolean; +size: number; +modificationDate: Date; - #open: () => void; +path: $ReadOnlyArray; downloadHref: void | (() => Promise); #cachedDownloadHref: UrlType | void; @@ -594,7 +585,6 @@ class RemoteFile implements GalleryFile { fileSize, modificationDate, path, - setPath, remotePath, token, }: {| @@ -604,7 +594,6 @@ class RemoteFile implements GalleryFile { fileSize: number, modificationDate: Date, path: $ReadOnlyArray, - setPath: ($ReadOnlyArray) => void, remotePath: string, token: string, |}) { @@ -615,7 +604,6 @@ class RemoteFile implements GalleryFile { this.size = fileSize; this.modificationDate = modificationDate; this.path = path; - this.#open = () => setPath([...path, this]); if (!this.isFolder) { const filestoreId = path[0].id; this.downloadHref = async () => { @@ -977,7 +965,6 @@ export function useGalleryListing({ size, version, thumbnailId, - setPath, token, }) ); @@ -1072,7 +1059,6 @@ export function useGalleryListing({ filesystemId, filesystemName, path, - setPath, }) ); } catch (e) { @@ -1173,7 +1159,6 @@ export function useGalleryListing({ fileSize, modificationDate, path, - setPath, remotePath, token, })