Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dimensions and Metrics Explorer UX update #2027

Merged
merged 20 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9ad994c
Add screen_view, ad_impression, campaign_details events to EventBuilder
ikuleshov Apr 25, 2024
934b569
remove UA toggle
ikuleshov Jul 23, 2024
51b6ba3
Merge pull request #3 from googleanalytics/main
ikuleshov Aug 15, 2024
550ee96
update the react-spinner version
ikuleshov Sep 18, 2024
1070431
remove unimplemented LineItem component
ikuleshov Sep 18, 2024
ce8bc8f
Force Typography to use span tag instead of div to avoid compilation …
ikuleshov Sep 19, 2024
f997657
remove UA code and tests
ikuleshov Sep 19, 2024
ebc919e
fix tests
ikuleshov Sep 19, 2024
8a6b0e5
Dimensions and Metrics Explorer UX update
ikuleshov Sep 26, 2024
a41443a
update loader-spinner version
ikuleshov Sep 26, 2024
97da7e0
Merge branch 'googleanalytics-main' into dims_metrics_explorer
ikuleshov Sep 26, 2024
369e288
Merge branch 'googleanalytics-main' into dims_metrics_explorer
ikuleshov Sep 26, 2024
3fe59ac
Merge branch 'dims_metrics_explorer' of github.com:ikuleshov/ga-dev-t…
ikuleshov Sep 26, 2024
70da4eb
Merge branch 'dims_metrics_explorer' of github.com:ikuleshov/ga-dev-t…
ikuleshov Sep 26, 2024
735658c
Merge remote-tracking branch 'origin/dims_metrics_explorer' into dims…
ikuleshov Oct 3, 2024
a5eeab1
Merge remote-tracking branch 'origin/dims_metrics_explorer' into dims…
ikuleshov Oct 3, 2024
77eba37
Merge remote-tracking branch 'origin/dims_metrics_explorer' into dims…
ikuleshov Oct 3, 2024
fe46925
Merge remote-tracking branch 'origin/dims_metrics_explorer' into dims…
ikuleshov Oct 3, 2024
c6d734c
Merge remote-tracking branch 'origin/dims_metrics_explorer' into dims…
ikuleshov Oct 3, 2024
aef71a5
Merge branch 'main' into dims_metrics_explorer
ikuleshov Oct 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,23 @@
"react-helmet": "^6.1.0",
"react-icons": "^4.8.0",
"react-json-view": "^1.21.3",
"react-markdown": "^9.0.1",
"react-loader-spinner": "^6.1.6",
"react-redux": "^8.0.5",
"react-syntax-highlighter": "^15.5.0",
"redux": "^4.2.1",
"remark-gfm": "^4.0.0",
"tsconfig-paths-webpack-plugin": "^4.0.1",
"use-debounce": "^9.0.4",
"use-query-params": "^0.4.3"
},
"devDependencies": {
"@reach/router": "^1.3.4",
"@testing-library/jest-dom": "^6.1.2",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^13.1.8",
"@types/gapi": "^0.0.39",
"@types/gapi.auth2": "^0.0.54",
"@reach/router": "^1.3.4",
"@types/gapi.client.analytics": "^3.0.7",
"@types/gapi.client.analyticsadmin": "^1.0.0",
"@types/gapi.client.analyticsdata": "^1.0.2",
Expand Down
196 changes: 129 additions & 67 deletions src/components/ga4/DimensionsMetricsExplorer/Compatible.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import { navigate } from "gatsby"
import * as React from "react"
import QueryExplorerLink from "../QueryExplorer/BasicReport/QueryExplorerLink"
import { CompatibleHook } from "./useCompatibility"
import Autocomplete from '@mui/material/Autocomplete';
import {Dimension, Metric} from '@/components/ga4/DimensionsMetricsExplorer/useDimensionsAndMetrics';
import TextField from '@mui/material/TextField';

const PREFIX = 'Compatible';

Expand All @@ -23,9 +26,9 @@ const classes = {
};

const StyledPaper = styled(Paper)((
{
theme
}
{
theme
}
) => ({
[`&.${classes.compatible}`]: {
padding: theme.spacing(2),
Expand Down Expand Up @@ -56,89 +59,148 @@ const StyledPaper = styled(Paper)((
}
}));

const WithProperty: React.FC<
CompatibleHook & { property: PropertySummary | undefined }
> = ({
dimensions,
metrics,
removeMetric,
removeDimension,
property,
hasFieldSelected,
}) => {
type CompatibleProps =
CompatibleHook
& {
property: PropertySummary | undefined,
allMetrics: Metric[],
allDimensions: Dimension[]
}
const WithProperty: React.FC<CompatibleProps> = ({
dimensions,
metrics,
removeMetric,
removeDimension, setDimensions, setMetrics,
property,
hasFieldSelected, incompatibleDimensions, incompatibleMetrics,
allDimensions,
allMetrics,
}) => {


if (property === undefined) {
return null
}

return (
<>
<Typography>
As you choose dimensions & metrics (by clicking the checkbox next to
their name), they will be added here. Incompatible dimensions & metrics
will be grayed out.
</Typography>
<div className={classes.chipGrid}>
<Typography className={classes.chipLabel}>Dimensions:</Typography>
<div className={classes.chips}>
{dimensions !== undefined && dimensions.length > 0
? dimensions.map(d => (
<Chip
variant="outlined"
key={d.apiName}
label={d.apiName}
onClick={() => navigate(`#${d.apiName}`)}
onDelete={() => removeDimension(d)}
/>
))
: "No dimensions selected."}
</div>
<Typography className={classes.chipLabel}>Metrics:</Typography>
<div className={classes.chips}>
{metrics !== undefined && metrics.length > 0
? metrics?.map(m => (
<Chip
variant="outlined"
key={m.apiName}
label={m.apiName}
onDelete={() => removeMetric(m)}
/>
))
: "No metrics selected."}
</div>
</div>
{hasFieldSelected && (
<>
<Typography>
Use these fields in the{" "}
<QueryExplorerLink dimensions={dimensions} metrics={metrics} />
As you choose dimensions & metrics, they will be added here.
Incompatible dimensions & metrics will be grayed out.
</Typography>
)}
</>
<div className={classes.chipGrid}>
<Typography className={classes.chipLabel}>Dimensions:</Typography>
<div className={classes.chips}>
<Autocomplete<Dimension, true>
fullWidth
autoComplete
multiple
isOptionEqualToValue={(a, b) => a.apiName === b.apiName}
onChange={(event, value) => setDimensions(value)}
value={dimensions || []}
options={allDimensions}
getOptionDisabled={(option) =>
incompatibleDimensions?.find(d => d.apiName === option.apiName) !== undefined
}
getOptionLabel={dimension => `${dimension.apiName}: ${dimension.uiName}` || ""}
renderInput={params => (
<TextField
{...params}
size="small"
variant="outlined"
helperText={
<>
Select dimensions.
</>
}
/>
)}
renderTags={(tagValue, getTagProps) =>
tagValue.map((option, index) => {
return (
<Chip
key={option.apiName}
label={option.apiName}
onClick={() => navigate(`#${option.apiName}`)}
onDelete={() => removeDimension(option)}
/>
);
})
}
/>
</div>
<Typography className={classes.chipLabel}>Metrics:</Typography>
<div className={classes.chips}>
<Autocomplete<Metric, true>
fullWidth
autoComplete
multiple
isOptionEqualToValue={(a, b) => a.apiName === b.apiName}
onChange={(event, value) => setMetrics(value)}
value={metrics || []}
options={allMetrics}
getOptionDisabled={(option) =>
incompatibleMetrics?.find(d => d.apiName === option.apiName) !== undefined
}
getOptionLabel={metric => `${metric.apiName}: ${metric.uiName}` || ""}
renderInput={params => (
<TextField
{...params}
size="small"
variant="outlined"
helperText={
<>
Select metrics.
</>
}
/>
)}
renderTags={(tagValue, getTagProps) =>
tagValue.map((option, index) => {
return (
<Chip
key={option.apiName}
label={option.apiName}
onClick={() => navigate(`#${option.apiName}`)}
onDelete={() => removeMetric(option)}
/>
);
})
}
/>
</div>
</div>
{hasFieldSelected && (
<Typography>
Use these fields in the{" "}
<QueryExplorerLink dimensions={dimensions} metrics={metrics} />
</Typography>
)}
</>
)
}

const Compatible: React.FC<
CompatibleHook & { property: PropertySummary | undefined }
CompatibleHook & { allDimensions: Dimension[], allMetrics: Metric[], property: PropertySummary | undefined }
> = props => {

const { reset, property, hasFieldSelected } = props

return (
<StyledPaper className={classes.compatible}>
<Typography variant="h3">
Compatible Fields
<IconButton disabled={!hasFieldSelected} onClick={reset}>
<Replay />
</IconButton>
</Typography>
<WithProperty {...props} property={property} />
{property === undefined && (
<Typography>
Pick a property above to enable this functionality.
<StyledPaper className={classes.compatible}>
<Typography variant="h3">
Compatible Fields
<IconButton disabled={!hasFieldSelected} onClick={reset}>
<Replay />
</IconButton>
</Typography>
)}
</StyledPaper>
<WithProperty {...props} property={property} />
{property === undefined && (
<Typography>
Pick a property above to enable this functionality.
</Typography>
)}
</StyledPaper>
);
}

Expand Down
87 changes: 36 additions & 51 deletions src/components/ga4/DimensionsMetricsExplorer/Field.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import * as React from "react"

import { styled } from '@mui/material/styles';
import {styled} from '@mui/material/styles';

import IconLink from "@mui/icons-material/Link"
import Typography from "@mui/material/Typography"

import InlineCode from "@/components/InlineCode"
import { CopyIconButton } from "@/components/CopyButton"
import {CopyIconButton} from "@/components/CopyButton"
import ExternalLink from "@/components/ExternalLink"
import { Dimension, Metric } from "./useDimensionsAndMetrics"
import { QueryParam } from "."
import { AccountSummary, PropertySummary } from "@/types/ga4/StreamPicker"
import {Dimension, Metric} from "./useDimensionsAndMetrics"
import {QueryParam} from "."
import {AccountSummary, PropertySummary} from "@/types/ga4/StreamPicker"
import LabeledCheckbox from "@/components/LabeledCheckbox"
import { CompatibleHook } from "./useCompatibility"
import {CompatibleHook} from "./useCompatibility"
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'

const PREFIX = 'Field';

Expand Down Expand Up @@ -83,7 +85,7 @@
],
]

const linkifyText = (

Check warning on line 88 in src/components/ga4/DimensionsMetricsExplorer/Field.tsx

View workflow job for this annotation

GitHub Actions / build (18.x)

'linkifyText' is assigned a value but never used
remainingString: string,
elements: (JSX.Element | string)[]
): [string, (JSX.Element | string)[]] => {
Expand Down Expand Up @@ -128,7 +130,6 @@

const Field: React.FC<FieldProps> = props => {


const {
field,
account,
Expand Down Expand Up @@ -158,27 +159,6 @@
return `${baseURL}${search}#${apiName}`
}, [field, apiName, account, property])

const withLinks = React.useMemo(() => {
let remainingText = description
let elements: (JSX.Element | string)[] = []
let mightHaveLinks = true
while (mightHaveLinks) {
const result = linkifyText(remainingText, elements)
remainingText = result[0]
elements = result[1]
if (remainingText === "") {
mightHaveLinks = false
}
}
return (
<>
{elements.map((e, idx) => (
<React.Fragment key={idx}>{e}</React.Fragment>
))}
</>
)
}, [description])

const isCompatible = React.useMemo(() => {
return (
incompatibleDimensions?.find(d => d.apiName === field.value.apiName) ===
Expand Down Expand Up @@ -208,29 +188,34 @@
}, [checked, addDimension, addMetric, removeDimension, removeMetric, field])

return (
<Root id={apiName} key={apiName}>
<Typography variant="h4" className={classes.heading}>
{property === undefined ? (
uiName
) : (
<LabeledCheckbox
className={classes.headingUIName}
checked={checked}
onChange={onChange}
disabled={!isCompatible}
>
{uiName}
</LabeledCheckbox>
)}
<InlineCode className={classes.apiName}>{apiName}</InlineCode>
<CopyIconButton
icon={<IconLink color="primary" />}
toCopy={link}
tooltipText={`Copy link to ${apiName}`}
/>
</Typography>
<Typography>{withLinks}</Typography>
</Root>
<>
{
<Root id={apiName} key={apiName}>
<Typography variant="h4" className={classes.heading}>
{property === undefined ? (
uiName
) : (
<LabeledCheckbox
className={classes.headingUIName}
checked={checked}
onChange={onChange}
disabled={!isCompatible}
>
{uiName}
</LabeledCheckbox>
)}
<InlineCode className={classes.apiName}>{apiName}</InlineCode>
<CopyIconButton
icon={<IconLink color="primary"/>}
toCopy={link}
tooltipText={`Copy link to ${apiName}`}
/>
</Typography>
<Typography><Markdown
remarkPlugins={[remarkGfm]}>{description}</Markdown></Typography>
</Root>
}
</>
);
}

Expand Down
Loading
Loading