Skip to content

Commit

Permalink
feat(google-analatics): add google analytics
Browse files Browse the repository at this point in the history
  • Loading branch information
sijav committed Dec 12, 2023
1 parent ca7d6ac commit 914309b
Show file tree
Hide file tree
Showing 26 changed files with 750 additions and 58 deletions.
4 changes: 3 additions & 1 deletion .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ VITE_WEBSOCKET_RETRY_TIMEOUT=5000
HOST=127.0.0.1
PORT=8081
VITE_USE_MOCK=false
VITE_DISCORD_URL=https://discord.gg/someengineering
VITE_DISCORD_URL=https://discord.gg/someengineering
VITE_GTM_DEV_ID=G-BEN98CFE8C
VITE_GTM_PROD_ID=
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ VITE_WEBSOCKET_RETRY_TIMEOUT=5000
HOST=127.0.0.1
PORT=8081
VITE_USE_MOCK=false
VITE_DISCORD_URL=https://discord.gg/someengineering
VITE_DISCORD_URL=https://discord.gg/someengineering
VITE_GTM_DEV_ID=G-BEN98CFE8C
VITE_GTM_PROD_ID=G-WBQZ5WW9X1
4 changes: 3 additions & 1 deletion .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ VITE_USE_PROXY=false
VITE_NETWORK_RETRY_COUNT=5
VITE_WEBSOCKET_RETRY_TIMEOUT=5000
VITE_USE_MOCK=false
VITE_DISCORD_URL=https://discord.gg/someengineering
VITE_DISCORD_URL=https://discord.gg/someengineering
VITE_GTM_DEV_ID=G-BEN98CFE8C
VITE_GTM_PROD_ID=G-WBQZ5WW9X1
96 changes: 75 additions & 21 deletions src/core/events/WebSocketEvents.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { PropsWithChildren, useCallback, useEffect, useRef } from 'react'
import { useUserProfile } from 'src/core/auth'
import { endPoints, env } from 'src/shared/constants'
import { useGTMDispatch } from 'src/shared/google-tag-manager'
import { WebSocketEvent } from 'src/shared/types/server'
import { WebSocketEventsContext } from './WebSocketEventsContext'

const WS_CLOSE_CODE_NO_RETRY = 4001

export const WebSocketEvents = ({ children }: PropsWithChildren) => {
const { selectedWorkspace, isAuthenticated, logout } = useUserProfile()
const sendToGTM = useGTMDispatch()
const noRetry = useRef(false)
const listeners = useRef<Record<string, (ev: MessageEvent) => void>>({})
const messagesToSend = useRef<{ message: string; resolve: (value: string) => void; reject: (err: unknown) => void }[]>([])
Expand All @@ -32,43 +34,83 @@ export const WebSocketEvents = ({ children }: PropsWithChildren) => {
} else {
onMessage(message as WebSocketEvent)
}
} catch {
/* empty */
} catch (err) {
const { message, name, stack = 'unknown' } = err as Error
sendToGTM({
event: 'socket-error',
api: `${env.wsUrl}/${endPoints.workspaces.workspace(selectedWorkspace?.id ?? 'unknown').events}`,
authorized: isAuthenticated ?? false,
message: message,
name,
stack,
state: 'on-message',
params: ev.data,
workspaceId: selectedWorkspace?.id ?? 'unknown',
})
}
}
if (websocket.current) {
websocket.current.addEventListener('message', listeners.current[randomId])
}
return () => handleRemoveListener(randomId)
},
[handleRemoveListener, logout],
[handleRemoveListener, isAuthenticated, logout, selectedWorkspace?.id, sendToGTM],
)

const handleSendData = useCallback((data: WebSocketEvent) => {
const message = JSON.stringify(data)
return new Promise<string>((resolve, reject) => {
try {
if (websocket.current && websocket.current.readyState === websocket.current.OPEN) {
websocket.current.send(message)
resolve(message)
} else if (websocket.current && websocket.current.readyState === websocket.current.CONNECTING) {
websocket.current.addEventListener('open', () => {
websocket.current?.send(JSON.stringify(data))
const handleSendData = useCallback(
(data: WebSocketEvent) => {
const message = JSON.stringify(data)
return new Promise<string>((resolve, reject) => {
try {
if (websocket.current && websocket.current.readyState === websocket.current.OPEN) {
websocket.current.send(message)
resolve(message)
} else if (websocket.current && websocket.current.readyState === websocket.current.CONNECTING) {
websocket.current.addEventListener('open', () => {
websocket.current?.send(JSON.stringify(data))
resolve(message)
})
} else {
messagesToSend.current.push({ message, resolve, reject })
}
} catch (err) {
const { message, name, stack = 'unknown' } = err as Error
sendToGTM({
event: 'socket-error',
api: `${env.wsUrl}/${endPoints.workspaces.workspace(selectedWorkspace?.id ?? 'unknown').events}`,
authorized: isAuthenticated ?? false,
message: message,
name,
stack,
state: 'send-message',
params: message,
workspaceId: selectedWorkspace?.id ?? 'unknown',
})
} else {
messagesToSend.current.push({ message, resolve, reject })
reject(err)
}
} catch (err) {
reject(err)
}
})
}, [])
})
},
[isAuthenticated, selectedWorkspace?.id, sendToGTM],
)

useEffect(() => {
if (isAuthenticated && selectedWorkspace?.id) {
let retryTimeout = env.webSocketRetryTimeout
const onClose = (ev: CloseEvent) => {
if (ev.code !== 1000) {
const { stack = 'unknown', name, message } = Error('Websocket connection closed')
sendToGTM({
event: 'socket-error',
api: `${env.wsUrl}/${endPoints.workspaces.workspace(selectedWorkspace?.id ?? 'unknown').events}`,
authorized: isAuthenticated ?? false,
message,
name,
stack,
state: 'on-open',
params: `reason: ${ev.reason}, code: ${ev.code}, was clean: ${ev.wasClean}`,
workspaceId: selectedWorkspace?.id ?? 'unknown',
})
}
if (ev.code !== WS_CLOSE_CODE_NO_RETRY && !noRetry.current) {
if (isAuthenticated && selectedWorkspace?.id) {
window.setTimeout(createWebSocket, retryTimeout)
Expand All @@ -82,6 +124,18 @@ export const WebSocketEvents = ({ children }: PropsWithChildren) => {
websocket.current?.send(message)
resolve(message)
} catch (err) {
const { message, name, stack = 'unknown' } = err as Error
sendToGTM({
event: 'socket-error',
api: `${env.wsUrl}/${endPoints.workspaces.workspace(selectedWorkspace?.id ?? 'unknown').events}`,
authorized: isAuthenticated ?? false,
message: message,
name,
stack,
state: 'on-open',
params: message,
workspaceId: selectedWorkspace?.id ?? 'unknown',
})
reject(err)
}
}
Expand Down Expand Up @@ -123,7 +177,7 @@ export const WebSocketEvents = ({ children }: PropsWithChildren) => {
} else {
noRetry.current = false
}
}, [selectedWorkspace?.id, isAuthenticated])
}, [selectedWorkspace?.id, isAuthenticated, sendToGTM])

return (
<WebSocketEventsContext.Provider value={{ addListener: handleAddListener, websocket, send: handleSendData }}>
Expand Down
12 changes: 10 additions & 2 deletions src/pages/panel/inventory/InventoryForm.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Trans } from '@lingui/macro'
import { Autocomplete, Box, Divider, Grid, Stack, TextField } from '@mui/material'
import { useQuery } from '@tanstack/react-query'
import { Dispatch, SetStateAction, useMemo } from 'react'
import { AxiosError } from 'axios'
import { Dispatch, SetStateAction, useEffect, useMemo } from 'react'
import { useUserProfile } from 'src/core/auth'
import { DefaultPropertiesKeys } from 'src/pages/panel/shared/constants'
import { getWorkspaceInventorySearchStartQuery } from 'src/pages/panel/shared/queries'
Expand All @@ -10,6 +11,7 @@ import { ErrorBoundaryFallback, NetworkErrorBoundary } from 'src/shared/error-bo
import { InventoryFormFilterRow } from './InventoryFormFilterRow'
import { InventoryFormTemplateObject, InventoryFormTemplates } from './InventoryFormTemplates'
import { InventoryAdvanceSearchConfig, getArrayFromInOP } from './utils'
import { useInventorySendToGTM } from './utils/useInventorySendToGTM'

interface InventoryFormProps {
setConfig: Dispatch<SetStateAction<InventoryAdvanceSearchConfig[]>>
Expand All @@ -21,12 +23,18 @@ interface InventoryFormProps {

export const InventoryForm = ({ searchCrit, kind, setKind, config, setConfig }: InventoryFormProps) => {
const { selectedWorkspace } = useUserProfile()
const { data: originalStartData } = useQuery({
const sendToGTM = useInventorySendToGTM()
const { data: originalStartData, error } = useQuery({
queryKey: ['workspace-inventory-search-start', selectedWorkspace?.id],
queryFn: getWorkspaceInventorySearchStartQuery,
throwOnError: false,
enabled: !!selectedWorkspace?.id,
})
useEffect(() => {
if (error) {
sendToGTM('getWorkspaceInventorySearchStartQuery', false, error as AxiosError, '')
}
}, [error, sendToGTM])
const startData = useMemo(() => originalStartData ?? { accounts: [], kinds: [], regions: [], severity: [] }, [originalStartData])
const processedStartData = useMemo(() => {
const clouds: string[] = []
Expand Down
45 changes: 43 additions & 2 deletions src/pages/panel/inventory/InventoryFormFilterRowProperty.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '@mui/material'
import { useInfiniteQuery } from '@tanstack/react-query'
import { useDebounce } from '@uidotdev/usehooks'
import { AxiosError } from 'axios'
import { ChangeEvent, HTMLAttributes, KeyboardEvent, UIEvent as ReactUIEvent, useEffect, useMemo, useRef, useState } from 'react'
import { useUserProfile } from 'src/core/auth'
import { OPType, defaultProperties, kindDurationTypes, kindSimpleTypes } from 'src/pages/panel/shared/constants'
Expand All @@ -20,6 +21,7 @@ import { isValidProp } from 'src/pages/panel/shared/utils'
import { panelUI } from 'src/shared/constants'
import { ResourceComplexKindSimpleTypeDefinitions } from 'src/shared/types/server'
import { getCustomedWorkspaceInventoryPropertyAttributesQuery } from './utils'
import { useInventorySendToGTM } from './utils/useInventorySendToGTM'

interface InventoryFormFilterRowPropertyProps {
selectedKind: string | null
Expand Down Expand Up @@ -79,14 +81,15 @@ export const InventoryFormFilterRowProperty = ({ selectedKind, defaultValue, kin
throwOnError: false,
enabled: !!selectedWorkspace?.id && !!kinds.length && isDictionary,
})
const kindsStr = JSON.stringify(kinds)
const pathComplete = useInfiniteQuery({
queryKey: [
'workspace-inventory-property-path-complete-query',
selectedWorkspace?.id,
isDefaultItemSelected ? '' : debouncedPath,
!fqn || isDefaultItemSelected ? '' : debouncedProp,
selectedKind,
JSON.stringify(kinds),
kindsStr,
] as const,
initialPageParam: {
limit: ITEMS_PER_PAGE,
Expand All @@ -98,10 +101,48 @@ export const InventoryFormFilterRowProperty = ({ selectedKind, defaultValue, kin
throwOnError: false,
enabled: !!selectedWorkspace?.id && !!kinds.length && !isDictionary,
})
const { data = null, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage } = isDictionary ? propertyAttributes : pathComplete
const { data = null, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage, error } = isDictionary ? propertyAttributes : pathComplete
const flatData = useMemo(() => (data?.pages.flat().filter((i) => i) as Exclude<typeof data, null>['pages'][number]) ?? null, [data])
const highlightedOptionRef = useRef<Exclude<typeof flatData, null>[number] | null>(null)

const sendToGTM = useInventorySendToGTM()
useEffect(() => {
if (error) {
if (isDictionary) {
const prop =
value === `${debouncedPath}.${debouncedProp}` || value === `${debouncedPath}.${debouncedProp.replace(/\./g, '․')}`
? ''
: debouncedProp
const path = debouncedPath
sendToGTM('getCustomedWorkspaceInventoryPropertyAttributesQuery', false, error as AxiosError, {
workspaceId: selectedWorkspace?.id,
prop: `${path.split('.').slice(-1)[0]}${prop ? `=~"${prop.replace(//g, '.')}"` : ''}` ? '' : debouncedProp,
query: selectedKind ? `is(${selectedKind})` : 'all',
})
} else {
sendToGTM('getCustomedWorkspaceInventoryPropertyAttributesQuery', false, error as AxiosError, {
workspaceId: selectedWorkspace?.id,
path: isDefaultItemSelected ? '' : debouncedPath,
prop: !fqn || isDefaultItemSelected ? '' : debouncedProp,
kinds: selectedKind ? [selectedKind] : (JSON.parse(kindsStr) as string[]),
fuzzy: true,
})
}
}
}, [
error,
sendToGTM,
debouncedPath,
debouncedProp,
isDictionary,
value,
selectedWorkspace?.id,
selectedKind,
isDefaultItemSelected,
fqn,
kindsStr,
])

useEffect(() => {
if (prevPropIndex.current > propIndex) {
prevFqn.current = 'object'
Expand Down
20 changes: 19 additions & 1 deletion src/pages/panel/inventory/InventoryFormFilterRowStringValue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { t } from '@lingui/macro'
import { Autocomplete, AutocompleteProps, CircularProgress, TextField, TypographyProps } from '@mui/material'
import { useInfiniteQuery } from '@tanstack/react-query'
import { useDebounce } from '@uidotdev/usehooks'
import { ChangeEvent, ReactNode, UIEvent as ReactUIEvent, useMemo, useRef, useState } from 'react'
import { AxiosError } from 'axios'
import { ChangeEvent, ReactNode, UIEvent as ReactUIEvent, useEffect, useMemo, useRef, useState } from 'react'
import { useUserProfile } from 'src/core/auth'
import { getWorkspaceInventoryPropertyValuesQuery } from 'src/pages/panel/shared/queries'
import { panelUI } from 'src/shared/constants'
import { ListboxComponent } from 'src/shared/react-window'
import { AutoCompleteValue } from 'src/shared/types/shared'
import { useInventorySendToGTM } from './utils/useInventorySendToGTM'

const ITEMS_PER_PAGE = 50

Expand Down Expand Up @@ -46,6 +48,7 @@ export function InventoryFormFilterRowStringValue<Multiple extends boolean, Netw
fetchNextPage,
hasNextPage,
isFetchingNextPage,
error,
} = useInfiniteQuery({
queryKey: [
'workspace-inventory-property-values',
Expand All @@ -67,6 +70,21 @@ export function InventoryFormFilterRowStringValue<Multiple extends boolean, Netw
throwOnError: false,
enabled: !!(selectedWorkspace?.id && !networkDisabled),
})
const sendToGTM = useInventorySendToGTM()
useEffect(() => {
if (error) {
sendToGTM('getWorkspaceInventoryPropertyValuesQuery', false, error as AxiosError, {
workspaceId: selectedWorkspace?.id,
query:
debouncedTyped &&
(!slectedTyped.current || slectedTyped.current !== debouncedTyped) &&
(!value || (Array.isArray(value) ? !value.find((i) => i.label === debouncedTyped) : value.label !== debouncedTyped))
? `${searchCrit} and ${propertyName} ~ ".*${debouncedTyped}.*"`
: searchCrit,
prop: propertyName,
})
}
}, [debouncedTyped, error, propertyName, searchCrit, selectedWorkspace?.id, sendToGTM, value])
const flatData = useMemo(
() =>
data?.pages
Expand Down
13 changes: 12 additions & 1 deletion src/pages/panel/inventory/InventoryTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useQuery } from '@tanstack/react-query'
import { useEffect, useRef, useState } from 'react'
import { useUserProfile } from 'src/core/auth'
import { getWorkspaceInventorySearchTableQuery } from 'src/pages/panel/shared/queries'
import { useGTMDispatch } from 'src/shared/google-tag-manager'
import { TablePagination, TableViewPage } from 'src/shared/layouts/panel-layout'
import { LoadingSuspenseFallback } from 'src/shared/loading'
import {
Expand All @@ -27,7 +28,7 @@ export const InventoryTable = ({ searchCrit, history }: InventoryTableProps) =>
const [dataCount, setDataCount] = useState(-1)
const [page, setPage] = useState(0)
const [rowsPerPage, setRowsPerPage] = useState(10)
const { selectedWorkspace } = useUserProfile()
const { selectedWorkspace, isAuthenticated } = useUserProfile()
const [rows, setRows] = useState<GetWorkspaceInventorySearchTableRow[]>([])
const [columns, setColumns] = useState<GetWorkspaceInventorySearchTableColumn[]>([])
const initializedRef = useRef(false)
Expand All @@ -44,6 +45,7 @@ export const InventoryTable = ({ searchCrit, history }: InventoryTableProps) =>
queryFn: getWorkspaceInventorySearchTableQuery,
enabled: !!selectedWorkspace?.id,
})
const sendToGTM = useGTMDispatch()
const [data, totalCount] = serverData ?? [[{ columns: [] }] as GetWorkspaceInventorySearchTableResponse, -1]
const [selectedRow, setSelectedRow] = useState<GetWorkspaceInventorySearchTableRow>()

Expand All @@ -61,6 +63,15 @@ export const InventoryTable = ({ searchCrit, history }: InventoryTableProps) =>
initializedRef.current = true
}, [searchCrit])

useEffect(() => {
sendToGTM({
event: 'inventory-search',
authorized: isAuthenticated ?? false,
q: searchCrit,
workspaceId: selectedWorkspace?.id ?? 'unknown',
})
}, [isAuthenticated, searchCrit, selectedWorkspace?.id, sendToGTM])

useEffect(() => {
if (!isLoading) {
const [{ columns: newColumns }, ...newRows] = data ?? [{ columns: [] }]
Expand Down
Loading

0 comments on commit 914309b

Please sign in to comment.