From 9dfea4647d415b6629967ec67d1c52182b71d57a Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Fri, 24 Jan 2025 12:10:02 +0000 Subject: [PATCH 01/26] Remove unused private property `#open` This should have been removed by commit ea6fbe25, when it replaced the mechanism for opening folders. --- .../gallery/__tests__/useGalleryActions.test.js | 3 --- .../ui/src/eln/gallery/useGalleryListing.js | 15 --------------- 2 files changed, 18 deletions(-) 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/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, }) From 6dd646783737e95c795c4d35ebe78a0957e696ef Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Mon, 27 Jan 2025 15:13:44 +0000 Subject: [PATCH 02/26] Only update name after rename is successful If the rename operation fails then we do not want to update the locally stored name otherwise we end up in a corrupted local state. --- src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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..92239478b 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js +++ b/src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js @@ -184,9 +184,10 @@ const NameFieldForLargeViewports = styled( 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)); + }); } return ( From 1dc5db7f8b4b330e42e5392d205988de62ae15dc Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Tue, 7 Jan 2025 17:08:49 +0000 Subject: [PATCH 03/26] Page load event --- src/main/webapp/ui/src/eln/gallery/index.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/webapp/ui/src/eln/gallery/index.js b/src/main/webapp/ui/src/eln/gallery/index.js index cec4a83d4..655903710 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 ( From a56170714fee7bc0e3e2b2c1f5b6b0c2c77c0e28 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Tue, 7 Jan 2025 17:18:20 +0000 Subject: [PATCH 04/26] Sidebar toggle event --- src/main/webapp/ui/src/eln/gallery/components/AppBar.js | 8 ++++++++ 1 file changed, 8 insertions(+) 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, + }); }} > From 33af57d48054a140776782e6ca689ecf461cf4c6 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Tue, 7 Jan 2025 17:21:10 +0000 Subject: [PATCH 05/26] Section change event --- src/main/webapp/ui/src/eln/gallery/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/webapp/ui/src/eln/gallery/index.js b/src/main/webapp/ui/src/eln/gallery/index.js index 655903710..9abdf1aa9 100644 --- a/src/main/webapp/ui/src/eln/gallery/index.js +++ b/src/main/webapp/ui/src/eln/gallery/index.js @@ -92,6 +92,9 @@ const WholePage = styled(() => { setSelectedSection({ mediaType }); setPath([]); setAppliedSearchTerm(""); + trackEvent("user:change:section:gallery", { + section: mediaType, + }); }} drawerOpen={drawerOpen} setDrawerOpen={setDrawerOpen} From a77137b4f60cc676d9416dbd74cdbd0fa24e7394 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Tue, 7 Jan 2025 17:26:13 +0000 Subject: [PATCH 06/26] Change view event --- .../ui/src/eln/gallery/components/MainPanel.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) 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..9701c504f 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, @@ -1292,7 +1293,7 @@ function GalleryMainPanel({ }), }); const [viewMenuAnchorEl, setViewMenuAnchorEl] = React.useState(null); - const [viewMode, setViewMode] = useUiPreference( + const [viewMode, _setViewMode] = useUiPreference( PREFERENCES.GALLERY_VIEW_MODE, { defaultValue: "grid", @@ -1301,6 +1302,7 @@ function GalleryMainPanel({ const [sortMenuAnchorEl, setSortMenuAnchorEl] = React.useState(null); const { moveFiles } = useGalleryActions(); const selection = useGallerySelection(); + const { trackEvent } = React.useContext(AnalyticsContext); const mouseSensor = useSensor(MouseSensor, { activationConstraint: { @@ -1322,6 +1324,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: () => ( @@ -1452,7 +1462,6 @@ function GalleryMainPanel({ avatar={} onClick={() => { setViewMode("grid"); - setViewMenuAnchorEl(null); selection.clear(); }} /> @@ -1464,7 +1473,6 @@ function GalleryMainPanel({ avatar={} onClick={() => { setViewMode("tree"); - setViewMenuAnchorEl(null); selection.clear(); }} /> @@ -1476,7 +1484,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, From ceb58900982ff275f8d62277f293eb26f6b54e53 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Fri, 10 Jan 2025 17:27:32 +0000 Subject: [PATCH 07/26] Change sort event --- .../src/eln/gallery/components/MainPanel.js | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) 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 9701c504f..38f69a1d3 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js +++ b/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js @@ -1543,16 +1543,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", + }); }} /> From 9979824b10633f7c6976eea18cf7748cb653d8b0 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Fri, 10 Jan 2025 17:31:28 +0000 Subject: [PATCH 08/26] Search --- src/main/webapp/ui/src/eln/gallery/index.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/webapp/ui/src/eln/gallery/index.js b/src/main/webapp/ui/src/eln/gallery/index.js index 9abdf1aa9..45ebb346e 100644 --- a/src/main/webapp/ui/src/eln/gallery/index.js +++ b/src/main/webapp/ui/src/eln/gallery/index.js @@ -124,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); + }} /> From a9e5feac3d70e31d2f4642a0c2ef74a4495320c5 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Fri, 10 Jan 2025 17:36:39 +0000 Subject: [PATCH 09/26] Tapped breadcrumb --- src/main/webapp/ui/src/eln/gallery/components/MainPanel.js | 2 ++ 1 file changed, 2 insertions(+) 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 38f69a1d3..1e1315ad0 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js +++ b/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js @@ -269,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 { From 8956e2601b0337af63c54d8ff571673d7cb57b6a Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Fri, 10 Jan 2025 17:39:39 +0000 Subject: [PATCH 10/26] Created folder --- src/main/webapp/ui/src/eln/gallery/components/Sidebar.js | 3 +++ 1 file changed, 3 insertions(+) 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..c8aeed2d1 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": { @@ -189,6 +190,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 +234,7 @@ const NewFolderMenuItem = ({ void createFolder(fId, name) .then(() => { onDialogClose(true); + trackEvent("user:created:folder:gallery"); }) .finally(() => { setSubmitting(false); From b82dd13611915f8f341a2bc20081dfe79a5fea5a Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Fri, 10 Jan 2025 17:40:49 +0000 Subject: [PATCH 11/26] Uploaded file --- src/main/webapp/ui/src/eln/gallery/components/Sidebar.js | 2 ++ 1 file changed, 2 insertions(+) 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 c8aeed2d1..f645e0368 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/Sidebar.js +++ b/src/main/webapp/ui/src/eln/gallery/components/Sidebar.js @@ -119,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 @@ -161,6 +162,7 @@ const UploadMenuItem = ({ onChange={({ target: { files } }) => { void uploadFiles(fId, [...files]).then(() => { onUploadComplete(); + trackEvent("user:uploaded:file:gallery"); }); }} type="file" From 5c70c5867db15ef2c5b575e9487a8fe146fe60ad Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Tue, 14 Jan 2025 17:29:07 +0000 Subject: [PATCH 12/26] Drag-and-drop files into Gallery --- .../ui/src/eln/gallery/components/MainPanel.js | 14 ++++++++++++-- .../ui/src/eln/gallery/components/TreeView.js | 3 +++ 2 files changed, 15 insertions(+), 2 deletions(-) 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 1e1315ad0..a5aaf894a 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js +++ b/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js @@ -410,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 @@ -1284,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) => { @@ -1292,6 +1296,13 @@ 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); @@ -1304,7 +1315,6 @@ function GalleryMainPanel({ const [sortMenuAnchorEl, setSortMenuAnchorEl] = React.useState(null); const { moveFiles } = useGalleryActions(); const selection = useGallerySelection(); - const { trackEvent } = React.useContext(AnalyticsContext); const mouseSensor = useSensor(MouseSensor, { activationConstraint: { 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, }); From 2be7a0350f464f95e22ace407f9bf61204e13462 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Fri, 17 Jan 2025 10:02:08 +0000 Subject: [PATCH 13/26] mobile info panel opened --- src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js | 3 +++ 1 file changed, 3 insertions(+) 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 92239478b..8ba1533e7 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 @@ -881,6 +882,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} From 6dfaee18123ba83903414a80aabcb01124237eaf Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Fri, 17 Jan 2025 10:12:38 +0000 Subject: [PATCH 14/26] drags files --- src/main/webapp/ui/src/eln/gallery/components/MainPanel.js | 3 +++ 1 file changed, 3 insertions(+) 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 a5aaf894a..3f480d642 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js +++ b/src/main/webapp/ui/src/eln/gallery/components/MainPanel.js @@ -1413,6 +1413,9 @@ function GalleryMainPanel({ filesBeingMoved ).then(() => { void refreshListing(); + trackEvent("user:drags:file:gallery", { + count: filesBeingMoved.size, + }); }); }} > From dd584d2e0c6d395ef49afa5f00f1309b016e8fac Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Tue, 21 Jan 2025 14:32:06 +0000 Subject: [PATCH 15/26] edit description --- src/main/webapp/ui/src/eln/gallery/useGalleryActions.js | 4 ++++ 1 file changed, 4 insertions(+) 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( From 790d0ac8aa3b0d6dae6fcb36872b6ebcc97f2104 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Tue, 21 Jan 2025 14:34:35 +0000 Subject: [PATCH 16/26] linked documents global id tapped --- .../eln/gallery/components/LinkedDocumentsPanel.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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} From 5b25ac7df15fcaf8ddb9b733aaa6c257c316b1db Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Tue, 21 Jan 2025 14:38:02 +0000 Subject: [PATCH 17/26] edit images --- src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js | 3 +++ 1 file changed, 3 insertions(+) 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..083487157 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 @@ -282,6 +283,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(); @@ -770,6 +772,7 @@ function ActionsMenu({ .elseThrow(); await uploadFiles(idOfFolderThatFileIsIn, [newFile]); void refreshListing(); + trackEvent("user:edit:image:gallery"); } catch (e) { addAlert( mkAlert({ From 62e4cb3d68c4ffa396e45b2254f3bb37bf98a39d Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Tue, 21 Jan 2025 17:00:37 +0000 Subject: [PATCH 18/26] edit documents --- src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js | 3 +++ 1 file changed, 3 insertions(+) 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 8ba1533e7..f2ddd5b0e 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js +++ b/src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js @@ -680,6 +680,7 @@ export const InfoPanelForLargeViewports: ComponentType<{||}> = () => { const { openPdfPreview } = usePdfPreview(); const primaryAction = usePrimaryAction(); const { openFolder } = useFolderOpen(); + const { trackEvent } = React.useContext(AnalyticsContext); return ( <> @@ -773,6 +774,7 @@ export const InfoPanelForLargeViewports: ComponentType<{||}> = () => { { window.open(action.url); + trackEvent("user:opens:document:collabora"); }} label="Edit" sx={{ @@ -789,6 +791,7 @@ export const InfoPanelForLargeViewports: ComponentType<{||}> = () => { { window.open(action.url); + trackEvent("user:opens:document:officeonline"); }} label="Edit" sx={{ From 167c6f3a62590d41a350212ba2e1a7cd87af5699 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Tue, 21 Jan 2025 17:35:21 +0000 Subject: [PATCH 19/26] more editing documents --- .../src/eln/gallery/components/ActionsMenu.js | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) 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 083487157..96021f761 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js +++ b/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js @@ -315,26 +315,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.")); }) ); @@ -529,7 +530,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(); From f345cb9c88bf490d3313d67d226ed2743b49c921 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Mon, 27 Jan 2025 14:55:40 +0000 Subject: [PATCH 20/26] duplicate files --- src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js | 1 + 1 file changed, 1 insertion(+) 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 96021f761..51c759c2c 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js +++ b/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js @@ -575,6 +575,7 @@ function ActionsMenu({ void duplicateFiles(selection.asSet()).then(() => { void refreshListing(); setActionsMenuAnchorEl(null); + trackEvent("user:duplicates:file:gallery"); }); }} compact From b94b55722c77742d0a83a626c753c1ae940b4ed1 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Mon, 27 Jan 2025 14:58:50 +0000 Subject: [PATCH 21/26] move files --- .../webapp/ui/src/eln/gallery/components/MoveDialog.js | 8 ++++++++ 1 file changed, 8 insertions(+) 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); } From 9534a14395e21035752967b01c5ee3ac2d80f6ce Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Mon, 27 Jan 2025 15:10:34 +0000 Subject: [PATCH 22/26] rename file --- src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js | 2 ++ src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js | 2 ++ 2 files changed, 4 insertions(+) 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 51c759c2c..3504df651 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js +++ b/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js @@ -197,6 +197,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={ 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 f2ddd5b0e..b9f13ae44 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js +++ b/src/main/webapp/ui/src/eln/gallery/components/InfoPanel.js @@ -180,6 +180,7 @@ 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); @@ -188,6 +189,7 @@ const NameFieldForLargeViewports = styled( void rename(file, name).then(() => { textField.current?.blur(); setName(file.transformFilename(() => name)); + trackEvent("user:renames:file:gallery"); }); } From 419600d778b102e456247f987dadcb631954e2f0 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Mon, 27 Jan 2025 15:17:59 +0000 Subject: [PATCH 23/26] upload new version --- .../webapp/ui/src/eln/gallery/components/ActionsMenu.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 3504df651..ee79d8f96 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js +++ b/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js @@ -89,6 +89,7 @@ const UploadNewVersionMenuItem = ({ folderId: FetchingData.Fetched, |}) => { const { uploadNewVersion } = useGalleryActions(); + const { trackEvent } = React.useContext(AnalyticsContext); const selection = useGallerySelection(); const newVersionInputRef = React.useRef(null); @@ -176,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" From 5ce1bb8dd1a80ffb134120d9d4cfd82442261ce9 Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Mon, 27 Jan 2025 15:18:47 +0000 Subject: [PATCH 24/26] download --- src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js | 1 + 1 file changed, 1 insertion(+) 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 ee79d8f96..1b7c8142b 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js +++ b/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js @@ -667,6 +667,7 @@ function ActionsMenu({ onClick={() => { void download(selection.asSet()).then(() => { setActionsMenuAnchorEl(null); + trackEvent("user:downloads:file:gallery"); }); }} compact From 0f64d35054d1a878767d7ec97f74e4a66d13bcda Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Mon, 27 Jan 2025 15:23:59 +0000 Subject: [PATCH 25/26] export --- src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js | 3 +++ 1 file changed, 3 insertions(+) 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 1b7c8142b..598321e79 100644 --- a/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js +++ b/src/main/webapp/ui/src/eln/gallery/components/ActionsMenu.js @@ -684,6 +684,9 @@ function ActionsMenu({ avatar={} onClick={() => { setExportOpen(true); + trackEvent("user:opens:export_dialog:gallery", { + count: selection.size, + }); }} compact disabled={exportAllowed.get().isError} From e79e3e4d7143cdc8d38b1429fa6b70c7ae3c95da Mon Sep 17 00:00:00 2001 From: Robert Lamacraft Date: Mon, 27 Jan 2025 15:25:41 +0000 Subject: [PATCH 26/26] irods --- src/main/webapp/ui/src/eln/gallery/components/MoveToIrods.js | 4 ++++ 1 file changed, 4 insertions(+) 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);