From 25ae4b95ee849acfd979c1e0f2c5cf17f7e6a9a9 Mon Sep 17 00:00:00 2001 From: Alek Perron Date: Wed, 14 Feb 2024 16:26:32 -0500 Subject: [PATCH] feat: SKFP-734 add GA4 metrics --- .../Cavatica/AnalyzeButton/index.tsx | 6 +- src/components/Layout/Header/index.tsx | 3 + .../FilterList/CustomFilterContainer.tsx | 3 + .../Search/SearchAutocomplete/index.tsx | 3 +- .../uiKit/search/GlobalSearch/index.tsx | 8 +- src/provider/KeycloakProvider.tsx | 23 ++- src/services/analytics.ts | 151 +++++++++++++++++- src/services/api/reports/index.ts | 4 +- src/store/report/thunks.tsx | 7 +- .../AuthorizedStudies/index.tsx | 5 + .../SavedSets/CreateEditModal/index.tsx | 3 + .../SavedSets/ListItem/index.tsx | 6 +- .../components/PageContent/index.tsx | 29 +++- .../PageContent/tabs/DataFiles/index.tsx | 1 + .../AddRemoveSaveSetModal.tsx | 2 + .../SetsManagementDropdown/index.tsx | 4 +- src/views/FileEntity/Title/index.tsx | 4 +- src/views/Persona/index.tsx | 11 +- 18 files changed, 242 insertions(+), 31 deletions(-) diff --git a/src/components/Cavatica/AnalyzeButton/index.tsx b/src/components/Cavatica/AnalyzeButton/index.tsx index cbc9e07fc..3d07ecc7f 100644 --- a/src/components/Cavatica/AnalyzeButton/index.tsx +++ b/src/components/Cavatica/AnalyzeButton/index.tsx @@ -10,6 +10,7 @@ import { BooleanOperators } from '@ferlab/ui/core/data/sqon/operators'; import { ISqonGroupFilter } from '@ferlab/ui/core/data/sqon/types'; import { CAVATICA_FILE_BATCH_SIZE } from 'views/DataExploration/utils/constant'; +import { trackCavaticaAction } from 'services/analytics'; import { CavaticaApi } from 'services/api/cavatica'; import { ICavaticaCreateProjectBody } from 'services/api/cavatica/models'; import { fetchAllFencesAuthentificationStatus } from 'store/fences/thunks'; @@ -27,6 +28,7 @@ interface OwnProps { sqon?: ISqonGroupFilter; type?: 'default' | 'primary'; disabled?: boolean; + index: string; } const CavaticaAnalyzeButton: React.FC = ({ @@ -34,6 +36,7 @@ const CavaticaAnalyzeButton: React.FC = ({ sqon, type = 'default', disabled = false, + index, }) => { const dispatch = useDispatch(); const cavatica = useCavaticaPassport(); @@ -54,7 +57,7 @@ const CavaticaAnalyzeButton: React.FC = ({ useEffect(() => { dispatch(fetchAllFencesAuthentificationStatus()); - }, []); + }, [dispatch]); // If the user is not connected to cavatica useEffect(() => { @@ -93,6 +96,7 @@ const CavaticaAnalyzeButton: React.FC = ({ ); }} handleImportBulkData={(value) => { + trackCavaticaAction(index); dispatch(startBulkImportJob(value)); }} dictionary={{ diff --git a/src/components/Layout/Header/index.tsx b/src/components/Layout/Header/index.tsx index d49752b46..20f9f9f5a 100644 --- a/src/components/Layout/Header/index.tsx +++ b/src/components/Layout/Header/index.tsx @@ -30,6 +30,7 @@ import LineStyleIcon from 'components/Icons/LineStyleIcon'; import HeaderLink from 'components/Layout/Header/HeaderLink'; import styles from 'components/Layout/Header/index.module.scss'; import GradientAccent from 'components/uiKit/GradientAccent'; +import { trackLogout, trackVisitResources } from 'services/analytics'; import { usePersona } from 'store/persona'; import { personaActions } from 'store/persona/slice'; import { userActions } from 'store/user/slice'; @@ -117,6 +118,7 @@ const Header = () => { trigger={['click']} overlay={ trackVisitResources(key)} items={[ { key: 'website', @@ -234,6 +236,7 @@ const Header = () => { ), onClick: () => { + trackLogout(); dispatch(personaActions.cleanLogout()); dispatch(userActions.cleanLogout()); window.sessionStorage.clear(); diff --git a/src/components/uiKit/FilterList/CustomFilterContainer.tsx b/src/components/uiKit/FilterList/CustomFilterContainer.tsx index 7d2422bcc..2f53cd637 100644 --- a/src/components/uiKit/FilterList/CustomFilterContainer.tsx +++ b/src/components/uiKit/FilterList/CustomFilterContainer.tsx @@ -9,6 +9,7 @@ import { IExtendedMappingResults, IGqlResults } from '@ferlab/ui/core/graphql/ty import { getFilters } from 'graphql/utils/Filters'; import { isUndefined } from 'lodash'; +import { trackFacetSearch } from 'services/analytics'; import { getFacetsDictionary, getFiltersDictionary } from 'utils/translation'; import CustomFilterSelector from './CustomFilterSelector'; @@ -58,6 +59,8 @@ const CustomFilterContainer = ({ }, [filtersOpen]); const onChange = (fg: IFilterGroup, f: IFilter[]) => { + trackFacetSearch(index, fg.field); + updateActiveQueryFilters({ queryBuilderId, filterGroup: fg, diff --git a/src/components/uiKit/search/GlobalSearch/Search/SearchAutocomplete/index.tsx b/src/components/uiKit/search/GlobalSearch/Search/SearchAutocomplete/index.tsx index 2d9632cbb..de60e98a6 100644 --- a/src/components/uiKit/search/GlobalSearch/Search/SearchAutocomplete/index.tsx +++ b/src/components/uiKit/search/GlobalSearch/Search/SearchAutocomplete/index.tsx @@ -1,8 +1,9 @@ import React, { useCallback, useEffect, useState } from 'react'; +import Empty from '@ferlab/ui/core/components/Empty'; import { Select, Tag } from 'antd'; import debounce from 'lodash/debounce'; import take from 'lodash/take'; -import Empty from '@ferlab/ui/core/components/Empty'; + import SearchLabel from 'components/uiKit/search/SearchLabel'; export type OptionsType = { diff --git a/src/components/uiKit/search/GlobalSearch/index.tsx b/src/components/uiKit/search/GlobalSearch/index.tsx index d8b68eb50..1d523e081 100644 --- a/src/components/uiKit/search/GlobalSearch/index.tsx +++ b/src/components/uiKit/search/GlobalSearch/index.tsx @@ -7,6 +7,7 @@ import { get } from 'lodash'; import Search, { TCustomHandleSearch } from 'components/uiKit/search/GlobalSearch/Search'; import { OptionsType } from 'components/uiKit/search/GlobalSearch/Search/SearchAutocomplete'; +import { trackFacetSearch } from 'services/analytics'; export interface ICustomSearchProps { queryBuilderId: string; @@ -42,15 +43,16 @@ const GlobalSearch = ({ tooltipText, }: OwnProps) => ( - onSelect={(values) => + onSelect={(values) => { + trackFacetSearch(index, field); updateActiveQueryField({ queryBuilderId, field, value: values, index, merge_strategy: MERGE_VALUES_STRATEGIES.OVERRIDE_VALUES, - }) - } + }); + }} index={index} tooltipText={tooltipText} emptyDescription={emptyDescription} diff --git a/src/provider/KeycloakProvider.tsx b/src/provider/KeycloakProvider.tsx index 04ee29980..33eb8f74b 100644 --- a/src/provider/KeycloakProvider.tsx +++ b/src/provider/KeycloakProvider.tsx @@ -1,21 +1,20 @@ -import React, { ReactElement } from "react"; -import { - AuthClientError, - AuthClientEvent, -} from "@react-keycloak/core/" -import EnvVariables from "helpers/EnvVariables"; -import { ReactKeycloakProvider as KeycloakProvider } from "@react-keycloak/web"; -import keycloak from "auth/keycloak-api/keycloak"; -import { trackAuthSuccess } from "services/analytics"; +import React, { ReactElement } from 'react'; +import { AuthClientError, AuthClientEvent } from '@react-keycloak/core/'; +import { ReactKeycloakProvider as KeycloakProvider } from '@react-keycloak/web'; +import keycloak from 'auth/keycloak-api/keycloak'; +import EnvVariables from 'helpers/EnvVariables'; + +import { trackAuthError, trackAuthSuccess } from 'services/analytics'; export interface IProvider { children: React.ReactNode; } const eventLogger = (eventType: AuthClientEvent, error?: AuthClientError) => { - if (EnvVariables.configFor("ENV") === "development" && error) { - console.error("eventLogger ", "eventType ", eventType); - console.error("eventLogger ", error); + if (EnvVariables.configFor('ENV') === 'development' && error) { + trackAuthError(); + console.error('eventLogger ', 'eventType ', eventType); + console.error('eventLogger ', error); } if (eventType === 'onAuthSuccess') { diff --git a/src/services/analytics.ts b/src/services/analytics.ts index be0bc8b31..45ac046cc 100644 --- a/src/services/analytics.ts +++ b/src/services/analytics.ts @@ -1,5 +1,10 @@ -import EnvironmentVariables from 'helpers/EnvVariables'; import ReactGA from 'react-ga4'; +import EnvironmentVariables from 'helpers/EnvVariables'; +import { capitalize } from 'lodash'; +import { FilterActionType } from 'views/DataExploration/components/PageContent'; +import { SetActionType } from 'views/DataExploration/components/SetsManagementDropdown'; + +import { SetType } from 'services/api/savedSet/models'; const measurementId = EnvironmentVariables.configFor('MEASUREMENT_ID'); const isDev = EnvironmentVariables.configFor('ENV') === 'development'; @@ -19,3 +24,147 @@ export const trackAuthSuccess = () => { }); } }; + +export const trackAuthError = () => { + if (isGaActive) { + ReactGA.event({ + category: 'Authentication', + action: 'login failed', + }); + } +}; + +export const trackLogout = () => { + if (isGaActive) { + ReactGA.event({ + category: 'Authentication', + action: 'logout', + }); + } +}; + +export const trackFacetSearch = (page: string, field: string) => { + if (isGaActive) { + ReactGA.event({ + category: 'FacetSearch', + action: `${capitalize(page)} -- ${field}`, + }); + } +}; + +export const trackReportDownload = (reportCategory: string) => { + if (isGaActive) { + ReactGA.event({ + category: 'Reports', + action: `report download -- ${reportCategory}`, + }); + } +}; + +/** + * DONE needs to be tested + **/ +export const trackCavaticaAction = (page: string) => { + if (isGaActive) { + ReactGA.event({ + category: 'Cavatica', + action: `Analyze -- ${capitalize(page)}`, + }); + } +}; + +export const trackSetActions = (action: string, setType: SetType) => { + let message = ''; + switch (action) { + case SetActionType.CREATE_SET: + message = 'Creating new Set'; + break; + case SetActionType.UPDATE_SET: + message = 'Updating existing Set'; + break; + case SetActionType.REMOVE_SET: + message = 'Removing existing Set'; + break; + case SetActionType.ADD_IDS: + message = 'Adding file(s) to existing Set'; + break; + case SetActionType.REMOVE_IDS: + message = 'Removing file(s) from existing Set'; + break; + default: + message = 'Unknown Action'; + break; + } + if (isGaActive) { + ReactGA.event({ + category: 'Sets', + action: `${setType} - ${message}`, + }); + } +}; + +export const trackFilterActions = (action: string, tabId: string) => { + let message = ''; + switch (action) { + case FilterActionType.CREATE_FILTER: + message = 'Creating new Filter'; + break; + case FilterActionType.UPDATE_FILER: + message = 'Updating existing Filter'; + break; + case FilterActionType.REMOVE_FILTER: + message = 'Removing existing Filter'; + break; + case FilterActionType.FAVORITE_FILTER: + message = 'Adding Filter to favorites'; + break; + case FilterActionType.SHARE_FILTER: + message = 'Sharing Filter'; + break; + default: + message = 'Unknown Action'; + break; + } + if (isGaActive) { + ReactGA.event({ + category: 'Filters', + action: `${tabId} - ${message}`, + }); + } +}; + +export const trackVisitResources = (resource: string) => { + if (isGaActive) { + ReactGA.event({ + category: 'Resources', + action: `Visit -- ${resource}`, + }); + } +}; + +export const trackRegistrationStarted = () => { + if (isGaActive) { + ReactGA.event({ + category: 'Registration', + action: 'Registration started', + }); + } +}; + +export const trackNCIConnection = (connected: boolean) => { + if (isGaActive) { + ReactGA.event({ + category: 'FencesConnections', + action: `${connected ? 'Connected to' : 'Disconnected from'} NCI CRDC Framework Services`, + }); + } +}; + +export const trackKFConnection = (connected: boolean) => { + if (isGaActive) { + ReactGA.event({ + category: 'FencesConnections', + action: `${connected ? 'Connected to' : 'Disconnected from'} Kids First Framework Services`, + }); + } +}; diff --git a/src/services/api/reports/index.ts b/src/services/api/reports/index.ts index 71ad11291..340506d1d 100644 --- a/src/services/api/reports/index.ts +++ b/src/services/api/reports/index.ts @@ -4,6 +4,7 @@ import EnvironmentVariables from 'helpers/EnvVariables'; import isEmpty from 'lodash/isEmpty'; import downloader from 'common/downloader'; +import { trackReportDownload } from 'services/analytics'; import { ReportConfig, ReportType } from './models'; @@ -42,7 +43,8 @@ export const headers = () => ({ }); const generateReport = (config: ReportConfig) => { - //TODO do we need google analytics tracking? + trackReportDownload(config.name); + let reportSqon; if (!config.sqon || isEmpty(config.sqon)) { diff --git a/src/store/report/thunks.tsx b/src/store/report/thunks.tsx index 0553f89c1..ab43ecf5e 100644 --- a/src/store/report/thunks.tsx +++ b/src/store/report/thunks.tsx @@ -10,6 +10,7 @@ import { startCase } from 'lodash'; import { v4 } from 'uuid'; import { getDefaultContentType } from 'common/downloader'; +import { trackReportDownload } from 'services/analytics'; import { ArrangerApi } from 'services/api/arranger'; import { ArrangerColumnStateResults } from 'services/api/arranger/models'; import { ReportApi } from 'services/api/reports'; @@ -61,7 +62,7 @@ const fetchReport = createAsyncThunk< duration: 0, }), ); - await ReportApi.generateReport(args.data).then((_) => { + await ReportApi.generateReport(args.data).then(() => { thunkAPI.dispatch(globalActions.destroyMessages([messageKey])); thunkAPI.dispatch( globalActions.displayNotification({ @@ -82,6 +83,8 @@ const fetchTsvReport = createAsyncThunk { const messageKey = 'report_pending'; + trackReportDownload(`${args.index}Tsv`); + thunkAPI.dispatch( globalActions.displayMessage({ type: 'loading', @@ -150,6 +153,8 @@ const generateLocalTsvReport = createAsyncThunk< // !! This function assumes that it is called only when the table is not empty. Said otherwise, data is never empty !! const messageKey = 'report_pending'; + trackReportDownload(`${args.index}-${args.fileName}-tsv`); + try { const formattedDate = format(new Date(), 'yyyy-MM-dd'); const formattedFileName = `kidsfirst-${args.fileName ?? args.index}-table-${formattedDate}.tsv`; diff --git a/src/views/Dashboard/components/DashboardCards/AuthorizedStudies/index.tsx b/src/views/Dashboard/components/DashboardCards/AuthorizedStudies/index.tsx index fcecf7bf1..83286c3c5 100644 --- a/src/views/Dashboard/components/DashboardCards/AuthorizedStudies/index.tsx +++ b/src/views/Dashboard/components/DashboardCards/AuthorizedStudies/index.tsx @@ -11,6 +11,7 @@ import { DATA_EXPLORATION_QB_ID } from 'views/DataExploration/utils/constant'; import { FENCE_NAMES } from 'common/fenceTypes'; import KidsFirstLoginIcon from 'components/Icons/KidsFirstLoginIcon'; import NciIcon from 'components/Icons/NciIcon'; +import { trackKFConnection, trackNCIConnection } from 'services/analytics'; import { useFenceAuthentification, useFencesAuthorizedStudies } from 'store/fences'; import { fenceDisconnection, @@ -34,9 +35,11 @@ const AuthorizedStudies = ({ id, className = '' }: DashboardCardProps) => { name: 'Kids First Framework Services', icon: , onConnectToFence: () => { + trackKFConnection(true); dispatch(fenceOpenAuhentificationTab(FENCE_NAMES.gen3)); }, onDisconnectFromFence: () => { + trackKFConnection(false); dispatch(fenceDisconnection(FENCE_NAMES.gen3)); }, }, @@ -45,9 +48,11 @@ const AuthorizedStudies = ({ id, className = '' }: DashboardCardProps) => { name: 'NCI CRDC Framework Services', icon: , onConnectToFence: () => { + trackNCIConnection(true); dispatch(fenceOpenAuhentificationTab(FENCE_NAMES.dcf)); }, onDisconnectFromFence: () => { + trackNCIConnection(false); dispatch(fenceDisconnection(FENCE_NAMES.dcf)); }, }, diff --git a/src/views/Dashboard/components/DashboardCards/SavedSets/CreateEditModal/index.tsx b/src/views/Dashboard/components/DashboardCards/SavedSets/CreateEditModal/index.tsx index ec6050333..202f18a9b 100644 --- a/src/views/Dashboard/components/DashboardCards/SavedSets/CreateEditModal/index.tsx +++ b/src/views/Dashboard/components/DashboardCards/SavedSets/CreateEditModal/index.tsx @@ -12,6 +12,7 @@ import { } from 'views/DataExploration/components/SetsManagementDropdown'; import filtersToName from 'common/sqonToName'; +import { trackSetActions } from 'services/analytics'; import { IUserSetOutput, SetType } from 'services/api/savedSet/models'; import { PROJECT_ID, useSavedSet } from 'store/savedSet'; import { createSavedSet, updateSavedSet } from 'store/savedSet/thunks'; @@ -79,6 +80,7 @@ const CreateEditModal = ({ ]); } else { if (saveSetActionType === SetActionType.UPDATE_SET && currentSaveSet) { + trackSetActions(SetActionType.UPDATE_SET, setType); dispatch( updateSavedSet({ onCompleteCb: onSuccessCreateCb, @@ -88,6 +90,7 @@ const CreateEditModal = ({ }), ); } else { + trackSetActions(SetActionType.CREATE_SET, setType); dispatch( createSavedSet({ idField, diff --git a/src/views/Dashboard/components/DashboardCards/SavedSets/ListItem/index.tsx b/src/views/Dashboard/components/DashboardCards/SavedSets/ListItem/index.tsx index 0b0433d60..db6eae5e4 100644 --- a/src/views/Dashboard/components/DashboardCards/SavedSets/ListItem/index.tsx +++ b/src/views/Dashboard/components/DashboardCards/SavedSets/ListItem/index.tsx @@ -17,6 +17,7 @@ import { PARTICIPANTS_SAVED_SETS_FIELD, } from 'views/DataExploration/utils/constant'; +import { trackSetActions } from 'services/analytics'; import { IUserSetOutput } from 'services/api/savedSet/models'; import { getSetFieldId } from 'store/savedSet'; import { deleteSavedSet } from 'store/savedSet/thunks'; @@ -86,7 +87,10 @@ const ListItem = ({ data, icon, queryBuilderId }: OwnProps) => { content: intl.get('components.savedSets.popupConfirm.delete.content'), cancelText: intl.get('components.savedSets.popupConfirm.delete.cancelText'), okButtonProps: { danger: true }, - onOk: () => dispatch(deleteSavedSet(data.id)), + onOk: () => { + trackSetActions(SetActionType.REMOVE_SET, data.setType); + dispatch(deleteSavedSet(data.id)); + }, }) } extra={ diff --git a/src/views/DataExploration/components/PageContent/index.tsx b/src/views/DataExploration/components/PageContent/index.tsx index bb9b9fbd1..3126f418d 100644 --- a/src/views/DataExploration/components/PageContent/index.tsx +++ b/src/views/DataExploration/components/PageContent/index.tsx @@ -34,6 +34,7 @@ import GenericFilters from 'components/uiKit/FilterList/GenericFilters'; import { FilterInfo } from 'components/uiKit/FilterList/types'; import { getNoDataOptionValue } from 'components/utils/filterUtils'; import useQBStateWithSavedFilters from 'hooks/useQBStateWithSavedFilters'; +import { trackFilterActions } from 'services/analytics'; import { ArrangerApi } from 'services/api/arranger'; import { SavedFilterTag } from 'services/api/savedFilter/models'; import { globalActions } from 'store/global'; @@ -63,6 +64,15 @@ import styles from './index.module.scss'; const { Title } = Typography; export const MAX_TITLE_LENGTH = 200; + +export enum FilterActionType { + UPDATE_FILER = 'UPDATE_FILER', + CREATE_FILTER = 'CREATE_FILTER', + REMOVE_FILTER = 'REMOVE_FILTER', + FAVORITE_FILTER = 'CREATE_SET', + SHARE_FILTER = 'HIDDEN', +} + type OwnProps = { fileMapping: IExtendedMappingResults; biospecimenMapping: IExtendedMappingResults; @@ -139,13 +149,24 @@ const PageContent = ({ }; }; - const handleOnUpdateFilter = (filter: ISavedFilter) => dispatch(updateSavedFilter(filter)); - const handleOnSaveFilter = (filter: ISavedFilter) => + const handleOnUpdateFilter = (filter: ISavedFilter) => { + trackFilterActions(FilterActionType.UPDATE_FILER, tabId); + dispatch(updateSavedFilter(filter)); + }; + const handleOnSaveFilter = (filter: ISavedFilter) => { + trackFilterActions(FilterActionType.CREATE_FILTER, tabId); dispatch(createSavedFilter(addTagToFilter(filter))); - const handleOnDeleteFilter = (id: string) => dispatch(deleteSavedFilter(id)); - const handleOnSaveAsFavorite = (filter: ISavedFilter) => + }; + const handleOnDeleteFilter = (id: string) => { + trackFilterActions(FilterActionType.REMOVE_FILTER, tabId); + dispatch(deleteSavedFilter(id)); + }; + const handleOnSaveAsFavorite = (filter: ISavedFilter) => { + trackFilterActions(FilterActionType.FAVORITE_FILTER, tabId); dispatch(setSavedFilterAsDefault(addTagToFilter(filter))); + }; const handleOnShareFilter = (filter: ISavedFilter) => { + trackFilterActions(FilterActionType.SHARE_FILTER, tabId); copy(`${getCurrentUrl()}?${SHARED_FILTER_ID_QUERY_PARAM_KEY}=${filter.id}`); dispatch( globalActions.displayMessage({ diff --git a/src/views/DataExploration/components/PageContent/tabs/DataFiles/index.tsx b/src/views/DataExploration/components/PageContent/tabs/DataFiles/index.tsx index 210b957eb..0ee71a390 100644 --- a/src/views/DataExploration/components/PageContent/tabs/DataFiles/index.tsx +++ b/src/views/DataExploration/components/PageContent/tabs/DataFiles/index.tsx @@ -439,6 +439,7 @@ const DataFilesTab = ({ sqon }: OwnProps) => { fileIds={selectedAllResults ? [] : selectedKeys} sqon={sqon} key="file-cavatica-upload" + index={INDEXES.FILE} />, ], }} diff --git a/src/views/DataExploration/components/SetsManagementDropdown/AddRemoveSaveSetModal.tsx b/src/views/DataExploration/components/SetsManagementDropdown/AddRemoveSaveSetModal.tsx index 46a99725f..f8ed472a1 100644 --- a/src/views/DataExploration/components/SetsManagementDropdown/AddRemoveSaveSetModal.tsx +++ b/src/views/DataExploration/components/SetsManagementDropdown/AddRemoveSaveSetModal.tsx @@ -5,6 +5,7 @@ import { ISqonGroupFilter } from '@ferlab/ui/core/data/sqon/types'; import { Form, Modal } from 'antd'; import { Store } from 'antd/lib/form/interface'; +import { trackSetActions } from 'services/analytics'; import { IUserSetOutput, SetType } from 'services/api/savedSet/models'; import { PROJECT_ID, useSavedSet } from 'store/savedSet'; import { updateSavedSet } from 'store/savedSet/thunks'; @@ -77,6 +78,7 @@ const AddRemoveSaveSetModal = ({ switch (setActionType) { case SetActionType.ADD_IDS: case SetActionType.REMOVE_IDS: + trackSetActions(setActionType, type); dispatch( updateSavedSet({ id: setId, diff --git a/src/views/DataExploration/components/SetsManagementDropdown/index.tsx b/src/views/DataExploration/components/SetsManagementDropdown/index.tsx index 00fc0b27a..f3a8da4c0 100644 --- a/src/views/DataExploration/components/SetsManagementDropdown/index.tsx +++ b/src/views/DataExploration/components/SetsManagementDropdown/index.tsx @@ -14,7 +14,6 @@ import { IBiospecimenEntity } from 'graphql/biospecimens/models'; import { IFileEntity } from 'graphql/files/models'; import { IQueryResults } from 'graphql/models'; import { IParticipantEntity } from 'graphql/participants/models'; -import { IVariantEntity } from '../../../../graphql/variants/models'; import { MenuClickEventHandler, MenuInfo } from 'rc-menu/lib/interface'; import CreateEditModal from 'views/Dashboard/components/DashboardCards/SavedSets/CreateEditModal'; @@ -25,6 +24,8 @@ import { SetType } from 'services/api/savedSet/models'; import { useSavedSet } from 'store/savedSet'; import { numberWithCommas } from 'utils/string'; +import { IVariantEntity } from '../../../../graphql/variants/models'; + import AddRemoveSaveSetModal from './AddRemoveSaveSetModal'; import styles from './index.module.scss'; @@ -47,6 +48,7 @@ export enum SetActionType { CREATE_SET = 'CREATE_SET', HIDDEN = 'HIDDEN', UPDATE_SET = 'UPDATE_SET', + REMOVE_SET = 'REMOVE_SET', } type ModalState = { diff --git a/src/views/FileEntity/Title/index.tsx b/src/views/FileEntity/Title/index.tsx index 63b4d63ca..894f7ebe8 100644 --- a/src/views/FileEntity/Title/index.tsx +++ b/src/views/FileEntity/Title/index.tsx @@ -87,7 +87,9 @@ const FileEntityTitle: React.FC = ({ file, loading }) => { isDisabled={false} hasTooManyFiles={false} /> - {file && } + {file && ( + + )} ), }; diff --git a/src/views/Persona/index.tsx b/src/views/Persona/index.tsx index 5c6e08a24..d43a99d4c 100644 --- a/src/views/Persona/index.tsx +++ b/src/views/Persona/index.tsx @@ -1,16 +1,18 @@ import { useEffect, useState } from 'react'; import { useDispatch } from 'react-redux'; import { useKeycloak } from '@react-keycloak/web'; -import { KidsFirstKeycloakTokenParsed } from 'common/tokenTypes'; -import { fetchPersonaUser } from 'store/persona/thunks'; + import { REDIRECT_URI_KEY } from 'common/constants'; +import { KidsFirstKeycloakTokenParsed } from 'common/tokenTypes'; +import Spinner from 'components/uiKit/Spinner'; import useQueryParams from 'hooks/useQueryParams'; +import { trackRegistrationStarted } from 'services/analytics'; +import { usePersona } from 'store/persona'; +import { fetchPersonaUser } from 'store/persona/thunks'; import { STATIC_ROUTES } from 'utils/routes'; import Registration from './components/RegistrationForm'; import TermsConditions from './components/TermsConditions'; -import { usePersona } from 'store/persona'; -import Spinner from 'components/uiKit/Spinner'; enum Steps { LOADING, @@ -69,6 +71,7 @@ const PersonaRegistration = () => { isMultiStep hidden={step !== Steps.TERMSANDCONDITIONS} onFinish={() => { + trackRegistrationStarted(); setStep(Steps.REGISTRATION); }} />