diff --git a/package.json b/package.json index 340dbd36..199d3424 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "react-helmet": "^6.1.0", "react-icons": "^4.8.0", "react-json-view": "^1.21.3", - "react-loader-spinner": "^5.3.4", + "react-loader-spinner": "^6.1.6", "react-redux": "^8.0.5", "react-syntax-highlighter": "^15.5.0", "redux": "^4.2.1", diff --git a/src/components/AccountExplorer/HighlightText.tsx b/src/components/AccountExplorer/HighlightText.tsx deleted file mode 100644 index 2891e44c..00000000 --- a/src/components/AccountExplorer/HighlightText.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import * as React from "react" - -interface HighlightTextProps { - text: string - search?: string - className?: string -} -const HighlightText: React.FC = ({ - text, - search, - className, -}) => { - if (search === undefined) { - return <>{text} - } - const match = new RegExp(`(${search})`, "gi") - const matchArray = text.match(match) - if (matchArray === null) { - return <>{text} - } - - const matchedText = matchArray[0] - const index = text.indexOf(matchedText) - const beginning = text.substring(0, index) - const middle = text.substring(index, index + matchedText.length) - const end = text.substring(index + matchedText.length) - return ( - <> - {beginning} - {middle} - {end} - - ) -} -export default HighlightText diff --git a/src/components/AccountExplorer/ViewTable.tsx b/src/components/AccountExplorer/ViewTable.tsx deleted file mode 100644 index 5021d976..00000000 --- a/src/components/AccountExplorer/ViewTable.tsx +++ /dev/null @@ -1,281 +0,0 @@ -import * as React from "react" - -import { styled } from '@mui/material/styles'; -import Table from "@mui/material/Table" -import TableBody from "@mui/material/TableBody" -import TableCell from "@mui/material/TableCell" -import TableHead from "@mui/material/TableHead" -import TableRow from "@mui/material/TableRow" -import Typography from "@mui/material/Typography" - -import { CopyIconButton } from "@/components/CopyButton" -import HighlightText from "./HighlightText" -import Spinner from "@/components/Spinner" -import { RequestStatus } from "@/types" -import useFlattenedViews from "../ViewSelector/useFlattenedViews" -import { AccountSummary, ProfileSummary, WebPropertySummary } from "@/types/ua" - -const PREFIX = 'ViewsTable'; - -const classes = { - id: `${PREFIX}-id`, - mark: `${PREFIX}-mark`, - link: `${PREFIX}-link`, - tableCell: `${PREFIX}-tableCell`, - copyIconButton: `${PREFIX}-copyIconButton` -}; - -const StyledTable = styled(Table)(( - { - theme - } -) => ({ - [`& .${classes.id}`]: { - color: theme.palette.text.secondary, - }, - - [`& .${classes.mark}`]: { - backgroundColor: theme.palette.success.light, - }, - - [`& .${classes.link}`]: { - color: theme.palette.info.main, - }, - - [`& .${classes.tableCell}`]: { - display: "flex", - justifyContent: "space-between", - alignItems: "center", - }, - - [`& .${classes.copyIconButton}`]: { - color: theme.palette.text.secondary, - } -})); - -interface ViewTableProps { - flattenedViewsRequest: ReturnType - className?: string - search?: string -} - -interface ViewCellProps { - firstRow: JSX.Element | string - secondRow?: JSX.Element | string - copyToolTip: string - textToCopy: string -} -const APVCell: React.FC = ({ - firstRow, - secondRow, - copyToolTip, - textToCopy, -}) => { - - return ( - -
-
-
{firstRow}
- {secondRow &&
{secondRow}
} -
- -
-
- ) -} - -const maxCellWidth = 25 -const textClamp = (text: string, maxWidth: number) => { - if (text.length <= maxWidth) { - return text - } else { - return text.substring(0, maxWidth - 3) + "..." - } -} - -const AccountCell: React.FC<{ - account: AccountSummary | undefined - - search: string | undefined -}> = ({ account, search }) => { - if (account === undefined) { - return null - } - return ( - - } - secondRow={ - - } - /> - ) -} - -const PropertyCell: React.FC<{ - property: WebPropertySummary | undefined - - search: string | undefined -}> = ({ property, search }) => { - if (property === undefined) { - return No UA properties for account. - } - - return ( - - } - secondRow={ - - } - /> - ) -} - -const ViewCell: React.FC<{ - account: AccountSummary | undefined - property: WebPropertySummary | undefined - view: ProfileSummary | undefined - - search: string | undefined -}> = ({ account, property, view, search }) => { - if (view === undefined) { - return No UA views for account. - } - const viewUrl = `https://analytics.google.com/analytics/web/#/report/vistors-overview/a${account?.id}w${property?.internalWebPropertyId}p${view?.id}` - return ( - - - - - } - secondRow={ - - } - /> - - } - /> - - ) -} - -const ViewsTable: React.FC = ({ - flattenedViewsRequest, - className, - search, -}) => { - - return ( - - - - Account - Property - View - Table ID - - - - {flattenedViewsRequest.status === RequestStatus.Successful ? ( - flattenedViewsRequest.flattenedViews.length === 0 ? ( - - No results - - ) : ( - flattenedViewsRequest.flattenedViews.map(apv => { - return ( - - - - - - ) - }) - ) - ) : ( - - - - Loading views… - - - - )} - - - ); -} - -export default ViewsTable diff --git a/src/components/AccountExplorer/index.spec.tsx b/src/components/AccountExplorer/index.spec.tsx deleted file mode 100644 index a103e26d..00000000 --- a/src/components/AccountExplorer/index.spec.tsx +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" -import * as renderer from "@testing-library/react" -import { withProviders } from "../../test-utils" -import "@testing-library/jest-dom" - -import AccountExplorer from "./index" - -describe("AccountExplorer", () => { - it("renders without error for an unauthorized user", async () => { - const { wrapped } = withProviders(, { - isLoggedIn: false, - }) - const { findByText } = renderer.render(wrapped) - - const heading = await findByText("Overview") - expect(heading).toBeVisible() - }) - describe("with an authorized user", () => { - describe("with accounts", () => { - it("selects the first account & shows it in the tree", async () => { - const { wrapped, gapi } = withProviders() - const { findByText } = renderer.render(wrapped) - await renderer.act(async () => { - await gapi!.client!.analytics!.management!.accountSummaries!.list!() - }) - const viewColumn = await findByText("View Name 1 1 1") - expect(viewColumn).toBeVisible() - }) - it("picking a view updates the table", async () => { - const { wrapped, gapi } = withProviders() - - const { findByText, findByLabelText } = renderer.render(wrapped) - await renderer.act(async () => { - await gapi!.client!.analytics!.management!.accountSummaries!.list!() - }) - await renderer.act(async () => { - // Choose the second view in the list - const viewSelect = await findByLabelText("view") - renderer.fireEvent.keyDown(viewSelect, { key: "ArrowDown" }) - renderer.fireEvent.keyDown(viewSelect, { key: "Return" }) - }) - - const viewColumn = await findByText("View Name 1 1 2") - expect(viewColumn).toBeVisible() - }) - it("searching for a view updates the table", async () => { - const { wrapped, gapi } = withProviders() - - const { findByText, findByPlaceholderText } = renderer.render(wrapped) - await renderer.act(async () => { - await gapi!.client!.analytics!.management!.accountSummaries!.list!() - }) - await renderer.act(async () => { - // Choose the second view in the list - const searchForView = await findByPlaceholderText( - "Start typing to search..." - ) - renderer.fireEvent.change(searchForView, { - target: { value: "View Name 2 1 1" }, - }) - }) - - const idColumn = await findByText("ga:view-id-2-1-1") - expect(idColumn).toBeVisible() - }) - }) - }) -}) diff --git a/src/components/AccountExplorer/index.tsx b/src/components/AccountExplorer/index.tsx deleted file mode 100644 index dcf7221d..00000000 --- a/src/components/AccountExplorer/index.tsx +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" -import { styled } from '@mui/material/styles'; -import TextField from "@mui/material/TextField" -import Typography from "@mui/material/Typography" -import Paper from "@mui/material/Paper" -import { useDebounce } from "use-debounce" - -import ViewSelector from "@/components/ViewSelector" -import ViewsTable from "./ViewTable" -import useAccountPropertyView, { - UAAccountPropertyView, -} from "../ViewSelector/useAccountPropertyView" -import { StorageKey } from "@/constants" -import useFlattenedViews from "../ViewSelector/useFlattenedViews" - -const PREFIX = 'AccountExplorer'; - -const classes = { - viewSelector: `${PREFIX}-viewSelector`, - section: `${PREFIX}-section`, - paper: `${PREFIX}-paper`, - header: `${PREFIX}-header`, - heading: `${PREFIX}-heading`, - search: `${PREFIX}-search`, - searchInput: `${PREFIX}-searchInput`, - table: `${PREFIX}-table` -}; - -const Root = styled('div')(( - { - theme - } -) => ({ - [`& .${classes.viewSelector}`]: { - marginBottom: theme.spacing(1), - }, - - [`& .${classes.section}`]: { - padding: theme.spacing(1), - }, - - [`& .${classes.paper}`]: { - padding: theme.spacing(3), - }, - - [`& .${classes.header}`]: { - margin: theme.spacing(0, 1, 0), - padding: theme.spacing(0, 1, 0), - }, - - [`& .${classes.heading}`]: { - margin: theme.spacing(2), - textAlign: "center", - }, - - [`& .${classes.search}`]: { - display: "flex", - "flex-direction": "column", - "align-items": "center", - padding: theme.spacing(0, 1, 0), - // Search title Title - }, - - [`& .${classes.searchInput}`]: { - margin: theme.spacing(1), - padding: theme.spacing(1, 1), - width: "100%", - "max-width": theme.breakpoints.values.sm, - }, - - [`& .${classes.table}`]: { - "margin-top": theme.spacing(6), - } -})); - -const containsQuery = ( - searchQuery: string, - apv: UAAccountPropertyView -): boolean => { - const pattern = new RegExp(`(${searchQuery})`, "ig") - const hasMatch = - apv.account?.name?.match(pattern) || - apv.account?.id?.match(pattern) || - apv.property?.name?.match(pattern) || - apv.property?.id?.match(pattern) || - apv.view?.name?.match(pattern) || - apv.view?.id?.match(pattern) - return !!hasMatch -} - -enum QueryParam { - Account = "a", - Property = "b", - View = "c", -} - -const AccountExplorer = () => { - - - const [searchQuery, setSearchQuery] = React.useState("") - const [debouncedQuery] = useDebounce(searchQuery, 100, { trailing: true }) - const selectedAPV = useAccountPropertyView( - StorageKey.accountExplorerAPV, - QueryParam - ) - - const filterViews = React.useCallback( - (fv: UAAccountPropertyView) => containsQuery(debouncedQuery, fv), - [debouncedQuery] - ) - - const flattenedViewsRequest = useFlattenedViews( - selectedAPV.account, - selectedAPV.property, - filterViews - ) - - return ( - ( - Overview - - Use this tool to search or browse through your accounts, properties, and - views, See what accounts you have access to, and find the IDs that you - need for the API or for another tool or service that integrates with - Google Analytics. - - -
-
- - Search for your account information… - - setSearchQuery(e.target.value)} - variant="outlined" - size="small" - /> - - …or browse through all your accounts - - - -
-
-
-
) - ); -} - -export default AccountExplorer diff --git a/src/components/CampaignURLBuilder/Web/index.tsx b/src/components/CampaignURLBuilder/Web/index.tsx index 6bada358..f8f055ea 100644 --- a/src/components/CampaignURLBuilder/Web/index.tsx +++ b/src/components/CampaignURLBuilder/Web/index.tsx @@ -137,7 +137,7 @@ export const WebURLBuilder: React.FC = ({ version }) => { return ( ( - + This tool allows you to easily add campaign parameters to URLs so you can measure {customCampaigns} in Google Analytics. diff --git a/src/components/DimensionsMetricsExplorer/ColumnGroupList.tsx b/src/components/DimensionsMetricsExplorer/ColumnGroupList.tsx deleted file mode 100644 index 48032576..00000000 --- a/src/components/DimensionsMetricsExplorer/ColumnGroupList.tsx +++ /dev/null @@ -1,532 +0,0 @@ -// Copyright 2019 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import { styled } from '@mui/material/styles'; - -import Typography from "@mui/material/Typography" -import IconButton from "@mui/material/IconButton" -import Tooltip from "@mui/material/Tooltip" -import LinkIcon from "@mui/icons-material/Link" -import Button from "@mui/material/Button" -import RemoveCircle from "@mui/icons-material/RemoveCircle" -import AddCircle from "@mui/icons-material/AddCircle" -import Info from "@mui/icons-material/Info" -import {groupBy, map, sortBy} from "lodash" -import {Set} from "immutable" -import {navigate} from "gatsby" -import classnames from "classnames" - -import {CopyIconButton} from "@/components/CopyButton" -import LabeledCheckbox from "@/components/LabeledCheckbox" -import {CUBE_NAMES, CUBES_BY_COLUMN_NAME, CubesByColumnName} from "./cubes" -import {Column} from "@/types/ua" - -const PREFIX = 'ColumnGroupList'; - -const classes = { - accordionTitle: `${PREFIX}-accordionTitle`, - expandContract: `${PREFIX}-expandContract`, - column: `${PREFIX}-column`, - columnSubgroupTitle: `${PREFIX}-columnSubgroupTitle`, - columnSubgroup: `${PREFIX}-columnSubgroup`, - deprecatedColumn: `${PREFIX}-deprecatedColumn`, - checkbox: `${PREFIX}-checkbox`, - deprecatedCheckbox: `${PREFIX}-deprecatedCheckbox`, - columnDetails: `${PREFIX}-columnDetails`, - columnLabel: `${PREFIX}-columnLabel`, - columnButton: `${PREFIX}-columnButton`, - name: `${PREFIX}-name`, - id: `${PREFIX}-id`, - popover: `${PREFIX}-popover`, - paper: `${PREFIX}-paper`, - labelText: `${PREFIX}-labelText` -}; - -const Root = styled('div')(( - { - theme - } -) => ({ - [`& .${classes.accordionTitle}`]: { margin: 0 }, - - [`& .${classes.expandContract}`]: { - margin: theme.spacing(1), - }, - - [`& .${classes.column}`]: { - display: "flex", - alignItems: "baseline", - padding: "unset", - }, - - [`& .${classes.columnSubgroupTitle}`]: { - marginBottom: theme.spacing(1), - marginTop: theme.spacing(0.5), - marginLeft: theme.spacing(-1), - "& > svg": { - marginRight: theme.spacing(1), - }, - "& > a": { - marginLeft: theme.spacing(1), - }, - display: "flex", - }, - - [`& .${classes.columnSubgroup}`]: { - marginLeft: theme.spacing(4), - marginBottom: theme.spacing(1), - }, - - [`&.${classes.deprecatedColumn}`]: { - textDecoration: "line-through", - }, - - [`& .${classes.checkbox}`]: { - padding: "unset", - paddingRight: theme.spacing(1), - }, - - [`& .${classes.deprecatedCheckbox}`]: { - padding: "unset", - paddingRight: theme.spacing(1), - visibility: "hidden", - }, - - [`& .${classes.columnDetails}`]: { - display: "flex", - flexDirection: "column", - }, - - [`&.${classes.columnLabel}`]: { - display: "flex", - alignItems: "flex-start", - flexWrap: "wrap", - position: "relative", - top: theme.spacing(-1), - }, - - [`& .${classes.columnButton}`]: { - padding: "unset", - paddingLeft: theme.spacing(1), - }, - - [`& .${classes.name}`]: { marginRight: theme.spacing(1) }, - - [`& .${classes.id}`]: { - "& > button": { - // display: "none", - padding: "unset", - paddingLeft: theme.spacing(1), - }, - // "&:hover": { - // "& > button": { - // display: "unset", - // }, - // }, - }, - - [`& .${classes.popover}`]: { - pointerEvents: "none", - }, - - [`& .${classes.paper}`]: { - padding: theme.spacing(1), - }, - - [`& .${classes.labelText}`]: { - display: "flex", - flexDirection: "row", - alignItems: "center", - } -})); - -type ColumnLabelProps = { - column: Column - isDeprecated: boolean -} -const ColumnLabel: React.FC = ({ column, isDeprecated }) => { - - const slug = React.useMemo( - () => - `/dimensions-metrics-explorer/${ - column.attributes?.group.replace(/ /g, "-").toLowerCase() || "" - }#${column.id?.replace("ga:", "")}`, - [column] - ) - - return ( - -
- - {column.attributes?.uiName} - - - {column.id} - - - - navigate(slug)} - className={classes.columnButton} - > - - - -
-
- ); -} - -const SelectableColumn: React.FC<{ - column: Column - selected: boolean - disabled: boolean - setSelected: (selected: boolean) => void -}> = ({ column, selected, disabled, setSelected }) => { - - const isDeprecated = React.useMemo( - () => column.attributes?.status !== "PUBLIC", - [column.attributes] - ) - return ( - - - - ) -} - -const ColumnSubgroup: React.FC<{ - columns: Column[] - name: "Dimensions" | "Metrics" - allowableCubes: Set - allowDeprecated: boolean - onlySegments: boolean - cubesByColumnName: CubesByColumnName - selectedColumns: Set - selectColumn: (column: string, selected: boolean) => void -}> = ({ - columns, - name, - selectColumn, - selectedColumns, - allowableCubes, - allowDeprecated, - onlySegments, - cubesByColumnName, -}) => { - - // Move deprecated columns to the bottom - const sortedColumns = React.useMemo( - () => - sortBy(columns, column => - column.attributes?.status === "PUBLIC" ? 0 : 1 - ) - .filter( - column => - (allowDeprecated && column.attributes?.status !== "PUBLIC") || - column.attributes?.status === "PUBLIC" - ) - .filter(column => { - if (onlySegments) { - return column.attributes?.allowedInSegments === "true" - } else { - return true - } - }), - [columns, allowDeprecated, onlySegments] - ) - - return ( -
- - {name} - -
- {sortedColumns.length === 0 ? ( - <>No {name}. - ) : ( - sortedColumns.map(column => { - const disabled = - allowableCubes.intersect(cubesByColumnName.get(column.id!, Set())) - .size === 0 - return ( - selectColumn(column.id!, selected)} - disabled={disabled} - selected={selectedColumns.contains(column.id!)} - /> - ) - }) - )} -
-
- ) -} - -const ColumnGroup: React.FC<{ - open: boolean - toggleOpen: () => void - name: string - columns: Column[] - onlySegments: boolean - allowDeprecated: boolean - allowableCubes: Set - cubesByColumnName: CubesByColumnName - selectedColumns: Set - selectColumn: (column: string, selected: boolean) => void -}> = ({ - open, - toggleOpen, - name, - allowDeprecated, - onlySegments, - columns, - allowableCubes, - cubesByColumnName, - selectedColumns, - selectColumn, -}) => { - - - if (!open) { - return ( - - - {name} - - ) - } else { - return ( - <> - - - {name} - - - - - - column.attributes?.type === "DIMENSION" - )} - allowableCubes={allowableCubes} - allowDeprecated={allowDeprecated} - onlySegments={onlySegments} - cubesByColumnName={cubesByColumnName} - selectColumn={selectColumn} - selectedColumns={selectedColumns} - /> - column.attributes?.type === "METRIC" - )} - allowableCubes={allowableCubes} - allowDeprecated={allowDeprecated} - onlySegments={onlySegments} - cubesByColumnName={cubesByColumnName} - selectColumn={selectColumn} - selectedColumns={selectedColumns} - /> - - ) - } -} - -const ColumnGroupList: React.FC<{ - allowDeprecated: boolean - onlySegments: boolean - columns: Column[] - searchTerms: string[] -}> = ({ allowDeprecated, onlySegments, columns, searchTerms }) => { - - const filteredColumns = React.useMemo(() => { - let filtered: Column[] = columns - - if (!allowDeprecated) { - filtered = filtered.filter( - column => column?.attributes?.status !== "DEPRECATED" - ) - } - - if (onlySegments) { - filtered = filtered.filter( - column => column?.attributes?.allowedInSegments === "true" - ) - } - - filtered = filtered.filter(column => - searchTerms.every( - term => - column?.id?.toLowerCase().indexOf(term) !== -1 || - column?.attributes?.uiName.toLowerCase().indexOf(term) !== -1 - ) - ) - - return filtered - }, [columns, searchTerms, allowDeprecated, onlySegments]) - // Group all the columns by group - const groupedColumns = React.useMemo(() => - // JS Sets guarantee insertion order is preserved, which is important - // because the key order in this groupBy determines the order that - // they appear in the UI. - { - return groupBy(filteredColumns, column => column.attributes?.group) - }, [filteredColumns]) - - // Set of column groups that are currently expanded. - const [open, setOpen] = React.useState>(() => { - return Set() - }) - - // Expand/Collapse callbacks - const toggleGroupOpen = React.useCallback( - (group: string) => - setOpen(oldOpen => - oldOpen.contains(group) ? oldOpen.remove(group) : oldOpen.add(group) - ), - [setOpen] - ) - - const collapseAll = React.useCallback(() => setOpen(Set()), [setOpen]) - - const expandAll = React.useCallback( - () => setOpen(Set.fromKeys(groupedColumns)), - [setOpen, groupedColumns] - ) - - // When a search term is entered, auto-expand all groups. - React.useEffect(() => { - if (searchTerms.length !== 0) { - expandAll() - } - }, [searchTerms.length, expandAll]) - - // selectedColumns is the set of selected columns Each column is - // associated with one or more "cubes", and a only columns that share - // cubes may be mutually selected. - const [selectedColumns, setSelectedColumns] = React.useState>( - () => Set() - ) - - const selectColumn = React.useCallback( - (column: string, selected: boolean) => - setSelectedColumns(oldSelected => - selected ? oldSelected.add(column) : oldSelected.remove(column) - ), - [setSelectedColumns] - ) - - // The set of allowable cubes. When any columns are selected, the set of - // allowable cubes is the intersection of the cubes for those columns - const allowableCubes = React.useMemo>( - () => - selectedColumns - .map( - columnId => - CUBES_BY_COLUMN_NAME.get(columnId!) || (Set() as Set) - ) - .reduce((cubes1, cubes2) => cubes1!.intersect(cubes2!), CUBE_NAMES), - [selectedColumns] - ) - - let showExpandAll = open.size < Object.keys(groupedColumns).length - let showCollapseAll = open.size > 0 - return ( - -
-
- {showExpandAll ? ( - - ) : null} - {showCollapseAll ? ( - - ) : null} -
-
- {map(groupedColumns, (columns, groupName) => ( - toggleGroupOpen(groupName)} - allowableCubes={allowableCubes} - cubesByColumnName={CUBES_BY_COLUMN_NAME} - selectedColumns={selectedColumns} - selectColumn={selectColumn} - /> - ))} -
-
-
- ) -} - -export default ColumnGroupList diff --git a/src/components/DimensionsMetricsExplorer/Explorer.tsx b/src/components/DimensionsMetricsExplorer/Explorer.tsx deleted file mode 100644 index a1e0fae8..00000000 --- a/src/components/DimensionsMetricsExplorer/Explorer.tsx +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2019 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import { styled } from '@mui/material/styles'; - -import TextField from "@mui/material/TextField" -import IconButton from "@mui/material/IconButton" -import Clear from "@mui/icons-material/Clear" -import { useDebounce } from "use-debounce" - -import { StorageKey } from "@/constants" -import { Dispatch, failed, inProgress, notStarted, successful } from "@/types" -import LabeledCheckbox from "@/components/LabeledCheckbox" -import { usePersistentBoolean, usePersistentString } from "../../hooks" -import ColumnGroupList from "./ColumnGroupList" -import useAnchorRedirects from "./useAnchorRedirects" -import useColumns from "./useColumns" -import { Typography } from "@mui/material" -import PrettyJson from "../PrettyJson" - -const PREFIX = 'Explorer'; - -const classes = { - search: `${PREFIX}-search`, - searchInput: `${PREFIX}-searchInput` -}; - -const Root = styled('div')(( - { - theme - } -) => ({ - [`& .${classes.search}`]: { - display: "flex", - flexDirection: "column", - "&> label": { - margin: theme.spacing(0), - marginTop: theme.spacing(-0.5), - marginBottom: theme.spacing(-1), - }, - }, - - [`& .${classes.searchInput}`]: { - maxWidth: theme.spacing(60), - } -})); - -const Search: React.FC<{ - searchText: string | undefined - setSearchText: Dispatch - onlySegments: boolean - setOnlySegments: Dispatch - allowDeprecated: boolean - setAllowDeprecated: Dispatch -}> = ({ - searchText, - setSearchText, - onlySegments, - setOnlySegments, - allowDeprecated, - setAllowDeprecated, -}) => { - - return ( -
- setSearchText(e.target.value)} - InputProps={{ - endAdornment: ( - setSearchText("")}> - - - ), - }} - /> - - Only show fields that are allowed in segments - - - Include deprecated fields - -
- ) -} - -const Explorer: React.FC = () => { - const [searchText, setSearchText] = usePersistentString( - StorageKey.dimensionsMetricsExplorerSearch, - "" - ) - const [allowDeprecated, setAllowDeprecated] = usePersistentBoolean( - StorageKey.dimensionsMetricsExplorerAllowDeprecated, - false - ) - const [onlySegments, setOnlySegments] = usePersistentBoolean( - StorageKey.dimensionsMetricsExplorerOnlySegments, - false - ) - - const searchTerms = React.useMemo( - () => - searchText - ?.toLowerCase() - .split(/\s+/) - .filter(term => term.length > 0), - [searchText] - ) - - const [throttledSearch] = useDebounce(searchTerms, 100, { trailing: true }) - - const columnsRequest = useColumns() - - useAnchorRedirects(successful(columnsRequest)?.columns) - - return ( - - - {successful(columnsRequest) && ( - - )} - {(inProgress(columnsRequest) || notStarted(columnsRequest)) && ( -
Loading dimensions and metrics...
- )} - {failed(columnsRequest) && ( -
- There was an error calling the api. - Details: - -
- )} -
- ); -} - -export default Explorer diff --git a/src/components/DimensionsMetricsExplorer/GroupInfoTemplate.tsx b/src/components/DimensionsMetricsExplorer/GroupInfoTemplate.tsx deleted file mode 100644 index aea25e36..00000000 --- a/src/components/DimensionsMetricsExplorer/GroupInfoTemplate.tsx +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import { styled } from '@mui/material/styles'; - -import Typography from "@mui/material/Typography" -import Chip from "@mui/material/Chip" -import ArrowBack from "@mui/icons-material/ArrowBack" -import LinkIcon from "@mui/icons-material/Link" -import classnames from "classnames" -import { Link } from "gatsby" -import { sortBy } from "lodash" - -import Layout from "@/components/Layout" -import { CopyIconButton } from "@/components/CopyButton" -import { Column } from "./common-types" - -const PREFIX = 'GroupInfoTemplate'; - -const classes = { - deprecatedText: `${PREFIX}-deprecatedText`, - returnLink: `${PREFIX}-returnLink`, - columnHeading: `${PREFIX}-columnHeading`, - chips: `${PREFIX}-chips`, - linkIcon: `${PREFIX}-linkIcon` -}; - -const StyledLayout = styled(Layout)(( - { - theme - } -) => ({ - [`& .${classes.deprecatedText}`]: { - textDecoration: "line-through", - }, - - [`& .${classes.returnLink}`]: { - display: "flex", - alignItems: "center", - "& svg": { - marginRight: theme.spacing(1), - }, - }, - - [`& .${classes.columnHeading}`]: { - marginBottom: theme.spacing(1), - display: "flex", - alignItems: "baseline", - "&> span": { - marginLeft: theme.spacing(1), - }, - }, - - [`& .${classes.chips}`]: { - "& div": { - marginRight: theme.spacing(1), - }, - marginBottom: theme.spacing(1), - }, - - [`& .${classes.linkIcon}`]: { - alignSelf: "center", - marginLeft: theme.spacing(1), - } -})); - -type GroupInfoTemplateProps = { - pageContext: { - groupName: string - dimensions: Column[] - metrics: Column[] - } -} - -type ColumnProps = { - column: Column -} - -const ColumnInfo: React.FC = ({ - column: { attributes }, - column, -}) => { - // TODO make the uiName be linkAble - - return ( -
- - - {attributes?.uiName}{" "} - - {column.id}{" "} - - - - -
- - {attributes?.addedInApiVersion === "3" ? ( - - ) : attributes?.addedInApiVersion === "4" ? ( - - ) : null} -
- {attributes?.status === "DEPRECATED" && ( - - This field is deprecated and should no longer be used. - - )} - {attributes?.description} - {!attributes?.allowedInSegments && ( - - This field is disallowed in segments. - - )} -
- ) -} - -const GroupInfoTemplate: React.FC< - GroupInfoTemplateProps & { location: { pathname: string } } -> = ({ - pageContext: { groupName, dimensions, metrics }, - location: { pathname }, -}) => { - - return ( - - - {groupName} group - - - - - - Dimensions & Metrics Explorer - - Dimensions - {sortBy(dimensions, column => - column.attributes?.status === "PUBLIC" ? 0 : 1 - ).map(item => ( - - ))} - Metrics - {sortBy(metrics, column => - column.attributes?.status === "PUBLIC" ? 0 : 1 - ).map(item => ( - - ))} - - ); -} -export default GroupInfoTemplate diff --git a/src/components/DimensionsMetricsExplorer/common-types.ts b/src/components/DimensionsMetricsExplorer/common-types.ts deleted file mode 100644 index 248a5cae..00000000 --- a/src/components/DimensionsMetricsExplorer/common-types.ts +++ /dev/null @@ -1,52 +0,0 @@ -interface CommonAttributes { - group: string; - uiName: string; - description: string; - allowedInSegments?: "true" | "false"; - addedInApiVersion: number | string; -} - -interface DimensionAttributes { - type: "DIMENSION"; - dataType: "STRING"; -} - -interface MetricAttributes { - type: "METRIC"; - dataType: "INTEGER" | "PERCENT" | "TIME" | "CURRENCY" | "FLOAT"; - calculation?: string; -} - -interface DeprecatedAttributes { - replacedBy: string; - status: "DEPRECATED"; -} - -interface PublicAttributes { - status: "PUBLIC"; -} - -interface TemplateAttributes { - minTemplateIndex: number; - maxTemplateIndex: number; -} - -interface PremiumTemplateAttributes extends TemplateAttributes { - premiumMinTemplateIndex: number; - premiumMaxTemplateIndex: number; -} - -type Attributes = CommonAttributes & - (DimensionAttributes | MetricAttributes) & - (DeprecatedAttributes | PublicAttributes) & - ({} | TemplateAttributes | PremiumTemplateAttributes); - -// A single Dimension or Metric -export interface Column { - id: string; - kind: string; - attributes: Attributes; -} - -// Columns grouped by group -export type Groups = { [key: string]: Column[] }; diff --git a/src/components/DimensionsMetricsExplorer/cubes.ts b/src/components/DimensionsMetricsExplorer/cubes.ts deleted file mode 100644 index 0a70cbd1..00000000 --- a/src/components/DimensionsMetricsExplorer/cubes.ts +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import { reduce } from "lodash" -import { Set, Map } from "immutable" -// TODO - If time allows, this file should be processed at build time instead -// of runtime. -import CUBES from "./ga_cubes.json" - -// The ga_cubes.json file is a mapping of cubes to column names. The -// format looks like this: -// -// { cube: {column1: 1, column2: 1}} -// -// In other words, each set of columns is an object where the keys are -// column names and the values are meaningless placeholders -export type Cubes = { [cube: string]: { [column: string]: any } } - -// Mapping of Column names to sets of cubes -export type CubesByColumnName = Map> - -// Take the Cubes format and invert it to instead be a map of column names to a -// set of cubes. -// -// In the demo, a user checks a column and the UI updates other columns based -// on compatability (they are disabled if they are incompatable). Since only -// columns that share a cube can be queried together, this means only columns -// that share a cube are compatable with each other. -export const CUBES_BY_COLUMN_NAME: CubesByColumnName = reduce( - CUBES, - (cubesByColumn, columnList, cubeName) => - reduce( - columnList, - (cubesByColumn, _, columnName) => - cubesByColumn.update(columnName, Set(), cubes => cubes.add(cubeName)), - cubesByColumn - ), - Map() -) - -export const CUBE_NAMES: Set = Set.fromKeys(CUBES) diff --git a/src/components/DimensionsMetricsExplorer/ga_cubes.json b/src/components/DimensionsMetricsExplorer/ga_cubes.json deleted file mode 100644 index a24e9755..00000000 --- a/src/components/DimensionsMetricsExplorer/ga_cubes.json +++ /dev/null @@ -1,9603 +0,0 @@ -{ - "Cube:analytics/per_ecommerce_refund_import_without_transaction_product_dimensions": { - "ga:transactionId": 1, - "ga:quantityRefunded": 1, - "ga:transactionRevenue": 1 - }, - "per_campaign_content": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:referralPath": 1, - "ga:metroId": 1, - "ga:percentNewSessions": 1, - "ga:backfillClicks": 1, - "ga:avgServerConnectionTime": 1, - "ga:newUsers": 1, - "ga:dcmClickSite": 1, - "ga:dbmClickLineItemId": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:dsAdvertiserId": 1, - "ga:flashVersion": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:internalPromotionId": 1, - "ga:searchDestinationPage": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dsEngineAccount": 1, - "ga:adwordsCreativeID": 1, - "ga:networkLocation": 1, - "ga:dfpCoverage": 1, - "ga:sourceMedium": 1, - "ga:pageLoadSample": 1, - "ga:pageDepth": 1, - "ga:landingContentGroup4": 1, - "ga:landingContentGroup3": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:sessions": 1, - "ga:landingContentGroup2": 1, - "ga:landingContentGroup1": 1, - "ga:previousPagePath": 1, - "ga:dbmClickSite": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:dcmClickSpotId": 1, - "ga:landingContentGroup5": 1, - "ga:adsenseCoverage": 1, - "ga:screenResolution": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:avgScreenviewDuration": 1, - "ga:socialActivityContentUrl": 1, - "ga:source": 1, - "ga:percentSearchRefinements": 1, - "ga:dsAdGroup": 1, - "ga:networkDomain": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmClickCreativeId": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:screenName": 1, - "ga:internalPromotionCreative": 1, - "ga:transactionRevenue": 1, - "ga:adSlot": 1, - "ga:secondPagePath": 1, - "ga:entranceRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:searchUsed": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:dfpLineItemId": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:avgDomainLookupTime": 1, - "ga:dbmClickInsertionOrder": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:dcmClickCreativeType": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:internalPromotionName": 1, - "ga:dbmClickLineItem": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:cityId": 1, - "ga:organicSearches": 1, - "ga:searchKeywordRefinement": 1, - "ga:landingScreenName": 1, - "ga:isTrueViewVideoAd": 1, - "ga:dbmClickAdvertiser": 1, - "ga:dcmFloodlightSpotId": 1, - "ga:previousContentGroup1": 1, - "ga:searchKeyword": 1, - "ga:previousContentGroup2": 1, - "ga:adsenseECPM": 1, - "ga:previousContentGroup3": 1, - "ga:adxImpressionsPerSession": 1, - "ga:previousContentGroup4": 1, - "ga:searchRefinements": 1, - "ga:dcmFloodlightActivity": 1, - "ga:appName": 1, - "ga:dsAdvertiser": 1, - "ga:latitude": 1, - "ga:nthMonth": 1, - "ga:previousContentGroup5": 1, - "ga:avgTimeOnPage": 1, - "ga:sourcePropertyTrackingId": 1, - "ga:adxCTR": 1, - "ga:continentId": 1, - "ga:deviceCategory": 1, - "ga:dcmClickSitePlacement": 1, - "ga:dbmClickCreativeId": 1, - "ga:nthWeek": 1, - "ga:dsCampaign": 1, - "ga:interestInMarketCategory": 1, - "ga:adMatchType": 1, - "ga:adwordsCustomerID": 1, - "ga:totalPublisherRevenue": 1, - "ga:userAgeBracket": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:dcmFloodlightActivityGroup": 1, - "ga:trafficType": 1, - "ga:avgDomInteractiveTime": 1, - "ga:adsenseRevenue": 1, - "ga:continent": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:customVarValueXX": 1, - "ga:landingPagePath": 1, - "ga:channelGrouping": 1, - "ga:searchCategory": 1, - "ga:dfpRevenue": 1, - "ga:adwordsCustomerName": 1, - "ga:dsCampaignId": 1, - "ga:mobileDeviceInfo": 1, - "ga:keyword": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:contentGroup1": 1, - "ga:contentGroup2": 1, - "ga:contentGroup3": 1, - "ga:contentGroup4": 1, - "ga:contentGroup5": 1, - "ga:dbmClickExchange": 1, - "ga:goalCompletionsAll": 1, - "ga:dcmClickCreativeTypeId": 1, - "ga:language": 1, - "ga:adsenseAdsClicks": 1, - "ga:searchAfterDestinationPage": 1, - "ga:isMobile": 1, - "ga:searchResultViews": 1, - "ga:exitScreenName": 1, - "ga:totalPublisherECPM": 1, - "ga:internalPromotionPosition": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:socialNetwork": 1, - "ga:dbmClickExchangeId": 1, - "ga:dsKeyword": 1, - "ga:adDistributionNetwork": 1, - "ga:userBucket": 1, - "ga:domInteractiveTime": 1, - "ga:dsKeywordId": 1, - "ga:percentSessionsWithSearch": 1, - "ga:longitude": 1, - "ga:dcmClickAdTypeId": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:mobileInputSelector": 1, - "ga:timeOnScreen": 1, - "ga:shoppingStage": 1, - "ga:adGroup": 1, - "ga:week": 1, - "ga:dcmClickCampaign": 1, - "ga:sourcePropertyDisplayName": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dbmClickAdvertiserId": 1, - "ga:hour": 1, - "ga:adQueryWordCount": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:dbmClickCreativeName": 1, - "ga:searchStartPage": 1, - "ga:domContentLoadedTime": 1, - "ga:nextPagePath": 1, - "ga:dcmClickSitePlacementId": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:contentGroupUniqueViews2": 1, - "ga:contentGroupUniqueViews1": 1, - "ga:adTargetingType": 1, - "ga:screenDepth": 1, - "ga:uniqueEvents": 1, - "ga:contentGroupUniqueViews5": 1, - "ga:users": 1, - "ga:contentGroupUniqueViews4": 1, - "ga:appInstallerId": 1, - "ga:contentGroupUniqueViews3": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:dcmClickRenderingId": 1, - "ga:adKeywordMatchType": 1, - "ga:searchDepth": 1, - "ga:subContinent": 1, - "ga:adsenseExits": 1, - "ga:appId": 1, - "ga:checkoutOptions": 1, - "ga:internalPromotionCTR": 1, - "ga:daysSinceLastSession": 1, - "ga:pageviews": 1, - "ga:userType": 1, - "ga:dcmClickCreative": 1, - "ga:sessionCount": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:dcmClickSiteId": 1, - "ga:externalActivityId": 1, - "ga:dbmClickSiteId": 1, - "ga:speedMetricsSample": 1, - "ga:dcmClickCreativeVersion": 1, - "ga:browserSize": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:minute": 1, - "ga:dcmFloodlightActivityGroupId": 1, - "ga:year": 1, - "ga:exitPagePath": 1, - "ga:sessionsPerUser": 1, - "ga:adTargetingOption": 1, - "ga:entranceBounceRate": 1, - "ga:customVarNameXX": 1, - "ga:transactionsPerSession": 1, - "ga:appVersion": 1, - "ga:dcmClickAdvertiserId": 1, - "ga:pageDownloadTime": 1, - "ga:dcmFloodlightActivityAndGroup": 1, - "ga:country": 1, - "ga:goalValueAll": 1, - "ga:userGender": 1, - "ga:pagePath": 1, - "ga:dcmClickCampaignId": 1, - "ga:adMatchedQuery": 1, - "ga:totalPublisherImpressions": 1, - "ga:dsAdGroupId": 1, - "ga:totalValue": 1, - "ga:hasSocialSourceReferral": 1, - "ga:browserVersion": 1, - "ga:adsenseAdsViewed": 1, - "ga:nthMinute": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:operatingSystemVersion": 1, - "ga:mobileDeviceMarketingName": 1, - "ga:totalPublisherCoverage": 1, - "ga:sessionDurationBucket": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:dateHourMinute": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:adDisplayUrl": 1, - "ga:transactionsPerUser": 1, - "ga:dcmClickAdType": 1, - "ga:metro": 1, - "ga:internalPromotionClicks": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:city": 1, - "ga:domLatencyMetricsSample": 1, - "ga:transactions": 1, - "ga:countryIsoCode": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dsAgency": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:clientId": 1, - "ga:dcmFloodlightActivityId": 1, - "ga:searchSessions": 1, - "ga:fullReferrer": 1, - "ga:dfpLineItemName": 1, - "ga:dcmClickAdvertiser": 1, - "ga:nextContentGroup1": 1, - "ga:hostname": 1, - "ga:nextContentGroup2": 1, - "ga:nextContentGroup3": 1, - "ga:nextContentGroup4": 1, - "ga:sessionDuration": 1, - "ga:adxECPM": 1, - "ga:nextContentGroup5": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:interestOtherCategory": 1, - "ga:adContent": 1, - "ga:internalPromotionViews": 1, - "ga:dataSource": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:pageTitle": 1, - "ga:userDefinedValue": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:dsEngineAccountId": 1, - "ga:adPlacementDomain": 1, - "ga:backfillRevenue": 1, - "ga:subContinentCode": 1, - "ga:mobileDeviceModel": 1, - "ga:adFormat": 1, - "ga:adwordsCriteriaID": 1, - "ga:date": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:javaEnabled": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:medium": 1, - "ga:adDestinationUrl": 1, - "ga:region": 1, - "ga:pagePathLevel4": 1, - "ga:pagePathLevel1": 1, - "ga:dcmClickAdId": 1, - "ga:searchDuration": 1, - "ga:pagePathLevel3": 1, - "ga:backfillImpressions": 1, - "ga:dcmClickAd": 1, - "ga:pagePathLevel2": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dsAgencyId": 1, - "ga:dayOfWeekName": 1, - "ga:adsensePageImpressions": 1, - "ga:mobileDeviceBranding": 1, - "ga:avgRedirectionTime": 1, - "ga:pageLoadTime": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:dcmFloodlightAdvertiserId": 1, - "ga:browser": 1, - "ga:transactionRevenuePerSession": 1, - "ga:interestAffinityCategory": 1, - "ga:regionId": 1, - "ga:adPlacementUrl": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:dbmClickInsertionOrderId": 1, - "ga:totalPublisherCTR": 1, - "ga:campaignCode": 1 - }, - "audience_size": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:metroId": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:flashVersion": 1, - "ga:backfillCTR": 1, - "ga:internalPromotionId": 1, - "ga:searchDestinationPage": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:adwordsCreativeID": 1, - "ga:networkLocation": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:experimentName": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:pageDepth": 1, - "ga:landingContentGroup4": 1, - "ga:landingContentGroup3": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:landingContentGroup2": 1, - "ga:landingContentGroup1": 1, - "ga:previousPagePath": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:landingContentGroup5": 1, - "ga:adsenseCoverage": 1, - "ga:screenResolution": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:userTimingCategory": 1, - "ga:percentSearchRefinements": 1, - "ga:experimentOutcomeType": 1, - "ga:networkDomain": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:screenName": 1, - "ga:productRemovesFromCart": 1, - "ga:internalPromotionCreative": 1, - "ga:transactionRevenue": 1, - "ga:secondPagePath": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:dfpLineItemId": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:socialInteractionNetworkAction": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:internalPromotionName": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:cityId": 1, - "ga:organicSearches": 1, - "ga:landingScreenName": 1, - "ga:previousContentGroup1": 1, - "ga:previousContentGroup2": 1, - "ga:adsenseECPM": 1, - "ga:previousContentGroup3": 1, - "ga:adxImpressionsPerSession": 1, - "ga:previousContentGroup4": 1, - "ga:searchRefinements": 1, - "ga:appName": 1, - "ga:quantityRefunded": 1, - "ga:latitude": 1, - "ga:previousContentGroup5": 1, - "ga:avgTimeOnPage": 1, - "ga:sourcePropertyTrackingId": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:continentId": 1, - "ga:deviceCategory": 1, - "ga:interestInMarketCategory": 1, - "ga:adMatchType": 1, - "ga:adwordsCustomerID": 1, - "ga:totalPublisherRevenue": 1, - "ga:userAgeBracket": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:continent": 1, - "ga:goalXXAbandons": 1, - "ga:customVarValueXX": 1, - "ga:landingPagePath": 1, - "ga:dfpRevenue": 1, - "ga:adwordsCustomerName": 1, - "ga:mobileDeviceInfo": 1, - "ga:pageviewsPerSession": 1, - "ga:adwordsAdGroupID": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:contentGroup1": 1, - "ga:contentGroup2": 1, - "ga:socialInteractionAction": 1, - "ga:contentGroup3": 1, - "ga:contentGroup4": 1, - "ga:contentGroup5": 1, - "ga:socialInteractionNetwork": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:language": 1, - "ga:adsenseAdsClicks": 1, - "ga:searchAfterDestinationPage": 1, - "ga:socialInteractions": 1, - "ga:userTimingLabel": 1, - "ga:experimentVariant": 1, - "ga:isMobile": 1, - "ga:searchResultViews": 1, - "ga:exitScreenName": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:internalPromotionPosition": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:adDistributionNetwork": 1, - "ga:domInteractiveTime": 1, - "ga:socialEngagementType": 1, - "ga:percentSessionsWithSearch": 1, - "ga:longitude": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:mobileInputSelector": 1, - "ga:timeOnScreen": 1, - "ga:shoppingStage": 1, - "ga:experimentCombination": 1, - "ga:sourcePropertyDisplayName": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:nextPagePath": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:contentGroupUniqueViews2": 1, - "ga:contentGroupUniqueViews1": 1, - "ga:adTargetingType": 1, - "ga:screenDepth": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:contentGroupUniqueViews5": 1, - "ga:contentGroupUniqueViews4": 1, - "ga:appInstallerId": 1, - "ga:contentGroupUniqueViews3": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:adKeywordMatchType": 1, - "ga:searchDepth": 1, - "ga:subContinent": 1, - "ga:adsenseExits": 1, - "ga:appId": 1, - "ga:checkoutOptions": 1, - "ga:internalPromotionCTR": 1, - "ga:pageviews": 1, - "ga:userTimingVariable": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:browserSize": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:exitPagePath": 1, - "ga:sessionsPerUser": 1, - "ga:adTargetingOption": 1, - "ga:entranceBounceRate": 1, - "ga:customVarNameXX": 1, - "ga:previousPageLinkId": 1, - "ga:quantityRemovedFromCart": 1, - "ga:socialInteractionTarget": 1, - "ga:transactionsPerSession": 1, - "ga:appVersion": 1, - "ga:pageDownloadTime": 1, - "ga:country": 1, - "ga:goalValueAll": 1, - "ga:userGender": 1, - "ga:pagePath": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:browserVersion": 1, - "ga:adsenseAdsViewed": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:operatingSystemVersion": 1, - "ga:mobileDeviceMarketingName": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:experimentId": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:adDisplayUrl": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:metro": 1, - "ga:internalPromotionClicks": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:city": 1, - "ga:domLatencyMetricsSample": 1, - "ga:transactions": 1, - "ga:countryIsoCode": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:searchSessions": 1, - "ga:dfpLineItemName": 1, - "ga:productRefunds": 1, - "ga:socialInteractionNetworkActionSession": 1, - "ga:nextContentGroup1": 1, - "ga:hostname": 1, - "ga:nextContentGroup2": 1, - "ga:nextContentGroup3": 1, - "ga:nextContentGroup4": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:nextContentGroup5": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:interestOtherCategory": 1, - "ga:internalPromotionViews": 1, - "ga:dataSource": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:pageTitle": 1, - "ga:userDefinedValue": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:adPlacementDomain": 1, - "ga:backfillRevenue": 1, - "ga:subContinentCode": 1, - "ga:mobileDeviceModel": 1, - "ga:adFormat": 1, - "ga:adwordsCriteriaID": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:userTimingValue": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:javaEnabled": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:adDestinationUrl": 1, - "ga:region": 1, - "ga:pagePathLevel4": 1, - "ga:quantityAddedToCart": 1, - "ga:pagePathLevel1": 1, - "ga:searchDuration": 1, - "ga:pagePathLevel3": 1, - "ga:backfillImpressions": 1, - "ga:pagePathLevel2": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:adsensePageImpressions": 1, - "ga:mobileDeviceBranding": 1, - "ga:avgRedirectionTime": 1, - "ga:pageLoadTime": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:browser": 1, - "ga:transactionRevenuePerSession": 1, - "ga:interestAffinityCategory": 1, - "ga:regionId": 1, - "ga:adPlacementUrl": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_cost_data_import": { - "ga:adGroup": 1, - "ga:referralPath": 1, - "ga:adwordsCampaignID": 1, - "ga:CPC": 1, - "ga:adDisplayUrl": 1, - "ga:adwordsCriteriaID": 1, - "ga:impressions": 1, - "ga:adSlotPosition": 1, - "ga:adContent": 1, - "ga:source": 1, - "ga:campaign": 1, - "ga:adSlot": 1, - "ga:CTR": 1, - "ga:CPM": 1, - "ga:medium": 1, - "ga:adDestinationUrl": 1, - "ga:keyword": 1, - "ga:adCost": 1, - "ga:adClicks": 1 - }, - "per_content_id_dimension_widening": { - "ga:dimensionXX": 1, - "ga:pagePath": 1, - "ga:metricXX": 1 - }, - "per_active_visitors_date_active_visitors_28": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:28dayUsers": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "cohorts_overview_nth_week": { - "ga:acquisitionTrafficChannel": 1, - "ga:acquisitionSource": 1, - "ga:cohortRevenuePerUser": 1, - "ga:avgSessionDuration": 1, - "ga:cohortActiveUsers": 1, - "ga:cohortTotalUsersWithLifetimeCriteria": 1, - "ga:goalCompletionsAll": 1, - "ga:transactions": 1, - "ga:transactionRevenue": 1, - "ga:cohortSessionsPerUserWithLifetimeCriteria": 1, - "ga:cohort": 1, - "ga:goalConversionRateAll": 1, - "ga:cohortGoalCompletionsPerUserWithLifetimeCriteria": 1, - "ga:cohortGoalCompletionsPerUser": 1, - "ga:acquisitionMedium": 1, - "ga:transactionsPerSession": 1, - "ga:cohortRevenuePerUserWithLifetimeCriteria": 1, - "ga:cohortSessionDurationPerUserWithLifetimeCriteria": 1, - "ga:cohortPageviewsPerUser": 1, - "ga:cohortTotalUsers": 1, - "ga:cohortNthWeek": 1, - "ga:acquisitionCampaign": 1, - "ga:sessions": 1, - "ga:cohortRetentionRate": 1, - "ga:acquisitionSourceMedium": 1, - "ga:cohortAppviewsPerUser": 1, - "ga:cohortSessionsPerUser": 1, - "ga:sessionDuration": 1, - "ga:cohortPageviewsPerUserWithLifetimeCriteria": 1, - "ga:screenviews": 1, - "ga:pageviews": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:transactionRevenuePerSession": 1, - "ga:cohortSessionDurationPerUser": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:pageviewsPerSession": 1, - "ga:cohortAppviewsPerUserWithLifetimeCriteria": 1 - }, - "per_social": { - "ga:month": 1, - "ga:yearWeek": 1, - "ga:week": 1, - "ga:date": 1, - "ga:dayOfWeekName": 1, - "ga:nthMonth": 1, - "ga:day": 1, - "ga:yearMonth": 1, - "ga:year": 1, - "ga:socialNetwork": 1, - "ga:hour": 1, - "ga:socialActivityContentUrl": 1, - "ga:isoYearIsoWeek": 1, - "ga:isoYear": 1, - "ga:nthWeek": 1, - "ga:nthDay": 1, - "ga:isoWeek": 1, - "ga:nthHour": 1, - "ga:dateHour": 1, - "ga:dayOfWeek": 1 - }, - "per_geo_dimension_widening": { - "ga:dimensionXX": 1, - "ga:countryIsoCode": 1, - "ga:subContinentCode": 1, - "ga:cityId": 1, - "ga:regionId": 1 - }, - "per_campaign_id_dimension_widening": { - "ga:dimensionXX": 1, - "ga:adGroup": 1, - "ga:campaign": 1, - "ga:referralPath": 1, - "ga:medium": 1, - "ga:metricXX": 1, - "ga:keyword": 1, - "ga:adContent": 1, - "ga:source": 1, - "ga:campaignCode": 1 - }, - "per_wmx_site": { - "ga:country": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:week": 1, - "ga:date": 1, - "ga:adMatchedQuery": 1, - "ga:dayOfWeekName": 1, - "ga:nthMonth": 1, - "ga:day": 1, - "ga:yearMonth": 1, - "ga:year": 1, - "ga:deviceCategory": 1, - "ga:source": 1, - "ga:countryIsoCode": 1, - "ga:nthWeek": 1, - "ga:nthDay": 1, - "ga:medium": 1, - "ga:users": 1, - "ga:sourceMedium": 1, - "ga:dayOfWeek": 1 - }, - "per_ecommerce_dimension_widening": { - "ga:productVariant": 1, - "ga:dimensionXX": 1, - "ga:productBrand": 1, - "ga:metricXX": 1, - "ga:productSku": 1, - "ga:productCategoryHierarchy": 1, - "ga:productName": 1 - }, - "per_absolute_unique_visitors": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:percentNewSessions": 1, - "ga:backfillClicks": 1, - "ga:week": 1, - "ga:newUsers": 1, - "ga:hour": 1, - "ga:adxMonetizedPageviews": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:dfpCoverage": 1, - "ga:users": 1, - "ga:appInstallerId": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:adsenseExits": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:sessions": 1, - "ga:appId": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:screenviews": 1, - "ga:avgScreenviewDuration": 1, - "ga:pageviews": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:nthDay": 1, - "ga:entrances": 1, - "ga:totalPublisherClicks": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:year": 1, - "ga:transactionRevenue": 1, - "ga:sessionsPerUser": 1, - "ga:entranceBounceRate": 1, - "ga:entranceRate": 1, - "ga:transactionsPerSession": 1, - "ga:appVersion": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:totalPublisherImpressions": 1, - "ga:adsenseAdsViewed": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:appName": 1, - "ga:transactionsPerUser": 1, - "ga:nthMonth": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:avgTimeOnPage": 1, - "ga:adxCTR": 1, - "ga:transactions": 1, - "ga:goalConversionRateAll": 1, - "ga:nthWeek": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:totalPublisherRevenue": 1, - "ga:uniqueSocialInteractions": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:sessionDuration": 1, - "ga:adxECPM": 1, - "ga:adsenseRevenue": 1, - "ga:isoYear": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:dayOfWeek": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:goalCompletionsAll": 1, - "ga:adsenseAdsClicks": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:socialInteractions": 1, - "ga:backfillImpressions": 1, - "ga:month": 1, - "ga:totalPublisherECPM": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:bounces": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:adsensePageImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:transactionRevenuePerSession": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1, - "ga:timeOnScreen": 1 - }, - "individual_user_report": { - "ga:acquisitionTrafficChannel": 1, - "ga:subContinentCode": 1, - "ga:goalValuePerSession": 1, - "ga:metroId": 1, - "ga:acquisitionSource": 1, - "ga:metro": 1, - "ga:latitude": 1, - "ga:avgSessionDuration": 1, - "ga:city": 1, - "ga:deviceCategory": 1, - "ga:continentId": 1, - "ga:transactions": 1, - "ga:transactionRevenue": 1, - "ga:goalCompletionsAll": 1, - "ga:countryIsoCode": 1, - "ga:goalConversionRateAll": 1, - "ga:acquisitionMedium": 1, - "ga:clientId": 1, - "ga:region": 1, - "ga:transactionsPerSession": 1, - "ga:networkLocation": 1, - "ga:goalXXValue": 1, - "ga:country": 1, - "ga:goalXXConversionRate": 1, - "ga:goalValueAll": 1, - "ga:subContinent": 1, - "ga:acquisitionCampaign": 1, - "ga:bounces": 1, - "ga:sessions": 1, - "ga:acquisitionSourceMedium": 1, - "ga:totalValue": 1, - "ga:sessionDuration": 1, - "ga:goalXXCompletions": 1, - "ga:screenviews": 1, - "ga:regionIsoCode": 1, - "ga:continent": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:pageviews": 1, - "ga:dimensionXX": 1, - "ga:networkDomain": 1, - "ga:cityId": 1, - "ga:bounceRate": 1, - "ga:transactionRevenuePerSession": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:pageviewsPerSession": 1, - "ga:longitude": 1, - "ga:regionId": 1 - }, - "per_active_visitors_day_active_visitors_14": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:14dayUsers": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_campaign_segmented_with_local_currency": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:referralPath": 1, - "ga:transactionTax": 1, - "ga:percentNewSessions": 1, - "ga:backfillClicks": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:adxMonetizedPageviews": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:goalStartsAll": 1, - "ga:dfpCoverage": 1, - "ga:localRefundAmount": 1, - "ga:goalXXValue": 1, - "ga:sourceMedium": 1, - "ga:uniquePurchases": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:sessions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:source": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:localTransactionShipping": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:productRemovesFromCart": 1, - "ga:transactionRevenue": 1, - "ga:adSlot": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:localProductRefundAmount": 1, - "ga:organicSearches": 1, - "ga:isTrueViewVideoAd": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:appName": 1, - "ga:quantityRefunded": 1, - "ga:nthMonth": 1, - "ga:avgTimeOnPage": 1, - "ga:adxCTR": 1, - "ga:goalXXAbandonRate": 1, - "ga:nthWeek": 1, - "ga:totalPublisherRevenue": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:trafficType": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXCompletions": 1, - "ga:goalXXAbandons": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:channelGrouping": 1, - "ga:dfpRevenue": 1, - "ga:keyword": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:localItemRevenue": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:adsenseAdsClicks": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:socialNetwork": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:percentSessionsWithSearch": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:adGroup": 1, - "ga:localTransactionTax": 1, - "ga:week": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:appInstallerId": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:adsenseExits": 1, - "ga:appId": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:searchExits": 1, - "ga:externalActivityId": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:adSlotPosition": 1, - "ga:year": 1, - "ga:sessionsPerUser": 1, - "ga:adTargetingOption": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:appVersion": 1, - "ga:goalValueAll": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:searchSessions": 1, - "ga:fullReferrer": 1, - "ga:productRefunds": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:adContent": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:adPlacementDomain": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:localTransactionRevenue": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:medium": 1, - "ga:adDestinationUrl": 1, - "ga:quantityAddedToCart": 1, - "ga:currencyCode": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:adsensePageImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:transactionRevenuePerSession": 1, - "ga:adPlacementUrl": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1, - "ga:campaignCode": 1 - }, - "gwo_bandit_combination_metrics": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:experimentCombination": 1, - "ga:percentNewSessions": 1, - "ga:backfillClicks": 1, - "ga:newUsers": 1, - "ga:goalValueAllPerSearch": 1, - "ga:adxMonetizedPageviews": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:refundAmount": 1, - "ga:experimentName": 1, - "ga:searchDepth": 1, - "ga:adsenseExits": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:sessions": 1, - "ga:exceptions": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:pageviews": 1, - "ga:percentSearchRefinements": 1, - "ga:goalXXStarts": 1, - "ga:experimentOutcomeType": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:totalPublisherClicks": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:searchExits": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:transactionRevenue": 1, - "ga:entranceBounceRate": 1, - "ga:entranceRate": 1, - "ga:experimentOutcomes": 1, - "ga:goalAbandonRateAll": 1, - "ga:transactionsPerSession": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:goalValueAll": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:chanceToBeatOriginal": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:compareToOriginal": 1, - "ga:experimentId": 1, - "ga:totalRefunds": 1, - "ga:avgSearchDuration": 1, - "ga:adsenseECPM": 1, - "ga:goalValuePerSession": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:avgTimeOnPage": 1, - "ga:adxCTR": 1, - "ga:goalXXAbandonRate": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:totalPublisherRevenue": 1, - "ga:searchSessions": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:sessionDuration": 1, - "ga:adxECPM": 1, - "ga:experimentStarts": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXCompletions": 1, - "ga:goalXXAbandons": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:fatalExceptions": 1, - "ga:backfillRevenue": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:goalCompletionsAll": 1, - "ga:searchExitRate": 1, - "ga:adsenseAdsClicks": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:experimentVariant": 1, - "ga:searchDuration": 1, - "ga:searchResultViews": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:totalPublisherECPM": 1, - "ga:exits": 1, - "ga:bounces": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:adsensePageImpressions": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:transactionRevenuePerSession": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_active_visitors_date_active_visitors_14": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:14dayUsers": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_wmx_query": { - "ga:country": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:week": 1, - "ga:date": 1, - "ga:adMatchedQuery": 1, - "ga:dayOfWeekName": 1, - "ga:nthMonth": 1, - "ga:day": 1, - "ga:hostname": 1, - "ga:yearMonth": 1, - "ga:year": 1, - "ga:deviceCategory": 1, - "ga:source": 1, - "ga:countryIsoCode": 1, - "ga:landingPagePath": 1, - "ga:nthWeek": 1, - "ga:nthDay": 1, - "ga:medium": 1, - "ga:users": 1, - "ga:sourceMedium": 1, - "ga:dayOfWeek": 1 - }, - "Cube:analytics/per_value_site_search_without_transaction_product_metrics": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:referralPath": 1, - "ga:metroId": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:dcmClickSite": 1, - "ga:dbmClickLineItemId": 1, - "ga:adxMonetizedPageviews": 1, - "ga:dsAdvertiserId": 1, - "ga:flashVersion": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:internalPromotionId": 1, - "ga:searchDestinationPage": 1, - "ga:goalStartsAll": 1, - "ga:dsEngineAccount": 1, - "ga:adwordsCreativeID": 1, - "ga:sessionsToTransaction": 1, - "ga:networkLocation": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:sourceMedium": 1, - "ga:uniquePurchases": 1, - "ga:pageDepth": 1, - "ga:landingContentGroup4": 1, - "ga:landingContentGroup3": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:landingContentGroup2": 1, - "ga:landingContentGroup1": 1, - "ga:previousPagePath": 1, - "ga:dbmClickSite": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:dcmClickSpotId": 1, - "ga:landingContentGroup5": 1, - "ga:adsenseCoverage": 1, - "ga:screenResolution": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:source": 1, - "ga:percentSearchRefinements": 1, - "ga:dsAdGroup": 1, - "ga:networkDomain": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:dcmClickCreativeId": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:screenName": 1, - "ga:productRemovesFromCart": 1, - "ga:internalPromotionCreative": 1, - "ga:productName": 1, - "ga:adSlot": 1, - "ga:secondPagePath": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:searchUsed": 1, - "ga:avgEventValue": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:dbmClickInsertionOrder": 1, - "ga:socialInteractionNetworkAction": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:dcmClickCreativeType": 1, - "ga:dfpClicks": 1, - "ga:internalPromotionName": 1, - "ga:dbmClickLineItem": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:cityId": 1, - "ga:organicSearches": 1, - "ga:searchKeywordRefinement": 1, - "ga:landingScreenName": 1, - "ga:dbmClickAdvertiser": 1, - "ga:dcmFloodlightSpotId": 1, - "ga:previousContentGroup1": 1, - "ga:searchKeyword": 1, - "ga:previousContentGroup2": 1, - "ga:adsenseECPM": 1, - "ga:previousContentGroup3": 1, - "ga:adxImpressionsPerSession": 1, - "ga:previousContentGroup4": 1, - "ga:searchRefinements": 1, - "ga:dcmFloodlightActivity": 1, - "ga:appName": 1, - "ga:dsAdvertiser": 1, - "ga:quantityRefunded": 1, - "ga:latitude": 1, - "ga:nthMonth": 1, - "ga:previousContentGroup5": 1, - "ga:avgTimeOnPage": 1, - "ga:sourcePropertyTrackingId": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:continentId": 1, - "ga:deviceCategory": 1, - "ga:dcmClickSitePlacement": 1, - "ga:dbmClickCreativeId": 1, - "ga:nthWeek": 1, - "ga:dsCampaign": 1, - "ga:interestInMarketCategory": 1, - "ga:adMatchType": 1, - "ga:adwordsCustomerID": 1, - "ga:totalPublisherRevenue": 1, - "ga:userAgeBracket": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:dcmFloodlightActivityGroup": 1, - "ga:trafficType": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:continent": 1, - "ga:goalXXAbandons": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:customVarValueXX": 1, - "ga:landingPagePath": 1, - "ga:channelGrouping": 1, - "ga:searchCategory": 1, - "ga:dfpRevenue": 1, - "ga:adwordsCustomerName": 1, - "ga:dsCampaignId": 1, - "ga:mobileDeviceInfo": 1, - "ga:keyword": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:orderCouponCode": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:socialInteractionAction": 1, - "ga:dbmClickExchange": 1, - "ga:socialInteractionNetwork": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dcmClickCreativeTypeId": 1, - "ga:language": 1, - "ga:adsenseAdsClicks": 1, - "ga:searchAfterDestinationPage": 1, - "ga:affiliation": 1, - "ga:socialInteractions": 1, - "ga:isMobile": 1, - "ga:searchResultViews": 1, - "ga:exitScreenName": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:internalPromotionPosition": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:socialNetwork": 1, - "ga:dbmClickExchangeId": 1, - "ga:dsKeyword": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:adDistributionNetwork": 1, - "ga:userBucket": 1, - "ga:socialEngagementType": 1, - "ga:dsKeywordId": 1, - "ga:percentSessionsWithSearch": 1, - "ga:longitude": 1, - "ga:dcmClickAdTypeId": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:mobileInputSelector": 1, - "ga:timeOnScreen": 1, - "ga:shoppingStage": 1, - "ga:adGroup": 1, - "ga:week": 1, - "ga:dcmClickCampaign": 1, - "ga:sourcePropertyDisplayName": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dbmClickAdvertiserId": 1, - "ga:hour": 1, - "ga:adQueryWordCount": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:daysToTransaction": 1, - "ga:dbmClickCreativeName": 1, - "ga:searchStartPage": 1, - "ga:productListClicks": 1, - "ga:nextPagePath": 1, - "ga:dcmClickSitePlacementId": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:adTargetingType": 1, - "ga:productSku": 1, - "ga:screenDepth": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:appInstallerId": 1, - "ga:dcmClickRenderingId": 1, - "ga:adKeywordMatchType": 1, - "ga:searchDepth": 1, - "ga:subContinent": 1, - "ga:adsenseExits": 1, - "ga:appId": 1, - "ga:checkoutOptions": 1, - "ga:internalPromotionCTR": 1, - "ga:daysSinceLastSession": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:userType": 1, - "ga:dcmClickCreative": 1, - "ga:transactionId": 1, - "ga:sessionCount": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:searchExits": 1, - "ga:dcmClickSiteId": 1, - "ga:externalActivityId": 1, - "ga:dbmClickSiteId": 1, - "ga:dcmClickCreativeVersion": 1, - "ga:browserSize": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:minute": 1, - "ga:dcmFloodlightActivityGroupId": 1, - "ga:year": 1, - "ga:exitPagePath": 1, - "ga:sessionsPerUser": 1, - "ga:adTargetingOption": 1, - "ga:entranceBounceRate": 1, - "ga:customVarNameXX": 1, - "ga:quantityRemovedFromCart": 1, - "ga:socialInteractionTarget": 1, - "ga:appVersion": 1, - "ga:dcmClickAdvertiserId": 1, - "ga:dcmFloodlightActivityAndGroup": 1, - "ga:country": 1, - "ga:goalValueAll": 1, - "ga:userGender": 1, - "ga:pagePath": 1, - "ga:dcmClickCampaignId": 1, - "ga:adMatchedQuery": 1, - "ga:totalPublisherImpressions": 1, - "ga:dsAdGroupId": 1, - "ga:browserVersion": 1, - "ga:adsenseAdsViewed": 1, - "ga:nthMinute": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:operatingSystemVersion": 1, - "ga:mobileDeviceMarketingName": 1, - "ga:totalPublisherCoverage": 1, - "ga:sessionDurationBucket": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:dateHourMinute": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:adDisplayUrl": 1, - "ga:dcmClickAdType": 1, - "ga:metro": 1, - "ga:internalPromotionClicks": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:city": 1, - "ga:sessionsWithEvent": 1, - "ga:countryIsoCode": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dsAgency": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:clientId": 1, - "ga:dcmFloodlightActivityId": 1, - "ga:searchSessions": 1, - "ga:fullReferrer": 1, - "ga:productRefunds": 1, - "ga:dcmClickAdvertiser": 1, - "ga:socialInteractionNetworkActionSession": 1, - "ga:nextContentGroup1": 1, - "ga:hostname": 1, - "ga:nextContentGroup2": 1, - "ga:nextContentGroup3": 1, - "ga:nextContentGroup4": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:nextContentGroup5": 1, - "ga:interestOtherCategory": 1, - "ga:internalPromotionViews": 1, - "ga:productCategory": 1, - "ga:dataSource": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:userDefinedValue": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:dsEngineAccountId": 1, - "ga:adPlacementDomain": 1, - "ga:backfillRevenue": 1, - "ga:subContinentCode": 1, - "ga:mobileDeviceModel": 1, - "ga:adFormat": 1, - "ga:adwordsCriteriaID": 1, - "ga:date": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:searchExitRate": 1, - "ga:javaEnabled": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:medium": 1, - "ga:adDestinationUrl": 1, - "ga:region": 1, - "ga:quantityAddedToCart": 1, - "ga:dcmClickAdId": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:dcmClickAd": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dsAgencyId": 1, - "ga:dayOfWeekName": 1, - "ga:adsensePageImpressions": 1, - "ga:mobileDeviceBranding": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:dcmFloodlightAdvertiserId": 1, - "ga:browser": 1, - "ga:interestAffinityCategory": 1, - "ga:regionId": 1, - "ga:adPlacementUrl": 1, - "ga:adxRevenue": 1, - "ga:dbmClickInsertionOrderId": 1, - "ga:totalPublisherCTR": 1, - "ga:campaignCode": 1 - }, - "per_events_with_local_currency": { - "ga:referralPath": 1, - "ga:transactionTax": 1, - "ga:metroId": 1, - "ga:percentNewSessions": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:dcmClickSite": 1, - "ga:eventAction": 1, - "ga:dbmClickLineItemId": 1, - "ga:dsAdvertiserId": 1, - "ga:flashVersion": 1, - "ga:isoWeek": 1, - "ga:internalPromotionId": 1, - "ga:goalStartsAll": 1, - "ga:dsEngineAccount": 1, - "ga:adwordsCreativeID": 1, - "ga:networkLocation": 1, - "ga:localRefundAmount": 1, - "ga:goalXXValue": 1, - "ga:sourceMedium": 1, - "ga:experimentName": 1, - "ga:uniquePurchases": 1, - "ga:pageDepth": 1, - "ga:landingContentGroup4": 1, - "ga:landingContentGroup3": 1, - "ga:sessions": 1, - "ga:landingContentGroup2": 1, - "ga:landingContentGroup1": 1, - "ga:dbmClickSite": 1, - "ga:metricXX": 1, - "ga:dcmClickSpotId": 1, - "ga:landingContentGroup5": 1, - "ga:screenResolution": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:socialActivityContentUrl": 1, - "ga:source": 1, - "ga:experimentOutcomeType": 1, - "ga:dsAdGroup": 1, - "ga:networkDomain": 1, - "ga:timeOnPage": 1, - "ga:localTransactionShipping": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmClickCreativeId": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:screenName": 1, - "ga:productRemovesFromCart": 1, - "ga:internalPromotionCreative": 1, - "ga:transactionRevenue": 1, - "ga:adSlot": 1, - "ga:eventCategory": 1, - "ga:secondPagePath": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:socialInteractionsPerSession": 1, - "ga:adwordsCampaignID": 1, - "ga:productListCTR": 1, - "ga:dbmClickInsertionOrder": 1, - "ga:socialInteractionNetworkAction": 1, - "ga:hits": 1, - "ga:dcmClickCreativeType": 1, - "ga:internalPromotionName": 1, - "ga:dbmClickLineItem": 1, - "ga:cityId": 1, - "ga:localProductRefundAmount": 1, - "ga:landingScreenName": 1, - "ga:dbmClickAdvertiser": 1, - "ga:dcmFloodlightSpotId": 1, - "ga:searchKeyword": 1, - "ga:dcmFloodlightActivity": 1, - "ga:appName": 1, - "ga:dsAdvertiser": 1, - "ga:quantityRefunded": 1, - "ga:latitude": 1, - "ga:nthMonth": 1, - "ga:avgTimeOnPage": 1, - "ga:sourcePropertyTrackingId": 1, - "ga:goalXXAbandonRate": 1, - "ga:continentId": 1, - "ga:deviceCategory": 1, - "ga:dcmClickSitePlacement": 1, - "ga:dbmClickCreativeId": 1, - "ga:nthWeek": 1, - "ga:dsCampaign": 1, - "ga:interestInMarketCategory": 1, - "ga:adMatchType": 1, - "ga:adwordsCustomerID": 1, - "ga:userAgeBracket": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:dcmFloodlightActivityGroup": 1, - "ga:trafficType": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:goalXXCompletions": 1, - "ga:continent": 1, - "ga:goalXXAbandons": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:customVarValueXX": 1, - "ga:landingPagePath": 1, - "ga:channelGrouping": 1, - "ga:adwordsCustomerName": 1, - "ga:dsCampaignId": 1, - "ga:mobileDeviceInfo": 1, - "ga:keyword": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:localItemRevenue": 1, - "ga:contentGroup1": 1, - "ga:contentGroup2": 1, - "ga:socialInteractionAction": 1, - "ga:contentGroup3": 1, - "ga:contentGroup4": 1, - "ga:contentGroup5": 1, - "ga:dbmClickExchange": 1, - "ga:socialInteractionNetwork": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dcmClickCreativeTypeId": 1, - "ga:language": 1, - "ga:socialInteractions": 1, - "ga:experimentVariant": 1, - "ga:isMobile": 1, - "ga:exitScreenName": 1, - "ga:productRevenuePerPurchase": 1, - "ga:internalPromotionPosition": 1, - "ga:bounces": 1, - "ga:socialNetwork": 1, - "ga:dbmClickExchangeId": 1, - "ga:dsKeyword": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:adDistributionNetwork": 1, - "ga:userBucket": 1, - "ga:socialEngagementType": 1, - "ga:dsKeywordId": 1, - "ga:longitude": 1, - "ga:dcmClickAdTypeId": 1, - "ga:nthHour": 1, - "ga:mobileInputSelector": 1, - "ga:timeOnScreen": 1, - "ga:shoppingStage": 1, - "ga:adGroup": 1, - "ga:localTransactionTax": 1, - "ga:experimentCombination": 1, - "ga:week": 1, - "ga:dcmClickCampaign": 1, - "ga:sourcePropertyDisplayName": 1, - "ga:dbmClickAdvertiserId": 1, - "ga:hour": 1, - "ga:adQueryWordCount": 1, - "ga:dbmClickCreativeName": 1, - "ga:productListClicks": 1, - "ga:dcmClickSitePlacementId": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:contentGroupUniqueViews2": 1, - "ga:contentGroupUniqueViews1": 1, - "ga:adTargetingType": 1, - "ga:screenDepth": 1, - "ga:uniqueEvents": 1, - "ga:contentGroupUniqueViews5": 1, - "ga:users": 1, - "ga:contentGroupUniqueViews4": 1, - "ga:appInstallerId": 1, - "ga:contentGroupUniqueViews3": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:dcmClickRenderingId": 1, - "ga:adKeywordMatchType": 1, - "ga:subContinent": 1, - "ga:adsenseExits": 1, - "ga:appId": 1, - "ga:checkoutOptions": 1, - "ga:internalPromotionCTR": 1, - "ga:daysSinceLastSession": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:userType": 1, - "ga:dcmClickCreative": 1, - "ga:sessionCount": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:screenviewsPerSession": 1, - "ga:dcmClickSiteId": 1, - "ga:externalActivityId": 1, - "ga:dbmClickSiteId": 1, - "ga:dcmClickCreativeVersion": 1, - "ga:browserSize": 1, - "ga:minute": 1, - "ga:dcmFloodlightActivityGroupId": 1, - "ga:adSlotPosition": 1, - "ga:year": 1, - "ga:exitPagePath": 1, - "ga:sessionsPerUser": 1, - "ga:entranceBounceRate": 1, - "ga:customVarNameXX": 1, - "ga:quantityRemovedFromCart": 1, - "ga:socialInteractionTarget": 1, - "ga:transactionsPerSession": 1, - "ga:appVersion": 1, - "ga:dcmClickAdvertiserId": 1, - "ga:dcmFloodlightActivityAndGroup": 1, - "ga:country": 1, - "ga:goalValueAll": 1, - "ga:userGender": 1, - "ga:pagePath": 1, - "ga:dcmClickCampaignId": 1, - "ga:adMatchedQuery": 1, - "ga:dsAdGroupId": 1, - "ga:totalValue": 1, - "ga:hasSocialSourceReferral": 1, - "ga:browserVersion": 1, - "ga:nthMinute": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:eventLabel": 1, - "ga:operatingSystemVersion": 1, - "ga:mobileDeviceMarketingName": 1, - "ga:sessionDurationBucket": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:experimentId": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:dateHourMinute": 1, - "ga:itemQuantity": 1, - "ga:goalValuePerSession": 1, - "ga:adDisplayUrl": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:dcmClickAdType": 1, - "ga:metro": 1, - "ga:internalPromotionClicks": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:city": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:countryIsoCode": 1, - "ga:goalConversionRateAll": 1, - "ga:dsAgency": 1, - "ga:clientId": 1, - "ga:dcmFloodlightActivityId": 1, - "ga:fullReferrer": 1, - "ga:productRefunds": 1, - "ga:dcmClickAdvertiser": 1, - "ga:socialInteractionNetworkActionSession": 1, - "ga:hostname": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:interestOtherCategory": 1, - "ga:adContent": 1, - "ga:internalPromotionViews": 1, - "ga:dataSource": 1, - "ga:pageTitle": 1, - "ga:userDefinedValue": 1, - "ga:dsEngineAccountId": 1, - "ga:subContinentCode": 1, - "ga:mobileDeviceModel": 1, - "ga:adFormat": 1, - "ga:adwordsCriteriaID": 1, - "ga:date": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:day": 1, - "ga:localTransactionRevenue": 1, - "ga:javaEnabled": 1, - "ga:medium": 1, - "ga:region": 1, - "ga:pagePathLevel4": 1, - "ga:quantityAddedToCart": 1, - "ga:currencyCode": 1, - "ga:pagePathLevel1": 1, - "ga:dcmClickAdId": 1, - "ga:pagePathLevel3": 1, - "ga:dcmClickAd": 1, - "ga:pagePathLevel2": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:dsAgencyId": 1, - "ga:dayOfWeekName": 1, - "ga:mobileDeviceBranding": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:dcmFloodlightAdvertiserId": 1, - "ga:browser": 1, - "ga:transactionRevenuePerSession": 1, - "ga:interestAffinityCategory": 1, - "ga:regionId": 1, - "ga:dbmClickInsertionOrderId": 1, - "ga:campaignCode": 1 - }, - "gdn_targeting": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:percentNewSessions": 1, - "ga:backfillClicks": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:adwordsCreativeID": 1, - "ga:adCost": 1, - "ga:dfpCoverage": 1, - "ga:localRefundAmount": 1, - "ga:goalXXValue": 1, - "ga:sourceMedium": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:sessions": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:source": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:localTransactionShipping": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:ROI": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:transactionRevenue": 1, - "ga:adSlot": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:dfpLineItemId": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:localProductRefundAmount": 1, - "ga:organicSearches": 1, - "ga:isTrueViewVideoAd": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:nthMonth": 1, - "ga:avgTimeOnPage": 1, - "ga:adxCTR": 1, - "ga:goalXXAbandonRate": 1, - "ga:deviceCategory": 1, - "ga:nthWeek": 1, - "ga:adwordsCustomerID": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:trafficType": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXCompletions": 1, - "ga:goalXXAbandons": 1, - "ga:ROAS": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:channelGrouping": 1, - "ga:dfpRevenue": 1, - "ga:keyword": 1, - "ga:adwordsCustomerName": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:localItemRevenue": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:socialInteractionNetwork": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:adsenseAdsClicks": 1, - "ga:isMobile": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:socialNetwork": 1, - "ga:costPerTransaction": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:adDistributionNetwork": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:adGroup": 1, - "ga:localTransactionTax": 1, - "ga:week": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:productListClicks": 1, - "ga:domContentLoadedTime": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:adKeywordMatchType": 1, - "ga:searchDepth": 1, - "ga:adsenseExits": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:year": 1, - "ga:sessionsPerUser": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:transactions": 1, - "ga:costPerConversion": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:searchSessions": 1, - "ga:dfpLineItemName": 1, - "ga:productRefunds": 1, - "ga:costPerGoalConversion": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:adContent": 1, - "ga:dataSource": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:adwordsCriteriaID": 1, - "ga:date": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:localTransactionRevenue": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:CPM": 1, - "ga:medium": 1, - "ga:adDestinationUrl": 1, - "ga:quantityAddedToCart": 1, - "ga:currencyCode": 1, - "ga:searchDuration": 1, - "ga:margin": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:CPC": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:pageLoadTime": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:productListViews": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "local_transaction": { - "ga:localItemRevenue": 1, - "ga:localTransactionRevenue": 1, - "ga:localTransactionTax": 1, - "ga:transactionId": 1, - "ga:localProductRefundAmount": 1, - "ga:localTransactionShipping": 1, - "ga:currencyCode": 1, - "ga:localRefundAmount": 1 - }, - "all_metrics_for_cohorts_overview": { - "ga:sessions": 1, - "ga:sessionDuration": 1, - "ga:avgSessionDuration": 1, - "ga:screenviews": 1, - "ga:pageviews": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalCompletionsAll": 1, - "ga:transactions": 1, - "ga:transactionRevenue": 1, - "ga:goalConversionRateAll": 1, - "ga:transactionRevenuePerSession": 1, - "ga:revenuePerTransaction": 1, - "ga:transactionsPerSession": 1, - "ga:screenviewsPerSession": 1, - "ga:pageviewsPerSession": 1 - }, - "per_wmx_url": { - "ga:goalValuePerSession": 1, - "ga:percentNewSessions": 1, - "ga:week": 1, - "ga:transactionsPerUser": 1, - "ga:nthMonth": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:newUsers": 1, - "ga:goalXXAbandonRate": 1, - "ga:deviceCategory": 1, - "ga:transactions": 1, - "ga:countryIsoCode": 1, - "ga:goalConversionRateAll": 1, - "ga:nthWeek": 1, - "ga:goalStartsAll": 1, - "ga:goalXXValue": 1, - "ga:users": 1, - "ga:sourceMedium": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:sessions": 1, - "ga:hostname": 1, - "ga:sessionDuration": 1, - "ga:goalXXCompletions": 1, - "ga:pageviews": 1, - "ga:source": 1, - "ga:goalXXAbandons": 1, - "ga:goalXXStarts": 1, - "ga:landingPagePath": 1, - "ga:bounceRate": 1, - "ga:nthDay": 1, - "ga:revenuePerTransaction": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:date": 1, - "ga:day": 1, - "ga:year": 1, - "ga:transactionRevenue": 1, - "ga:goalCompletionsAll": 1, - "ga:sessionsPerUser": 1, - "ga:medium": 1, - "ga:transactionsPerSession": 1, - "ga:goalAbandonRateAll": 1, - "ga:country": 1, - "ga:goalXXConversionRate": 1, - "ga:goalValueAll": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:bounces": 1, - "ga:dayOfWeekName": 1, - "ga:totalValue": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:transactionRevenuePerSession": 1, - "ga:totalRefunds": 1 - }, - "per_active_visitors_date_active_visitors_1": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:1dayUsers": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_content_with_local_currency": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:metroId": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:flashVersion": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:internalPromotionId": 1, - "ga:searchDestinationPage": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:adwordsCreativeID": 1, - "ga:networkLocation": 1, - "ga:dfpCoverage": 1, - "ga:localRefundAmount": 1, - "ga:goalXXValue": 1, - "ga:experimentName": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:pageDepth": 1, - "ga:landingContentGroup4": 1, - "ga:landingContentGroup3": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:landingContentGroup2": 1, - "ga:landingContentGroup1": 1, - "ga:previousPagePath": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:landingContentGroup5": 1, - "ga:adsenseCoverage": 1, - "ga:screenResolution": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:userTimingCategory": 1, - "ga:percentSearchRefinements": 1, - "ga:experimentOutcomeType": 1, - "ga:networkDomain": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:localTransactionShipping": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:screenName": 1, - "ga:productRemovesFromCart": 1, - "ga:internalPromotionCreative": 1, - "ga:transactionRevenue": 1, - "ga:secondPagePath": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:socialInteractionNetworkAction": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:internalPromotionName": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:cityId": 1, - "ga:localProductRefundAmount": 1, - "ga:organicSearches": 1, - "ga:landingScreenName": 1, - "ga:previousContentGroup1": 1, - "ga:previousContentGroup2": 1, - "ga:adsenseECPM": 1, - "ga:previousContentGroup3": 1, - "ga:adxImpressionsPerSession": 1, - "ga:previousContentGroup4": 1, - "ga:searchRefinements": 1, - "ga:appName": 1, - "ga:quantityRefunded": 1, - "ga:latitude": 1, - "ga:nthMonth": 1, - "ga:previousContentGroup5": 1, - "ga:avgTimeOnPage": 1, - "ga:sourcePropertyTrackingId": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:continentId": 1, - "ga:deviceCategory": 1, - "ga:nthWeek": 1, - "ga:interestInMarketCategory": 1, - "ga:adMatchType": 1, - "ga:adwordsCustomerID": 1, - "ga:totalPublisherRevenue": 1, - "ga:userAgeBracket": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:continent": 1, - "ga:goalXXAbandons": 1, - "ga:isoYear": 1, - "ga:customVarValueXX": 1, - "ga:landingPagePath": 1, - "ga:dfpRevenue": 1, - "ga:adwordsCustomerName": 1, - "ga:mobileDeviceInfo": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:localItemRevenue": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:contentGroup1": 1, - "ga:contentGroup2": 1, - "ga:socialInteractionAction": 1, - "ga:contentGroup3": 1, - "ga:contentGroup4": 1, - "ga:contentGroup5": 1, - "ga:socialInteractionNetwork": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:language": 1, - "ga:adsenseAdsClicks": 1, - "ga:searchAfterDestinationPage": 1, - "ga:socialInteractions": 1, - "ga:userTimingLabel": 1, - "ga:experimentVariant": 1, - "ga:isMobile": 1, - "ga:searchResultViews": 1, - "ga:exitScreenName": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:internalPromotionPosition": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:adDistributionNetwork": 1, - "ga:userBucket": 1, - "ga:domInteractiveTime": 1, - "ga:socialEngagementType": 1, - "ga:percentSessionsWithSearch": 1, - "ga:longitude": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:mobileInputSelector": 1, - "ga:timeOnScreen": 1, - "ga:shoppingStage": 1, - "ga:localTransactionTax": 1, - "ga:experimentCombination": 1, - "ga:week": 1, - "ga:sourcePropertyDisplayName": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:nextPagePath": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:contentGroupUniqueViews2": 1, - "ga:contentGroupUniqueViews1": 1, - "ga:adTargetingType": 1, - "ga:screenDepth": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:contentGroupUniqueViews5": 1, - "ga:contentGroupUniqueViews4": 1, - "ga:appInstallerId": 1, - "ga:contentGroupUniqueViews3": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:adKeywordMatchType": 1, - "ga:searchDepth": 1, - "ga:subContinent": 1, - "ga:adsenseExits": 1, - "ga:appId": 1, - "ga:checkoutOptions": 1, - "ga:internalPromotionCTR": 1, - "ga:daysSinceLastSession": 1, - "ga:pageviews": 1, - "ga:userTimingVariable": 1, - "ga:goalXXStarts": 1, - "ga:userType": 1, - "ga:sessionCount": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:externalActivityId": 1, - "ga:speedMetricsSample": 1, - "ga:browserSize": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:minute": 1, - "ga:year": 1, - "ga:exitPagePath": 1, - "ga:sessionsPerUser": 1, - "ga:adTargetingOption": 1, - "ga:entranceBounceRate": 1, - "ga:customVarNameXX": 1, - "ga:previousPageLinkId": 1, - "ga:quantityRemovedFromCart": 1, - "ga:socialInteractionTarget": 1, - "ga:transactionsPerSession": 1, - "ga:appVersion": 1, - "ga:pageDownloadTime": 1, - "ga:country": 1, - "ga:goalValueAll": 1, - "ga:userGender": 1, - "ga:pagePath": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:browserVersion": 1, - "ga:adsenseAdsViewed": 1, - "ga:nthMinute": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:operatingSystemVersion": 1, - "ga:mobileDeviceMarketingName": 1, - "ga:totalPublisherCoverage": 1, - "ga:sessionDurationBucket": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:experimentId": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:dateHourMinute": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:adDisplayUrl": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:metro": 1, - "ga:internalPromotionClicks": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:city": 1, - "ga:domLatencyMetricsSample": 1, - "ga:transactions": 1, - "ga:countryIsoCode": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:clientId": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:socialInteractionNetworkActionSession": 1, - "ga:nextContentGroup1": 1, - "ga:hostname": 1, - "ga:nextContentGroup2": 1, - "ga:nextContentGroup3": 1, - "ga:nextContentGroup4": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:nextContentGroup5": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:interestOtherCategory": 1, - "ga:internalPromotionViews": 1, - "ga:dataSource": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:pageTitle": 1, - "ga:userDefinedValue": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:adPlacementDomain": 1, - "ga:backfillRevenue": 1, - "ga:subContinentCode": 1, - "ga:mobileDeviceModel": 1, - "ga:adFormat": 1, - "ga:adwordsCriteriaID": 1, - "ga:date": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:localTransactionRevenue": 1, - "ga:searchExitRate": 1, - "ga:javaEnabled": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:adDestinationUrl": 1, - "ga:region": 1, - "ga:pagePathLevel4": 1, - "ga:quantityAddedToCart": 1, - "ga:currencyCode": 1, - "ga:pagePathLevel1": 1, - "ga:searchDuration": 1, - "ga:pagePathLevel3": 1, - "ga:backfillImpressions": 1, - "ga:pagePathLevel2": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:adsensePageImpressions": 1, - "ga:mobileDeviceBranding": 1, - "ga:avgRedirectionTime": 1, - "ga:pageLoadTime": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:browser": 1, - "ga:transactionRevenuePerSession": 1, - "ga:interestAffinityCategory": 1, - "ga:regionId": 1, - "ga:adPlacementUrl": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "ga_experiment_results_metrics": { - "ga:experimentName": 1, - "ga:experimentCombination": 1, - "ga:nthDay": 1, - "ga:experimentVariant": 1, - "ga:experimentId": 1 - }, - "per_geo_dimension_widening_country_iso_code": { - "ga:dimensionXX": 1, - "ga:countryIsoCode": 1 - }, - "per_geo_dimension_widening_region_id": { - "ga:dimensionXX": 1, - "ga:regionId": 1 - }, - "per_active_visitors_nthday_active_visitors_30": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:30dayUsers": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_active_visitors_date_active_visitors_7": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:7dayUsers": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "phone_analytics": { - "ga:referralPath": 1, - "ga:adGroup": 1, - "ga:metroId": 1, - "ga:week": 1, - "ga:metro": 1, - "ga:nthMonth": 1, - "ga:latitude": 1, - "ga:yearMonth": 1, - "ga:city": 1, - "ga:hour": 1, - "ga:continentId": 1, - "ga:deviceCategory": 1, - "ga:countryIsoCode": 1, - "ga:nthWeek": 1, - "ga:interestInMarketCategory": 1, - "ga:networkLocation": 1, - "ga:userAgeBracket": 1, - "ga:sourceMedium": 1, - "ga:subContinent": 1, - "ga:interestOtherCategory": 1, - "ga:continent": 1, - "ga:isTablet": 1, - "ga:adContent": 1, - "ga:source": 1, - "ga:campaign": 1, - "ga:userType": 1, - "ga:networkDomain": 1, - "ga:dataSource": 1, - "ga:landingPagePath": 1, - "ga:nthDay": 1, - "ga:channelGrouping": 1, - "ga:keyword": 1, - "ga:dayOfWeek": 1, - "ga:subContinentCode": 1, - "ga:date": 1, - "ga:day": 1, - "ga:year": 1, - "ga:exitPagePath": 1, - "ga:medium": 1, - "ga:region": 1, - "ga:isMobile": 1, - "ga:country": 1, - "ga:month": 1, - "ga:userGender": 1, - "ga:yearWeek": 1, - "ga:adwordsCampaignID": 1, - "ga:dayOfWeekName": 1, - "ga:socialNetwork": 1, - "ga:regionIsoCode": 1, - "ga:cityId": 1, - "ga:interestAffinityCategory": 1, - "ga:longitude": 1, - "ga:nthHour": 1, - "ga:regionId": 1, - "ga:dateHour": 1 - }, - "per_dimension_widening": { - "ga:mobileDeviceModel": 1, - "ga:appName": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:javaEnabled": 1, - "ga:language": 1, - "ga:appVersion": 1, - "ga:networkLocation": 1, - "ga:isMobile": 1, - "ga:appInstallerId": 1, - "ga:pagePath": 1, - "ga:appId": 1, - "ga:metricXX": 1, - "ga:hostname": 1, - "ga:browserVersion": 1, - "ga:mobileDeviceBranding": 1, - "ga:screenResolution": 1, - "ga:isTablet": 1, - "ga:dimensionXX": 1, - "ga:networkDomain": 1, - "ga:sessionCount": 1, - "ga:operatingSystemVersion": 1, - "ga:browser": 1, - "ga:mobileDeviceMarketingName": 1, - "ga:pageTitle": 1, - "ga:mobileInputSelector": 1 - }, - "per_active_visitors_day_active_visitors_28": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:28dayUsers": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_active_visitors_day_active_visitors_1": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:1dayUsers": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_goal_funnel_request": { - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:sessions": 1, - "ga:transactionsPerUser": 1, - "ga:metricXX": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:transactions": 1, - "ga:transactionRevenue": 1, - "ga:goalCompletionsAll": 1, - "ga:sessionsPerUser": 1, - "ga:dimensionXX": 1, - "ga:goalConversionRateAll": 1, - "ga:transactionRevenuePerSession": 1, - "ga:transactionsPerSession": 1, - "ga:revenuePerTransaction": 1, - "ga:users": 1, - "ga:totalRefunds": 1 - }, - "per_tv_campaign": { - "ga:month": 1, - "ga:yearWeek": 1, - "ga:week": 1, - "ga:date": 1, - "ga:dayOfWeekName": 1, - "ga:nthMonth": 1, - "ga:metricXX": 1, - "ga:yearMonth": 1, - "ga:day": 1, - "ga:minute": 1, - "ga:nthMinute": 1, - "ga:year": 1, - "ga:hour": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:isoYear": 1, - "ga:nthWeek": 1, - "ga:isoWeek": 1, - "ga:nthDay": 1, - "ga:nthHour": 1, - "ga:dateHour": 1, - "ga:dayOfWeek": 1, - "ga:dateHourMinute": 1 - }, - "all_metrics_for_audiences_overview": { - "ga:goalValuePerSession": 1, - "ga:metroId": 1, - "ga:percentNewSessions": 1, - "ga:week": 1, - "ga:acquisitionSource": 1, - "ga:transactionsPerUser": 1, - "ga:metro": 1, - "ga:nthMonth": 1, - "ga:latitude": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:newUsers": 1, - "ga:city": 1, - "ga:goalXXAbandonRate": 1, - "ga:continentId": 1, - "ga:transactions": 1, - "ga:countryIsoCode": 1, - "ga:goalConversionRateAll": 1, - "ga:flashVersion": 1, - "ga:nthWeek": 1, - "ga:interestInMarketCategory": 1, - "ga:goalStartsAll": 1, - "ga:networkLocation": 1, - "ga:userAgeBracket": 1, - "ga:goalXXValue": 1, - "ga:users": 1, - "ga:revenuePerUser": 1, - "ga:subContinent": 1, - "ga:sessions": 1, - "ga:sessionDuration": 1, - "ga:screenResolution": 1, - "ga:goalXXCompletions": 1, - "ga:screenviews": 1, - "ga:interestOtherCategory": 1, - "ga:continent": 1, - "ga:pageviews": 1, - "ga:goalXXAbandons": 1, - "ga:goalXXStarts": 1, - "ga:userType": 1, - "ga:networkDomain": 1, - "ga:bounceRate": 1, - "ga:nthDay": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:acquisitionTrafficChannel": 1, - "ga:subContinentCode": 1, - "ga:browserSize": 1, - "ga:date": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:day": 1, - "ga:year": 1, - "ga:transactionRevenue": 1, - "ga:goalCompletionsAll": 1, - "ga:sessionsPerUser": 1, - "ga:javaEnabled": 1, - "ga:language": 1, - "ga:acquisitionMedium": 1, - "ga:region": 1, - "ga:transactionsPerSession": 1, - "ga:goalAbandonRateAll": 1, - "ga:country": 1, - "ga:goalXXConversionRate": 1, - "ga:goalValueAll": 1, - "ga:month": 1, - "ga:userGender": 1, - "ga:yearWeek": 1, - "ga:acquisitionCampaign": 1, - "ga:bounces": 1, - "ga:dayOfWeekName": 1, - "ga:acquisitionSourceMedium": 1, - "ga:totalValue": 1, - "ga:browserVersion": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:cityId": 1, - "ga:operatingSystemVersion": 1, - "ga:browser": 1, - "ga:transactionRevenuePerSession": 1, - "ga:interestAffinityCategory": 1, - "ga:longitude": 1, - "ga:regionId": 1 - }, - "per_social_plus_site": { - "ga:goalValuePerSession": 1, - "ga:week": 1, - "ga:nthMonth": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:hour": 1, - "ga:transactions": 1, - "ga:goalConversionRateAll": 1, - "ga:nthWeek": 1, - "ga:isoWeek": 1, - "ga:goalXXValue": 1, - "ga:refundAmount": 1, - "ga:adsenseExits": 1, - "ga:sessions": 1, - "ga:metricXX": 1, - "ga:sessionDuration": 1, - "ga:goalXXCompletions": 1, - "ga:screenviews": 1, - "ga:pageviews": 1, - "ga:socialActivityContentUrl": 1, - "ga:isoYear": 1, - "ga:bounceRate": 1, - "ga:nthDay": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:date": 1, - "ga:day": 1, - "ga:year": 1, - "ga:transactionRevenue": 1, - "ga:goalCompletionsAll": 1, - "ga:entranceBounceRate": 1, - "ga:entranceRate": 1, - "ga:transactionsPerSession": 1, - "ga:goalXXConversionRate": 1, - "ga:goalValueAll": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:bounces": 1, - "ga:dayOfWeekName": 1, - "ga:totalValue": 1, - "ga:hasSocialSourceReferral": 1, - "ga:hits": 1, - "ga:socialNetwork": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:pageValue": 1, - "ga:exitRate": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:transactionRevenuePerSession": 1, - "ga:uniquePageviews": 1, - "ga:nthHour": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1 - }, - "all_metrics_for_active_visitors_cubes": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_campaign_shasta_with_local_currency": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:adwordsCreativeID": 1, - "ga:dfpCoverage": 1, - "ga:adCost": 1, - "ga:localRefundAmount": 1, - "ga:goalXXValue": 1, - "ga:sourceMedium": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:source": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:localTransactionShipping": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:ROI": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:transactionRevenue": 1, - "ga:adSlot": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:localProductRefundAmount": 1, - "ga:organicSearches": 1, - "ga:isTrueViewVideoAd": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:nthMonth": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:deviceCategory": 1, - "ga:nthWeek": 1, - "ga:adwordsCustomerID": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:trafficType": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:ROAS": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:channelGrouping": 1, - "ga:dfpRevenue": 1, - "ga:adwordsCustomerName": 1, - "ga:keyword": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:localItemRevenue": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:adsenseAdsClicks": 1, - "ga:isMobile": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:socialNetwork": 1, - "ga:costPerTransaction": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:adDistributionNetwork": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:adGroup": 1, - "ga:localTransactionTax": 1, - "ga:week": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:adKeywordMatchType": 1, - "ga:searchDepth": 1, - "ga:adsenseExits": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:year": 1, - "ga:sessionsPerUser": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:transactions": 1, - "ga:costPerConversion": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:costPerGoalConversion": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:adContent": 1, - "ga:dataSource": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:adwordsCriteriaID": 1, - "ga:date": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:localTransactionRevenue": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:CPM": 1, - "ga:medium": 1, - "ga:adDestinationUrl": 1, - "ga:quantityAddedToCart": 1, - "ga:currencyCode": 1, - "ga:searchDuration": 1, - "ga:margin": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:CPC": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:pageLoadTime": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_dfa_floodlight_model": { - "ga:metroId": 1, - "ga:percentNewSessions": 1, - "ga:week": 1, - "ga:dbmConversions": 1, - "ga:newUsers": 1, - "ga:hour": 1, - "ga:flashVersion": 1, - "ga:isoWeek": 1, - "ga:internalPromotionId": 1, - "ga:goalStartsAll": 1, - "ga:networkLocation": 1, - "ga:goalXXValue": 1, - "ga:refundAmount": 1, - "ga:subContinent": 1, - "ga:sessions": 1, - "ga:metricXX": 1, - "ga:screenResolution": 1, - "ga:isTablet": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:networkDomain": 1, - "ga:bounceRate": 1, - "ga:nthDay": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:browserSize": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:dcmFloodlightActivityGroupId": 1, - "ga:year": 1, - "ga:internalPromotionCreative": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:goalAbandonRateAll": 1, - "ga:transactionsPerSession": 1, - "ga:dcmCTR": 1, - "ga:dcmFloodlightActivityAndGroup": 1, - "ga:country": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalValue": 1, - "ga:browserVersion": 1, - "ga:dbmROAS": 1, - "ga:internalPromotionName": 1, - "ga:cityId": 1, - "ga:operatingSystemVersion": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:dateHour": 1, - "ga:dcmFloodlightSpotId": 1, - "ga:totalRefunds": 1, - "ga:goalValuePerSession": 1, - "ga:dcmFloodlightActivity": 1, - "ga:metro": 1, - "ga:latitude": 1, - "ga:nthMonth": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:city": 1, - "ga:goalXXAbandonRate": 1, - "ga:deviceCategory": 1, - "ga:continentId": 1, - "ga:transactions": 1, - "ga:countryIsoCode": 1, - "ga:goalConversionRateAll": 1, - "ga:nthWeek": 1, - "ga:dcmRPC": 1, - "ga:dcmFloodlightActivityId": 1, - "ga:dcmFloodlightActivityGroup": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:goalXXCompletions": 1, - "ga:continent": 1, - "ga:goalXXAbandons": 1, - "ga:isoYear": 1, - "ga:dbmCost": 1, - "ga:dataSource": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:subContinentCode": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:day": 1, - "ga:goalCompletionsAll": 1, - "ga:dbmCTR": 1, - "ga:javaEnabled": 1, - "ga:language": 1, - "ga:region": 1, - "ga:dcmROAS": 1, - "ga:isMobile": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:internalPromotionPosition": 1, - "ga:bounces": 1, - "ga:dayOfWeekName": 1, - "ga:dbmClicks": 1, - "ga:dcmImpressions": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:dcmROI": 1, - "ga:dcmMargin": 1, - "ga:dcmFloodlightAdvertiserId": 1, - "ga:browser": 1, - "ga:transactionRevenuePerSession": 1, - "ga:dbmImpressions": 1, - "ga:longitude": 1, - "ga:regionId": 1, - "ga:nthHour": 1 - }, - "per_product_with_local_currency": { - "ga:metroId": 1, - "ga:week": 1, - "ga:productCheckouts": 1, - "ga:dcmClickCampaign": 1, - "ga:dcmClickSite": 1, - "ga:eventAction": 1, - "ga:dbmClickAdvertiserId": 1, - "ga:hour": 1, - "ga:dbmClickLineItemId": 1, - "ga:dbmClickCreativeName": 1, - "ga:dsAdvertiserId": 1, - "ga:productListClicks": 1, - "ga:flashVersion": 1, - "ga:dcmClickSitePlacementId": 1, - "ga:isoWeek": 1, - "ga:internalPromotionId": 1, - "ga:dsEngineAccount": 1, - "ga:productSku": 1, - "ga:networkLocation": 1, - "ga:sourceMedium": 1, - "ga:dcmClickRenderingId": 1, - "ga:uniquePurchases": 1, - "ga:productListPosition": 1, - "ga:subContinent": 1, - "ga:dbmClickSite": 1, - "ga:metricXX": 1, - "ga:dcmClickSpotId": 1, - "ga:screenResolution": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:socialActivityContentUrl": 1, - "ga:source": 1, - "ga:userType": 1, - "ga:dsAdGroup": 1, - "ga:networkDomain": 1, - "ga:dcmClickCreative": 1, - "ga:transactionId": 1, - "ga:sessionCount": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:dcmClickCreativeId": 1, - "ga:productVariant": 1, - "ga:dcmClickSiteId": 1, - "ga:dbmClickSiteId": 1, - "ga:screenName": 1, - "ga:dcmClickCreativeVersion": 1, - "ga:browserSize": 1, - "ga:productRemovesFromCart": 1, - "ga:dcmFloodlightActivityGroupId": 1, - "ga:year": 1, - "ga:internalPromotionCreative": 1, - "ga:productName": 1, - "ga:quantityRemovedFromCart": 1, - "ga:eventCategory": 1, - "ga:buyToDetailRate": 1, - "ga:dcmClickAdvertiserId": 1, - "ga:dcmFloodlightActivityAndGroup": 1, - "ga:country": 1, - "ga:userGender": 1, - "ga:pagePath": 1, - "ga:productListCTR": 1, - "ga:dcmClickCampaignId": 1, - "ga:dbmClickInsertionOrder": 1, - "ga:dsAdGroupId": 1, - "ga:hasSocialSourceReferral": 1, - "ga:browserVersion": 1, - "ga:dcmClickCreativeType": 1, - "ga:internalPromotionName": 1, - "ga:dbmClickLineItem": 1, - "ga:cityId": 1, - "ga:eventLabel": 1, - "ga:operatingSystemVersion": 1, - "ga:localProductRefundAmount": 1, - "ga:sessionDurationBucket": 1, - "ga:landingScreenName": 1, - "ga:dateHour": 1, - "ga:dbmClickAdvertiser": 1, - "ga:dcmFloodlightSpotId": 1, - "ga:itemQuantity": 1, - "ga:searchKeyword": 1, - "ga:dcmFloodlightActivity": 1, - "ga:dsAdvertiser": 1, - "ga:dcmClickAdType": 1, - "ga:metro": 1, - "ga:quantityRefunded": 1, - "ga:latitude": 1, - "ga:nthMonth": 1, - "ga:yearMonth": 1, - "ga:city": 1, - "ga:continentId": 1, - "ga:deviceCategory": 1, - "ga:countryIsoCode": 1, - "ga:dcmClickSitePlacement": 1, - "ga:dbmClickCreativeId": 1, - "ga:dsAgency": 1, - "ga:nthWeek": 1, - "ga:dsCampaign": 1, - "ga:interestInMarketCategory": 1, - "ga:clientId": 1, - "ga:userAgeBracket": 1, - "ga:productCategoryHierarchy": 1, - "ga:dcmFloodlightActivityId": 1, - "ga:productRefunds": 1, - "ga:dcmFloodlightActivityGroup": 1, - "ga:dcmClickAdvertiser": 1, - "ga:productBrand": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:hostname": 1, - "ga:quantityCheckedOut": 1, - "ga:continent": 1, - "ga:interestOtherCategory": 1, - "ga:adContent": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:landingPagePath": 1, - "ga:dataSource": 1, - "ga:productListName": 1, - "ga:channelGrouping": 1, - "ga:dsCampaignId": 1, - "ga:pageTitle": 1, - "ga:keyword": 1, - "ga:userDefinedValue": 1, - "ga:dsEngineAccountId": 1, - "ga:dayOfWeek": 1, - "ga:productCategoryLevel1": 1, - "ga:localItemRevenue": 1, - "ga:productCategoryLevel2": 1, - "ga:subContinentCode": 1, - "ga:productCategoryLevel5": 1, - "ga:date": 1, - "ga:productCategoryLevel3": 1, - "ga:screenColors": 1, - "ga:productCategoryLevel4": 1, - "ga:operatingSystem": 1, - "ga:day": 1, - "ga:dbmClickExchange": 1, - "ga:productDetailViews": 1, - "ga:dcmClickCreativeTypeId": 1, - "ga:javaEnabled": 1, - "ga:language": 1, - "ga:medium": 1, - "ga:region": 1, - "ga:quantityAddedToCart": 1, - "ga:currencyCode": 1, - "ga:isMobile": 1, - "ga:dcmClickAdId": 1, - "ga:exitScreenName": 1, - "ga:dcmClickAd": 1, - "ga:productRevenuePerPurchase": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:internalPromotionPosition": 1, - "ga:dsAgencyId": 1, - "ga:dayOfWeekName": 1, - "ga:socialNetwork": 1, - "ga:dbmClickExchangeId": 1, - "ga:regionIsoCode": 1, - "ga:dsKeyword": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dcmFloodlightAdvertiserId": 1, - "ga:browser": 1, - "ga:userBucket": 1, - "ga:interestAffinityCategory": 1, - "ga:dsKeywordId": 1, - "ga:productCouponCode": 1, - "ga:longitude": 1, - "ga:dcmClickAdTypeId": 1, - "ga:regionId": 1, - "ga:nthHour": 1, - "ga:dbmClickInsertionOrderId": 1 - }, - "smart_goals": { - "ga:referralPath": 1, - "ga:adGroup": 1, - "ga:metroId": 1, - "ga:percentNewSessions": 1, - "ga:week": 1, - "ga:newUsers": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:flashVersion": 1, - "ga:goalStartsAll": 1, - "ga:adwordsCreativeID": 1, - "ga:networkLocation": 1, - "ga:goalXXValue": 1, - "ga:sourceMedium": 1, - "ga:adKeywordMatchType": 1, - "ga:searchDepth": 1, - "ga:subContinent": 1, - "ga:sessions": 1, - "ga:screenResolution": 1, - "ga:searchUniques": 1, - "ga:isTablet": 1, - "ga:pageviews": 1, - "ga:source": 1, - "ga:percentSearchRefinements": 1, - "ga:goalXXStarts": 1, - "ga:networkDomain": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:nthDay": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:searchExits": 1, - "ga:browserSize": 1, - "ga:year": 1, - "ga:transactionRevenue": 1, - "ga:entranceBounceRate": 1, - "ga:adSlot": 1, - "ga:entranceRate": 1, - "ga:transactionsPerSession": 1, - "ga:goalAbandonRateAll": 1, - "ga:country": 1, - "ga:goalValueAll": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:totalValue": 1, - "ga:browserVersion": 1, - "ga:cityId": 1, - "ga:operatingSystemVersion": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:searchRefinements": 1, - "ga:metro": 1, - "ga:nthMonth": 1, - "ga:latitude": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:city": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:continentId": 1, - "ga:deviceCategory": 1, - "ga:transactions": 1, - "ga:countryIsoCode": 1, - "ga:goalConversionRateAll": 1, - "ga:avgSearchDepth": 1, - "ga:nthWeek": 1, - "ga:adwordsCustomerID": 1, - "ga:searchSessions": 1, - "ga:trafficType": 1, - "ga:sessionDuration": 1, - "ga:goalXXCompletions": 1, - "ga:continent": 1, - "ga:adContent": 1, - "ga:goalXXAbandons": 1, - "ga:campaign": 1, - "ga:dataSource": 1, - "ga:channelGrouping": 1, - "ga:keyword": 1, - "ga:adwordsCustomerName": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:subContinentCode": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:adwordsCriteriaID": 1, - "ga:date": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:day": 1, - "ga:goalCompletionsAll": 1, - "ga:searchExitRate": 1, - "ga:javaEnabled": 1, - "ga:language": 1, - "ga:medium": 1, - "ga:adDestinationUrl": 1, - "ga:region": 1, - "ga:isMobile": 1, - "ga:searchDuration": 1, - "ga:searchResultViews": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:bounces": 1, - "ga:dayOfWeekName": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:browser": 1, - "ga:transactionRevenuePerSession": 1, - "ga:adDistributionNetwork": 1, - "ga:percentSessionsWithSearch": 1, - "ga:longitude": 1, - "ga:nthHour": 1, - "ga:regionId": 1 - }, - "per_active_visitors_nthday_active_visitors_28": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:28dayUsers": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "gwo_bandit_metrics": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:experimentCombination": 1, - "ga:percentNewSessions": 1, - "ga:backfillClicks": 1, - "ga:newUsers": 1, - "ga:goalValueAllPerSearch": 1, - "ga:adxMonetizedPageviews": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:refundAmount": 1, - "ga:experimentName": 1, - "ga:searchDepth": 1, - "ga:adsenseExits": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:sessions": 1, - "ga:exceptions": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:pageviews": 1, - "ga:percentSearchRefinements": 1, - "ga:goalXXStarts": 1, - "ga:experimentOutcomeType": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:totalPublisherClicks": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:searchExits": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:transactionRevenue": 1, - "ga:entranceBounceRate": 1, - "ga:entranceRate": 1, - "ga:experimentOutcomes": 1, - "ga:goalAbandonRateAll": 1, - "ga:transactionsPerSession": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:goalValueAll": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:experimentId": 1, - "ga:totalRefunds": 1, - "ga:avgSearchDuration": 1, - "ga:adsenseECPM": 1, - "ga:goalValuePerSession": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:avgTimeOnPage": 1, - "ga:adxCTR": 1, - "ga:goalXXAbandonRate": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:totalPublisherRevenue": 1, - "ga:searchSessions": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:sessionDuration": 1, - "ga:adxECPM": 1, - "ga:experimentStarts": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXCompletions": 1, - "ga:goalXXAbandons": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:fatalExceptions": 1, - "ga:backfillRevenue": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:goalCompletionsAll": 1, - "ga:searchExitRate": 1, - "ga:adsenseAdsClicks": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:experimentVariant": 1, - "ga:searchDuration": 1, - "ga:searchResultViews": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:totalPublisherECPM": 1, - "ga:exits": 1, - "ga:bounces": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:adsensePageImpressions": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:transactionRevenuePerSession": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "Cube:analytics/per_value_site_search_without_transaction_product_dimensions": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:referralPath": 1, - "ga:transactionTax": 1, - "ga:metroId": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:dcmClickSite": 1, - "ga:dbmClickLineItemId": 1, - "ga:adxMonetizedPageviews": 1, - "ga:dsAdvertiserId": 1, - "ga:flashVersion": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:internalPromotionId": 1, - "ga:searchDestinationPage": 1, - "ga:goalStartsAll": 1, - "ga:dsEngineAccount": 1, - "ga:adwordsCreativeID": 1, - "ga:sessionsToTransaction": 1, - "ga:networkLocation": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:sourceMedium": 1, - "ga:uniquePurchases": 1, - "ga:pageDepth": 1, - "ga:landingContentGroup4": 1, - "ga:landingContentGroup3": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:landingContentGroup2": 1, - "ga:landingContentGroup1": 1, - "ga:previousPagePath": 1, - "ga:dbmClickSite": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:dcmClickSpotId": 1, - "ga:landingContentGroup5": 1, - "ga:adsenseCoverage": 1, - "ga:screenResolution": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:source": 1, - "ga:percentSearchRefinements": 1, - "ga:dsAdGroup": 1, - "ga:networkDomain": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmClickCreativeId": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:screenName": 1, - "ga:productRemovesFromCart": 1, - "ga:internalPromotionCreative": 1, - "ga:transactionRevenue": 1, - "ga:adSlot": 1, - "ga:secondPagePath": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:searchUsed": 1, - "ga:avgEventValue": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:dbmClickInsertionOrder": 1, - "ga:socialInteractionNetworkAction": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:dcmClickCreativeType": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:internalPromotionName": 1, - "ga:dbmClickLineItem": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:cityId": 1, - "ga:organicSearches": 1, - "ga:searchKeywordRefinement": 1, - "ga:landingScreenName": 1, - "ga:dbmClickAdvertiser": 1, - "ga:dcmFloodlightSpotId": 1, - "ga:previousContentGroup1": 1, - "ga:searchKeyword": 1, - "ga:previousContentGroup2": 1, - "ga:adsenseECPM": 1, - "ga:previousContentGroup3": 1, - "ga:adxImpressionsPerSession": 1, - "ga:previousContentGroup4": 1, - "ga:searchRefinements": 1, - "ga:dcmFloodlightActivity": 1, - "ga:appName": 1, - "ga:dsAdvertiser": 1, - "ga:quantityRefunded": 1, - "ga:latitude": 1, - "ga:nthMonth": 1, - "ga:previousContentGroup5": 1, - "ga:avgTimeOnPage": 1, - "ga:sourcePropertyTrackingId": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:continentId": 1, - "ga:deviceCategory": 1, - "ga:dcmClickSitePlacement": 1, - "ga:dbmClickCreativeId": 1, - "ga:nthWeek": 1, - "ga:dsCampaign": 1, - "ga:interestInMarketCategory": 1, - "ga:adMatchType": 1, - "ga:adwordsCustomerID": 1, - "ga:totalPublisherRevenue": 1, - "ga:userAgeBracket": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:dcmFloodlightActivityGroup": 1, - "ga:trafficType": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:continent": 1, - "ga:goalXXAbandons": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:customVarValueXX": 1, - "ga:landingPagePath": 1, - "ga:channelGrouping": 1, - "ga:searchCategory": 1, - "ga:dfpRevenue": 1, - "ga:adwordsCustomerName": 1, - "ga:dsCampaignId": 1, - "ga:mobileDeviceInfo": 1, - "ga:keyword": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:orderCouponCode": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:socialInteractionAction": 1, - "ga:dbmClickExchange": 1, - "ga:socialInteractionNetwork": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dcmClickCreativeTypeId": 1, - "ga:language": 1, - "ga:adsenseAdsClicks": 1, - "ga:searchAfterDestinationPage": 1, - "ga:affiliation": 1, - "ga:socialInteractions": 1, - "ga:isMobile": 1, - "ga:searchResultViews": 1, - "ga:exitScreenName": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:internalPromotionPosition": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:socialNetwork": 1, - "ga:dbmClickExchangeId": 1, - "ga:dsKeyword": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:adDistributionNetwork": 1, - "ga:userBucket": 1, - "ga:socialEngagementType": 1, - "ga:dsKeywordId": 1, - "ga:percentSessionsWithSearch": 1, - "ga:longitude": 1, - "ga:dcmClickAdTypeId": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:mobileInputSelector": 1, - "ga:timeOnScreen": 1, - "ga:shoppingStage": 1, - "ga:adGroup": 1, - "ga:week": 1, - "ga:dcmClickCampaign": 1, - "ga:sourcePropertyDisplayName": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dbmClickAdvertiserId": 1, - "ga:hour": 1, - "ga:adQueryWordCount": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:daysToTransaction": 1, - "ga:dbmClickCreativeName": 1, - "ga:searchStartPage": 1, - "ga:productListClicks": 1, - "ga:nextPagePath": 1, - "ga:dcmClickSitePlacementId": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:adTargetingType": 1, - "ga:screenDepth": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:appInstallerId": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:dcmClickRenderingId": 1, - "ga:adKeywordMatchType": 1, - "ga:searchDepth": 1, - "ga:subContinent": 1, - "ga:adsenseExits": 1, - "ga:appId": 1, - "ga:checkoutOptions": 1, - "ga:internalPromotionCTR": 1, - "ga:daysSinceLastSession": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:userType": 1, - "ga:dcmClickCreative": 1, - "ga:transactionId": 1, - "ga:sessionCount": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:searchExits": 1, - "ga:dcmClickSiteId": 1, - "ga:externalActivityId": 1, - "ga:dbmClickSiteId": 1, - "ga:dcmClickCreativeVersion": 1, - "ga:browserSize": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:minute": 1, - "ga:dcmFloodlightActivityGroupId": 1, - "ga:year": 1, - "ga:exitPagePath": 1, - "ga:sessionsPerUser": 1, - "ga:adTargetingOption": 1, - "ga:entranceBounceRate": 1, - "ga:customVarNameXX": 1, - "ga:quantityRemovedFromCart": 1, - "ga:socialInteractionTarget": 1, - "ga:transactionsPerSession": 1, - "ga:appVersion": 1, - "ga:dcmClickAdvertiserId": 1, - "ga:dcmFloodlightActivityAndGroup": 1, - "ga:country": 1, - "ga:goalValueAll": 1, - "ga:userGender": 1, - "ga:pagePath": 1, - "ga:dcmClickCampaignId": 1, - "ga:adMatchedQuery": 1, - "ga:totalPublisherImpressions": 1, - "ga:dsAdGroupId": 1, - "ga:totalValue": 1, - "ga:browserVersion": 1, - "ga:adsenseAdsViewed": 1, - "ga:nthMinute": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:operatingSystemVersion": 1, - "ga:mobileDeviceMarketingName": 1, - "ga:totalPublisherCoverage": 1, - "ga:sessionDurationBucket": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:dateHourMinute": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:adDisplayUrl": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:dcmClickAdType": 1, - "ga:metro": 1, - "ga:internalPromotionClicks": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:city": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:countryIsoCode": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dsAgency": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:clientId": 1, - "ga:dcmFloodlightActivityId": 1, - "ga:searchSessions": 1, - "ga:fullReferrer": 1, - "ga:productRefunds": 1, - "ga:dcmClickAdvertiser": 1, - "ga:socialInteractionNetworkActionSession": 1, - "ga:nextContentGroup1": 1, - "ga:hostname": 1, - "ga:nextContentGroup2": 1, - "ga:nextContentGroup3": 1, - "ga:nextContentGroup4": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:nextContentGroup5": 1, - "ga:interestOtherCategory": 1, - "ga:internalPromotionViews": 1, - "ga:dataSource": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:userDefinedValue": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:dsEngineAccountId": 1, - "ga:adPlacementDomain": 1, - "ga:backfillRevenue": 1, - "ga:subContinentCode": 1, - "ga:mobileDeviceModel": 1, - "ga:adFormat": 1, - "ga:adwordsCriteriaID": 1, - "ga:date": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:searchExitRate": 1, - "ga:javaEnabled": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:medium": 1, - "ga:adDestinationUrl": 1, - "ga:region": 1, - "ga:quantityAddedToCart": 1, - "ga:dcmClickAdId": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:dcmClickAd": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dsAgencyId": 1, - "ga:dayOfWeekName": 1, - "ga:adsensePageImpressions": 1, - "ga:mobileDeviceBranding": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:dcmFloodlightAdvertiserId": 1, - "ga:browser": 1, - "ga:transactionRevenuePerSession": 1, - "ga:interestAffinityCategory": 1, - "ga:regionId": 1, - "ga:adPlacementUrl": 1, - "ga:adxRevenue": 1, - "ga:dbmClickInsertionOrderId": 1, - "ga:totalPublisherCTR": 1, - "ga:campaignCode": 1 - }, - "per_orphan": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:percentNewSessions": 1, - "ga:backfillClicks": 1, - "ga:week": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:adxMonetizedPageviews": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:productListClicks": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:goalStartsAll": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:appInstallerId": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:uniquePurchases": 1, - "ga:searchDepth": 1, - "ga:adsenseExits": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:sessions": 1, - "ga:appId": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:pageviews": 1, - "ga:percentSearchRefinements": 1, - "ga:goalXXStarts": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:entrances": 1, - "ga:totalPublisherClicks": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:searchExits": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:screenName": 1, - "ga:productRemovesFromCart": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:year": 1, - "ga:transactionRevenue": 1, - "ga:sessionsPerUser": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:transactionsPerSession": 1, - "ga:appVersion": 1, - "ga:avgEventValue": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:goalValueAll": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:hits": 1, - "ga:eventValue": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:organicSearches": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:adsenseECPM": 1, - "ga:goalValuePerSession": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:appName": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:quantityRefunded": 1, - "ga:nthMonth": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:avgTimeOnPage": 1, - "ga:adxCTR": 1, - "ga:sessionsWithEvent": 1, - "ga:goalXXAbandonRate": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:nthWeek": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:totalPublisherRevenue": 1, - "ga:searchSessions": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:productRefunds": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:adsenseRevenue": 1, - "ga:uniqueScreenviews": 1, - "ga:goalXXCompletions": 1, - "ga:goalXXAbandons": 1, - "ga:isoYear": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:dayOfWeek": 1, - "ga:backfillRevenue": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:date": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:searchExitRate": 1, - "ga:adsenseAdsClicks": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:searchResultViews": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:productRevenuePerPurchase": 1, - "ga:month": 1, - "ga:totalPublisherECPM": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:bounces": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:adsensePageImpressions": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:transactionRevenuePerSession": 1, - "ga:percentSessionsWithSearch": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1, - "ga:timeOnScreen": 1 - }, - "ga_exp_objective_metrics": { - "ga:avgSearchDuration": 1, - "ga:adsenseECPM": 1, - "ga:goalValuePerSession": 1, - "ga:experimentCombination": 1, - "ga:searchRefinements": 1, - "ga:avgSessionDuration": 1, - "ga:goalValueAllPerSearch": 1, - "ga:goalXXAbandonRate": 1, - "ga:transactions": 1, - "ga:goalConversionRateAll": 1, - "ga:avgSearchDepth": 1, - "ga:goalStartsAll": 1, - "ga:goalXXValue": 1, - "ga:searchSessions": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:refundAmount": 1, - "ga:experimentName": 1, - "ga:searchDepth": 1, - "ga:sessions": 1, - "ga:exceptions": 1, - "ga:sessionDuration": 1, - "ga:adsenseCoverage": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXCompletions": 1, - "ga:screenviews": 1, - "ga:searchUniques": 1, - "ga:pageviews": 1, - "ga:percentSearchRefinements": 1, - "ga:goalXXAbandons": 1, - "ga:goalXXStarts": 1, - "ga:experimentOutcomeType": 1, - "ga:bounceRate": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:pageviewsPerSession": 1, - "ga:searchExits": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:adsenseCTR": 1, - "ga:transactionRevenue": 1, - "ga:goalCompletionsAll": 1, - "ga:searchExitRate": 1, - "ga:adsenseAdsClicks": 1, - "ga:transactionsPerSession": 1, - "ga:goalAbandonRateAll": 1, - "ga:experimentVariant": 1, - "ga:searchDuration": 1, - "ga:searchResultViews": 1, - "ga:goalXXConversionRate": 1, - "ga:goalValueAll": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:bounces": 1, - "ga:adsensePageImpressions": 1, - "ga:totalValue": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:adsenseAdsViewed": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:transactionRevenuePerSession": 1, - "ga:exceptionsPerScreenview": 1, - "ga:percentSessionsWithSearch": 1, - "ga:experimentId": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:totalRefunds": 1 - }, - "per_active_visitors_day_active_visitors_30": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:30dayUsers": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_active_visitors_day_active_visitors_7": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:7dayUsers": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "cohorts_overview_nth_day": { - "ga:acquisitionTrafficChannel": 1, - "ga:acquisitionSource": 1, - "ga:cohortRevenuePerUser": 1, - "ga:avgSessionDuration": 1, - "ga:cohortActiveUsers": 1, - "ga:cohortTotalUsersWithLifetimeCriteria": 1, - "ga:goalCompletionsAll": 1, - "ga:transactions": 1, - "ga:transactionRevenue": 1, - "ga:cohortSessionsPerUserWithLifetimeCriteria": 1, - "ga:cohort": 1, - "ga:goalConversionRateAll": 1, - "ga:cohortGoalCompletionsPerUserWithLifetimeCriteria": 1, - "ga:cohortGoalCompletionsPerUser": 1, - "ga:acquisitionMedium": 1, - "ga:transactionsPerSession": 1, - "ga:cohortRevenuePerUserWithLifetimeCriteria": 1, - "ga:cohortSessionDurationPerUserWithLifetimeCriteria": 1, - "ga:cohortPageviewsPerUser": 1, - "ga:cohortTotalUsers": 1, - "ga:acquisitionCampaign": 1, - "ga:sessions": 1, - "ga:cohortRetentionRate": 1, - "ga:acquisitionSourceMedium": 1, - "ga:cohortAppviewsPerUser": 1, - "ga:cohortNthDay": 1, - "ga:cohortSessionsPerUser": 1, - "ga:sessionDuration": 1, - "ga:cohortPageviewsPerUserWithLifetimeCriteria": 1, - "ga:screenviews": 1, - "ga:pageviews": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:transactionRevenuePerSession": 1, - "ga:cohortSessionDurationPerUser": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:pageviewsPerSession": 1, - "ga:cohortAppviewsPerUserWithLifetimeCriteria": 1 - }, - "per_goal_request_uri": { - "ga:goalValuePerSession": 1, - "ga:week": 1, - "ga:date": 1, - "ga:nthMonth": 1, - "ga:yearMonth": 1, - "ga:day": 1, - "ga:minute": 1, - "ga:year": 1, - "ga:hour": 1, - "ga:goalXXAbandonRate": 1, - "ga:goalCompletionsAll": 1, - "ga:goalConversionRateAll": 1, - "ga:nthWeek": 1, - "ga:isoWeek": 1, - "ga:goalStartsAll": 1, - "ga:goalAbandonRateAll": 1, - "ga:goalXXValue": 1, - "ga:goalXXConversionRate": 1, - "ga:goalValueAll": 1, - "ga:month": 1, - "ga:goalPreviousStep1": 1, - "ga:yearWeek": 1, - "ga:goalPreviousStep3": 1, - "ga:goalPreviousStep2": 1, - "ga:sessions": 1, - "ga:dayOfWeekName": 1, - "ga:metricXX": 1, - "ga:nthMinute": 1, - "ga:goalXXCompletions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:goalXXAbandons": 1, - "ga:goalXXStarts": 1, - "ga:isoYear": 1, - "ga:nthDay": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:goalCompletionLocation": 1, - "ga:nthHour": 1, - "ga:dateHour": 1, - "ga:dayOfWeek": 1, - "ga:dateHourMinute": 1, - "ga:dcmFloodlightQuantity": 1 - }, - "per_web_property_query_RESTRICTED": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:percentNewSessions": 1, - "ga:backfillClicks": 1, - "ga:week": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:productListClicks": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:goalStartsAll": 1, - "ga:adCost": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:users": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:uniquePurchases": 1, - "ga:searchDepth": 1, - "ga:adsenseExits": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:sessions": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:pageviews": 1, - "ga:percentSearchRefinements": 1, - "ga:goalXXStarts": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:entrances": 1, - "ga:totalPublisherClicks": 1, - "ga:revenuePerTransaction": 1, - "ga:ROI": 1, - "ga:screenviewsPerSession": 1, - "ga:searchExits": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:productRemovesFromCart": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:year": 1, - "ga:transactionRevenue": 1, - "ga:sessionsPerUser": 1, - "ga:entranceBounceRate": 1, - "ga:CTR": 1, - "ga:quantityRemovedFromCart": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:transactionsPerSession": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:goalValueAll": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:adsenseECPM": 1, - "ga:goalValuePerSession": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:quantityRefunded": 1, - "ga:nthMonth": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:avgTimeOnPage": 1, - "ga:adxCTR": 1, - "ga:sessionsWithEvent": 1, - "ga:goalXXAbandonRate": 1, - "ga:transactions": 1, - "ga:costPerConversion": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:nthWeek": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:totalPublisherRevenue": 1, - "ga:searchSessions": 1, - "ga:adClicks": 1, - "ga:uniqueSocialInteractions": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:productRefunds": 1, - "ga:totalEvents": 1, - "ga:costPerGoalConversion": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXCompletions": 1, - "ga:goalXXAbandons": 1, - "ga:ROAS": 1, - "ga:isoYear": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:dayOfWeek": 1, - "ga:backfillRevenue": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:date": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:searchExitRate": 1, - "ga:adsenseAdsClicks": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:CPM": 1, - "ga:socialInteractions": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:searchResultViews": 1, - "ga:margin": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:productRevenuePerPurchase": 1, - "ga:month": 1, - "ga:totalPublisherECPM": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:CPC": 1, - "ga:bounces": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:costPerTransaction": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:productListViews": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:transactionRevenuePerSession": 1, - "ga:percentSessionsWithSearch": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_sitelink_extension": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:referralPath": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:adwordsCreativeID": 1, - "ga:dfpCoverage": 1, - "ga:adCost": 1, - "ga:localRefundAmount": 1, - "ga:goalXXValue": 1, - "ga:sourceMedium": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:source": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:localTransactionShipping": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:ROI": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:transactionRevenue": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:localProductRefundAmount": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:nthMonth": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:deviceCategory": 1, - "ga:nthWeek": 1, - "ga:adwordsCustomerID": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:trafficType": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:ROAS": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:channelGrouping": 1, - "ga:dfpRevenue": 1, - "ga:adwordsCustomerName": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:localItemRevenue": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:adsenseAdsClicks": 1, - "ga:isMobile": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:costPerTransaction": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:adDistributionNetwork": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:localTransactionTax": 1, - "ga:week": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:adsenseExits": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:year": 1, - "ga:sessionsPerUser": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:adDisplayUrl": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:transactions": 1, - "ga:costPerConversion": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:costPerGoalConversion": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:adContent": 1, - "ga:dataSource": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:localTransactionRevenue": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:CPM": 1, - "ga:medium": 1, - "ga:adDestinationUrl": 1, - "ga:quantityAddedToCart": 1, - "ga:currencyCode": 1, - "ga:searchDuration": 1, - "ga:margin": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:CPC": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:pageLoadTime": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_campaign_with_local_currency": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:referralPath": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:adCost": 1, - "ga:localRefundAmount": 1, - "ga:goalXXValue": 1, - "ga:sourceMedium": 1, - "ga:experimentName": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:source": 1, - "ga:percentSearchRefinements": 1, - "ga:experimentOutcomeType": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:localTransactionShipping": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:ROI": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:transactionRevenue": 1, - "ga:adSlot": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:localProductRefundAmount": 1, - "ga:organicSearches": 1, - "ga:isTrueViewVideoAd": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:appName": 1, - "ga:quantityRefunded": 1, - "ga:nthMonth": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:deviceCategory": 1, - "ga:nthWeek": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:trafficType": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:ROAS": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:channelGrouping": 1, - "ga:dfpRevenue": 1, - "ga:keyword": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:localItemRevenue": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:adsenseAdsClicks": 1, - "ga:experimentVariant": 1, - "ga:isMobile": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:socialNetwork": 1, - "ga:costPerTransaction": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:adGroup": 1, - "ga:localTransactionTax": 1, - "ga:experimentCombination": 1, - "ga:week": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:appInstallerId": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:adsenseExits": 1, - "ga:appId": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:externalActivityId": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:adSlotPosition": 1, - "ga:year": 1, - "ga:sessionsPerUser": 1, - "ga:adTargetingOption": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:appVersion": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:experimentId": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:transactions": 1, - "ga:costPerConversion": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:searchSessions": 1, - "ga:fullReferrer": 1, - "ga:productRefunds": 1, - "ga:costPerGoalConversion": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:adContent": 1, - "ga:dataSource": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:adPlacementDomain": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:localTransactionRevenue": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:CPM": 1, - "ga:medium": 1, - "ga:adDestinationUrl": 1, - "ga:quantityAddedToCart": 1, - "ga:currencyCode": 1, - "ga:searchDuration": 1, - "ga:margin": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:CPC": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:pageLoadTime": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:transactionRevenuePerSession": 1, - "ga:adPlacementUrl": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1, - "ga:campaignCode": 1 - }, - "Cube:analytics/per_ecommerce_refund_import_without_transaction_product_metrics": { - "ga:transactionId": 1, - "ga:quantityRefunded": 1, - "ga:productSku": 1 - }, - "per_active_visitors_nthday_active_visitors_1": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:1dayUsers": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_dfa_model": { - "ga:metroId": 1, - "ga:percentNewSessions": 1, - "ga:week": 1, - "ga:dbmConversions": 1, - "ga:dcmLastEventAdvertiserId": 1, - "ga:newUsers": 1, - "ga:hour": 1, - "ga:dbmLastEventLineItemId": 1, - "ga:dcmLastEventAdvertiser": 1, - "ga:flashVersion": 1, - "ga:isoWeek": 1, - "ga:internalPromotionId": 1, - "ga:dcmLastEventCampaignId": 1, - "ga:goalStartsAll": 1, - "ga:dbmLastEventCreativeName": 1, - "ga:networkLocation": 1, - "ga:goalXXValue": 1, - "ga:users": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:subContinent": 1, - "ga:sessions": 1, - "ga:dbmLastEventSiteId": 1, - "ga:dcmLastEventAd": 1, - "ga:metricXX": 1, - "ga:dcmLastEventSpotId": 1, - "ga:screenResolution": 1, - "ga:isTablet": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:networkDomain": 1, - "ga:bounceRate": 1, - "ga:nthDay": 1, - "ga:revenuePerTransaction": 1, - "ga:dbmLastEventAdvertiser": 1, - "ga:dbmLastEventAdvertiserId": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:browserSize": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:year": 1, - "ga:dcmLastEventSitePlacementId": 1, - "ga:internalPromotionCreative": 1, - "ga:transactionRevenue": 1, - "ga:sessionsPerUser": 1, - "ga:dbmCPM": 1, - "ga:goalAbandonRateAll": 1, - "ga:transactionsPerSession": 1, - "ga:dcmLastEventAdType": 1, - "ga:dcmCTR": 1, - "ga:country": 1, - "ga:dcmLastEventCreativeVersion": 1, - "ga:goalValueAll": 1, - "ga:dcmLastEventSite": 1, - "ga:dbmLastEventInsertionOrderId": 1, - "ga:dcmCost": 1, - "ga:totalValue": 1, - "ga:browserVersion": 1, - "ga:dcmLastEventCreativeId": 1, - "ga:dbmROAS": 1, - "ga:internalPromotionName": 1, - "ga:cityId": 1, - "ga:operatingSystemVersion": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:dcmLastEventCreative": 1, - "ga:dateHour": 1, - "ga:dbmLastEventSite": 1, - "ga:totalRefunds": 1, - "ga:dcmLastEventSitePlacement": 1, - "ga:dcmLastEventSiteId": 1, - "ga:goalValuePerSession": 1, - "ga:dcmLastEventCampaign": 1, - "ga:transactionsPerUser": 1, - "ga:metro": 1, - "ga:latitude": 1, - "ga:nthMonth": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:city": 1, - "ga:goalXXAbandonRate": 1, - "ga:deviceCategory": 1, - "ga:continentId": 1, - "ga:transactions": 1, - "ga:countryIsoCode": 1, - "ga:dbmLastEventExchange": 1, - "ga:goalConversionRateAll": 1, - "ga:nthWeek": 1, - "ga:dcmRPC": 1, - "ga:dbmLastEventCreativeId": 1, - "ga:dcmClicks": 1, - "ga:dcmLastEventAttributionType": 1, - "ga:sessionDuration": 1, - "ga:dbmLastEventExchangeId": 1, - "ga:dbmLastEventInsertionOrder": 1, - "ga:goalXXCompletions": 1, - "ga:continent": 1, - "ga:goalXXAbandons": 1, - "ga:isoYear": 1, - "ga:dbmCost": 1, - "ga:dcmLastEventCreativeType": 1, - "ga:dataSource": 1, - "ga:pageviewsPerSession": 1, - "ga:dcmLastEventAdTypeId": 1, - "ga:dayOfWeek": 1, - "ga:dcmLastEventCreativeTypeId": 1, - "ga:dcmLastEventAdId": 1, - "ga:subContinentCode": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:day": 1, - "ga:dcmLastEventRenderingId": 1, - "ga:goalCompletionsAll": 1, - "ga:dbmCTR": 1, - "ga:javaEnabled": 1, - "ga:language": 1, - "ga:region": 1, - "ga:dcmROAS": 1, - "ga:dbmLastEventLineItem": 1, - "ga:isMobile": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:internalPromotionPosition": 1, - "ga:bounces": 1, - "ga:dayOfWeekName": 1, - "ga:dbmClicks": 1, - "ga:dcmImpressions": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:dcmROI": 1, - "ga:dcmMargin": 1, - "ga:browser": 1, - "ga:transactionRevenuePerSession": 1, - "ga:dbmImpressions": 1, - "ga:longitude": 1, - "ga:regionId": 1, - "ga:nthHour": 1 - }, - "per_geo_dimension_widening_city_id": { - "ga:dimensionXX": 1, - "ga:cityId": 1 - }, - "smart_data_dimension_subcube": { - "ga:percentNewSessions": 1, - "ga:week": 1, - "ga:transactionsPerUser": 1, - "ga:date": 1, - "ga:nthMonth": 1, - "ga:day": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:newUsers": 1, - "ga:year": 1, - "ga:sessionsPerUser": 1, - "ga:transactions": 1, - "ga:transactionRevenue": 1, - "ga:nthWeek": 1, - "ga:medium": 1, - "ga:transactionsPerSession": 1, - "ga:users": 1, - "ga:sourceMedium": 1, - "ga:revenuePerUser": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:bounces": 1, - "ga:sessions": 1, - "ga:dayOfWeekName": 1, - "ga:sessionDuration": 1, - "ga:pageviews": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:source": 1, - "ga:bounceRate": 1, - "ga:transactionRevenuePerSession": 1, - "ga:channelGrouping": 1, - "ga:nthDay": 1, - "ga:revenuePerTransaction": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1 - }, - "per_campaign_dart_search": { - "ga:transactionTax": 1, - "ga:percentNewSessions": 1, - "ga:week": 1, - "ga:avgServerConnectionTime": 1, - "ga:newUsers": 1, - "ga:hour": 1, - "ga:avgPageLoadTime": 1, - "ga:dsAdvertiserId": 1, - "ga:domContentLoadedTime": 1, - "ga:flashVersion": 1, - "ga:isoWeek": 1, - "ga:goalStartsAll": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dsEngineAccount": 1, - "ga:goalXXValue": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:pageLoadSample": 1, - "ga:adsenseExits": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:sessions": 1, - "ga:metricXX": 1, - "ga:dsRevenuePerClick": 1, - "ga:screenResolution": 1, - "ga:screenviews": 1, - "ga:avgScreenviewDuration": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:dsAdGroup": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:nthDay": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:redirectionTime": 1, - "ga:speedMetricsSample": 1, - "ga:browserSize": 1, - "ga:year": 1, - "ga:transactionRevenue": 1, - "ga:sessionsPerUser": 1, - "ga:entranceBounceRate": 1, - "ga:entranceRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dsCPC": 1, - "ga:avgDomainLookupTime": 1, - "ga:dsAdGroupId": 1, - "ga:totalValue": 1, - "ga:browserVersion": 1, - "ga:pageValue": 1, - "ga:exitRate": 1, - "ga:operatingSystemVersion": 1, - "ga:organicSearches": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:dsCost": 1, - "ga:dsImpressions": 1, - "ga:goalValuePerSession": 1, - "ga:dsAdvertiser": 1, - "ga:transactionsPerUser": 1, - "ga:dsReturnOnAdSpend": 1, - "ga:transactionShipping": 1, - "ga:nthMonth": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:avgTimeOnPage": 1, - "ga:domLatencyMetricsSample": 1, - "ga:goalXXAbandonRate": 1, - "ga:transactions": 1, - "ga:goalConversionRateAll": 1, - "ga:dsAgency": 1, - "ga:nthWeek": 1, - "ga:dsCampaign": 1, - "ga:sessionDuration": 1, - "ga:avgDomInteractiveTime": 1, - "ga:uniqueScreenviews": 1, - "ga:goalXXCompletions": 1, - "ga:avgUserTimingValue": 1, - "ga:goalXXAbandons": 1, - "ga:isoYear": 1, - "ga:serverResponseTime": 1, - "ga:dsCampaignId": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:dsEngineAccountId": 1, - "ga:date": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:dsClicks": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:avgServerResponseTime": 1, - "ga:goalCompletionsAll": 1, - "ga:javaEnabled": 1, - "ga:language": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:bounces": 1, - "ga:dsAgencyId": 1, - "ga:dayOfWeekName": 1, - "ga:avgPageDownloadTime": 1, - "ga:dsProfit": 1, - "ga:avgRedirectionTime": 1, - "ga:pageLoadTime": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:dsKeyword": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:browser": 1, - "ga:transactionRevenuePerSession": 1, - "ga:dsCTR": 1, - "ga:domInteractiveTime": 1, - "ga:dsKeywordId": 1, - "ga:nthHour": 1, - "ga:userTimingSample": 1, - "ga:timeOnScreen": 1 - }, - "per_query_with_cost_metrics": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:referralPath": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:adwordsCreativeID": 1, - "ga:dfpCoverage": 1, - "ga:adCost": 1, - "ga:localRefundAmount": 1, - "ga:goalXXValue": 1, - "ga:sourceMedium": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:source": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:localTransactionShipping": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:ROI": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:transactionRevenue": 1, - "ga:adSlot": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:localProductRefundAmount": 1, - "ga:organicSearches": 1, - "ga:isTrueViewVideoAd": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:nthMonth": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:deviceCategory": 1, - "ga:nthWeek": 1, - "ga:adMatchType": 1, - "ga:adwordsCustomerID": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:trafficType": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:ROAS": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:channelGrouping": 1, - "ga:dfpRevenue": 1, - "ga:adwordsCustomerName": 1, - "ga:keyword": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:localItemRevenue": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:adsenseAdsClicks": 1, - "ga:isMobile": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:socialNetwork": 1, - "ga:costPerTransaction": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:adDistributionNetwork": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:adGroup": 1, - "ga:localTransactionTax": 1, - "ga:week": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:adQueryWordCount": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:adKeywordMatchType": 1, - "ga:searchDepth": 1, - "ga:adsenseExits": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:year": 1, - "ga:sessionsPerUser": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:adMatchedQuery": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:adDisplayUrl": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:transactions": 1, - "ga:costPerConversion": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:costPerGoalConversion": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:adContent": 1, - "ga:dataSource": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:adwordsCriteriaID": 1, - "ga:date": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:localTransactionRevenue": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:CPM": 1, - "ga:medium": 1, - "ga:adDestinationUrl": 1, - "ga:quantityAddedToCart": 1, - "ga:currencyCode": 1, - "ga:searchDuration": 1, - "ga:margin": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:CPC": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:pageLoadTime": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "gwo_transaction_subcube": { - "ga:itemQuantity": 1, - "ga:transactionTax": 1, - "ga:experimentCombination": 1, - "ga:productRemovesFromCart": 1, - "ga:transactionShipping": 1, - "ga:quantityRefunded": 1, - "ga:productCheckouts": 1, - "ga:transactions": 1, - "ga:transactionRevenue": 1, - "ga:productDetailViews": 1, - "ga:productListClicks": 1, - "ga:quantityRemovedFromCart": 1, - "ga:buyToDetailRate": 1, - "ga:quantityAddedToCart": 1, - "ga:experimentVariant": 1, - "ga:refundAmount": 1, - "ga:productRevenuePerPurchase": 1, - "ga:experimentName": 1, - "ga:uniquePurchases": 1, - "ga:productRefunds": 1, - "ga:productListCTR": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:quantityCheckedOut": 1, - "ga:productAddsToCart": 1, - "ga:productListViews": 1, - "ga:experimentOutcomeType": 1, - "ga:revenuePerItem": 1, - "ga:transactionId": 1, - "ga:cartToDetailRate": 1, - "ga:itemRevenue": 1, - "ga:revenuePerTransaction": 1, - "ga:experimentId": 1, - "ga:totalRefunds": 1 - }, - "enhanced_campaign": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:adCost": 1, - "ga:goalXXValue": 1, - "ga:sourceMedium": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:source": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:ROI": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:transactionRevenue": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:nthMonth": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:nthWeek": 1, - "ga:adwordsCustomerID": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:trafficType": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:ROAS": 1, - "ga:campaign": 1, - "ga:isoYear": 1, - "ga:dfpRevenue": 1, - "ga:adwordsCustomerName": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:adsenseAdsClicks": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:costPerTransaction": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:adDistributionNetwork": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:adGroup": 1, - "ga:week": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:adsenseExits": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:externalActivityId": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:year": 1, - "ga:sessionsPerUser": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:transactions": 1, - "ga:costPerConversion": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:costPerGoalConversion": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:CPM": 1, - "ga:medium": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:margin": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:CPC": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:pageLoadTime": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:productListViews": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_content_with_gwo_id_and_outcomes": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:metroId": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:flashVersion": 1, - "ga:backfillCTR": 1, - "ga:isoWeek": 1, - "ga:internalPromotionId": 1, - "ga:searchDestinationPage": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:adwordsCreativeID": 1, - "ga:networkLocation": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:experimentName": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:pageDepth": 1, - "ga:landingContentGroup4": 1, - "ga:landingContentGroup3": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:landingContentGroup2": 1, - "ga:landingContentGroup1": 1, - "ga:previousPagePath": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:landingContentGroup5": 1, - "ga:adsenseCoverage": 1, - "ga:screenResolution": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:userTimingCategory": 1, - "ga:percentSearchRefinements": 1, - "ga:experimentOutcomeType": 1, - "ga:networkDomain": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:screenName": 1, - "ga:productRemovesFromCart": 1, - "ga:internalPromotionCreative": 1, - "ga:transactionRevenue": 1, - "ga:secondPagePath": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:avgSearchResultViews": 1, - "ga:adwordsCampaignID": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:socialInteractionNetworkAction": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:internalPromotionName": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:cityId": 1, - "ga:organicSearches": 1, - "ga:landingScreenName": 1, - "ga:previousContentGroup1": 1, - "ga:previousContentGroup2": 1, - "ga:adsenseECPM": 1, - "ga:previousContentGroup3": 1, - "ga:adxImpressionsPerSession": 1, - "ga:previousContentGroup4": 1, - "ga:searchRefinements": 1, - "ga:appName": 1, - "ga:quantityRefunded": 1, - "ga:latitude": 1, - "ga:nthMonth": 1, - "ga:previousContentGroup5": 1, - "ga:avgTimeOnPage": 1, - "ga:sourcePropertyTrackingId": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:continentId": 1, - "ga:deviceCategory": 1, - "ga:nthWeek": 1, - "ga:interestInMarketCategory": 1, - "ga:adMatchType": 1, - "ga:adwordsCustomerID": 1, - "ga:totalPublisherRevenue": 1, - "ga:userAgeBracket": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:experimentStarts": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:continent": 1, - "ga:goalXXAbandons": 1, - "ga:isoYear": 1, - "ga:customVarValueXX": 1, - "ga:landingPagePath": 1, - "ga:dfpRevenue": 1, - "ga:adwordsCustomerName": 1, - "ga:mobileDeviceInfo": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:adwordsAdGroupID": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:contentGroup1": 1, - "ga:contentGroup2": 1, - "ga:socialInteractionAction": 1, - "ga:contentGroup3": 1, - "ga:contentGroup4": 1, - "ga:contentGroup5": 1, - "ga:socialInteractionNetwork": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:language": 1, - "ga:adsenseAdsClicks": 1, - "ga:searchAfterDestinationPage": 1, - "ga:socialInteractions": 1, - "ga:userTimingLabel": 1, - "ga:experimentVariant": 1, - "ga:isMobile": 1, - "ga:searchResultViews": 1, - "ga:exitScreenName": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:internalPromotionPosition": 1, - "ga:bounces": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:adDistributionNetwork": 1, - "ga:userBucket": 1, - "ga:domInteractiveTime": 1, - "ga:socialEngagementType": 1, - "ga:percentSessionsWithSearch": 1, - "ga:longitude": 1, - "ga:nthHour": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:mobileInputSelector": 1, - "ga:timeOnScreen": 1, - "ga:shoppingStage": 1, - "ga:experimentCombination": 1, - "ga:week": 1, - "ga:sourcePropertyDisplayName": 1, - "ga:goalValueAllPerSearch": 1, - "ga:hour": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:nextPagePath": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:contentGroupUniqueViews2": 1, - "ga:contentGroupUniqueViews1": 1, - "ga:adTargetingType": 1, - "ga:screenDepth": 1, - "ga:uniqueEvents": 1, - "ga:users": 1, - "ga:contentGroupUniqueViews5": 1, - "ga:contentGroupUniqueViews4": 1, - "ga:appInstallerId": 1, - "ga:contentGroupUniqueViews3": 1, - "ga:revenuePerUser": 1, - "ga:refundAmount": 1, - "ga:adKeywordMatchType": 1, - "ga:searchDepth": 1, - "ga:subContinent": 1, - "ga:adsenseExits": 1, - "ga:appId": 1, - "ga:checkoutOptions": 1, - "ga:internalPromotionCTR": 1, - "ga:daysSinceLastSession": 1, - "ga:pageviews": 1, - "ga:userTimingVariable": 1, - "ga:goalXXStarts": 1, - "ga:userType": 1, - "ga:sessionCount": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:externalActivityId": 1, - "ga:speedMetricsSample": 1, - "ga:browserSize": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:minute": 1, - "ga:year": 1, - "ga:exitPagePath": 1, - "ga:sessionsPerUser": 1, - "ga:adTargetingOption": 1, - "ga:entranceBounceRate": 1, - "ga:customVarNameXX": 1, - "ga:previousPageLinkId": 1, - "ga:quantityRemovedFromCart": 1, - "ga:socialInteractionTarget": 1, - "ga:experimentOutcomes": 1, - "ga:transactionsPerSession": 1, - "ga:appVersion": 1, - "ga:pageDownloadTime": 1, - "ga:country": 1, - "ga:goalValueAll": 1, - "ga:userGender": 1, - "ga:pagePath": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:browserVersion": 1, - "ga:adsenseAdsViewed": 1, - "ga:nthMinute": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:adxCoverage": 1, - "ga:operatingSystemVersion": 1, - "ga:mobileDeviceMarketingName": 1, - "ga:totalPublisherCoverage": 1, - "ga:sessionDurationBucket": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:experimentId": 1, - "ga:dateHour": 1, - "ga:totalRefunds": 1, - "ga:dateHourMinute": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:adDisplayUrl": 1, - "ga:transactionsPerUser": 1, - "ga:transactionShipping": 1, - "ga:metro": 1, - "ga:internalPromotionClicks": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:city": 1, - "ga:domLatencyMetricsSample": 1, - "ga:transactions": 1, - "ga:countryIsoCode": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:clientId": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:socialInteractionNetworkActionSession": 1, - "ga:nextContentGroup1": 1, - "ga:hostname": 1, - "ga:nextContentGroup2": 1, - "ga:nextContentGroup3": 1, - "ga:nextContentGroup4": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:nextContentGroup5": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:interestOtherCategory": 1, - "ga:internalPromotionViews": 1, - "ga:dataSource": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:pageTitle": 1, - "ga:userDefinedValue": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:adPlacementDomain": 1, - "ga:backfillRevenue": 1, - "ga:subContinentCode": 1, - "ga:mobileDeviceModel": 1, - "ga:adFormat": 1, - "ga:adwordsCriteriaID": 1, - "ga:date": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:javaEnabled": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:adDestinationUrl": 1, - "ga:region": 1, - "ga:pagePathLevel4": 1, - "ga:quantityAddedToCart": 1, - "ga:pagePathLevel1": 1, - "ga:searchDuration": 1, - "ga:pagePathLevel3": 1, - "ga:backfillImpressions": 1, - "ga:pagePathLevel2": 1, - "ga:goalXXConversionRate": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:dayOfWeekName": 1, - "ga:adsensePageImpressions": 1, - "ga:mobileDeviceBranding": 1, - "ga:avgRedirectionTime": 1, - "ga:pageLoadTime": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:productListViews": 1, - "ga:browser": 1, - "ga:transactionRevenuePerSession": 1, - "ga:interestAffinityCategory": 1, - "ga:regionId": 1, - "ga:adPlacementUrl": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_user_id_dimension_widening": { - "ga:dimensionXX": 1 - }, - "per_geo_dimension_widening_sub_continent_code": { - "ga:dimensionXX": 1, - "ga:subContinentCode": 1 - }, - "store_visits": { - "ga:referralPath": 1, - "ga:adGroup": 1, - "ga:metroId": 1, - "ga:percentNewSessions": 1, - "ga:week": 1, - "ga:metro": 1, - "ga:nthMonth": 1, - "ga:latitude": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:newUsers": 1, - "ga:city": 1, - "ga:avgTimeOnPage": 1, - "ga:hour": 1, - "ga:continentId": 1, - "ga:deviceCategory": 1, - "ga:countryIsoCode": 1, - "ga:nthWeek": 1, - "ga:networkLocation": 1, - "ga:users": 1, - "ga:sourceMedium": 1, - "ga:subContinent": 1, - "ga:sessions": 1, - "ga:sessionDuration": 1, - "ga:continent": 1, - "ga:isTablet": 1, - "ga:pageviews": 1, - "ga:adContent": 1, - "ga:source": 1, - "ga:campaign": 1, - "ga:networkDomain": 1, - "ga:timeOnPage": 1, - "ga:dataSource": 1, - "ga:bounceRate": 1, - "ga:nthDay": 1, - "ga:channelGrouping": 1, - "ga:entrances": 1, - "ga:keyword": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:subContinentCode": 1, - "ga:date": 1, - "ga:day": 1, - "ga:year": 1, - "ga:sessionsPerUser": 1, - "ga:entranceBounceRate": 1, - "ga:medium": 1, - "ga:entranceRate": 1, - "ga:region": 1, - "ga:isMobile": 1, - "ga:country": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:adwordsCampaignID": 1, - "ga:exits": 1, - "ga:bounces": 1, - "ga:dayOfWeekName": 1, - "ga:regionIsoCode": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:cityId": 1, - "ga:uniquePageviews": 1, - "ga:longitude": 1, - "ga:nthHour": 1, - "ga:regionId": 1, - "ga:dateHour": 1 - }, - "per_active_visitors_nthday_active_visitors_7": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:7dayUsers": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "per_exception": { - "ga:percentNewSessions": 1, - "ga:week": 1, - "ga:appName": 1, - "ga:nthMonth": 1, - "ga:yearMonth": 1, - "ga:avgSessionDuration": 1, - "ga:newUsers": 1, - "ga:avgTimeOnPage": 1, - "ga:hour": 1, - "ga:sessionsWithEvent": 1, - "ga:deviceCategory": 1, - "ga:flashVersion": 1, - "ga:nthWeek": 1, - "ga:isoWeek": 1, - "ga:appInstallerId": 1, - "ga:totalEvents": 1, - "ga:sessions": 1, - "ga:appId": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:exceptionDescription": 1, - "ga:sessionDuration": 1, - "ga:screenResolution": 1, - "ga:uniqueScreenviews": 1, - "ga:screenviews": 1, - "ga:isTablet": 1, - "ga:avgScreenviewDuration": 1, - "ga:pageviews": 1, - "ga:isoYear": 1, - "ga:timeOnPage": 1, - "ga:dataSource": 1, - "ga:nthDay": 1, - "ga:screenviewsPerSession": 1, - "ga:mobileDeviceInfo": 1, - "ga:pageTitle": 1, - "ga:pageviewsPerSession": 1, - "ga:dayOfWeek": 1, - "ga:fatalExceptions": 1, - "ga:mobileDeviceModel": 1, - "ga:screenName": 1, - "ga:browserSize": 1, - "ga:date": 1, - "ga:screenColors": 1, - "ga:operatingSystem": 1, - "ga:day": 1, - "ga:year": 1, - "ga:javaEnabled": 1, - "ga:language": 1, - "ga:appVersion": 1, - "ga:isMobile": 1, - "ga:avgEventValue": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:month": 1, - "ga:yearWeek": 1, - "ga:exits": 1, - "ga:pagePath": 1, - "ga:dayOfWeekName": 1, - "ga:browserVersion": 1, - "ga:mobileDeviceBranding": 1, - "ga:eventValue": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:exitRate": 1, - "ga:isoYearIsoWeek": 1, - "ga:dimensionXX": 1, - "ga:operatingSystemVersion": 1, - "ga:browser": 1, - "ga:mobileDeviceMarketingName": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:nthHour": 1, - "ga:dateHour": 1, - "ga:mobileInputSelector": 1, - "ga:timeOnScreen": 1 - }, - "channel_grouping_rule_key": { - "ga:sessions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1 - }, - "per_active_visitors_date_active_visitors_30": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:30dayUsers": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - }, - "cohorts_overview_nth_month": { - "ga:acquisitionTrafficChannel": 1, - "ga:acquisitionSource": 1, - "ga:cohortRevenuePerUser": 1, - "ga:avgSessionDuration": 1, - "ga:cohortActiveUsers": 1, - "ga:cohortTotalUsersWithLifetimeCriteria": 1, - "ga:goalCompletionsAll": 1, - "ga:transactions": 1, - "ga:transactionRevenue": 1, - "ga:cohortSessionsPerUserWithLifetimeCriteria": 1, - "ga:cohort": 1, - "ga:goalConversionRateAll": 1, - "ga:cohortGoalCompletionsPerUserWithLifetimeCriteria": 1, - "ga:cohortGoalCompletionsPerUser": 1, - "ga:acquisitionMedium": 1, - "ga:transactionsPerSession": 1, - "ga:cohortRevenuePerUserWithLifetimeCriteria": 1, - "ga:cohortSessionDurationPerUserWithLifetimeCriteria": 1, - "ga:cohortPageviewsPerUser": 1, - "ga:cohortTotalUsers": 1, - "ga:acquisitionCampaign": 1, - "ga:sessions": 1, - "ga:cohortRetentionRate": 1, - "ga:acquisitionSourceMedium": 1, - "ga:cohortAppviewsPerUser": 1, - "ga:cohortSessionsPerUser": 1, - "ga:sessionDuration": 1, - "ga:cohortPageviewsPerUserWithLifetimeCriteria": 1, - "ga:screenviews": 1, - "ga:pageviews": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:transactionRevenuePerSession": 1, - "ga:cohortSessionDurationPerUser": 1, - "ga:cohortNthMonth": 1, - "ga:revenuePerTransaction": 1, - "ga:screenviewsPerSession": 1, - "ga:pageviewsPerSession": 1, - "ga:cohortAppviewsPerUserWithLifetimeCriteria": 1 - }, - "per_active_visitors_nthday_active_visitors_14": { - "ga:totalPublisherRevenuePer1000Sessions": 1, - "ga:transactionTax": 1, - "ga:backfillClicks": 1, - "ga:percentNewSessions": 1, - "ga:avgServerConnectionTime": 1, - "ga:productCheckouts": 1, - "ga:newUsers": 1, - "ga:RPC": 1, - "ga:adxMonetizedPageviews": 1, - "ga:avgPageLoadTime": 1, - "ga:backfillCTR": 1, - "ga:goalStartsAll": 1, - "ga:avgDomContentLoadedTime": 1, - "ga:domainLookupTime": 1, - "ga:dfpCoverage": 1, - "ga:goalXXValue": 1, - "ga:uniquePurchases": 1, - "ga:pageLoadSample": 1, - "ga:sessions": 1, - "ga:totalPublisherMonetizedPageviews": 1, - "ga:exceptions": 1, - "ga:metricXX": 1, - "ga:adxImpressions": 1, - "ga:adsenseCoverage": 1, - "ga:searchUniques": 1, - "ga:screenviews": 1, - "ga:productAddsToCart": 1, - "ga:avgScreenviewDuration": 1, - "ga:percentSearchRefinements": 1, - "ga:dfpImpressions": 1, - "ga:timeOnPage": 1, - "ga:bounceRate": 1, - "ga:entrances": 1, - "ga:revenuePerTransaction": 1, - "ga:dcmFloodlightQuantity": 1, - "ga:redirectionTime": 1, - "ga:productRemovesFromCart": 1, - "ga:dbmCPA": 1, - "ga:dbmCPC": 1, - "ga:transactionRevenue": 1, - "ga:dbmCPM": 1, - "ga:CTR": 1, - "ga:entranceRate": 1, - "ga:buyToDetailRate": 1, - "ga:goalAbandonRateAll": 1, - "ga:avgEventValue": 1, - "ga:dcmCTR": 1, - "ga:adxViewableImpressionsPercent": 1, - "ga:socialInteractionsPerSession": 1, - "ga:fatalExceptionsPerScreenview": 1, - "ga:avgSearchResultViews": 1, - "ga:backfillRevenuePer1000Sessions": 1, - "ga:productListCTR": 1, - "ga:avgDomainLookupTime": 1, - "ga:hits": 1, - "ga:totalPublisherImpressionsPerSession": 1, - "ga:adxClicks": 1, - "ga:pageValue": 1, - "ga:dfpClicks": 1, - "ga:dfpImpressionsPerSession": 1, - "ga:organicSearches": 1, - "ga:adsenseECPM": 1, - "ga:adxImpressionsPerSession": 1, - "ga:searchRefinements": 1, - "ga:quantityRefunded": 1, - "ga:avgTimeOnPage": 1, - "ga:goalXXAbandonRate": 1, - "ga:adxCTR": 1, - "ga:totalPublisherRevenue": 1, - "ga:adClicks": 1, - "ga:adsenseViewableImpressionPercent": 1, - "ga:uniqueSocialInteractions": 1, - "ga:totalEvents": 1, - "ga:itemsPerPurchase": 1, - "ga:productRefundAmount": 1, - "ga:avgDomInteractiveTime": 1, - "ga:goalXXCompletions": 1, - "ga:adsenseRevenue": 1, - "ga:goalXXAbandons": 1, - "ga:dbmCost": 1, - "ga:dfpRevenue": 1, - "ga:pageviewsPerSession": 1, - "ga:fatalExceptions": 1, - "ga:searchGoalXXConversionRate": 1, - "ga:goalCompletionsAll": 1, - "ga:productDetailViews": 1, - "ga:dbmCTR": 1, - "ga:14dayUsers": 1, - "ga:adsenseAdsClicks": 1, - "ga:socialInteractions": 1, - "ga:dcmROAS": 1, - "ga:searchResultViews": 1, - "ga:productRevenuePerPurchase": 1, - "ga:totalPublisherECPM": 1, - "ga:bounces": 1, - "ga:dbmClicks": 1, - "ga:searchGoalConversionRateAll": 1, - "ga:avgPageDownloadTime": 1, - "ga:revenuePerItem": 1, - "ga:cartToDetailRate": 1, - "ga:dbmImpressions": 1, - "ga:domInteractiveTime": 1, - "ga:percentSessionsWithSearch": 1, - "ga:adsenseAdUnitsViewed": 1, - "ga:timeOnScreen": 1, - "ga:dbmConversions": 1, - "ga:goalValueAllPerSearch": 1, - "ga:dfpViewableImpressionsPercent": 1, - "ga:domContentLoadedTime": 1, - "ga:productListClicks": 1, - "ga:uniqueDimensionCombinations": 1, - "ga:uniqueEvents": 1, - "ga:refundAmount": 1, - "ga:searchDepth": 1, - "ga:pageviews": 1, - "ga:goalXXStarts": 1, - "ga:itemRevenue": 1, - "ga:nthDay": 1, - "ga:totalPublisherClicks": 1, - "ga:screenviewsPerSession": 1, - "ga:serverConnectionTime": 1, - "ga:searchExits": 1, - "ga:speedMetricsSample": 1, - "ga:backfillViewableImpressionsPercent": 1, - "ga:entranceBounceRate": 1, - "ga:quantityRemovedFromCart": 1, - "ga:transactionsPerSession": 1, - "ga:pageDownloadTime": 1, - "ga:goalValueAll": 1, - "ga:dcmCost": 1, - "ga:totalPublisherImpressions": 1, - "ga:totalValue": 1, - "ga:adsenseAdsViewed": 1, - "ga:eventValue": 1, - "ga:exitRate": 1, - "ga:dfpECPM": 1, - "ga:backfillMonetizedPageviews": 1, - "ga:dbmROAS": 1, - "ga:adxCoverage": 1, - "ga:totalPublisherCoverage": 1, - "ga:dcmFloodlightRevenue": 1, - "ga:uniquePageviews": 1, - "ga:exceptionsPerScreenview": 1, - "ga:totalRefunds": 1, - "ga:itemQuantity": 1, - "ga:avgSearchDuration": 1, - "ga:goalValuePerSession": 1, - "ga:transactionShipping": 1, - "ga:avgSessionDuration": 1, - "ga:backfillECPM": 1, - "ga:domLatencyMetricsSample": 1, - "ga:sessionsWithEvent": 1, - "ga:transactions": 1, - "ga:avgSearchDepth": 1, - "ga:goalConversionRateAll": 1, - "ga:dfpMonetizedPageviews": 1, - "ga:dcmRPC": 1, - "ga:searchSessions": 1, - "ga:productRefunds": 1, - "ga:dcmClicks": 1, - "ga:sessionDuration": 1, - "ga:quantityCheckedOut": 1, - "ga:adxECPM": 1, - "ga:uniqueScreenviews": 1, - "ga:avgUserTimingValue": 1, - "ga:dfpRevenuePer1000Sessions": 1, - "ga:backfillCoverage": 1, - "ga:serverResponseTime": 1, - "ga:totalPublisherViewableImpressionsPercent": 1, - "ga:backfillRevenue": 1, - "ga:date": 1, - "ga:dcmCPC": 1, - "ga:userTimingValue": 1, - "ga:day": 1, - "ga:dfpCTR": 1, - "ga:adsenseCTR": 1, - "ga:avgServerResponseTime": 1, - "ga:searchExitRate": 1, - "ga:backfillImpressionsPerSession": 1, - "ga:quantityAddedToCart": 1, - "ga:searchDuration": 1, - "ga:backfillImpressions": 1, - "ga:goalXXConversionRate": 1, - "ga:exits": 1, - "ga:adxRevenuePer1000Sessions": 1, - "ga:impressions": 1, - "ga:adsensePageImpressions": 1, - "ga:avgRedirectionTime": 1, - "ga:eventsPerSessionWithEvent": 1, - "ga:pageLoadTime": 1, - "ga:dcmImpressions": 1, - "ga:calcMetric_\u003cNAME\u003e": 1, - "ga:goalAbandonsAll": 1, - "ga:dcmROI": 1, - "ga:productListViews": 1, - "ga:dcmMargin": 1, - "ga:transactionRevenuePerSession": 1, - "ga:userTimingSample": 1, - "ga:adxRevenue": 1, - "ga:totalPublisherCTR": 1 - } -} diff --git a/src/components/DimensionsMetricsExplorer/index.spec.tsx b/src/components/DimensionsMetricsExplorer/index.spec.tsx deleted file mode 100644 index 7136ce7b..00000000 --- a/src/components/DimensionsMetricsExplorer/index.spec.tsx +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" -import * as renderer from "@testing-library/react" -import { withProviders } from "../../test-utils" -import userEvent from "@testing-library/user-event" -import "@testing-library/jest-dom" - -import DimensionMetricsExplorer from "./index" - -describe("Dimensions and Metrics Explorer", () => { - // This test may go out of date, but we want at least once instance of making - // sure the intersection logic works for compatable dimensions. - it("disables incompatable metric when 'User Type' dimension is selected", async () => { - const { wrapped, gapi } = withProviders() - const { getByText, findByLabelText } = renderer.render(wrapped) - - // Wait for api promise to resolve so it won't render "fetching". - await renderer.act(async () => { - // metadata: { columns: { list: () => metadataColumnsPromise } }, - await gapi!.client!.analytics!.metadata!.columns!.list!() - // await gapi.client.analytics.management.accountSummaries.list() - }) - - await renderer.act(async () => { - userEvent.click(getByText("User")) - const userType = await findByLabelText(/User Type/) - const oneDayActiveUsers = await findByLabelText(/1 Day Active Users/) - expect(userType).not.toBeDisabled() - expect(oneDayActiveUsers).not.toBeDisabled() - userEvent.click(userType) - expect(oneDayActiveUsers).toBeDisabled() - }) - }) -}) diff --git a/src/components/DimensionsMetricsExplorer/index.tsx b/src/components/DimensionsMetricsExplorer/index.tsx deleted file mode 100644 index b2d74734..00000000 --- a/src/components/DimensionsMetricsExplorer/index.tsx +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import Typography from "@mui/material/Typography" -import Explorer from "./Explorer" - -export const DimensionsMetricsExplorer = () => { - return ( - <> - - The Dimensions & Metrics Explorer lists and describes all of the - dimensions and metrics available through the Core Reporting API. - - - - The Dimensions & Metrics Explorer has the following features: - - - - Explore all of the dimensions and metrics – Search or - browse by group. Select a dimension or metric for additional details - such as descriptions and attributes. - - - - Identify valid combinations – Not all dimensions and - metrics can be queried together. Only certain dimensions and metrics can - be used together to create valid combinations. Select a dimension or - metric checkbox to see all the other values that can be combined in the - same query. - - - - - ) -} - -export default DimensionsMetricsExplorer diff --git a/src/components/DimensionsMetricsExplorer/useAnchorRedirects.ts b/src/components/DimensionsMetricsExplorer/useAnchorRedirects.ts deleted file mode 100644 index a6affec6..00000000 --- a/src/components/DimensionsMetricsExplorer/useAnchorRedirects.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { navigate } from "gatsby" -import { useLocation } from "@reach/router" -import { useEffect } from "react" - -// This is used to do client-side redirects from the old ga:id style hash that -// was used in the old demos and tools site. -const useAnchorRedirects = ( - columns: gapi.client.analytics.Column[] | undefined -) => { - const { hash, pathname } = useLocation() - - useEffect(() => { - if (hash === undefined || hash === "" || columns === undefined) { - return - } - if (hash.startsWith("#ga:")) { - const id = hash.substring(1) - const column = columns.find(column => { - return column.id === id - }) - // This is the case where there isn't a dim/met to redirect to. - if (column === undefined) { - return - } - const group = column.attributes!.group - const newUrl = - pathname + - group.toLowerCase().replaceAll(" ", "-") + - "#" + - hash.substring(4) - navigate(newUrl, { replace: true }) - } - }, [hash, columns, pathname]) -} - -export default useAnchorRedirects diff --git a/src/components/DimensionsMetricsExplorer/useColumns.ts b/src/components/DimensionsMetricsExplorer/useColumns.ts deleted file mode 100644 index 60fbec38..00000000 --- a/src/components/DimensionsMetricsExplorer/useColumns.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { StorageKey } from "@/constants" -import useCached from "@/hooks/useCached" -import { Requestable, RequestStatus } from "@/types" -import { Column } from "@/types/ua" -import moment from "moment" -import { useCallback, useMemo } from "react" -import { useSelector } from "react-redux" - -const useColumns = (): Requestable< - { columns: Column[] }, - {}, - {}, - { error: any } -> => { - const gapi = useSelector((a: AppState) => a.gapi) - const metadataAPI = useMemo(() => gapi?.client?.analytics?.metadata, [gapi]) - - const requestReady = useMemo(() => metadataAPI !== undefined, [metadataAPI]) - - const makeRequest = useCallback(async () => { - if (metadataAPI === undefined) { - throw new Error("Invalid invariant - metadataAPI must be defined here.") - } - return metadataAPI.columns - .list({ reportType: "ga" }) - .then(response => response.result.items) - }, [metadataAPI]) - - const columnsRequest = useCached( - StorageKey.dimensionsMetricsExplorerColumns, - makeRequest, - moment.duration(5, "minutes"), - requestReady - ) - - return useMemo(() => { - switch (columnsRequest.status) { - case RequestStatus.Successful: { - const columns = columnsRequest.value - if (columns === undefined) { - throw new Error("invalid invarint - columns must be defined here") - } - return { status: columnsRequest.status, columns } - } - case RequestStatus.NotStarted: - case RequestStatus.InProgress: - return { status: columnsRequest.status } - case RequestStatus.Failed: { - return columnsRequest - } - } - }, [columnsRequest]) -} - -export default useColumns diff --git a/src/components/HitBuilder/HitCard.tsx b/src/components/HitBuilder/HitCard.tsx deleted file mode 100644 index c3ba719f..00000000 --- a/src/components/HitBuilder/HitCard.tsx +++ /dev/null @@ -1,405 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import React from "react" - -import { styled } from '@mui/material/styles'; - -import Warning from "@mui/icons-material/Warning" -import ErrorIcon from "@mui/icons-material/Error" -import Button from "@mui/material/Button" -import TextField from "@mui/material/TextField" -import Check from "@mui/icons-material/Check" -import Send from "@mui/icons-material/Send" -import Cached from "@mui/icons-material/Cached" -import Paper from "@mui/material/Paper" -import Typography from "@mui/material/Typography" -import {orange, green, yellow, red} from "@mui/material/colors" -import classnames from "classnames" - -import { PAB } from "@/components/Buttons" -import CopyButton from "@/components/CopyButton" -import { ParametersAPI, Validation } from "./hooks" -const PREFIX = 'HitCard'; - -enum HitStatus { - Unvalidated = "UNVALIDATED", - Validating = "VALIDATING", - Valid = "VALID", - Invalid = "INVALID", - Sent = "Sent", - Sending = "Sending", -} - -const classes = { - hitElement: `${PREFIX}-hitElement`, - hitElementActions: `${PREFIX}-hitElementActions`, - addParameterButton: `${PREFIX}-addParameterButton`, - validationStatus: `${PREFIX}-validationStatus`, - httpInfo: `${PREFIX}-httpInfo`, - payload: `${PREFIX}-payload`, - hitStatusValidating: `${PREFIX}-hitStatus-${HitStatus.Validating}`, - hitStatusSending: `${PREFIX}-hitStatus-${HitStatus.Sending}`, - hitStatusInvalid: `${PREFIX}-hitStatus-${HitStatus.Invalid}`, - hitStatusSent: `${PREFIX}-hitStatus-${HitStatus.Sent}`, - hitStatusValid: `${PREFIX}-hitStatus-${HitStatus.Valid}`, - hitStatusUnvalidated: `${PREFIX}-hitStatus-${HitStatus.Unvalidated}` -}; - -const Root = styled('div')(( - { - theme - } -) => ({ - [`& .${classes.hitElement}`]: { - padding: theme.spacing(2, 3), - display: "flex", - flexDirection: "column", - }, - - [`&.${classes.hitElementActions}`]: { - marginTop: theme.spacing(2), - display: "flex", - "& > button": { - marginRight: theme.spacing(1), - }, - }, - - [`& .${classes.addParameterButton}`]: { - marginLeft: theme.spacing(1), - }, - - [`& .${classes.validationStatus}`]: { - // Picked this value through a bit of trial and error, but having a - // minHeight makes this not jump around during the "sending" and - // "validating" states. - minHeight: theme.spacing(24), - margin: theme.spacing(-3, -3, 1, -3), - padding: theme.spacing(0, 3), - "& > span": { - "& > svg": { - fontSize: theme.typography.h1.fontSize, - }, - "& > h3": { - marginLeft: theme.spacing(1), - fontSize: theme.typography.h2.fontSize, - }, - display: "flex", - alignItems: "center", - marginTop: theme.spacing(1), - }, - }, - - [`& .${classes.httpInfo}`]: { - margin: theme.spacing(1, 0, 2, 0), - "& > span": { - fontFamily: "'Source Code Pro', monospace", - }, - }, - - [`& .${classes.payload}`]: { - flexGrow: 1, - }, - [`& .${classes.hitStatusValidating}`]: { - backgroundColor: orange[100], - color: orange[900], - }, - [`& .${classes.hitStatusSending}`]: { - backgroundColor: orange[100], - color: orange[900], - }, - [`& .${classes.hitStatusInvalid}`]: { - backgroundColor: red[100], - color: red[900], - }, - [`& .${classes.hitStatusSent}`]: { - backgroundColor: green[100], - color: green[900], - }, - [`& .${classes.hitStatusValid}`]: { - backgroundColor: green[100], - color: green[900], - }, - [`& .${classes.hitStatusUnvalidated}`]: { - backgroundColor: yellow[100], - color: yellow[900], - }, -})); - -interface HitCardProps { - hitPayload: string - hitStatus: Validation["hitStatus"] - validationMessages: Validation["validationMessages"] - sendHit: Validation["sendHit"] - validateHit: Validation["validateHit"] - addParameter: ParametersAPI["addParameter"] - hasParameter: ParametersAPI["hasParameter"] - setParametersFromString: ParametersAPI["setParametersFromString"] -} - -const HitCard: React.FC = ({ - validateHit, - sendHit, - hitPayload, - hitStatus, - validationMessages, - addParameter, - hasParameter, - setParametersFromString, -}) => { - - const [value, setValue] = React.useState(hitPayload) - - // Update the localState of then input when the hitPayload changes. - React.useEffect(() => { - setValue(hitPayload) - }, [hitPayload]) - - const onChange = React.useCallback( - (e: React.ChangeEvent) => { - setValue(e.target.value) - setParametersFromString(e.target.value) - }, - [setParametersFromString] - ) - return ( - - - -
- - POST /collect HTTP/1.1 - -
- - Host: www.google-analytics.com - -
- - -
-
- ) -} - -interface ValidationStatusProps { - validationMessages: Validation["validationMessages"] - hitStatus: Validation["hitStatus"] - addParameter: ParametersAPI["addParameter"] - hasParameter: ParametersAPI["hasParameter"] -} - -const ValidationStatus: React.FC = ({ - validationMessages, - hitStatus, - addParameter, - hasParameter, -}) => { - - - let headerIcon: JSX.Element | null = null - let hitHeading: JSX.Element | null = null - let hitContent: JSX.Element[] | JSX.Element | null = null - switch (hitStatus) { - case HitStatus.Sent: - case HitStatus.Valid: { - headerIcon = - hitHeading = Hit is valid! - hitContent = ( - <> - - Use the controls below to copy the hit or share it with coworkers. - - - You can also send the hit to Google Analytics and watch it in action - in the Real Time view. - - - ) - break - } - case HitStatus.Invalid: { - headerIcon = - hitHeading = Hit is invalid! - hitContent = ( -
    - {validationMessages.map(message => { - let addParameterButton: JSX.Element | null = null - if ( - message.code === "VALUE_REQUIRED" && - !hasParameter(message.param) - ) { - addParameterButton = ( - - ) - } - return ( -
  • - - {message.description} - {addParameterButton} - -
  • - ) - })} -
- ) - break - } - case HitStatus.Sending: - case HitStatus.Validating: { - headerIcon = - hitHeading = ( - - {hitStatus === HitStatus.Sending ? "Sending" : "Validating"} hit... - - ) - break - } - case HitStatus.Unvalidated: { - headerIcon = - hitHeading = ( - This hit has not been validated. - ) - hitContent = ( - <> - - You can update the hit using any of the controls below. - - - When you're done editing parameters, click the "Validate hit" button - to make sure everything's OK. - - - ) - break - } - default: { - throw new Error(`${hitStatus} has not been accounted for.`) - } - } - return ( - - - {headerIcon} - {hitHeading} - - {hitContent} - - ) -} - -interface HitActionsProps { - hitPayload: string - hitStatus: Validation["hitStatus"] - validateHit: Validation["validateHit"] - sendHit: Validation["sendHit"] -} - -const HitActions: React.FC = ({ - hitStatus, - hitPayload, - validateHit, - sendHit, -}) => { - - - switch (hitStatus) { - case HitStatus.Sent: - case HitStatus.Valid: { - const sendHitButton = ( - - : } - onClick={sendHit} - className="Button Button--success Button-withIcon" - variant="contained" - > - Send to GA - - - ) - - const sharableLinkToHit = - window.location.protocol + - "//" + - window.location.host + - window.location.pathname + - "?" + - hitPayload - return ( - - {sendHitButton} - - - - ); - } - default: { - return ( - -
- - {hitStatus === HitStatus.Validating - ? "Validating..." - : "Validate hit"} - -
-
- ) - } - } -} - -export default HitCard diff --git a/src/components/HitBuilder/Parameters.tsx b/src/components/HitBuilder/Parameters.tsx deleted file mode 100644 index bb7e1a63..00000000 --- a/src/components/HitBuilder/Parameters.tsx +++ /dev/null @@ -1,317 +0,0 @@ -import * as React from "react" - -import { styled } from '@mui/material/styles'; - -import {Delete, Refresh} from "@mui/icons-material" -import FormControl from "@mui/material/FormControl" -import InputLabel from "@mui/material/InputLabel" -import MenuItem from "@mui/material/MenuItem" -import Select from "@mui/material/Select" -import TextField from "@mui/material/TextField" -import Typography from "@mui/material/Typography" -import InputAdornment from "@mui/material/InputAdornment" -import Tooltip from "@mui/material/Tooltip" -import IconButton from "@mui/material/IconButton" -import Autocomplete from "@mui/material/Autocomplete" -import Add from "@mui/icons-material/Add" -import Button from "@mui/material/Button" -import {v4 as uuid} from "uuid" - -import {HIT_TYPES, Property} from "./types" -import {ParametersAPI, Validation} from "./hooks" - -const PREFIX = 'Parameters'; - -const classes = { - subdued: `${PREFIX}-subdued`, - propertyOption: `${PREFIX}-propertyOption`, - inputs: `${PREFIX}-inputs`, - addedParam: `${PREFIX}-addedParam` -}; - -const Root = styled('section')(( - { - theme - } -) => ({ - [`& .${classes.subdued}`]: { - color: theme.palette.grey[500], - }, - - [`& .${classes.propertyOption}`]: { - display: "flex", - width: "100%", - flexDirection: "column", - position: "relative", - "& > span": { - position: "absolute", - right: theme.spacing(2), - }, - }, - - [`&.${classes.inputs}`]: { - maxWidth: "600px", - display: "flex", - flexDirection: "column", - "& > div": { - margin: theme.spacing(1), - }, - "& > button": { - alignSelf: "flex-end", - margin: theme.spacing(2), - marginRight: theme.spacing(1), - }, - }, - - [`& .${classes.addedParam}`]: { - display: "flex", - "& > div:first-child": { - marginRight: theme.spacing(1), - }, - "& > div:nth-child(2)": { - flexGrow: 1, - }, - } -})); - -interface ParametersProps { - updateParameterName: ParametersAPI["updateParameterName"] - updateParameterValue: ParametersAPI["updateParameterValue"] - removeParameter: ParametersAPI["removeParameter"] - shouldFocus: ParametersAPI["shouldFocus"] - addParameter: ParametersAPI["addParameter"] - parameters: ParametersAPI["parameters"] - properties: Property[] - validationMessages: Validation["validationMessages"] -} -const Parameters: React.FC = ({ - updateParameterName, - updateParameterValue, - shouldFocus, - removeParameter, - addParameter, - parameters, - properties, -}) => { - - const newParam = React.useRef(null) - const [v, t, tid, cid, ...otherParams] = parameters - - const setHitType = React.useCallback( - (hitType: string) => { - updateParameterValue(t.id, hitType) - }, - [t.id, updateParameterValue] - ) - - const setCid = React.useCallback( - (newId: string) => { - updateParameterValue(cid.id, newId) - }, - [cid.id, updateParameterValue] - ) - - const setTid = React.useCallback( - (newTid: string) => { - updateParameterValue(tid.id, newTid) - }, - [tid.id, updateParameterValue] - ) - const [localPropertyInput, setLocalPropertyInput] = React.useState("") - - React.useEffect(() => { - if (tid.value !== localPropertyInput) { - setLocalPropertyInput(tid.value as string) - } - }, [tid.value, localPropertyInput]) - - return ( - - - v - - - - - id="t" - data-testid={`change-t`} - blurOnSelect - openOnFocus - autoHighlight - autoSelect - multiple={false} - options={HIT_TYPES} - freeSolo - getOptionLabel={a => a} - value={t.value as string} - renderInput={params => ( - - )} - onChange={(_, value) => { - typeof value === "string" && setHitType(value) - }} - /> - - - id="tid" - blurOnSelect - freeSolo - openOnFocus - autoHighlight - multiple={false} - options={properties} - getOptionLabel={ (a) => typeof a === "string" ? a : a.id} - inputValue={localPropertyInput} - onChange={(_, value) => { - if (value !== null) { - // TODO fix the type here later. - setTid((value as any).id) - } - }} - onInputChange={(_, value, reason) => { - // Don't set the local property input if the reason was reset. - if (reason === "clear" || reason === "input") { - setLocalPropertyInput(value) - setTid(value) - } - }} - filterOptions={(options, state) => { - return options.filter(option => { - return [option.group, option.id, option.name].find(v => - v.match(state.inputValue) - ) - }) - }} - renderOption={(props, a) => { - return ( - -
- - {a.name} - - - {a.id} - - - {a.group} - -
-
- ) - }} - renderInput={params => ( - - )} - /> - - setCid(e.target.value)} - label="cid" - variant="outlined" - size="small" - InputProps={{ - endAdornment: ( - - - setCid(uuid())} - > - - - - - ), - }} - /> - - {otherParams.map((param, idx) => { - const isDuplicate = - otherParams.find( - other => - param.name !== "" && - other.id !== param.id && - param.name === other.name - ) !== undefined - const helperText = isDuplicate ? "Duplicate Parameter Name" : undefined - return ( -
- { - updateParameterName(param.id, e.target.value) - }} - /> - { - updateParameterValue(param.id, e.target.value) - }} - InputProps={{ - endAdornment: ( - - - { - removeParameter(param.id) - }} - > - - - - - ), - }} - /> -
- ) - })} - - -
- ); -} -export default Parameters diff --git a/src/components/HitBuilder/hit.ts b/src/components/HitBuilder/hit.ts deleted file mode 100644 index 2ec3b95e..00000000 --- a/src/components/HitBuilder/hit.ts +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import { WindowLocation } from "@reach/router" - -import { - Param, - Params, - RequiredParams, - ParamV, - ParamT, - ParamTId, - ParamCId, - ParamOptional, - HIT_TYPES, -} from "./types" - -const DEFAULT_HIT = "v=1&t=pageview" - -/** - * Gets the initial hit from the URL if present. If no hit is found in the URL - * the default hit is used. - * @return The default hit. - */ -export function getInitialHitAndUpdateUrl(l: WindowLocation): string { - const query = l.search.slice(1) - - if (query === "") { - return DEFAULT_HIT - } - // Remove the query params after initial load. - window.history.replaceState({}, document.title, window.location.pathname) - return query -} - -/** - * Accepts a hit payload or URL and converts it into an array of param objects - * where the required params are always first and in the correct order. - * @param hit A query string or hit payload. - */ -export function convertHitToParams( - nextId: () => number, - hit: string = "" -): Params { - // If the hit contains a "?", remove it and all characters before it. - const searchIndex = hit.indexOf("?") - if (searchIndex > -1) hit = hit.slice(searchIndex + 1) - - let query = new URLSearchParams() - try { - query = new URLSearchParams(hit) - } catch (e) { - // It's common to paste in a string that's invalid, but we can easily - // recover from here. - } - - // Create required params first, regardless of order in the hit. - const v: ParamV = { - id: nextId(), - name: RequiredParams.V, - value: query.get(RequiredParams.V) || "1", - required: true, - } - const t: ParamT = { - id: nextId(), - name: RequiredParams.T, - value: query.get(RequiredParams.T) || HIT_TYPES[0], - required: true, - } - const tid: ParamTId = { - id: nextId(), - name: RequiredParams.T_Id, - value: query.get(RequiredParams.T_Id) || "", - required: true, - } - const cid: ParamCId = { - id: nextId(), - name: RequiredParams.C_Id, - value: query.get(RequiredParams.C_Id) || "", - required: true, - } - query.delete(RequiredParams.V) - query.delete(RequiredParams.T) - query.delete(RequiredParams.T_Id) - query.delete(RequiredParams.C_Id) - - // Create optional params after required params. - const others: ParamOptional[] = Array.from(query).map(([name, v]) => { - const value = v === undefined ? "" : v - return { - name, - value, - id: nextId(), - isOptional: true, - } - }) - const params: Params = [v, t, tid, cid, ...others] - return params -} - -/** - * Returns the hit model data as a query string. - * @param params An array of param objects. - */ -export function convertParamsToHit(params: Param[]): string { - const searchParams = new URLSearchParams() - - //const query: { [name: string]: any } = {} - for (const { name, value } of params) { - if (value === "") { - continue - } - searchParams.append(name, value) - //query[name] = value - } - - // Convert the URLSearchParams object to a string. - const searchParamsString = searchParams.toString() - // Replace the encoded commas with commas. - const decodedSearchParamsString = searchParamsString.replace(/%2C/g, ',') - - return decodedSearchParamsString -} - -export interface ValidationResult { - response: { - parserMessage: any[] - hitParsingResult: { - valid: boolean - parserMessage: { - messageType: any - description: string - messageCode: any - parameter: string - }[] - hit: string - }[] - } - hit: string -} - -/** - * Sends a validation request to the Measurement Protocol Validation Server - * and returns a promise that will be fulfilled with the response. - * @param hit A Measurement Protocol hit payload. - */ -export async function getHitValidationResult( - hit: string -): Promise { - const apiResponse = await fetch( - "https://www.google-analytics.com/debug/collect", - { - method: "POST", - body: hit, - } - ) - const asJson = await apiResponse.json() - return { response: asJson, hit } -} diff --git a/src/components/HitBuilder/hooks.ts b/src/components/HitBuilder/hooks.ts deleted file mode 100644 index fbca49e9..00000000 --- a/src/components/HitBuilder/hooks.ts +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import { useSelector } from "react-redux" -import { useLocation } from "@reach/router" - -import { Params, Param, ValidationMessage, HitStatus, Property } from "./types" -import * as hitUtils from "./hit" - -const formatMessage = (message: { - parameter: any - description: string - messageType: any - messageCode: any -}) => { - const linkRegex = /Please see http:\/\/goo\.gl\/a8d4RP#\w+ for details\.$/ - return { - param: message.parameter, - description: message.description.replace(linkRegex, "").trim(), - type: message.messageType, - code: message.messageCode, - } -} - -const sleep = async (milliseconds: number): Promise => { - return new Promise(resolve => { - window.setTimeout(() => { - resolve() - }, milliseconds) - }) -} - -export type Validation = { - validationMessages: ValidationMessage[] - hitStatus: HitStatus - // Validate the hit against the measurement protocol validation server - validateHit: () => void - // Send the hit to GA - sendHit: () => void -} -type UseValidationServer = (parameters: Params) => Validation -export const useValidationServer: UseValidationServer = parameters => { - const [hitStatus, setHitStatus] = React.useState(HitStatus.Unvalidated) - - React.useEffect(() => { - setHitStatus(HitStatus.Unvalidated) - }, [parameters]) - - const [validationMessages, setValidationMessages] = React.useState< - ValidationMessage[] - >([]) - - const validateHit = React.useCallback(() => { - setHitStatus(HitStatus.Validating) - try { - const hit = hitUtils.convertParamsToHit(parameters) - Promise.all([ - hitUtils.getHitValidationResult(hit), - sleep(500), - ]).then(([validationResult, _]) => { - const result = validationResult.response.hitParsingResult[0] - const validationMessages = result.parserMessage.filter( - // TODO - I might want to do something different with ERRORS - // versus INFOs. Check what the current one does. - message => message.messageType === "ERROR" - ) - setValidationMessages(validationMessages.map(formatMessage)) - if (result.valid) { - setHitStatus(HitStatus.Valid) - } else { - setHitStatus(HitStatus.Invalid) - } - }) - } catch (e) {} - }, [parameters]) - - const sendHit = React.useCallback(async () => { - setHitStatus(HitStatus.Sending) - const hit = hitUtils.convertParamsToHit(parameters) - await Promise.all([ - sleep(500), - fetch("https://www.google-analytics.com/collect", { - method: "POST", - body: hit, - }), - ]) - setHitStatus(HitStatus.Sent) - }, [parameters]) - - return { validationMessages, validateHit, hitStatus, sendHit } -} - -let id = 0 -const nextId = () => { - id++ - return id -} - -export type ParametersAPI = { - updateParameterName: (id: number, newName: string) => void - updateParameterValue: (id: number, newValue: any) => void - addParameter: (parameterName?: string) => void - removeParameter: (id: number) => void - hasParameter: (parameterName: string) => boolean - setParametersFromString: (paramString: string) => void - parameters: Params - shouldFocus: (id: number, value: boolean) => boolean - setFocus: (id: number, value: boolean) => void -} -type UseParameters = () => ParametersAPI -export const useParameters: UseParameters = () => { - const location = useLocation() - - const [parameters, setParameters] = React.useState(() => { - const initial = hitUtils.getInitialHitAndUpdateUrl(location) - return hitUtils.convertHitToParams(nextId, initial) - }) - - const [focusData, setFocusData] = React.useState< - | { - id: number - value: boolean - } - | undefined - >(undefined) - - const setParametersFromString = React.useCallback((paramString: string) => { - setFocusData(undefined) - setParameters(hitUtils.convertHitToParams(nextId, paramString)) - }, []) - - // Sets the focus to a particular param/value combo - const setFocus = React.useCallback((id: number, value = false) => { - setFocusData({ id, value }) - }, []) - - const resetFocus = React.useCallback(() => { - setFocusData(undefined) - }, [setFocusData]) - - const shouldFocus = React.useCallback( - (id: number, value = false) => { - if (focusData === undefined) { - return false - } - // Not sure about the value part. - return focusData.id === id && focusData.value === value - }, - [focusData] - ) - - const hasParameter = React.useCallback( - (parameterName: string): boolean => { - const param = parameters.find(p => p.name === parameterName) - return param !== undefined - }, - [parameters] - ) - - const addParameter = React.useCallback( - (parameterName?: string) => { - const id = nextId() - const nuParameter: Param = { id, name: parameterName || "", value: "" } - setParameters(([v, t, tid, cid, ...others]) => { - return [v, t, tid, cid, ...others.concat([nuParameter])] - }) - setFocus(id, parameterName !== undefined) - }, - [setFocus] - ) - - const removeParameter = React.useCallback( - (id: number) => { - setParameters(([v, t, tid, cid, ...others]) => { - resetFocus() - return [v, t, tid, cid, ...others.filter(a => a.id !== id)] - }) - }, - [resetFocus] - ) - - const updateParameterName = React.useCallback( - (id: number, newName: string) => { - setParameters(([v, t, tid, cid, ...others]) => { - return [ - v, - t, - tid, - cid, - ...others.map(param => - param.id === id ? { ...param, name: newName } : param - ), - ] - }) - }, - [] - ) - - const updateParameterValue = React.useCallback( - (id: number, newValue: any) => { - setParameters(params => { - const nuParams = params.map(param => - param.id === id ? { ...param, value: newValue } : param - ) as Params - return nuParams - }) - }, - [] - ) - - return { - setFocus, - shouldFocus, - updateParameterName, - updateParameterValue, - addParameter, - removeParameter, - hasParameter, - setParametersFromString, - parameters, - } -} - -type UseProperties = () => { - properties: Property[] -} -// This hook encapsulates the logic for getting the user's GA properties using -// the management api. -export const useProperties: UseProperties = () => { - const gapi = useSelector((state: AppState) => state.gapi) - const managementAPI = React.useMemo( - () => gapi?.client?.analytics?.management, - [gapi] - ) - const [properties, setProperties] = React.useState([]) - - React.useEffect(() => { - if (managementAPI === undefined) { - return - } - ;(async () => { - const summaries = (await managementAPI.accountSummaries?.list({})).result - const properties: Property[] = [] - summaries.items?.forEach(account => { - const accountName = account.name || "" - account.webProperties?.forEach(property => { - const propertyName = property.name || "" - const propertyId = property.id || "" - properties.push({ - name: propertyName, - id: propertyId, - group: accountName, - }) - }) - }) - setProperties(properties) - })() - }, [managementAPI]) - - return { properties } -} diff --git a/src/components/HitBuilder/index.spec.tsx b/src/components/HitBuilder/index.spec.tsx deleted file mode 100644 index ee88e0e0..00000000 --- a/src/components/HitBuilder/index.spec.tsx +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import * as renderer from "@testing-library/react" -import userEvent from "@testing-library/user-event" -import "@testing-library/jest-dom" - -import { withProviders } from "@/test-utils" -import HitBuilder from "./index" - -const getInputs = async ( - findByLabelText: (label: string) => Promise -) => { - const v = await findByLabelText("v") - const t = await findByLabelText("t") - const tid = await findByLabelText("tid") - const cid = (await findByLabelText("cid")) as HTMLInputElement - const hitPayload = (await findByLabelText("Hit payload")) as HTMLInputElement - - return { v, t, tid, cid, hitPayload } -} - -describe("HitBuilder", () => { - // test("can render page without error", () => { - // const { wrapped } = withProviders() - // renderer.render(wrapped) - // }) - - // TODO - Make tests for layout.spec.tsx that makes sure that all demos that - // should require auth do. - - describe("When authorized", () => { - describe("Initial parameter values are right", () => { - test("with no query parameters", async () => { - const { wrapped } = withProviders() - const { findByLabelText } = renderer.render(wrapped) - - const { hitPayload } = await getInputs(findByLabelText) - expect(hitPayload).toHaveValue("v=1&t=pageview") - }) - - test("with query parameters for a non-default t parameter", async () => { - const queryParams = "v=1&t=screenview&tid=UA-fake&cid=abc&an=def&cd=ghi" - - const { wrapped } = withProviders(, { - path: `/hit-builder?${queryParams}`, - }) - const { findByLabelText, findAllByLabelText } = renderer.render(wrapped) - - const { v, t, tid, cid, hitPayload } = await getInputs(findByLabelText) - expect(hitPayload).toHaveValue(queryParams) - - expect(v).toContainHTML("1") - expect(t).toHaveValue("screenview") - expect(tid).toHaveValue("UA-fake") - expect(cid).toHaveValue("abc") - - const parameterLabels = await findAllByLabelText("Parameter name") - expect(parameterLabels).toHaveLength(2) - - // an parameter - expect(parameterLabels[0]).toHaveValue("an") - const def = await findByLabelText("Value for an") - expect(def).toHaveValue("def") - - // cd parameter - expect(parameterLabels[1]).toHaveValue("cd") - const ghi = await findByLabelText("Value for cd") - expect(ghi).toHaveValue("ghi") - }) - }) - - test("adding a parameter gives its name label focus", async () => { - const { wrapped } = withProviders() - const { findAllByLabelText, findByText } = renderer.render(wrapped) - - const addParameter = await findByText("Add parameter") - - await renderer.act(async () => { - userEvent.click(addParameter) - }) - - // Check that new field is focused - const parameterLabels = await findAllByLabelText("Parameter name") - expect(parameterLabels).toHaveLength(1) - expect(parameterLabels[0]).toHaveFocus() - }) - - describe("updates the hit payload", () => { - test("when t parameter is changed", async () => { - const { wrapped } = withProviders() - const { findByLabelText } = renderer.render(wrapped) - - const t = await findByLabelText("t") - - await renderer.act(async () => { - await userEvent.type(t, "{selectall}{backspace}pageview", { - delay: 50, - }) - }) - - expect(t).toHaveValue("pageview") - }) - - test("when cid parameter is changed", async () => { - const { wrapped } = withProviders() - const { findByLabelText } = renderer.render(wrapped) - const { cid, hitPayload } = await getInputs(findByLabelText) - - await renderer.act(async () => { - userEvent.clear(cid) - await userEvent.type(cid, "cid123", { delay: 50 }) - }) - - expect(cid).toHaveValue("cid123") - expect(hitPayload.value).toContain("cid123") - }) - - test("when tid parameter is changed", async () => { - const { wrapped } = withProviders() - const { findByLabelText } = renderer.render(wrapped) - const { tid, hitPayload } = await getInputs(findByLabelText) - - await renderer.act(async () => { - userEvent.clear(tid) - await userEvent.type(tid, "tid123", { delay: 50 }) - }) - - expect(tid).toHaveValue("tid123") - expect(hitPayload.value).toContain("tid123") - }) - - test("clicking 'generate uuid' generates a... uuid???", async () => { - const { wrapped } = withProviders() - const { findByLabelText, findByTestId } = renderer.render(wrapped) - const { cid, hitPayload } = await getInputs(findByLabelText) - - await renderer.act(async () => { - const generateUuid = await findByTestId("generate-uuid") - userEvent.click(generateUuid) - }) - - expect(cid.value).not.toEqual("") - expect(hitPayload.value).toContain(cid.value) - }) - }) - - describe("when adding a parameter", () => { - test("updates hit payload when adding or changing parameter name & value", async () => { - const { wrapped } = withProviders() - const { findByLabelText, findByText } = renderer.render(wrapped) - const { hitPayload } = await getInputs(findByLabelText) - const addParameter = await findByText("Add parameter") - - await renderer.act(async () => { - userEvent.click(addParameter) - - const newParameterName = await findByLabelText("Parameter name") - await userEvent.type(newParameterName, "paramName", { delay: 50 }) - - const newParameterValue = await findByLabelText("Value for paramName") - await userEvent.type(newParameterValue, "paramValue", { delay: 50 }) - }) - - expect(hitPayload.value).toContain("paramName=paramValue") - - // Tests modifying parameter after adding it - const paramField = await findByLabelText("Parameter name") - - await renderer.act(async () => { - await userEvent.type(paramField, "{selectall}{backspace}newName", { - delay: 50, - }) - }) - expect(paramField).toHaveValue("newName") - expect(hitPayload.value).toContain("newName=paramValue") - - // Tests modifying param value after param name is changed - - const paramValue = await findByLabelText("Value for newName") - - await renderer.act(async () => { - await userEvent.type( - paramValue, - "{selectall}{backspace}paramValue2", - { delay: 50 } - ) - }) - expect(hitPayload.value).toContain("newName=paramValue2") - }) - - test("updates hit payload when removing parameter", async () => { - const { wrapped } = withProviders() - const { findByLabelText, findByText, findByTestId } = renderer.render( - wrapped - ) - const { hitPayload } = await getInputs(findByLabelText) - const addParameter = await findByText("Add parameter") - - await renderer.act(async () => { - userEvent.click(addParameter) - - const newParameterName = await findByLabelText("Parameter name") - await userEvent.type(newParameterName, "paramName", { delay: 50 }) - - const newParameterValue = await findByLabelText("Value for paramName") - await userEvent.type(newParameterValue, "paramValue", { delay: 50 }) - - const removeParameter = await findByTestId("remove-paramName") - userEvent.click(removeParameter) - }) - - expect(hitPayload.value).not.toContain("paramName=paramValue") - }) - }) - - describe("Validate hit", () => { - // TODO this should be cleaned up through types and better (global?) - // mocks in the future. - const fetchMock = jest.fn(async () => ({ - json: async () => ({ - parserMessage: [], - hitParsingResult: [{ valid: true, parserMessage: [], hit: "" }], - }), - })) - ;(global as any).fetch = fetchMock - - test("when valid updates the ui accordingly", async () => { - const queryParams = - "v=1&t=pageview&tid=UA-54516992-1&cid=555&dh=mydemo.com&dp=%2Fhome&dt=homepage" - - const { wrapped } = withProviders(, { - path: `/hit-builder?${queryParams}`, - }) - - const { findByText, findByLabelText } = renderer.render(wrapped) - - const { hitPayload } = await getInputs(findByLabelText) - expect(hitPayload).toHaveValue(queryParams) - - const validateHitButton = renderer.screen.getByText("Validate hit") - await renderer.act(async () => { - validateHitButton.click() - }) - - const result = await findByText("Hit is valid!") - expect(result).not.toEqual("") - }) - }) - }) -}) diff --git a/src/components/HitBuilder/index.tsx b/src/components/HitBuilder/index.tsx deleted file mode 100644 index ba55326e..00000000 --- a/src/components/HitBuilder/index.tsx +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import Typography from "@mui/material/Typography" - -import { Url } from "@/constants" -import ExternalLink from "@/components/ExternalLink" -import Parameters from "./Parameters" -import HitCard from "./HitCard" -import * as hitUtils from "./hit" -import * as hooks from "./hooks" - -const HitBuilder: React.FC = () => { - const { properties } = hooks.useProperties() - const [hitPayload, setHitPayload] = React.useState("") - - const { - updateParameterName, - updateParameterValue, - addParameter, - removeParameter, - parameters, - hasParameter, - setParametersFromString, - shouldFocus, - } = hooks.useParameters() - - const { - hitStatus, - validationMessages, - validateHit, - sendHit, - } = hooks.useValidationServer(parameters) - - // Update the hitPayload whenever the parameters change. - React.useEffect(() => { - setHitPayload(hitUtils.convertParamsToHit(parameters)) - }, [parameters]) - - return ( -
- - This tools allows you to construct and validate{" "} - - Measurement Protocol - {" "} - hits using the{" "} - - Measurement Protocol Validation Server - - . - - - - To get started, use the controls below to construct a new hit or paste - an existing hit into the text box in the hit summary. - - - - The box below displays the full hit and its validation status. You can - update the hit in the text box and the parameter details below will be - automatically updated. - - - - - Hit parameter details - - The fields below are a breakdown of the individual parameters and values - for the hit in the text box above. When you update these values, the hit - above will be automatically updated. - - - - - References - - - Click the info link to the right of each parameter in the details - section to go directly to its documentation. For general references, - refer to the links below: - - - -
  • - - Parameter reference - -
  • -
  • - - Examples of common hits - -
  • -
    -
    - ) -} - -export default HitBuilder diff --git a/src/components/HitBuilder/types.ts b/src/components/HitBuilder/types.ts deleted file mode 100644 index 500378e9..00000000 --- a/src/components/HitBuilder/types.ts +++ /dev/null @@ -1,144 +0,0 @@ -export const HIT_TYPES = [ - "pageview", - "screenview", - "event", - "transaction", - "item", - "social", - "exception", - "timing", -] - -export enum ActionType { - SetHitPayload = "SET_HIT_PAYLOAD", - SetHitStatus = "SET_HIT_STATUS", - SetAuthorized = "SET_AUTHORIZED", - AddParam = "ADD_PARAM", - RemoveParam = "REMOVE_PARAM", - EditParamName = "EDIT_PARAM_NAME", - EditParamValue = "EDIT_PARAM_VALUE", - ReplaceParams = "REPLACE_PARAMS", - SetUserProperties = "SET_USER_PROPERTIES", - SetValidationMessages = "SET_VALIDATION_MESSAGES", -} - -export interface SetHitStatus { - type: ActionType.SetHitStatus - status: HitStatus -} - -export interface SetAuthorized { - type: ActionType.SetAuthorized -} - -export interface AddParam { - type: ActionType.AddParam -} - -export interface RemoveParam { - type: ActionType.RemoveParam - id: number -} - -export interface EditParamName { - type: ActionType.EditParamName - name: string - id: number -} - -export interface EditParamValue { - type: ActionType.EditParamValue - value: string - id: number -} - -export interface ReplaceParams { - type: ActionType.ReplaceParams - params: Params -} - -export interface SetUserProperties { - type: ActionType.SetUserProperties - properties: Property[] -} - -export interface SetValidationMessages { - type: ActionType.SetValidationMessages - validationMessages: ValidationMessage[] -} - -export interface SetHitPayload { - type: ActionType.SetHitPayload - hitPayload: string -} - -export type HitAction = - | SetHitStatus - | SetAuthorized - | AddParam - | RemoveParam - | EditParamName - | EditParamValue - | ReplaceParams - | SetUserProperties - | SetValidationMessages - | SetHitPayload - -export enum HitStatus { - Unvalidated = "UNVALIDATED", - Validating = "VALIDATING", - Valid = "VALID", - Invalid = "INVALID", - Sent = "Sent", - Sending = "Sending", -} - -export enum RequiredParams { - V = "v", - T = "t", - T_Id = "tid", - C_Id = "cid", -} - -export type ParamV = ParamType -export type ParamT = ParamType -export type ParamTId = ParamType -export type ParamCId = ParamType -export type ParamOptional = ParamType - -export type Params = [ParamV, ParamT, ParamTId, ParamCId, ...ParamOptional[]] - -export type Param = - | ParamType - | ParamType - | ParamType - | ParamType - | ParamType - -interface ParamType { - id: number - name: T - value: string - required?: true - isOptional?: true -} - -export interface Property { - name: string - id: string - group: string -} -export interface ValidationMessage { - param: string - description: string - code: "VALUE_REQUIRED" -} - -export interface State { - hitPayload: string - hitStatus: HitStatus - isAuthorized: boolean - params: Params - properties: Property[] - validationMessages: ValidationMessage[] -} diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index 0510e054..3944a7d6 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -204,16 +204,6 @@ const Template: React.FC> = ({
    ) } - if (linkData.type === "ga4toggle") { - return ( -
  • - -
  • - ) - } return ( > = ({ ) } - if (linkData.type === "ga4toggle") { - return ( -
  • - -
  • - ) - } return (
  • ({ - [`&.${classes.paper}`]: {}, - - [`& .${classes.preamble}`]: { - padding: theme.spacing(2, 2, 0, 2), - margin: "unset", - }, - - [`& .${classes.container}`]: { - maxHeight: 440, - }, - - [`& .${classes.breakAll}`]: { - wordBreak: "break-all", - }, - - [`& .${classes.reportLink}`]: { - marginTop: theme.spacing(1), - marginBottom: theme.spacing(1), - } -})); - -const ReportTable: React.FC<{ - queryResponse: gapi.client.analytics.GaData - columns: gapi.client.analytics.Column[] | undefined -}> = ({ queryResponse, columns }) => { - - - if (queryResponse === undefined) { - return null - } - return ( - - - - - {queryResponse.columnHeaders?.map(header => ( - - {columns?.find(c => c.id === header.name)?.attributes?.uiName || - header.name} - - ))} - - - - {queryResponse.rows?.map((row, idx) => ( - - {row.map((column, innerIdx) => ( - - {column} - - ))} - - ))} - -
    -
    - ) -} - -interface ReportProps { - queryResponse: QueryResponse - columns: gapi.client.analytics.Column[] | undefined - permalink: string | undefined -} - -const Report: React.FC = ({ - queryResponse, - columns, - permalink, -}) => { - - - const requestURL = React.useMemo(() => { - if ( - queryResponse === undefined || - queryResponse.status !== APIStatus.Success - ) { - return undefined - } - const [base, queryParamString] = queryResponse.response.selfLink!.split("?") - const existingQueryParams = new URLSearchParams(queryParamString) - const nuQueryParams = new URLSearchParams() - existingQueryParams.forEach((value, key) => { - nuQueryParams.append(key, value) - }) - return `${base}?${nuQueryParams.toString()}` - }, [queryResponse]) - - if (queryResponse === undefined) { - return null - } - - if (queryResponse.status === APIStatus.InProgress) { - return Loading results … - } - - if (queryResponse.status === APIStatus.Error) { - return ( - - - An error has occured - -
    - Error code: {queryResponse.error.code} - Error message: {queryResponse.error.message} -
    -
    - ); - } - - return ( - - - {queryResponse.response.profileInfo?.profileName} - -
    - - Showing {queryResponse.response.rows?.length} out of{" "} - {queryResponse.response.totalResults} total results. - - - {queryResponse.response.containsSampledData ? ( - <>Contains sampled data. - ) : ( - <>Does not contain sampled data. - )} - - - - - ), - }} - /> -
    - Link to this report -
    -
    - -
    - ) -} - -export default Report diff --git a/src/components/QueryExplorer/Sort.tsx b/src/components/QueryExplorer/Sort.tsx deleted file mode 100644 index 39f6a519..00000000 --- a/src/components/QueryExplorer/Sort.tsx +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import { styled } from '@mui/material/styles'; - -import Typography from "@mui/material/Typography" -import TextField from "@mui/material/TextField" -import Autocomplete from "@mui/material/Autocomplete" - -import { SortableColumn } from "." -import { Dispatch } from "@/types" -import { Column } from "@/types/ua" - -const PREFIX = 'Sort'; - -const classes = { - conceptOption: `${PREFIX}-conceptOption`, - nameId: `${PREFIX}-nameId`, - group: `${PREFIX}-group` -}; - -const Root - = styled('div')(() => ({ - [`& .${classes.conceptOption}`]: { - display: "flex", - width: "100%", - }, - - [`& .${classes.nameId}`]: { - flexGrow: 1, - display: "flex", - flexDirection: "column", - "& > p": { - margin: 0, - padding: 0, - }, - }, - - [`& .${classes.group}`]: {} -})); - -interface SortProps { - columns: Column[] - sort: SortableColumn[] | undefined - setSortIDs: Dispatch -} - -const Sort: React.FC = ({ columns, sort, setSortIDs }) => { - - const sortableColumns = React.useMemo( - () => - columns - .filter(column => { - if (sort === undefined) { - return true - } - return sort.find(s => s.id === column.id) === undefined - }) - // Create and ascending and descending option for every column. - .flatMap(column => [ - { ...column, sort: "ASCENDING" }, - { ...column, sort: "DESCENDING" }, - ]), - - [columns, sort] - ) - - // When the available columns change, filter out any values that are no - // longer valid. - React.useEffect(() => { - if (sort === undefined) { - return - } - const nuSort = sort.filter(column => columns.find(c => column.id === c.id)) - if (sort.length !== nuSort.length) { - setSortIDs(nuSort.map(s => `${s.id}@@@${s.sort}`)) - } - }, [columns, sort, setSortIDs]) - - // TODO renderOption={...} should be extracted since this and - // _ConceptMultiSelect use the same styling. - return ( - - - fullWidth - autoComplete - autoHighlight - multiple - noOptionsText="A Metric or Dimension is required in order to sort." - options={sortableColumns} - filterOptions={a => - a.filter(column => sort?.find(c => c.id === column.id) === undefined) - } - getOptionLabel={option => typeof option === "string" ? option : - `${option.sort === "ASCENDING" ? "" : "-"}${option.id}` - } - isOptionEqualToValue={(a, b) => a.id === b.id && a.sort === b.sort} - value={sort} - onChange={(_event, value, _state) => - setSortIDs((value as SortableColumn[]).map(s => `${s.id}@@@${s.sort}`)) - } - renderOption={(props, option) => ( -
  • -
    -
    - - {`${option.attributes!.uiName} (${ - option.sort === "ASCENDING" ? "Ascending" : "Descending" - })`} - - - {`${option.sort === "ASCENDING" ? "" : "-"}${option.id}`} - -
    - - {option.attributes!.group} - -
    -
  • - )} - renderInput={params => ( - - )} - /> -
    - ) -} - -export default Sort diff --git a/src/components/QueryExplorer/TSVDownload.tsx b/src/components/QueryExplorer/TSVDownload.tsx deleted file mode 100644 index 086878c4..00000000 --- a/src/components/QueryExplorer/TSVDownload.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from "react" - -import { styled } from '@mui/material/styles'; - -import GetApp from "@mui/icons-material/GetApp" - -const PREFIX = 'TSVDownload'; - -const classes = { - download: `${PREFIX}-download` -}; - -const Root = styled('a')(( - { - theme - } -) => ({ - [`&.${classes.download}`]: { - marginTop: theme.spacing(-1), - marginBottom: theme.spacing(2), - display: "flex", - alignItems: "center", - } -})); - -interface TSVDownloadProps { - queryResponse: gapi.client.analytics.GaData -} - -const TSVDownload: React.FC = ({ queryResponse }) => { - - - const csvContents = React.useMemo(() => { - const baseUrl = `data:text/tsv;charset=utf8,` - const header = - (queryResponse.columnHeaders?.map(header => header.name).join("\t") || - "") + "\n" - const rows = queryResponse.rows?.map(row => row.join("\t")).join("\n") || "" - const encoded = encodeURI(`${baseUrl}${header}${rows}`) - return encoded - }, [queryResponse]) - - const filename = React.useMemo( - () => - `query-explorer-export-${new Date().toISOString().substring(0, 10)}.tsv`, - [] - ) - - return ( - - - download .tsv - - ); -} - -export default TSVDownload diff --git a/src/components/QueryExplorer/index.tsx b/src/components/QueryExplorer/index.tsx deleted file mode 100644 index 8360c36c..00000000 --- a/src/components/QueryExplorer/index.tsx +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import { styled } from '@mui/material/styles'; - -import Tooltip from "@mui/material/Tooltip" -import Typography from "@mui/material/Typography" -import TextField from "@mui/material/TextField" -import Launch from "@mui/icons-material/Launch" - -import useDataAPIRequest from "./useDataAPIRequest" -import useInputs from "./useInputs" -import { StorageKey, Url } from "@/constants" -import ViewSelector from "@/components/ViewSelector" -import { - DimensionsPicker, - MetricsPicker, - SegmentPicker, - V3SamplingLevelPicker, -} from "@/components/UAPickers" -import { PAB } from "@/components/Buttons" -import LabeledCheckbox from "@/components/LabeledCheckbox" -import ExternalLink from "@/components/ExternalLink" -import Sort from "./Sort" -import Report from "./Report" -import usePermalink from "./usePermalink" -import { Column, ProfileSummary } from "@/types/ua" -import useUADimensionsAndMetrics, { - UADimensionsAndMetricsRequestCtx, -} from "../UAPickers/useDimensionsAndMetrics" -import { UASegmentsRequestCtx, useUASegments } from "../UAPickers/useUASegments" -import useAccountPropertyView from "../ViewSelector/useAccountPropertyView" -import { useHydratedPersistantString } from "@/hooks/useHydrated" -import { successful } from "@/types" - -const PREFIX = 'QueryExplorer'; - -const classes = { - inputs: `${PREFIX}-inputs`, - runButton: `${PREFIX}-runButton`, - externalReference: `${PREFIX}-externalReference`, - viewSelector: `${PREFIX}-viewSelector`, - showSegments: `${PREFIX}-showSegments`, - includeEmpty: `${PREFIX}-includeEmpty`, - conceptOption: `${PREFIX}-conceptOption` -}; - -const StyledUADimensionsAndMetricsRequestCtxProvider = styled(UADimensionsAndMetricsRequestCtx.Provider)(( - { - theme - } -) => ({ - [`& .${classes.inputs}`]: { - maxWidth: "500px", - marginBottom: theme.spacing(1), - display: "flex", - flexDirection: "column", - }, - - [`& .${classes.runButton}`]: { - alignSelf: "flex-start", - marginTop: theme.spacing(1), - }, - - [`& .${classes.externalReference}`]: { - "&:hover": { - opacity: 1.0, - }, - opacity: 0.3, - }, - - [`& .${classes.viewSelector}`]: { - maxWidth: "500px", - }, - - [`& .${classes.showSegments}`]: { - marginLeft: theme.spacing(1), - marginBottom: theme.spacing(1), - }, - - [`& .${classes.includeEmpty}`]: { - marginTop: theme.spacing(2), - marginBottom: theme.spacing(1), - }, - - [`& .${classes.conceptOption}`]: { - display: "flex", - flexDirection: "column", - "& > p": { - margin: 0, - padding: 0, - }, - } -})); - -const coreReportingApi = ( - Core Reporting API -) - -const startDateLink = ( - - start-date - -) - -const endDateLink = ( - - end-date - -) - -export type SortableColumn = Column & { sort: "ASCENDING" | "DESCENDING" } - -const DevsiteLink: React.FC<{ hash: string }> = ({ hash }) => { - - return ( - - - - - - ) -} - -export enum QueryParam { - Account = "a", - Property = "b", - View = "c", - ShowSegmentDefinitions = "d", - ViewID = "ids", - StartDate = "start-date", - EndDate = "end-date", - SelectedMetrics = "metrics", - SelectedDimensions = "dimensions", - Sort = "sort", - Filters = "filters", - Segment = "segment", - SamplingLevel = "samplingLevel", - StartIndex = "start-index", - MaxResults = "max-results", - IncludeEmptyRows = "include-empty-rows", -} - -export const QueryExplorer = () => { - - - const [viewID, setViewID] = useHydratedPersistantString( - StorageKey.queryExplorerViewID, - QueryParam.ViewID - ) - - const onSetView = React.useCallback( - (view: ProfileSummary | undefined) => { - if (view === undefined) { - return - } - setViewID(`ga:${view.id}`) - }, - [setViewID] - ) - - const accountPropertyView = useAccountPropertyView( - StorageKey.queryExplorerAPV, - QueryParam, - onSetView - ) - const uaDimensionsAndMetricsRequest = useUADimensionsAndMetrics( - accountPropertyView - ) - const uaSegmentsRequest = useUASegments() - const { - startDate, - setStartDate, - endDate, - setEndDate, - selectedMetrics, - setSelectedMetricIDs, - selectedDimensions, - setSelectedDimensionIDs, - setSortIDs, - filters, - setFilters, - setSegmentID, - showSegmentDefinition, - setShowSegmentDefiniton, - samplingValue, - setSamplingValue, - startIndex, - setStartIndex, - maxResults, - setMaxResults, - includeEmptyRows, - setIncludeEmptyRows, - segment, - sort, - } = useInputs(uaDimensionsAndMetricsRequest, uaSegmentsRequest) - const { account, property, view } = accountPropertyView - - const { - runQuery, - requiredParameters, - queryResponse, - } = useDataAPIRequest({ - viewID, - startDate, - endDate, - selectedMetrics, - selectedDimensions, - includeEmptyRows, - samplingValue, - segment, - startIndex, - maxResults, - filters, - sort, - }) - - const permalink = usePermalink({ - account, - property, - view, - viewID, - startDate, - endDate, - selectedMetrics, - selectedDimensions, - sort, - filters, - segment, - showSegmentDefinition, - startIndex, - maxResults, - includeEmptyRows, - }) - - const [updateLink, setUpdateLink] = React.useState(false) - const [currentLink, setCurrentLink] = React.useState() - React.useEffect(() => { - if (updateLink) { - setCurrentLink(permalink) - setUpdateLink(false) - } - }, [permalink, updateLink]) - - return ( - - Overview - - This tool lets you interact with the {coreReportingApi} by building - queries to get data from your Google Analytics views (profiles). You can - use these queries in any of the client libraries to build your own - tools. - - Select View - - - Set query parameters -
    - , - }} - size="small" - variant="outlined" - fullWidth - id="ids" - label="ids" - value={viewID || ""} - onChange={e => setViewID(e.target.value)} - required - helperText={<>The unique ID used to retrieve the Analytics data.} - /> - , - }} - size="small" - variant="outlined" - fullWidth - id="start-date" - label="start date" - value={startDate || ""} - onChange={e => setStartDate(e.target.value)} - required - helperText={ - <> - The start of the date range for the data request. Format should be - YYYY-MM-DD. See {startDateLink} for other allowed values. - - } - /> - , - }} - fullWidth - size="small" - variant="outlined" - id="end-date" - label="end date" - value={endDate || ""} - onChange={e => setEndDate(e.target.value)} - required - helperText={ - <> - The end of the date range for the data request. Format should be - YYYY-MM-DD. See {endDateLink} for other allowed values. - - } - /> - - - - , - }} - value={filters || ""} - onChange={e => setFilters(e.target.value)} - size="small" - variant="outlined" - id="filters" - label="filters" - fullWidth - helperText="The filters to apply to the query." - /> - - - - - Show segment definitions instead of IDs. - - - , - }} - size="small" - variant="outlined" - id="start-index" - label="start index" - fullWidth - helperText="The start index for the result. Indices are 1-based." - value={startIndex || ""} - onChange={e => setStartIndex(e.target.value)} - /> - , - }} - size="small" - variant="outlined" - id="max-results" - label="max results" - fullWidth - helperText="Maximum number of rows to include in the response." - value={maxResults || ""} - onChange={e => setMaxResults(e.target.value)} - /> - - runQuery(() => { - setUpdateLink(true) - }) - } - > - Run Query - - - include empty rows - -
    - -
    - ); -} - -export default QueryExplorer diff --git a/src/components/QueryExplorer/useDataAPIRequest.ts b/src/components/QueryExplorer/useDataAPIRequest.ts deleted file mode 100644 index 374eeb48..00000000 --- a/src/components/QueryExplorer/useDataAPIRequest.ts +++ /dev/null @@ -1,213 +0,0 @@ -import * as React from "react" - -import { V3SamplingLevel } from "@/components/UAPickers" -import { SortableColumn } from "." -import { useSelector } from "react-redux" -import { Column, Segment } from "@/types/ua" - -export enum APIStatus { - Error = "error", - InProgress = "in-progress", - Success = "success", -} - -export type QueryResponse = - | { status: APIStatus.Success; response: gapi.client.analytics.GaData } - | { status: APIStatus.InProgress } - | { - status: APIStatus.Error - error: { - code: number - message: string - errors: Array<{ domain: string; message: string; reason: string }> - } - } - | undefined - -type Arg = { - viewID: string | undefined - startDate: string | undefined - endDate: string | undefined - selectedMetrics: Column[] | undefined - selectedDimensions: Column[] | undefined - includeEmptyRows: boolean - samplingValue: V3SamplingLevel | undefined - segment: Segment | undefined - startIndex: string | undefined - maxResults: string | undefined - filters: string | undefined - sort: SortableColumn[] | undefined -} - -type UseDataAPIRequest = ( - arg: Arg -) => { - requiredParameters: boolean - accessToken: string | undefined - runQuery: (cb: () => void) => void - queryResponse: QueryResponse -} - -export const useDataAPIRequest: UseDataAPIRequest = ({ - viewID, - startDate, - endDate, - selectedMetrics, - selectedDimensions, - includeEmptyRows, - samplingValue: selectedSamplingValue, - segment, - startIndex, - maxResults, - filters, - sort, -}) => { - const gapi = useSelector((a: AppState) => a.gapi) - const user = useSelector((a: AppState) => a.user) - - const [queryResponse, setQueryResponse] = React.useState() - - const accessToken = React.useMemo( - () => user?.getAuthResponse().access_token, - [user] - ) - - const requiredParameters = React.useMemo(() => { - return ( - viewID !== "" && - startDate !== "" && - endDate !== "" && - selectedMetrics !== undefined && - selectedMetrics.length !== 0 - ) - }, [viewID, startDate, endDate, selectedMetrics]) - - const runQuery = React.useCallback( - (cb: () => void) => { - if ( - viewID === undefined || - gapi === undefined || - selectedMetrics === undefined || - selectedMetrics.length === 0 || - startDate === undefined || - endDate === undefined - ) { - return - } - const metrics = selectedMetrics.map(a => a.id).join(",") - - type ApiObject = { - /** Data format for the response. */ - alt?: string; - /** A comma-separated list of Analytics dimensions. E.g., 'ga:browser,ga:city'. */ - dimensions?: string; - /** - * End date for fetching Analytics data. Request can should specify an end date formatted as YYYY-MM-DD, or as a relative date (e.g., today, yesterday, or 7daysAgo). The default - * value is yesterday. - */ - "end-date": string; - /** Selector specifying which fields to include in a partial response. */ - fields?: string; - /** A comma-separated list of dimension or metric filters to be applied to Analytics data. */ - filters?: string; - /** Unique table ID for retrieving Analytics data. Table ID is of the form ga:XXXX, where XXXX is the Analytics view (profile) ID. */ - ids: string; - /** The response will include empty rows if this parameter is set to true, the default is true */ - "include-empty-rows"?: boolean; - /** API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. */ - key?: string; - /** The maximum number of entries to include in this feed. */ - "max-results"?: number; - /** A comma-separated list of Analytics metrics. E.g., 'ga:sessions,ga:pageviews'. At least one metric must be specified. */ - metrics: string; - /** OAuth 2.0 token for the current user. */ - oauth_token?: string; - /** The selected format for the response. Default format is JSON. */ - output?: string; - /** Returns response with indentations and line breaks. */ - prettyPrint?: boolean; - /** An opaque string that represents a user for quota purposes. Must not exceed 40 characters. */ - quotaUser?: string; - /** The desired sampling level. */ - samplingLevel?: string; - /** An Analytics segment to be applied to data. */ - segment?: string; - /** A comma-separated list of dimensions or metrics that determine the sort order for Analytics data. */ - sort?: string; - /** - * Start date for fetching Analytics data. Requests can specify a start date formatted as YYYY-MM-DD, or as a relative date (e.g., today, yesterday, or 7daysAgo). The default value - * is 7daysAgo. - */ - "start-date": string; - /** An index of the first entity to retrieve. Use this parameter as a pagination mechanism along with the max-results parameter. */ - "start-index"?: number; - /** Deprecated. Please use quotaUser instead. */ - userIp?: string; - } - - const apiObject: ApiObject = { - ids: viewID, - "start-date": startDate, - "end-date": endDate, - "include-empty-rows": includeEmptyRows, - "metrics": metrics - } - if (selectedDimensions !== undefined && selectedDimensions.length !== 0) { - const dimensions = selectedDimensions?.map(a => a.id).join(",") - apiObject["dimensions"] = dimensions - } - if (selectedSamplingValue !== undefined) { - apiObject["samplingLevel"] = selectedSamplingValue - } - if (segment !== undefined) { - apiObject["segment"] = segment.segmentId as string - } - if (startIndex !== undefined && startIndex !== "") { - apiObject["start-index"] = parseInt(startIndex) - } - if (maxResults !== undefined && maxResults !== "") { - apiObject["max-results"] = parseInt(maxResults) - } - if (filters !== undefined && filters !== "") { - apiObject["filters"] = filters - } - if (sort !== undefined && sort.length > 0) { - apiObject["sort"] = sort - .map(a => `${a.sort === "ASCENDING" ? "" : "-"}${a.id}`) - .join(",") - } - setQueryResponse({ status: APIStatus.InProgress }) - gapi.client.analytics.data.ga - .get(apiObject) - .then(response => { - setQueryResponse({ - status: APIStatus.Success, - response: response.result, - }) - cb() - }) - .catch(e => { - setQueryResponse({ status: APIStatus.Error, error: e.result.error }) - }) - }, - [ - viewID, - startDate, - endDate, - selectedDimensions, - selectedMetrics, - segment, - sort, - startIndex, - maxResults, - filters, - selectedSamplingValue, - includeEmptyRows, - gapi, - ] - ) - - return { runQuery, requiredParameters, queryResponse, accessToken } -} - -export default useDataAPIRequest diff --git a/src/components/QueryExplorer/useInputs.ts b/src/components/QueryExplorer/useInputs.ts deleted file mode 100644 index 592a881a..00000000 --- a/src/components/QueryExplorer/useInputs.ts +++ /dev/null @@ -1,210 +0,0 @@ -import * as React from "react" - -import { StorageKey } from "@/constants" -import { V3SamplingLevel } from "@/components/UAPickers" -import { QueryParam, SortableColumn } from "." -import { - useHydratedPersistantBoolean, - useHydratedPersistantString, - useKeyedHydratedPersistantArray, - useKeyedHydratedPersistantObject, -} from "@/hooks/useHydrated" -import { Dispatch, RequestStatus } from "@/types" -import { Column, Segment } from "@/types/ua" -import useUADimensionsAndMetrics from "../UAPickers/useDimensionsAndMetrics" -import { useUASegments } from "../UAPickers/useUASegments" - -export const useInputs = ( - uaDimensionsAndMetricsRequest: ReturnType, - uaSegmentsRequest: ReturnType -) => { - const [startDate, setStartDate] = useHydratedPersistantString( - StorageKey.queryExplorerStartDate, - QueryParam.StartDate, - "7daysAgo" - ) - const [endDate, setEndDate] = useHydratedPersistantString( - StorageKey.queryExplorerEndDate, - QueryParam.EndDate, - "yesterday" - ) - const [startIndex, setStartIndex] = useHydratedPersistantString( - StorageKey.queryExplorerStartIndex, - QueryParam.StartIndex - ) - const [maxResults, setMaxResults] = useHydratedPersistantString( - StorageKey.queryExplorerMaxResults, - QueryParam.MaxResults - ) - const [filters, setFilters] = useHydratedPersistantString( - StorageKey.queryExplorerFilters, - QueryParam.Filters - ) - - const getSegmentByID = React.useCallback( - (id: string | undefined) => { - if ( - id === undefined || - uaSegmentsRequest.status !== RequestStatus.Successful - ) { - return undefined - } - const builtInSegment = uaSegmentsRequest.segments.find(s => s.id === id) - if (builtInSegment !== undefined) { - return builtInSegment - } - // If the segment wasn't in the list of segments returned by the API, - // this was a custom (dynamic) segment defined by the user. - return { - definition: id, - name: `Add dynamic segment`, - segmentId: id, - id, - type: "DYNAMIC", - } - }, - [uaSegmentsRequest] - ) - - const [segment, setSegmentID] = useKeyedHydratedPersistantObject( - StorageKey.queryExplorerSegment, - QueryParam.Segment, - getSegmentByID - ) - - const getColumnsByIDs = React.useCallback( - (ids: string[] | undefined) => { - if ( - uaDimensionsAndMetricsRequest.status !== RequestStatus.Successful || - ids === undefined - ) { - return undefined - } - return uaDimensionsAndMetricsRequest.columns.filter(c => - ids.includes(c.id!) - ) - }, - [uaDimensionsAndMetricsRequest] - ) - - const [ - selectedMetrics, - setSelectedMetricIDs, - ] = useKeyedHydratedPersistantArray( - StorageKey.queryExplorerSelectedMetrics, - QueryParam.SelectedMetrics, - getColumnsByIDs - ) - - const [ - selectedDimensions, - setSelectedDimensionIDs, - ] = useKeyedHydratedPersistantArray( - StorageKey.queryExplorerSelectedDimensions, - QueryParam.SelectedDimensions, - getColumnsByIDs - ) - - const [includeEmptyRows, setIncludeEmptyRows] = useHydratedPersistantBoolean( - StorageKey.queryExplorerIncludeEmptyRows, - QueryParam.IncludeEmptyRows, - true - ) - const [ - showSegmentDefinition, - setShowSegmentDefiniton, - ] = useHydratedPersistantBoolean( - StorageKey.queryExplorerShowSegmentDefinition, - QueryParam.ShowSegmentDefinitions, - false - ) - const [ - samplingValueLocal, - setSamplingValueLocal, - ] = useHydratedPersistantString( - StorageKey.queryExplorerSamplingLevel, - QueryParam.SamplingLevel, - V3SamplingLevel.Default - ) - - const samplingValue = React.useMemo( - () => samplingValueLocal as V3SamplingLevel | undefined, - [samplingValueLocal] - ) - - const setSamplingValue: Dispatch< - V3SamplingLevel | undefined - > = React.useCallback( - a => { - setSamplingValueLocal(a as any) - }, - [setSamplingValueLocal] - ) - - const getSortByIDs = React.useCallback( - (ids: string[] | undefined) => { - if ( - uaDimensionsAndMetricsRequest.status !== RequestStatus.Successful || - ids === undefined - ) { - return undefined - } - return uaDimensionsAndMetricsRequest.columns - .flatMap(c => [ - { ...c, sort: "ASCENDING" }, - { ...c, sort: "DESCENDING" }, - ]) - .filter( - c => - ids.find(id => { - if (id.includes("@@@")) { - // TODO - add measurement to see if this branch is reached. - const [innerId, type] = id.split("@@@") - return c.id === innerId && type === c.sort - } - if (id.startsWith("-")) { - const actualId = id.substring(1) - return c.id === actualId && c.sort === "DESCENDING" - } - return c.id === id && c.sort === "ASCENDING" - }) !== undefined - ) - }, - [uaDimensionsAndMetricsRequest] - ) - - const [sort, setSortIDs] = useKeyedHydratedPersistantArray( - StorageKey.queryExplorerSort, - QueryParam.Sort, - getSortByIDs - ) - - return { - sort, - setSortIDs, - startDate, - setStartDate, - endDate, - setEndDate, - startIndex, - setStartIndex, - maxResults, - setMaxResults, - filters, - setFilters, - segment, - setSegmentID, - selectedMetrics, - setSelectedMetricIDs, - selectedDimensions, - setSelectedDimensionIDs, - includeEmptyRows, - setIncludeEmptyRows, - showSegmentDefinition, - setShowSegmentDefiniton, - samplingValue, - setSamplingValue, - } -} - -export default useInputs diff --git a/src/components/QueryExplorer/usePermalink.ts b/src/components/QueryExplorer/usePermalink.ts deleted file mode 100644 index 93aec745..00000000 --- a/src/components/QueryExplorer/usePermalink.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { useMemo } from "react" -import { QueryParam, SortableColumn } from "." -import { BooleanParam } from "serialize-query-params" -import { - AccountSummary, - ProfileSummary, - WebPropertySummary, -} from "../ViewSelector/useAccountPropertyView" -import { Column, Segment } from "@/types/ua" - -type Arg = { - account: AccountSummary | undefined - property: WebPropertySummary | undefined - view: ProfileSummary | undefined - viewID: string | undefined - startDate: string | undefined - endDate: string | undefined - selectedMetrics: Column[] | undefined - selectedDimensions: Column[] | undefined - sort: SortableColumn[] | undefined - filters: string | undefined - segment: Segment | undefined - showSegmentDefinition: boolean | undefined - startIndex: string | undefined - maxResults: string | undefined - includeEmptyRows: boolean | undefined -} - -const usePermalink = ({ - account, - property, - view, - viewID, - startDate, - endDate, - selectedMetrics, - selectedDimensions, - sort, - filters, - segment, - showSegmentDefinition, - startIndex, - maxResults, - includeEmptyRows, -}: Arg) => { - return useMemo(() => { - const urlParams = new URLSearchParams() - - if (account !== undefined) { - urlParams.append(QueryParam.Account, account.id!) - } - - if (property !== undefined) { - urlParams.append(QueryParam.Property, property.id!) - } - - if (view !== undefined) { - urlParams.append(QueryParam.View, view.id!) - } - - if (viewID !== undefined) { - urlParams.append(QueryParam.ViewID, viewID) - } - - if (startDate !== undefined) { - urlParams.append(QueryParam.StartDate, startDate) - } - - if (endDate !== undefined) { - urlParams.append(QueryParam.EndDate, endDate) - } - - if (selectedMetrics !== undefined) { - urlParams.append( - QueryParam.SelectedMetrics, - selectedMetrics.map(c => c.id).join(",") - ) - } - - if (selectedDimensions !== undefined) { - urlParams.append( - QueryParam.SelectedDimensions, - selectedDimensions.map(c => c.id).join(",") - ) - } - - if (sort !== undefined) { - urlParams.append( - QueryParam.Sort, - sort.map(s => `${s.sort === "DESCENDING" ? "-" : ""}${s.id}`).join(",") - ) - } - - if (filters !== undefined) { - urlParams.append(QueryParam.Filters, filters) - } - - if (segment !== undefined) { - urlParams.append(QueryParam.Segment, segment.id!) - } - - if (showSegmentDefinition !== undefined) { - urlParams.append( - QueryParam.ShowSegmentDefinitions, - BooleanParam.encode(showSegmentDefinition) as string - ) - } - - if (startIndex !== undefined) { - urlParams.append(QueryParam.StartIndex, startIndex) - } - - if (maxResults !== undefined) { - urlParams.append(QueryParam.MaxResults, maxResults) - } - - if (includeEmptyRows !== undefined) { - urlParams.append( - QueryParam.IncludeEmptyRows, - BooleanParam.encode(includeEmptyRows) as string - ) - } - - const { protocol, host, pathname } = window.location - return `${protocol}//${host}${pathname}?${urlParams}` - }, [ - account, - property, - view, - viewID, - startDate, - endDate, - selectedMetrics, - selectedDimensions, - sort, - filters, - segment, - showSegmentDefinition, - startIndex, - maxResults, - includeEmptyRows, - ]) -} -export default usePermalink diff --git a/src/components/RequestComposer/CohortRequest/index.tsx b/src/components/RequestComposer/CohortRequest/index.tsx deleted file mode 100644 index 151f6e0d..00000000 --- a/src/components/RequestComposer/CohortRequest/index.tsx +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" -import { styled } from '@mui/material/styles'; -import { useEffect } from "react" - -import { usePersistentBoolean } from "@/hooks" -import { StorageKey } from "@/constants" -import { - MetricPicker, - SegmentPicker, - V4SamplingLevelPicker, - CohortSizePicker, -} from "@/components/UAPickers" -import LinkedTextField from "@/components/LinkedTextField" -import LabeledCheckbox from "@/components/LabeledCheckbox" -import { linkFor, titleFor } from "../HistogramRequest" -import useCohortRequestParameters from "./useCohortRequestParameters" -import useCohortRequest from "./useCohortRequest" -import { ReportsRequest } from "../RequestComposer" -import { UAAccountPropertyView } from "@/components/ViewSelector/useAccountPropertyView" -import useUADimensionsAndMetrics, { - UADimensionsAndMetricsRequestCtx, -} from "@/components/UAPickers/useDimensionsAndMetrics" -import { successful } from "@/types" -import { Column } from "@/types/ua" -import { - UASegmentsRequestCtx, - useUASegments, -} from "@/components/UAPickers/useUASegments" -import { PropsWithChildren } from 'react' - -const PREFIX = 'CohortRequest'; - -const classes = { - showSegments: `${PREFIX}-showSegments` -}; - -const StyledUADimensionsAndMetricsRequestCtxProvider = styled(UADimensionsAndMetricsRequestCtx.Provider)(( - { - theme - } -) => ({ - [`& .${classes.showSegments}`]: { - marginLeft: theme.spacing(1), - marginBottom: theme.spacing(1), - } -})); - -interface CohortRequestProps { - apv: UAAccountPropertyView - controlWidth: string - setRequestObject: (request: ReportsRequest | undefined) => void -} - -const CohortRequest: React.FC> = ({ - apv, - controlWidth, - setRequestObject, - children, -}) => { - - const [ - showSegmentDefinition, - setShowSegmentDefinition, - ] = usePersistentBoolean(StorageKey.cohortRequestShowSegmentDefinition, false) - const uaDimensionsAndMetricsRequest = useUADimensionsAndMetrics(apv) - const segmentsRequest = useUASegments() - const { - viewId, - setViewId, - selectedMetric, - setSelectedMetricID, - cohortSize, - setCohortSize, - selectedSegment, - setSelectedSegmentID, - samplingLevel, - setSamplingLevel, - } = useCohortRequestParameters( - apv, - successful(uaDimensionsAndMetricsRequest)?.columns, - successful(segmentsRequest)?.segments - ) - const requestObject = useCohortRequest({ - viewId, - selectedMetric, - cohortSize, - selectedSegment, - samplingLevel, - }) - - useEffect(() => { - setRequestObject(requestObject) - }, [requestObject, setRequestObject]) - - const cohortFilter = React.useCallback( - (metric: NonNullable): boolean => - metric?.attributes?.group === "Lifetime Value and Cohorts", - [] - ) - - return ( - -
    - - - - - - - - Show segment definitions instead of IDs. - - - {children} -
    -
    - ); -} - -export default CohortRequest diff --git a/src/components/RequestComposer/CohortRequest/useCohortRequest.ts b/src/components/RequestComposer/CohortRequest/useCohortRequest.ts deleted file mode 100644 index 2a62f20e..00000000 --- a/src/components/RequestComposer/CohortRequest/useCohortRequest.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { useMemo } from "react" -import moment from "moment" - -import { CohortSize, V4SamplingLevel } from "@/components/UAPickers" -import { ReportsRequest, ReportRequest } from "../RequestComposer" -import { Column, Segment } from "@/types/ua" - -type Cohort = gapi.client.analyticsreporting.Cohort - -const dimensionFor = (cohortSize: CohortSize) => { - let dimensionName: string - switch (cohortSize) { - case CohortSize.Day: - dimensionName = "ga:cohortNthDay" - break - case CohortSize.Week: - dimensionName = "ga:cohortNthWeek" - break - case CohortSize.Month: - dimensionName = "ga:cohortNthMonth" - break - } - return { name: dimensionName } -} - -const cohortsFor = (cohortSize: CohortSize) => { - // Yes this type definition is a bit gnarly. But it helps us to not mess up which is v handy. - const cohorts: Cohort[] = [] - let now = moment() - switch (cohortSize) { - case CohortSize.Day: { - // For day, return 7 cohorts, one for each of the last 7 days (starting - // at yesterday). - for (let i = 0; i < 7; i++) { - now = now.subtract(1, "days") - const cohort: Cohort = { - type: "FIRST_VISIT_DATE", - name: now.format("YYYY-MM-DD"), - dateRange: { - startDate: now.format("YYYY-MM-DD"), - endDate: now.format("YYYY-MM-DD"), - }, - } - cohorts.push(cohort) - } - break - } - case CohortSize.Week: { - // Create cohorts for the past 6 weeks. - for (let i = 0; i < 6; i++) { - const startDate = now - .subtract(1, "week") - .startOf("week") - .format("YYYY-MM-DD") - const endDate = now.endOf("week").format("YYYY-MM-DD") - const cohort = { - type: "FIRST_VISIT_DATE", - name: startDate + " to " + endDate, - dateRange: { - startDate: startDate, - endDate: endDate, - }, - } - cohorts.push(cohort) - } - break - } - case CohortSize.Month: { - // Create cohorts for the past 3 months. - for (let i = 0; i < 3; i++) { - const startDate = now - .subtract(1, "month") - .startOf("month") - .format("YYYY-MM-DD") - const endDate = now.endOf("month").format("YYYY-MM-DD") - const cohort = { - type: "FIRST_VISIT_DATE", - name: startDate + " to " + endDate, - dateRange: { - startDate: startDate, - endDate: endDate, - }, - } - cohorts.push(cohort) - } - break - } - } - return cohorts -} - -const useCohortRequest = ({ - viewId, - selectedMetric, - selectedSegment, - cohortSize, - samplingLevel, -}: { - viewId: string - selectedMetric: Column | undefined - selectedSegment: Segment | undefined - cohortSize: CohortSize | undefined - samplingLevel: V4SamplingLevel | undefined -}) => { - const request = useMemo(() => { - if ( - viewId === undefined || - viewId === "" || - selectedMetric === undefined || - cohortSize === undefined - ) { - return undefined - } - const reportRequest: ReportRequest = { - viewId, - metrics: [{ expression: selectedMetric.id }], - dimensions: [ - { - name: "ga:cohort", - }, - dimensionFor(cohortSize), - ], - cohortGroup: { - cohorts: cohortsFor(cohortSize), - }, - } - if (selectedSegment !== undefined) { - reportRequest["segments"] = [ - { - segmentId: selectedSegment.segmentId, - }, - ] - reportRequest.dimensions = reportRequest.dimensions!.concat([ - { name: "ga:segment" }, - ]) - } - if (samplingLevel !== undefined) { - reportRequest["samplingLevel"] = samplingLevel - } - - return { - reportRequests: [reportRequest], - } - }, [viewId, selectedMetric, cohortSize, selectedSegment, samplingLevel]) - return request -} - -export default useCohortRequest diff --git a/src/components/RequestComposer/CohortRequest/useCohortRequestParameters.ts b/src/components/RequestComposer/CohortRequest/useCohortRequestParameters.ts deleted file mode 100644 index 925a01ab..00000000 --- a/src/components/RequestComposer/CohortRequest/useCohortRequestParameters.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { useState, useMemo, useCallback } from "react" - -import { V4SamplingLevel, CohortSize } from "@/components/UAPickers" -import { UAAccountPropertyView } from "@/components/ViewSelector/useAccountPropertyView" -import { useKeyedHydratedPersistantObject } from "@/hooks/useHydrated" -import { StorageKey } from "@/constants" -import { QueryParam } from "../RequestComposer" -import { Column, Segment } from "@/types/ua" - -const useCohortRequestParameters = ( - apv: UAAccountPropertyView, - columns: Column[] | undefined, - segments: Segment[] | undefined -) => { - const [viewId, setViewId] = useState("") - - const getColumnByID = useCallback( - (id: string | undefined) => { - if (id === undefined || columns === undefined) { - return undefined - } - return columns.find(c => c.id === id) - }, - [columns] - ) - - const [ - selectedMetric, - setSelectedMetricID, - ] = useKeyedHydratedPersistantObject( - StorageKey.requestComposerCohortMetric, - QueryParam.Metric, - getColumnByID - ) - - const [samplingLevel, setSamplingLevel] = useState() - - const getSegmentByID = useCallback( - (id: string | undefined) => { - if (id === undefined || segments === undefined) { - return undefined - } - return segments.find(c => c.id === id) - }, - [segments] - ) - - const [ - selectedSegment, - setSelectedSegmentID, - ] = useKeyedHydratedPersistantObject( - StorageKey.requestComposerCohortSegment, - QueryParam.Segment, - getSegmentByID - ) - const [cohortSize, setCohortSize] = useState( - CohortSize.Day - ) - - useMemo(() => { - const id = apv.view?.id - if (id !== undefined) { - setViewId(id) - } - }, [apv]) - - return { - viewId, - setViewId, - selectedMetric, - setSelectedMetricID, - selectedSegment, - setSelectedSegmentID, - samplingLevel, - setSamplingLevel, - cohortSize, - setCohortSize, - } -} - -export default useCohortRequestParameters diff --git a/src/components/RequestComposer/HistogramRequest/index.tsx b/src/components/RequestComposer/HistogramRequest/index.tsx deleted file mode 100644 index e6257410..00000000 --- a/src/components/RequestComposer/HistogramRequest/index.tsx +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" -import { styled } from '@mui/material/styles'; -import {PropsWithChildren, useEffect} from "react" - -import { usePersistentBoolean } from "@/hooks" -import { StorageKey } from "@/constants" -import LinkedTextField from "@/components/LinkedTextField" -import GADate from "@/components/GADate" -import { - MetricsPicker, - DimensionsPicker, - SegmentPicker, - V4SamplingLevelPicker, -} from "@/components/UAPickers" -import useHistogramRequest from "./useHistogramRequest" -import useHistogramRequestParameters from "./useHistogramRequestParameters" -import { ReportsRequest } from "../RequestComposer" -import LabeledCheckbox from "@/components/LabeledCheckbox" -import { UAAccountPropertyView } from "@/components/ViewSelector/useAccountPropertyView" -import { successful } from "@/types" -import useUADimensionsAndMetrics, { - UADimensionsAndMetricsRequestCtx, -} from "@/components/UAPickers/useDimensionsAndMetrics" -import { - UASegmentsRequestCtx, - useUASegments, -} from "@/components/UAPickers/useUASegments" - -const PREFIX = 'HistogramRequest'; - -const classes = { - showSegments: `${PREFIX}-showSegments` -}; - -const StyledUADimensionsAndMetricsRequestCtxProvider = styled(UADimensionsAndMetricsRequestCtx.Provider)(( - { - theme - } -) => ({ - [`& .${classes.showSegments}`]: { - marginLeft: theme.spacing(1), - marginBottom: theme.spacing(1), - } -})); - -export const linkFor = (hash: string) => - `https://developers.google.com/analytics/devguides/reporting/core/v4/rest/v4/reports/batchGet#${hash}` - -export const titleFor = (id: string) => `See ${id} on devsite.` - -interface HistogramRequestProps { - apv: UAAccountPropertyView - controlWidth: string - setRequestObject: (request: ReportsRequest | undefined) => void -} - -const HistogramRequest: React.FC> = ({ - apv, - controlWidth, - setRequestObject, - children, -}) => { - - const [ - showSegmentDefinition, - setShowSegmentDefinition, - ] = usePersistentBoolean( - StorageKey.histogramRequestShowSegmentDefinition, - false - ) - const uaDimensionsAndMetricsRequest = useUADimensionsAndMetrics(apv) - const segmentsRequest = useUASegments() - const { - viewId, - setViewId, - startDate, - setStartDate, - endDate, - setEndDate, - selectedDimensions, - setSelectedDimensionIDs, - selectedMetrics, - setSelectedMetricIDs, - buckets, - setBuckets, - filtersExpression, - setFiltersExpression, - selectedSegment, - setSelectedSegmentID, - samplingLevel, - setSamplingLevel, - } = useHistogramRequestParameters( - apv, - successful(uaDimensionsAndMetricsRequest)?.columns, - successful(segmentsRequest)?.segments - ) - const requestObject = useHistogramRequest({ - viewId, - startDate, - endDate, - selectedDimensions, - selectedMetrics, - buckets, - filtersExpression, - selectedSegment, - samplingLevel, - }) - - useEffect(() => { - setRequestObject(requestObject) - }, [requestObject, setRequestObject]) - - return ( - -
    - - - - - - - - - - - - Show segment definitions instead of IDs. - - - {children} -
    -
    - ); -} - -export default HistogramRequest diff --git a/src/components/RequestComposer/HistogramRequest/useHistogramRequest.ts b/src/components/RequestComposer/HistogramRequest/useHistogramRequest.ts deleted file mode 100644 index 6e88647a..00000000 --- a/src/components/RequestComposer/HistogramRequest/useHistogramRequest.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { useMemo } from "react" - -import { V4SamplingLevel } from "@/components/UAPickers" -import { ReportsRequest, ReportRequest } from "../RequestComposer" -import { Column, Segment } from "@/types/ua" - -interface Parameters { - selectedMetrics: Column[] | undefined - selectedDimensions: Column[] | undefined - buckets: string | undefined - viewId: string - startDate: string | undefined - endDate: string | undefined - filtersExpression: string | undefined - selectedSegment: Segment | undefined - samplingLevel: V4SamplingLevel | undefined -} - -const useHistogramRequest = ({ - selectedMetrics, - selectedDimensions, - buckets, - viewId, - startDate, - endDate, - filtersExpression, - selectedSegment, - samplingLevel, -}: Parameters): ReportsRequest | undefined => { - const histogramRequestObject = useMemo(() => { - if ( - viewId === undefined || - buckets === undefined || - startDate === undefined || - startDate === "" || - endDate === undefined || - endDate === "" - ) { - return undefined - } - const reportRequest: ReportRequest = { - viewId, - dateRanges: [ - { - startDate, - endDate, - }, - ], - } - - if (selectedMetrics !== undefined && selectedMetrics.length > 0) { - reportRequest["metrics"] = selectedMetrics.map(column => ({ - expression: column.id, - })) - } - if (selectedDimensions !== undefined && selectedDimensions.length > 0) { - reportRequest["dimensions"] = selectedDimensions.map(column => ({ - // TODO - The types for this are incorrect. Might need to check the - // client library code? - histogramBuckets: buckets.split(",").map(s => parseInt(s, 10)) as any, - name: column.id, - })) - } - if (filtersExpression !== undefined && filtersExpression !== "") { - reportRequest["filtersExpression"] = filtersExpression - } - if (selectedSegment !== undefined) { - reportRequest["segments"] = [{ segmentId: selectedSegment.segmentId }] - reportRequest["dimensions"] = (reportRequest["dimensions"] || []).concat([ - { - histogramBuckets: buckets.split(",").map(s => parseInt(s, 10)) as any, - name: "ga:segment", - }, - ]) - } - if (samplingLevel !== undefined) { - reportRequest["samplingLevel"] = samplingLevel - } - - return { - reportRequests: [reportRequest], - } - }, [ - selectedMetrics, - buckets, - selectedDimensions, - viewId, - startDate, - endDate, - filtersExpression, - selectedSegment, - samplingLevel, - ]) - - return histogramRequestObject -} - -export default useHistogramRequest diff --git a/src/components/RequestComposer/HistogramRequest/useHistogramRequestParameters.ts b/src/components/RequestComposer/HistogramRequest/useHistogramRequestParameters.ts deleted file mode 100644 index 95a3bdbb..00000000 --- a/src/components/RequestComposer/HistogramRequest/useHistogramRequestParameters.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { useState, useMemo, useCallback } from "react" - -import { usePersistentString } from "@/hooks" -import { StorageKey } from "@/constants" -import { V4SamplingLevel } from "@/components/UAPickers" -import { UAAccountPropertyView } from "@/components/ViewSelector/useAccountPropertyView" -import { - useKeyedHydratedPersistantArray, - useKeyedHydratedPersistantObject, -} from "@/hooks/useHydrated" -import { QueryParam } from "../RequestComposer" -import { Column, Segment } from "@/types/ua" - -const useHistogramRequestParameters = ( - apv: UAAccountPropertyView, - columns: Column[] | undefined, - segments: Segment[] | undefined -) => { - const [viewId, setViewId] = useState("") - - const getColumnsByIDs = useCallback( - (ids: string[] | undefined) => { - if (ids === undefined || columns === undefined) { - return undefined - } - return columns.filter(c => ids.includes(c.id!)) - }, - [columns] - ) - - const [ - selectedDimensions, - setSelectedDimensionIDs, - ] = useKeyedHydratedPersistantArray( - StorageKey.requestComposerHistogramDimensions, - QueryParam.Dimensions, - getColumnsByIDs - ) - const [ - selectedMetrics, - setSelectedMetricIDs, - ] = useKeyedHydratedPersistantArray( - StorageKey.requestComposerHistogramMetrics, - QueryParam.Metrics, - getColumnsByIDs - ) - const [samplingLevel, setSamplingLevel] = useState() - - const [startDate, setStartDate] = usePersistentString( - StorageKey.histogramStartDate, - "7daysAgo" - ) - const [endDate, setEndDate] = usePersistentString( - StorageKey.histogramEndDate, - "yesterday" - ) - const [buckets, setBuckets] = usePersistentString(StorageKey.histogramBuckets) - const [filtersExpression, setFiltersExpression] = usePersistentString( - StorageKey.histogramFiltersExpression, - "ga:browser=~^Chrome" - ) - - const getSegmentByID = useCallback( - (id: string | undefined) => { - if (id === undefined || segments === undefined) { - return undefined - } - return segments.find(c => c.id === id) - }, - [segments] - ) - - const [ - selectedSegment, - setSelectedSegmentID, - ] = useKeyedHydratedPersistantObject( - StorageKey.requestComposerHistogramSegment, - QueryParam.Segment, - getSegmentByID - ) - - useMemo(() => { - const id = apv.view?.id - if (id !== undefined) { - setViewId(id) - } - }, [apv]) - - return { - viewId, - setViewId, - startDate, - setStartDate, - endDate, - setEndDate, - selectedDimensions, - setSelectedDimensionIDs, - selectedMetrics, - setSelectedMetricIDs, - buckets, - setBuckets, - filtersExpression, - setFiltersExpression, - selectedSegment, - setSelectedSegmentID, - samplingLevel, - setSamplingLevel, - } -} - -export default useHistogramRequestParameters diff --git a/src/components/RequestComposer/MetricExpression/index.tsx b/src/components/RequestComposer/MetricExpression/index.tsx deleted file mode 100644 index db7580fb..00000000 --- a/src/components/RequestComposer/MetricExpression/index.tsx +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" -import { styled } from '@mui/material/styles'; -import {PropsWithChildren, useEffect} from "react" - -import { usePersistentBoolean } from "@/hooks" -import { StorageKey } from "@/constants" -import LinkedTextField from "@/components/LinkedTextField" -import GADate from "@/components/GADate" -import LabeledCheckbox from "@/components/LabeledCheckbox" -import { - DimensionsPicker, - SegmentPicker, - V4SamplingLevelPicker, -} from "@/components/UAPickers" -import { linkFor, titleFor } from "../HistogramRequest/" -import useMetricExpressionRequestParameters from "./useMetricExpressionRequestParameters" -import useMetricExpressionRequest from "./useMetricExpressionRequest" -import { ReportsRequest } from "../RequestComposer" -import { UAAccountPropertyView } from "@/components/ViewSelector/useAccountPropertyView" -import useUADimensionsAndMetrics, { - UADimensionsAndMetricsRequestCtx, -} from "@/components/UAPickers/useDimensionsAndMetrics" -import { successful } from "@/types" -import { - UASegmentsRequestCtx, - useUASegments, -} from "@/components/UAPickers/useUASegments" - -const PREFIX = 'MetricExpression'; - -const classes = { - showSegments: `${PREFIX}-showSegments` -}; - -const StyledUADimensionsAndMetricsRequestCtxProvider = styled(UADimensionsAndMetricsRequestCtx.Provider)(( - { - theme - } -) => ({ - [`& .${classes.showSegments}`]: { - marginLeft: theme.spacing(1), - marginBottom: theme.spacing(1), - } -})); - -interface MetricExpressionRequestProps { - apv: UAAccountPropertyView - controlWidth: string - setRequestObject: (request: ReportsRequest | undefined) => void -} - -const MetricExpression: React.FC> = ({ - apv, - controlWidth, - setRequestObject, - children, -}) => { - - const [ - showSegmentDefinition, - setShowSegmentDefinition, - ] = usePersistentBoolean( - StorageKey.metricExpressionRequestShowSegmentDefinition, - false - ) - const uaDimensionsAndMetricsRequest = useUADimensionsAndMetrics(apv) - const segmentsRequest = useUASegments() - const { - viewId, - setViewId, - startDate, - setStartDate, - endDate, - setEndDate, - metricExpressions, - setMetricExpressions, - metricAliases, - setMetricAliases, - selectedDimensions, - setSelectedDimensionIDs, - filtersExpression, - setFiltersExpression, - selectedSegment, - setSelectedSegmentID, - samplingLevel, - setSamplingLevel, - pageSize, - setPageSize, - pageToken, - setPageToken, - } = useMetricExpressionRequestParameters( - apv, - successful(uaDimensionsAndMetricsRequest)?.columns, - successful(segmentsRequest)?.segments - ) - const requestObject = useMetricExpressionRequest({ - viewId, - samplingLevel, - filtersExpression, - startDate, - endDate, - metricExpressions, - metricAliases, - selectedDimensions, - selectedSegment, - pageToken, - pageSize, - }) - - useEffect(() => { - setRequestObject(requestObject) - }, [requestObject, setRequestObject]) - - return ( - -
    - - - - - - - - - - - - Show segment definitions instead of IDs. - - - - - {children} -
    -
    - ); -} - -export default MetricExpression diff --git a/src/components/RequestComposer/MetricExpression/useMetricExpressionRequest.ts b/src/components/RequestComposer/MetricExpression/useMetricExpressionRequest.ts deleted file mode 100644 index d608a9a2..00000000 --- a/src/components/RequestComposer/MetricExpression/useMetricExpressionRequest.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { useMemo } from "react" - -import { V4SamplingLevel } from "@/components/UAPickers" -import { ReportsRequest, ReportRequest } from "../RequestComposer" -import { Column, Segment } from "@/types/ua" - -interface Parameters { - viewId: string - samplingLevel: V4SamplingLevel | undefined - filtersExpression: string | undefined - startDate: string | undefined - endDate: string | undefined - metricExpressions: string | undefined - metricAliases: string | undefined - selectedDimensions: Column[] | undefined - selectedSegment: Segment | undefined - pageToken: string | undefined - pageSize: string | undefined -} - -const useMetricExpressionRequest = ({ - viewId, - samplingLevel, - filtersExpression, - startDate, - endDate, - metricExpressions, - metricAliases, - selectedDimensions, - selectedSegment, - pageToken, - pageSize, -}: Parameters): ReportsRequest | undefined => { - const metricExpressionRequestObject = useMemo< - ReportsRequest | undefined - >(() => { - if ( - viewId === undefined || - viewId === "" || - metricExpressions === undefined || - metricExpressions === "" || - startDate === undefined || - startDate === "" || - endDate === undefined || - endDate === "" - ) { - return undefined - } - - const baseMetricExpressions = metricExpressions.split(",") - // TODO - there could be helpful error messaging here. - if (baseMetricExpressions.length === 0) { - return - } - const aliases = (metricAliases || "").split(",") - const metrics = baseMetricExpressions.map((expression, idx) => { - const alias = aliases[idx] - - type MetricType = { - expression: string, - alias?: string - } - const metric: MetricType = { - expression, - } - if (alias !== undefined) { - metric["alias"] = alias - } - return metric - }) - - const reportRequest: ReportRequest = { - viewId, - metrics, - dateRanges: [ - { - startDate, - endDate, - }, - ], - } - - if (selectedDimensions !== undefined && selectedDimensions.length > 0) { - reportRequest["dimensions"] = selectedDimensions.map(column => ({ - name: column.id, - })) - } - - if (filtersExpression !== undefined && filtersExpression !== "") { - reportRequest["filtersExpression"] = filtersExpression - } - - if (selectedSegment !== undefined) { - reportRequest["segments"] = [{ segmentId: selectedSegment.segmentId }] - reportRequest["dimensions"] = (reportRequest["dimensions"] || []).concat([ - { - name: "ga:segment", - }, - ]) - } - - if (pageToken !== undefined) { - reportRequest["pageToken"] = pageToken - } - - if (pageSize !== undefined) { - const parsed = parseInt(pageSize, 10) - if (!isNaN(parsed)) { - reportRequest["pageSize"] = parsed - } - } - - if (samplingLevel !== undefined) { - reportRequest["samplingLevel"] = samplingLevel - } - - return { - reportRequests: [reportRequest], - } - }, [ - viewId, - samplingLevel, - filtersExpression, - startDate, - endDate, - metricExpressions, - selectedDimensions, - selectedSegment, - pageToken, - pageSize, - metricAliases, - ]) - - return metricExpressionRequestObject -} - -export default useMetricExpressionRequest diff --git a/src/components/RequestComposer/MetricExpression/useMetricExpressionRequestParameters.ts b/src/components/RequestComposer/MetricExpression/useMetricExpressionRequestParameters.ts deleted file mode 100644 index 4e78f62c..00000000 --- a/src/components/RequestComposer/MetricExpression/useMetricExpressionRequestParameters.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { useState, useMemo, useCallback } from "react" - -import { usePersistentString } from "@/hooks" -import { StorageKey } from "@/constants" -import { V4SamplingLevel } from "@/components/UAPickers" -import { UAAccountPropertyView } from "@/components/ViewSelector/useAccountPropertyView" -import { - useKeyedHydratedPersistantArray, - useKeyedHydratedPersistantObject, -} from "@/hooks/useHydrated" -import { QueryParam } from "../RequestComposer" -import { Column, Segment } from "@/types/ua" - -const useMetricExpressionRequestParameters = ( - apv: UAAccountPropertyView, - columns: Column[] | undefined, - segments: Segment[] | undefined -) => { - const [viewId, setViewId] = useState("") - const [startDate, setStartDate] = usePersistentString( - StorageKey.metricExpressionStartDate, - "7daysAgo" - ) - const [endDate, setEndDate] = usePersistentString( - StorageKey.metricExpressionEndDate, - "yesterday" - ) - const [metricExpressions, setMetricExpressions] = usePersistentString( - StorageKey.metricExpressionMetricExpressions, - "" - ) - const [metricAliases, setMetricAliases] = usePersistentString( - StorageKey.metricExpressionMetricAliases, - "" - ) - - const getColumnsByIDs = useCallback( - (ids: string[] | undefined) => { - if (ids === undefined || columns === undefined) { - return undefined - } - return columns.filter(c => ids.includes(c.id!)) - }, - [columns] - ) - - const [ - selectedDimensions, - setSelectedDimensionIDs, - ] = useKeyedHydratedPersistantArray( - StorageKey.requestComposerMetricExpressionDimensions, - QueryParam.Dimensions, - getColumnsByIDs - ) - - const [filtersExpression, setFiltersExpression] = usePersistentString( - StorageKey.metricExpressionFiltersExpression, - "" - ) - - const getSegmentByID = useCallback( - (id: string | undefined) => { - if (id === undefined || segments === undefined) { - return undefined - } - return segments.find(c => c.id === id) - }, - [segments] - ) - - const [ - selectedSegment, - setSelectedSegmentID, - ] = useKeyedHydratedPersistantObject( - StorageKey.requestComposerMetricExpressionSegment, - QueryParam.Segment, - getSegmentByID - ) - - const [samplingLevel, setSamplingLevel] = useState< - V4SamplingLevel | undefined - >(V4SamplingLevel.Default) - const [pageToken, setPageToken] = usePersistentString( - StorageKey.metricExpressionPageToken - ) - const [pageSize, setPageSize] = usePersistentString( - StorageKey.metricExpressionPageSize - ) - - useMemo(() => { - const id = apv.view?.id - if (id !== undefined) { - setViewId(id) - } - }, [apv]) - - return { - viewId, - setViewId, - startDate, - setStartDate, - endDate, - setEndDate, - metricExpressions, - setMetricExpressions, - metricAliases, - setMetricAliases, - selectedDimensions, - setSelectedDimensionIDs, - filtersExpression, - setFiltersExpression, - selectedSegment, - setSelectedSegmentID, - samplingLevel, - setSamplingLevel, - pageToken, - setPageToken, - pageSize, - setPageSize, - } -} - -export default useMetricExpressionRequestParameters diff --git a/src/components/RequestComposer/PivotRequest/index.tsx b/src/components/RequestComposer/PivotRequest/index.tsx deleted file mode 100644 index 95fa9822..00000000 --- a/src/components/RequestComposer/PivotRequest/index.tsx +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" -import { styled } from '@mui/material/styles'; -import {PropsWithChildren, useEffect} from "react" - -import { usePersistentBoolean } from "@/hooks" -import { StorageKey } from "@/constants" -import GADate from "@/components/GADate" -import LinkedTextField from "@/components/LinkedTextField" -import LabeledCheckbox from "@/components/LabeledCheckbox" -import { - MetricsPicker, - DimensionsPicker, - SegmentPicker, - V4SamplingLevelPicker, -} from "@/components/UAPickers" -import { ReportsRequest } from "../RequestComposer" -import { linkFor, titleFor } from "../HistogramRequest" -import usePivotRequestParameters from "./usePivotRequestParameters" -import usePivotRequest from "./usePivotRequest" -import { UAAccountPropertyView } from "@/components/ViewSelector/useAccountPropertyView" -import useUADimensionsAndMetrics, { - UADimensionsAndMetricsRequestCtx, -} from "@/components/UAPickers/useDimensionsAndMetrics" -import { successful } from "@/types" -import { - UASegmentsRequestCtx, - useUASegments, -} from "@/components/UAPickers/useUASegments" - -const PREFIX = 'PivotRequest'; - -const classes = { - showSegments: `${PREFIX}-showSegments` -}; - -const StyledUADimensionsAndMetricsRequestCtxProvider = styled(UADimensionsAndMetricsRequestCtx.Provider)(( - { - theme - } -) => ({ - [`& .${classes.showSegments}`]: { - marginLeft: theme.spacing(1), - marginBottom: theme.spacing(1), - } -})); - -interface PivotRequestProps { - apv: UAAccountPropertyView - controlWidth: string - setRequestObject: (request: ReportsRequest | undefined) => void -} - -const PivotRequest: React.FC> = ({ - apv, - controlWidth, - setRequestObject, - children, -}) => { - - const [ - showSegmentDefinition, - setShowSegmentDefinition, - ] = usePersistentBoolean(StorageKey.pivotRequestShowSegmentDefinition, false) - - const uaDimensionsAndMetricsRequest = useUADimensionsAndMetrics(apv) - const segmentsRequest = useUASegments() - - const { - viewId, - setViewId, - startDate, - setStartDate, - endDate, - setEndDate, - selectedMetrics, - setSelectedMetricIDs, - selectedDimensions, - setSelectedDimensionIDs, - pivotMetrics, - setPivotMetricIDs, - pivotDimensions, - setPivotDimensionIDs, - startGroup, - setStartGroup, - selectedSegment, - setSelectedSegmentID, - samplingLevel, - setSamplingLevel, - maxGroupCount, - setMaxGroupCount, - includeEmptyRows, - setIncludeEmptyRows, - pageToken, - setPageToken, - pageSize, - setPageSize, - } = usePivotRequestParameters( - apv, - successful(uaDimensionsAndMetricsRequest)?.columns, - successful(segmentsRequest)?.segments - ) - const requestObject = usePivotRequest({ - viewId, - startDate, - endDate, - metrics: selectedMetrics, - dimensions: selectedDimensions, - pivotMetrics, - pivotDimensions, - selectedSegment, - startGroup, - samplingLevel, - maxGroupCount, - includeEmptyRows, - pageToken, - pageSize, - }) - - useEffect(() => { - setRequestObject(requestObject) - }, [requestObject, setRequestObject]) - - return ( - -
    - - - - - - - - - - - - - - Show segment definitions instead of IDs. - - - - - - Include Empty Rows - -
    - {children} -
    -
    - ); -} - -export default PivotRequest diff --git a/src/components/RequestComposer/PivotRequest/usePivotRequest.ts b/src/components/RequestComposer/PivotRequest/usePivotRequest.ts deleted file mode 100644 index ce0e46ee..00000000 --- a/src/components/RequestComposer/PivotRequest/usePivotRequest.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { useMemo } from "react" - -import { V4SamplingLevel } from "@/components/UAPickers" -import { Column, Segment } from "@/types/ua" - -type ReportRequest = gapi.client.analyticsreporting.ReportRequest -type Request = { reportRequests: Array } - -interface Parameters { - viewId: string | undefined - startDate: string | undefined - endDate: string | undefined - metrics: Column[] | undefined - pivotMetrics: Column[] | undefined - dimensions: Column[] | undefined - pivotDimensions: Column[] | undefined - startGroup: string | undefined - maxGroupCount: string | undefined - selectedSegment: Segment | undefined - samplingLevel: V4SamplingLevel | undefined - pageToken: string | undefined - pageSize: string | undefined - includeEmptyRows: boolean -} - -const usePivotRequest = ({ - viewId, - startDate, - endDate, - metrics, - pivotMetrics, - dimensions, - pivotDimensions, - startGroup, - maxGroupCount, - selectedSegment, - samplingLevel, - pageToken, - pageSize, - includeEmptyRows, -}: Parameters) => { - const request = useMemo(() => { - if ( - viewId === undefined || - viewId === "" || - startDate === undefined || - startDate === "" || - endDate === undefined || - endDate === "" || - metrics === undefined || - metrics.length === 0 || - dimensions === undefined || - dimensions.length === 0 || - pivotMetrics === undefined || - pivotMetrics.length === 0 || - pivotDimensions === undefined || - pivotDimensions.length === 0 - ) { - return undefined - } - const reportRequest: ReportRequest = { - viewId, - metrics: metrics.map(metric => ({ expression: metric.id })), - includeEmptyRows, - dimensions: dimensions.map(dimension => ({ name: dimension.id })), - pivots: [ - { - dimensions: pivotDimensions.map(dimension => ({ - name: dimension.id, - })), - metrics: pivotMetrics.map(pivot => ({ expression: pivot.id })), - }, - ], - } - if (startGroup !== undefined) { - const parsed = parseInt(startGroup, 10) - if (!isNaN(parsed)) { - reportRequest["pivots"]![0].startGroup = parsed - } - } - if (maxGroupCount !== undefined) { - const parsed = parseInt(maxGroupCount, 10) - if (!isNaN(parsed)) { - reportRequest["pivots"]![0].maxGroupCount = parsed - } - } - if (selectedSegment !== undefined) { - reportRequest["segments"] = [ - { - segmentId: selectedSegment.segmentId, - }, - ] - reportRequest.dimensions = reportRequest!.dimensions!.concat([ - { name: "ga:segment" }, - ]) - } - if (samplingLevel !== undefined) { - reportRequest["samplingLevel"] = samplingLevel - } - if (pageToken !== undefined) { - reportRequest["pageToken"] = pageToken - } - if (pageSize !== undefined) { - const parsed = parseInt(pageSize, 10) - if (!isNaN(parsed)) { - reportRequest["pageSize"] = parsed - } - } - - return { - reportRequests: [reportRequest], - } - }, [ - startDate, - endDate, - viewId, - metrics, - pivotMetrics, - dimensions, - pivotDimensions, - startGroup, - maxGroupCount, - selectedSegment, - samplingLevel, - pageToken, - pageSize, - includeEmptyRows, - ]) - return request -} - -export default usePivotRequest diff --git a/src/components/RequestComposer/PivotRequest/usePivotRequestParameters.ts b/src/components/RequestComposer/PivotRequest/usePivotRequestParameters.ts deleted file mode 100644 index b7c3ed3c..00000000 --- a/src/components/RequestComposer/PivotRequest/usePivotRequestParameters.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { useState, useMemo, useCallback } from "react" - -import { usePersistentString, usePersistentBoolean } from "@/hooks" -import { StorageKey } from "@/constants" -import { V4SamplingLevel } from "@/components/UAPickers" -import { UAAccountPropertyView } from "@/components/ViewSelector/useAccountPropertyView" -import { QueryParam } from "../RequestComposer" -import { - useKeyedHydratedPersistantArray, - useKeyedHydratedPersistantObject, -} from "@/hooks/useHydrated" -import { Column, Segment } from "@/types/ua" - -const usePivotRequestParameters = ( - apv: UAAccountPropertyView, - columns: Column[] | undefined, - segments: Segment[] | undefined -) => { - const [viewId, setViewId] = useState("") - const [startDate, setStartDate] = usePersistentString( - StorageKey.pivotRequestStartDate, - "7daysAgo" - ) - const [endDate, setEndDate] = usePersistentString( - StorageKey.pivotRequestEndDate, - "yesterday" - ) - const getColumnsByIDs = useCallback( - (ids: string[] | undefined) => { - if (ids === undefined || columns === undefined) { - return undefined - } - return columns.filter(c => ids.includes(c.id!)) - }, - [columns] - ) - - const [ - selectedDimensions, - setSelectedDimensionIDs, - ] = useKeyedHydratedPersistantArray( - StorageKey.requestComposerPivotDimensions, - QueryParam.Dimensions, - getColumnsByIDs - ) - const [ - selectedMetrics, - setSelectedMetricIDs, - ] = useKeyedHydratedPersistantArray( - StorageKey.requestComposerPivotMetrics, - QueryParam.Metrics, - getColumnsByIDs - ) - const [ - pivotMetrics, - setPivotMetricIDs, - ] = useKeyedHydratedPersistantArray( - StorageKey.requestComposerPivotPivotMetrics, - QueryParam.PivotMetrics, - getColumnsByIDs - ) - const [ - pivotDimensions, - setPivotDimensionIDs, - ] = useKeyedHydratedPersistantArray( - StorageKey.requestComposerPivotPivotDimensions, - QueryParam.PivotDimensions, - getColumnsByIDs - ) - const [startGroup, setStartGroup] = usePersistentString( - StorageKey.pivotRequestStartGroup - ) - const [maxGroupCount, setMaxGroupCount] = usePersistentString( - StorageKey.pivotRequestMaxGroupCount - ) - - const getSegmentByID = useCallback( - (id: string | undefined) => { - if (id === undefined || segments === undefined) { - return undefined - } - return segments.find(c => c.id === id) - }, - [segments] - ) - - const [ - selectedSegment, - setSelectedSegmentID, - ] = useKeyedHydratedPersistantObject( - StorageKey.requestComposerPivotSegment, - QueryParam.Segment, - getSegmentByID - ) - const [samplingLevel, setSamplingLevel] = useState< - V4SamplingLevel | undefined - >(V4SamplingLevel.Default) - const [pageToken, setPageToken] = usePersistentString( - StorageKey.pivotRequestPageToken - ) - const [pageSize, setPageSize] = usePersistentString( - StorageKey.pivotRequestPageSize - ) - const [includeEmptyRows, setIncludeEmptyRows] = usePersistentBoolean( - StorageKey.pivotRequestIncludeEmptyRows, - false - ) - - useMemo(() => { - const id = apv.view?.id - if (id !== undefined) { - setViewId(id) - } - }, [apv]) - - return { - viewId, - setViewId, - startDate, - setStartDate, - endDate, - setEndDate, - selectedMetrics, - setSelectedMetricIDs, - selectedDimensions, - setSelectedDimensionIDs, - pivotMetrics, - setPivotMetricIDs, - pivotDimensions, - setPivotDimensionIDs, - startGroup, - setStartGroup, - maxGroupCount, - setMaxGroupCount, - selectedSegment, - setSelectedSegmentID, - samplingLevel, - setSamplingLevel, - includeEmptyRows, - setIncludeEmptyRows, - pageToken, - setPageToken, - pageSize, - setPageSize, - } -} - -export default usePivotRequestParameters diff --git a/src/components/RequestComposer/ReportsTable.tsx b/src/components/RequestComposer/ReportsTable.tsx deleted file mode 100644 index 3ea14cd5..00000000 --- a/src/components/RequestComposer/ReportsTable.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import React, {PropsWithChildren, useState} from "react" - -import { styled } from '@mui/material/styles'; - -import Typography from "@mui/material/Typography" -import TableContainer from "@mui/material/TableContainer" -import Table from "@mui/material/Table" -import TableHead from "@mui/material/TableHead" -import TableRow from "@mui/material/TableRow" -import TableCell from "@mui/material/TableCell" -import TableBody from "@mui/material/TableBody" -import Tabs from "@mui/material/Tabs" -import Tab from "@mui/material/Tab" -import Box from "@mui/material/Box" - -import PrettyJson, { shouldCollapseResponse } from "@/components/PrettyJson" -import { GetReportsResponse } from "./api" -import Spinner from "@/components/Spinner" - -const PREFIX = 'ReportsTable'; - -const classes = { - loadingIndicator: `${PREFIX}-loadingIndicator`, - container: `${PREFIX}-container`, - makeRequest: `${PREFIX}-makeRequest`, - reports: `${PREFIX}-reports` -}; - -const Root = styled('section')(( - { - theme - } -) => ({ - [`& .${classes.loadingIndicator}`]: { - marginTop: theme.spacing(2), - display: "flex", - flexDirection: "column", - alignItems: "center", - }, - - [`& .${classes.container}`]: { - maxHeight: 440, - }, - - [`& .${classes.makeRequest}`]: { - marginTop: theme.spacing(1), - marginBottom: theme.spacing(2), - }, - - [`&.${classes.reports}`]: { - marginTop: theme.spacing(2), - } -})); - -type Props = { value: number, - index: number } - -const TabPanel: React.FC> = ({ - value, - index, - children, -}) => { - return ( - - ) -} - -interface ReportsTableProps { - response: GetReportsResponse | undefined - longRequest: boolean -} - -const ReportsTable: React.FC = ({ - response, - longRequest, -}) => { - - const [tab, setTab] = useState(0) - // TODO - Add in functionality so this works right with cohort requests (or - // just make a cohortRequest Table which might be clearer.) - // - if (longRequest) { - return Loading - } - - if (response === undefined) { - return null - } - return ( - - Response - { - // TODO - huh? - setTab(newValue as any) - }} - > - - - - - {response.reports?.map((reportData, reportIdx) => { - return ( - - - - - {reportData.columnHeader?.dimensions?.map(header => ( - {header} - ))} - {reportData.columnHeader?.metricHeader?.metricHeaderEntries?.map( - header => ( - {header.name} - ) - )} - - - - {reportData.data?.rows?.map((row, idx) => ( - - {row.dimensions?.map((column, innerIdx) => ( - - {column} - - ))} - {row?.metrics?.flatMap(({ values: dateRange }) => - dateRange?.map((column, innerIdx) => ( - - {column} - - )) - )} - - ))} - -
    -
    - ) - })} -
    - - - -
    - ); -} - -export default ReportsTable diff --git a/src/components/RequestComposer/RequestComposer.tsx b/src/components/RequestComposer/RequestComposer.tsx deleted file mode 100644 index e6b9f9b0..00000000 --- a/src/components/RequestComposer/RequestComposer.tsx +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" -import { styled } from '@mui/material/styles'; -import { useState } from "react" - -import Typography from "@mui/material/Typography" -import Tabs from "@mui/material/Tabs" -import Tab from "@mui/material/Tab" - -import { StorageKey } from "@/constants" -import ViewSelector from "@/components/ViewSelector" -import { PAB } from "@/components/Buttons" -import PrettyJson, { shouldCollapseRequest } from "@/components/PrettyJson" -import HistogramRequest from "./HistogramRequest" -import PivotRequest from "./PivotRequest" -import CohortRequest from "./CohortRequest" -import MetricExpression from "./MetricExpression" -import ReportsTable from "./ReportsTable" -import { useMakeReportsRequest } from "./api" -import TabPanel from "../TabPanel" -import { RequestComposerType } from "." -import useAccountPropertyView from "../ViewSelector/useAccountPropertyView" -import { navigate } from "gatsby" - -const PREFIX = 'RequestComposer'; - -const classes = { - viewSelector: `${PREFIX}-viewSelector`, - maxControlWidth: `${PREFIX}-maxControlWidth`, - makeRequest: `${PREFIX}-makeRequest` -}; - -const Root = styled('div')(( - { - theme - } -) => ({ - [`& .${classes.viewSelector}`]: { - flexDirection: "column", - maxWidth: "650px", - }, - - [`& .${classes.maxControlWidth}`]: { - maxWidth: "600px", - }, - - [`& .${classes.makeRequest}`]: { - marginTop: theme.spacing(1), - marginBottom: theme.spacing(2), - } -})); - -export type ReportRequest = gapi.client.analyticsreporting.ReportRequest -export type ReportsRequest = { reportRequests: Array } - -export enum QueryParam { - Account = "a", - Property = "b", - View = "c", - Dimensions = "d", - Metrics = "e", - Segment = "f", - PivotMetrics = "g", - PivotDimensions = "h", - Metric = "i", -} - -interface RequestComposerProps { - type: RequestComposerType -} - -const RequestComposer: React.FC = ({ type }) => { - - const tab = React.useMemo(() => { - switch (type) { - case RequestComposerType.Histogram: - return 0 - case RequestComposerType.Pivot: - return 1 - case RequestComposerType.Cohort: - return 2 - case RequestComposerType.MetricExpression: - return 3 - } - }, [type]) - - const pathForIdx = React.useCallback((idx: number) => { - switch (idx) { - case 0: - return `/request-composer/` - case 1: - return `/request-composer/pivot/` - case 2: - return `/request-composer/cohort/` - case 3: - return `/request-composer/metric-expression/` - default: - throw new Error("No matching idx") - } - }, []) - const [requestObject, setRequestObject] = useState() - - const { - makeRequest, - response, - longRequest, - canMakeRequest, - } = useMakeReportsRequest(requestObject) - - const button = React.useMemo(() => { - return ( - - Make Request - - ) - }, [makeRequest, canMakeRequest]) - - const accountPropertyView = useAccountPropertyView( - StorageKey.requestComposerAPV, - QueryParam - ) - - return ( - -
    - Select View - -
    -
    - { - const path = `${pathForIdx(newValue)}` - navigate(path) - }} - > - - - - - - - - {button} - - - - - {button} - - - - - {button} - - - - - {button} - - -
    -
    - -
    -
    - -
    -
    - ); -} - -export default RequestComposer diff --git a/src/components/RequestComposer/api.ts b/src/components/RequestComposer/api.ts deleted file mode 100644 index 707cc916..00000000 --- a/src/components/RequestComposer/api.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { useSelector } from "react-redux" -import { useEffect, useState, useCallback, useMemo } from "react" - -export type GetReportsResponse = gapi.client.analyticsreporting.GetReportsResponse - -type ReportingAPI = typeof gapi.client.analyticsreporting - -export const useAnalyticsReportingAPI = (): ReportingAPI | undefined => { - const gapi = useSelector((state: AppState) => state.gapi) - const [reportingAPI, setReportingAPI] = useState() - - useEffect(() => { - if (gapi === undefined) { - return - } - setReportingAPI(gapi?.client?.analyticsreporting) - }, [gapi]) - - return reportingAPI -} - -type GetReportsRequest = gapi.client.analyticsreporting.GetReportsRequest - -export const useMakeReportsRequest = ( - requestObject: GetReportsRequest | undefined -) => { - const reportingAPI = useAnalyticsReportingAPI() - const [response, setResponse] = useState() - const [longRequest, setLongRequest] = useState(false) - - const canMakeRequest = useMemo(() => { - return requestObject !== undefined - }, [requestObject]) - - const makeRequest = useCallback(() => { - if (reportingAPI === undefined || requestObject === undefined) { - return - } - ;(async () => { - const first = await Promise.race([ - (async () => { - const response = await reportingAPI.reports.batchGet( - {}, - requestObject - ) - setResponse(response.result) - setTimeout(() => { - setLongRequest(false) - }, 500) - return "API" - })(), - new Promise(resolve => { - window.setTimeout(() => { - resolve("TIMEOUT") - }, 300) - }), - ]) - if (first === "TIMEOUT") { - setLongRequest(true) - } - })() - }, [reportingAPI, requestObject]) - - return { makeRequest, response, longRequest, canMakeRequest } -} diff --git a/src/components/RequestComposer/index.tsx b/src/components/RequestComposer/index.tsx deleted file mode 100644 index b20512b2..00000000 --- a/src/components/RequestComposer/index.tsx +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import { styled } from '@mui/material/styles'; - -import Typography from "@mui/material/Typography" - -import ExternalLink from "@/components/ExternalLink" -import Tool from "./RequestComposer" - -const PREFIX = 'RequestComposer'; - -const classes = { - list: `${PREFIX}-list` -}; - -const Root = styled('div')(( - { - theme - } -) => ({ - [`& .${classes.list}`]: { - marginTop: theme.spacing(0), - } -})); - -export enum RequestComposerType { - Histogram = "histogram", - Pivot = "pivot", - Cohort = "cohort", - MetricExpression = "metric-expression", -} - -interface RequestComposerProps { - type: RequestComposerType -} - -const RequestComposer: React.FC = ({ type }) => { - - return ( - ( - Overview - - The Request Composer demonstrates how to compose the following Analytics - Reporting API v4 requests and visualize their responses: - -
      -
    • - - Histogram request - -
    • -
    • - - Pivot request - -
    • -
    • - - Cohort request - -
    • -
    • - - metric expressions - -
    • -
    - - This version of Request Composer does not support the following - features: - -
      -
    • - - multiple date ranges - -
    • -
    • - - advanced segment configuration - -
    • -
    • - - advanced filter configuration - -
    • -
    - To compose a request: -
      -
    1. Select an account, a property, and a view.
    2. -
    3. Select a request type (Histogram, Pivot, or Cohort).
    4. -
    5. Set query parameters.
    6. -
    7. Click Make Request.
    8. -
    - -
    ) - ); -} - -export default RequestComposer diff --git a/src/components/UAPickers/index.tsx b/src/components/UAPickers/index.tsx deleted file mode 100644 index 1b59a7f6..00000000 --- a/src/components/UAPickers/index.tsx +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import { styled } from '@mui/material/styles'; - -import { Typography, TextField } from "@mui/material" - -import Autocomplete, { - createFilterOptions, -} from "@mui/material/Autocomplete" -import { usePersistentString } from "@/hooks" -import { StorageKey } from "@/constants" -import { Column as ColumnT, Segment as SegmentT } from "@/types/ua" -import { Dispatch, RequestStatus, successful } from "@/types" -import { UADimensionsAndMetricsRequestCtx } from "./useDimensionsAndMetrics" -import { UASegmentsRequestCtx } from "./useUASegments" - - -const PREFIX = 'DimensionPicker'; - -const classes = { - option: `${PREFIX}-option`, - left: `${PREFIX}-left` -}; - -const Root = styled('div')(() => ({ - [`& .${classes.option}`]: { - display: "flex", - width: "100%", - }, - - [`& .${classes.left}`]: { - flexGrow: 1, - display: "flex", - flexDirection: "column", - } -})); - -export enum V4SamplingLevel { - Default = "DEFAULT", - SMALL = "SMALL", - LARGE = "LARGE", -} -export enum V3SamplingLevel { - Default = "DEFAULT", - Faster = "FASTER", - HigherPrecision = "HIGHER_PRECISION", -} -export enum CohortSize { - Day = "DAY", - Week = "WEEK", - Month = "MONTH", -} - -const removeDeprecatedColumns = (column: ColumnT): true | false => - column.attributes?.status !== "DEPRECATED" - - -const Column: React.FC<{ column: ColumnT }> = ({ column }) => { - return ( -
    -
    - - {column.attributes!.uiName} - - - {column.id} - -
    - - {column.attributes!.group} - -
    - ) -} - -const columnFilterOptions = createFilterOptions({ - stringify: option => `${option.id} ${option.attributes?.uiName || ""}`, -}) - -export const DimensionPicker: React.FC<{ - selectedDimension: ColumnT | undefined - setDimensionID: Dispatch - required?: true | undefined - helperText?: string -}> = ({ helperText, selectedDimension, setDimensionID, required }) => { - const request = React.useContext(UADimensionsAndMetricsRequestCtx) - - return ( - - filterOptions={columnFilterOptions} - fullWidth - autoComplete - autoHighlight - freeSolo - loading={request.status === RequestStatus.InProgress} - options={ - successful(request)?.dimensions.filter(removeDeprecatedColumns) || [] - } - getOptionLabel={(dimension) => typeof dimension === "string" ? dimension : dimension.id!} - value={selectedDimension || null} - onChange={(_event, value) => - setDimensionID(value === null ? undefined : (value as ColumnT).id) - } - renderOption={(props, column) => ( -
  • - -
  • - )} - renderInput={params => ( - - )} - /> - ) -} - -export const DimensionsPicker: React.FC<{ - selectedDimensions: ColumnT[] | undefined - setDimensionIDs: Dispatch - required?: true | undefined - helperText?: string - label?: string -}> = ({ - helperText, - selectedDimensions, - setDimensionIDs, - required, - label = "dimensions", -}) => { - const request = React.useContext(UADimensionsAndMetricsRequestCtx) - - return ( - - filterOptions={columnFilterOptions} - fullWidth - autoComplete - autoHighlight - freeSolo - multiple - loading={request.status === RequestStatus.InProgress} - options={ - successful(request) - ?.dimensions.filter(removeDeprecatedColumns) - .filter( - option => - (selectedDimensions || []).find(s => s.id === option.id) === - undefined - ) || [] - } - getOptionLabel={(dimension) => typeof dimension === "string" ? dimension : dimension.id!} - value={selectedDimensions || []} - onChange={(_event, value) => - setDimensionIDs((value as ColumnT[])?.map(c => c.id!)) - } - renderOption={(props, column) => ( -
  • - -
  • - )} - renderInput={params => ( - - )} - /> - ) -} - -export const MetricPicker: React.FC<{ - selectedMetric: ColumnT | undefined - setMetricID: Dispatch - required?: true | undefined - helperText?: string - filter?: (metric: ColumnT) => boolean -}> = ({ helperText, selectedMetric, setMetricID, required, filter }) => { - const request = React.useContext(UADimensionsAndMetricsRequestCtx) - - return ( - - filterOptions={columnFilterOptions} - fullWidth - autoComplete - autoHighlight - freeSolo - loading={request.status === RequestStatus.InProgress} - options={ - successful(request) - ?.metrics.filter(removeDeprecatedColumns) - .filter(filter !== undefined ? filter : () => true) || [] - } - getOptionLabel={(metric) => typeof metric === "string" ? metric : metric.id!} - value={selectedMetric || null} - onChange={(_event, value) => - setMetricID(value === null ? undefined : (value as ColumnT).id) - } - renderOption={(props, column) => ( -
  • - -
  • - )} - renderInput={params => ( - - )} - /> - ) -} - -export const MetricsPicker: React.FC<{ - selectedMetrics: ColumnT[] | undefined - setMetricIDs: Dispatch - required?: true | undefined - helperText?: string - label?: string -}> = ({ - helperText, - selectedMetrics, - setMetricIDs, - required, - label = "metrics", -}) => { - const request = React.useContext(UADimensionsAndMetricsRequestCtx) - - return ( - - filterOptions={columnFilterOptions} - fullWidth - autoComplete - autoHighlight - freeSolo - multiple - loading={request.status === RequestStatus.InProgress} - options={ - successful(request) - ?.metrics.filter(removeDeprecatedColumns) - .filter( - option => - (selectedMetrics || []).find(s => s.id === option.id) === - undefined - ) || [] - } - getOptionLabel={(metric) => typeof metric === "string" ? metric : metric.id!} - value={selectedMetrics || []} - onChange={(_event, value) => - setMetricIDs((value as ColumnT[])?.map(c => c.id!)) - } - renderOption={(props, column) => ( -
  • - -
  • - )} - renderInput={params => ( - - )} - /> - ) -} - -const Segment: React.FC<{ - segment: SegmentT - showSegmentDefinition: boolean -}> = ({ segment, showSegmentDefinition }) => { - const subtitleText = showSegmentDefinition - ? segment.definition || `${segment.name} has no segment definition.` - : segment.segmentId || "" - const abbreviatedText = - subtitleText.length > 40 - ? subtitleText.substring(0, 40) + "..." - : subtitleText - return ( - -
    -
    - - {segment.name} - - - {abbreviatedText} - -
    - - {segment.type === "CUSTOM" - ? "Custom Segment" - : segment.type === "DYNAMIC" - ? "Dynamic Segment" - : "Built In Segment"} - -
    -
    - ) -} - -const segmentFilterOptions = createFilterOptions({ - stringify: option => `${option.segmentId} ${option.name}`, -}) -export const SegmentPicker: React.FC<{ - segment: SegmentT | undefined - setSegmentID: Dispatch - showSegmentDefinition: boolean - required?: true | undefined - helperText?: string -}> = ({ - helperText, - segment, - setSegmentID, - required, - showSegmentDefinition, -}) => { - const request = React.useContext(UASegmentsRequestCtx) - - const getOptionLabel = React.useCallback( - (segment: SegmentT | string) => - typeof segment === "string" ? segment : (showSegmentDefinition - ? segment.definition || - (segment.name && `${segment.name} has no segment definition.`) - : segment.segmentId!) || "", - [showSegmentDefinition] - ) - - return ( - - fullWidth - autoComplete - autoHighlight - freeSolo - loading={request.status === RequestStatus.InProgress} - options={successful(request)?.segments || []} - isOptionEqualToValue={(a, b) => - a.id === b.id || a.definition === b.definition - } - getOptionLabel={getOptionLabel} - value={segment || null} - filterOptions={(options, params) => { - const filtered = segmentFilterOptions(options || [], params) - - // Add entry for creating a dynamic segment based on input. - if (params.inputValue !== "") { - filtered.push({ - definition: params.inputValue, - name: `Add dynamic segment`, - segmentId: params.inputValue, - id: params.inputValue, - type: "DYNAMIC", - }) - } - return filtered - }} - onChange={(_event, value) => { - setSegmentID(value === null ? undefined : (value as SegmentT).id) - }} - renderOption={(props, column) => ( -
  • - -
  • - )} - renderInput={params => ( - - )} - /> - ) -} - -export const V4SamplingLevelPicker: React.FC<{ - storageKey: StorageKey - setSamplingLevel: React.Dispatch< - React.SetStateAction - > - required?: true | undefined - helperText?: string -}> = ({ helperText, setSamplingLevel, required, storageKey }) => { - const [selected, setSelected] = usePersistentString(storageKey) - - React.useEffect(() => { - setSamplingLevel(selected as V4SamplingLevel) - }, [selected, setSamplingLevel]) - - return ( - , false, undefined, true> - fullWidth - autoComplete - autoHighlight - freeSolo - options={Object.values(V4SamplingLevel)} - getOptionLabel={segment => segment} - value={selected || null} - onChange={(_event, value) => - setSelected(value === null ? undefined : (value as V4SamplingLevel)) - } - renderOption={(props, column) => ( -
  • - {column} -
  • - )} - renderInput={params => ( - - )} - /> - ) -} - -export const V3SamplingLevelPicker: React.FC<{ - samplingLevel: V3SamplingLevel | undefined - setSamplingLevel: Dispatch - required?: true | undefined - helperText?: string -}> = ({ helperText, samplingLevel, setSamplingLevel, required }) => { - return ( - , false, undefined, true> - fullWidth - autoComplete - autoHighlight - freeSolo - options={Object.values(V3SamplingLevel)} - getOptionLabel={segment => segment} - value={samplingLevel || null} - onChange={(_event, value) => - setSamplingLevel( - value === null ? undefined : (value as V3SamplingLevel) - ) - } - renderOption={(props, column) => ( -
  • - {column} -
  • - )} - renderInput={params => ( - - )} - /> - ) -} - -export const CohortSizePicker: React.FC<{ - storageKey: StorageKey - setCohortSize: React.Dispatch> - required?: true | undefined - helperText?: string -}> = ({ helperText, setCohortSize, required, storageKey }) => { - const [selected, setSelected] = usePersistentString(storageKey) - - React.useEffect(() => { - setCohortSize(selected as CohortSize) - }, [selected, setCohortSize]) - - return ( - , false, undefined, true> - fullWidth - autoComplete - autoHighlight - freeSolo - options={Object.values(CohortSize)} - getOptionLabel={segment => segment} - value={selected || null} - onChange={(_event, value) => - setSelected(value === null ? undefined : (value as CohortSize)) - } - renderOption={(props, column) => ( -
  • - {column} -
  • - )} - renderInput={params => ( - - )} - /> - ) -} diff --git a/src/components/UAPickers/useDimensionsAndMetrics.ts b/src/components/UAPickers/useDimensionsAndMetrics.ts deleted file mode 100644 index bd09133a..00000000 --- a/src/components/UAPickers/useDimensionsAndMetrics.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { Column, UAAccountPropertyView } from "@/types/ua" -import { createContext, useCallback, useMemo } from "react" -import { useSelector } from "react-redux" -import useCached from "@/hooks/useCached" -import { StorageKey } from "@/constants" -import moment from "moment" -import { Requestable, RequestStatus } from "@/types" - -export const UADimensionsAndMetricsRequestCtx = createContext< - ReturnType ->({ status: RequestStatus.NotStarted }) - -interface Successful { - columns: Column[] - metrics: Column[] - dimensions: Column[] -} - -const useUADimensionsAndMetrics = ({ - account, - property, - view, -}: UAAccountPropertyView): Requestable => { - const gapi = useSelector((state: AppState) => state.gapi) - - const metadataAPI = useMemo(() => gapi?.client?.analytics?.metadata, [gapi]) - const managementAPI = useMemo(() => gapi?.client?.analytics?.management, [ - gapi, - ]) - - const requestReady = useMemo(() => { - if ( - metadataAPI === undefined || - managementAPI === undefined || - account === undefined || - property === undefined || - view === undefined - ) { - return false - } - return true - }, [metadataAPI, managementAPI, account, property, view]) - - const makeRequest = useCallback(async () => { - if ( - metadataAPI === undefined || - managementAPI === undefined || - account === undefined || - property === undefined || - view === undefined - ) { - throw new Error( - "Invalid invariant - metadataAPI, managementAPI, account, property, and view must be defined here." - ) - } - const columnsResponse = await metadataAPI.columns.list({ reportType: "ga" }) - const columns = columnsResponse.result.items - - const [ - customDimensionsResponse, - customMetricsResponse, - goalsResponse, - ] = await Promise.all([ - managementAPI.customDimensions.list({ - accountId: account.id!, - webPropertyId: property.id!, - }), - managementAPI.customMetrics.list({ - accountId: account.id!, - webPropertyId: property.id!, - }), - managementAPI.goals.list({ - accountId: account.id!, - webPropertyId: property.id!, - profileId: view.id!, - }), - ]) - - const customDimensions = customDimensionsResponse.result.items - const customMetrics = customMetricsResponse.result.items - const goals = goalsResponse.result.items - - return columns?.flatMap(column => { - if (customDimensions !== undefined && column.id === "ga:dimensionXX") { - return customDimensions.map( - dimension => - ({ - ...column, - id: dimension.id, - attributes: { ...column.attributes, uiName: dimension.name }, - } as Column) - ) - } - if (customMetrics !== undefined && column.id === "ga:metricXX") { - return customMetrics.map( - metric => - ({ - ...column, - id: metric.id, - attributes: { ...column.attributes, uiName: metric.name }, - } as Column) - ) - } - if ( - goals !== undefined && - column.attributes!.minTemplateIndex !== undefined && - /goalxx/i.test(column.id!) - ) { - return goals.map(goal => ({ - ...column, - id: column.id!.replace("XX", goal.id!), - attributes: { - ...column.attributes, - uiName: `${goal.name} (${column.attributes!.uiName.replace( - "XX", - goal.id! - )})`, - }, - })) - } - if (column.attributes!.minTemplateIndex !== undefined) { - let min = 0 - let max = 0 - if ( - property?.level === "PREMIUM" && - column.attributes!.premiumMinTemplateIndex !== undefined - ) { - min = parseInt(column.attributes!.premiumMinTemplateIndex, 10) - max = parseInt(column.attributes!.premiumMaxTemplateIndex, 10) - } else { - min = parseInt(column.attributes!.minTemplateIndex, 10) - max = parseInt(column.attributes!.maxTemplateIndex, 10) - } - const columns: gapi.client.analytics.Column[] = [] - for (let i = min; i <= max; i++) { - columns.push({ - ...column, - id: column.id!.replace("XX", i.toString()), - attributes: { - ...column.attributes, - uiName: column.attributes!.uiName.replace("XX", i.toString()), - }, - }) - } - return columns - } - return [column] - }) - }, [metadataAPI, managementAPI, account, property, view]) - - const columnsRequest = useCached( - // Even though account is sometimes undefined it doesn't really matter - // since this hook will re-run once it is. makeRequest is smartEnough to - // not do anything when account property or view are undefined. - `//ua-dims-mets/${account?.id}-${property?.id}-${view?.id}` as StorageKey, - makeRequest, - moment.duration(5, "minutes"), - requestReady - ) - - return useMemo(() => { - switch (columnsRequest.status) { - case RequestStatus.Successful: { - const columns = columnsRequest.value || [] - return { - status: columnsRequest.status, - columns, - dimensions: columns.filter(c => c.attributes?.type === "DIMENSION"), - metrics: columns.filter(c => c.attributes?.type === "METRIC"), - } - } - default: - return { status: columnsRequest.status } - } - }, [columnsRequest]) -} - -export default useUADimensionsAndMetrics diff --git a/src/components/UAPickers/useUASegments.ts b/src/components/UAPickers/useUASegments.ts deleted file mode 100644 index cd6b1672..00000000 --- a/src/components/UAPickers/useUASegments.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Segment } from "@/types/ua" -import { createContext, useCallback, useMemo } from "react" -import { useSelector } from "react-redux" -import useCached from "@/hooks/useCached" -import { StorageKey } from "@/constants" -import moment from "moment" -import { Requestable, RequestStatus } from "@/types" - -export const UASegmentsRequestCtx = createContext< - ReturnType ->({ status: RequestStatus.NotStarted }) - -interface Successful { - segments: Segment[] -} - -export const useUASegments = (): Requestable => { - const gapi = useSelector((state: AppState) => state.gapi) - const managementAPI = useMemo(() => gapi?.client.analytics.management, [gapi]) - - const requestSegments = useCallback(async () => { - if (managementAPI === undefined) { - return Promise.resolve(undefined) - } - const response = await managementAPI.segments.list({}) - return response.result.items - }, [managementAPI]) - - const requestReady = useMemo(() => { - return managementAPI !== undefined - }, [managementAPI]) - - const segmentsRequest = useCached( - StorageKey.uaSegments, - requestSegments, - moment.duration(5, "minutes"), - requestReady - ) - - return useMemo(() => { - switch (segmentsRequest.status) { - case RequestStatus.Successful: { - const segments = segmentsRequest.value || [] - return { - status: segmentsRequest.status, - segments, - } - } - default: - return { status: segmentsRequest.status } - } - }, [segmentsRequest]) -} diff --git a/src/components/ViewSelector/index.spec.tsx b/src/components/ViewSelector/index.spec.tsx deleted file mode 100644 index 37b8849d..00000000 --- a/src/components/ViewSelector/index.spec.tsx +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import * as renderer from "@testing-library/react" -import { withProviders } from "@/test-utils" -import "@testing-library/jest-dom" -import Sut, { Label, TestID } from "./index" -import useAccountPropertyView from "./useAccountPropertyView" -import { StorageKey } from "@/constants" -import { fireEvent, within } from "@testing-library/react" - -enum QueryParam { - Account = "a", - Property = "b", - View = "c", -} - -describe("ViewSelector", () => { - const DefaultSut: React.FC = () => { - const apv = useAccountPropertyView("a" as StorageKey, QueryParam) - return - } - test("doesn't crash on happy path", async () => { - const { wrapped } = withProviders() - const { findByLabelText } = renderer.render(wrapped) - - const account = await findByLabelText(Label.Account) - expect(account).toBeVisible() - - const property = await findByLabelText(Label.Property) - expect(property).toBeVisible() - - const view = await findByLabelText(Label.View) - expect(view).toBeVisible() - }) - test("can select account with no properties", async () => { - const accountName = "my account name" - const listAccountSummaries = jest.fn() - listAccountSummaries.mockReturnValue( - Promise.resolve({ - result: { - items: [{ name: accountName, id: "account id", properties: [] }], - }, - }) - ) - const { wrapped } = withProviders(, { - ua: { listAccountSummaries }, - }) - const { findByTestId } = renderer.render(wrapped) - - // Select first account. - const accountAC = await findByTestId(TestID.AccountAutocomplete) - fireEvent.keyDown(accountAC, { key: "ArrowDown" }) - fireEvent.keyDown(accountAC, { key: "Enter" }) - - const accountInput = within(accountAC).getByRole("textbox") - expect(accountInput).toHaveValue(accountName) - }) - describe("with autoFill={true}", () => { - const WithAutoFill: React.FC = () => { - const apv = useAccountPropertyView("a" as StorageKey, QueryParam) - return - } - test("automatically selects account & view when both available", async () => { - const { wrapped } = withProviders() - const { findByTestId } = renderer.render(wrapped) - - // Select first account. - const accountAC = await findByTestId(TestID.AccountAutocomplete) - fireEvent.keyDown(accountAC, { key: "ArrowDown" }) - fireEvent.keyDown(accountAC, { key: "Enter" }) - - const accountInput = within(accountAC).getByRole("textbox") - expect(accountInput).toHaveValue("Account Name 1") - - const propertyAC = await findByTestId(TestID.PropertyAutocomplete) - const propertyInput = within(propertyAC).getByRole("textbox") - expect(propertyInput).toHaveValue("Property Name 1 1") - - const viewAC = await findByTestId(TestID.ViewAutocomplete) - const viewInput = within(viewAC).getByRole("textbox") - expect(viewInput).toHaveValue("View Name 1 1 1") - }) - }) - describe("with autoFill={false}", () => { - const NoAutoFill: React.FC = () => { - const apv = useAccountPropertyView("a" as StorageKey, QueryParam) - return - } - test("doesn't automatically select property or view after selecting property", async () => { - const { wrapped } = withProviders() - const { findByTestId } = renderer.render(wrapped) - - // Select first account. - const accountAC = await findByTestId(TestID.AccountAutocomplete) - fireEvent.keyDown(accountAC, { key: "ArrowDown" }) - fireEvent.keyDown(accountAC, { key: "Enter" }) - - const accountInput = within(accountAC).getByRole("textbox") - expect(accountInput).toHaveValue("Account Name 1") - - const propertyAC = await findByTestId(TestID.PropertyAutocomplete) - const propertyInput = within(propertyAC).getByRole("textbox") - expect(propertyInput).toHaveValue("") - - const viewAC = await findByTestId(TestID.ViewAutocomplete) - const viewInput = within(viewAC).getByRole("textbox") - expect(viewInput).toHaveValue("") - }) - }) -}) diff --git a/src/components/ViewSelector/index.tsx b/src/components/ViewSelector/index.tsx deleted file mode 100644 index 08bbb934..00000000 --- a/src/components/ViewSelector/index.tsx +++ /dev/null @@ -1,215 +0,0 @@ -import * as React from "react" -import { styled } from '@mui/material/styles'; -import TextField from "@mui/material/TextField" -import Autocomplete from "@mui/material//Autocomplete" -import classnames from "classnames" - -import { Dispatch, RequestStatus, successful } from "@/types" -import { - AccountSummary, - ProfileSummary, - WebPropertySummary, -} from "./useAccountPropertyView" -import useAccountSummaries from "./useAccountSummaries" -import Typography from "@mui/material/Typography" -import Warning from "../Warning" -import InlineCode from "../InlineCode" - -const PREFIX = 'ViewSelector'; - -const classes = { - root: `${PREFIX}-root`, - formControl: `${PREFIX}-formControl` -}; - -const Root = styled('div')(( - { - theme - } -) => ({ - [`&.${classes.root}`]: { - display: "flex", - flexDirection: "unset", - width: "100%", - }, - - [`& .${classes.formControl}`]: { - width: "100%", - margin: theme.spacing(1), - marginLeft: "unset", - } -})); - -interface CommonProps { - account?: AccountSummary - setAccountID: Dispatch - property?: WebPropertySummary - setPropertyID: Dispatch - vertical?: boolean - className?: string - size?: "small" | "medium" - variant?: "outlined" | "standard" - autoFill?: boolean -} - -interface OnlyProperty extends CommonProps { - onlyProperty: true -} - -interface AlsoView extends CommonProps { - view?: ProfileSummary - setViewID: Dispatch - onlyProperty?: false | undefined -} - -type ViewSelectorProps = AlsoView | OnlyProperty - -export enum Label { - Account = "account", - Property = "property", - View = "view", -} - -export enum TestID { - AccountAutocomplete = "account-autocomplete", - PropertyAutocomplete = "property-autocomplete", - ViewAutocomplete = "view-autocomplete", -} - -const ViewSelector: React.FC = props => { - const { - autoFill, - account, - setAccountID, - property, - setPropertyID, - className, - size = "medium", - variant = "standard", - } = props - - - const request = useAccountSummaries(account, property) - - if (request.status === RequestStatus.Failed) { - return ( - - - There was an error while requesting your accounts. - - {request.error.message && ( - - Error Message: {request.error.message} - - )} - - ) - } - - return ( - - - data-testid={TestID.AccountAutocomplete} - blurOnSelect - openOnFocus - autoHighlight - noOptionsText="You don't have any Google Analytics accounts." - className={classes.formControl} - loading={request.status === RequestStatus.InProgress} - options={successful(request)?.accountSummaries || []} - value={account || null} - onChange={(_, a: AccountSummary | null) => { - setAccountID(a?.id || undefined) - - if (autoFill) { - // Update property ID based on new account. - const firstWebProperty = a?.webProperties?.[0] - setPropertyID(firstWebProperty?.id || undefined) - - // Update view ID based on new property if not onlyProperty. - const firstView = firstWebProperty?.profiles?.[0] - !props.onlyProperty && props.setViewID(firstView?.id || undefined) - } - }} - isOptionEqualToValue={(a, b) => a.id === b.id} - getOptionLabel={account => account.name || ""} - renderInput={params => ( - - )} - /> - - data-testid={TestID.PropertyAutocomplete} - blurOnSelect - openOnFocus - autoHighlight - className={classes.formControl} - loading={request.status === RequestStatus.InProgress} - options={successful(request)?.propertySummaries || []} - noOptionsText={ - account === undefined - ? "Select an account to show available properties." - : "You don't have any properties for this account." - } - value={property || null} - onChange={(_, p: WebPropertySummary | null) => { - setPropertyID(p?.id || undefined) - - if (autoFill) { - // Update view ID based on new property if not onlyProperty. - const firstView = p?.profiles?.[0] - !props.onlyProperty && props.setViewID(firstView?.id || undefined) - } - }} - isOptionEqualToValue={(a, b) => a.id === b.id} - getOptionLabel={property => property.name || ""} - renderInput={params => ( - - )} - /> - {props.onlyProperty ? null : ( - - data-testid={TestID.ViewAutocomplete} - blurOnSelect - openOnFocus - autoHighlight - className={classes.formControl} - loading={request.status === RequestStatus.InProgress} - options={successful(request)?.profileSummaries || []} - noOptionsText={ - account === undefined - ? "Select an account and property to show available views." - : property === undefined - ? "Select a property to show available views" - : "You don't have any views for this property." - } - value={props.view || null} - isOptionEqualToValue={(a, b) => a.id === b.id} - onChange={(_, v: ProfileSummary | null) => { - props.setViewID(v?.id || undefined) - }} - getOptionLabel={view => view.name || ""} - renderInput={params => ( - - )} - /> - )} - - ); -} - -export default ViewSelector diff --git a/src/components/ViewSelector/useAccountPropertyView.ts b/src/components/ViewSelector/useAccountPropertyView.ts deleted file mode 100644 index a33f176a..00000000 --- a/src/components/ViewSelector/useAccountPropertyView.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { StorageKey } from "@/constants" -import { useKeyedHydratedPersistantObject } from "@/hooks/useHydrated" -import { Dispatch, RequestStatus } from "@/types" -import { useCallback } from "react" -import useFlattenedViews from "./useFlattenedViews" - -export type AccountSummary = gapi.client.analytics.AccountSummary -export type WebPropertySummary = gapi.client.analytics.WebPropertySummary -export type ProfileSummary = gapi.client.analytics.ProfileSummary - -export interface UAAccountPropertyView { - account?: AccountSummary - property?: WebPropertySummary - view?: ProfileSummary -} - -interface UAAccountPropertyViewSetters { - setAccountID: Dispatch - setPropertyID: Dispatch - setViewID: Dispatch -} - -const useAccountPropertyView = ( - prefix: StorageKey, - queryParamKeys: { Account: string; Property: string; View: string }, - onSetView?: (p: ProfileSummary | undefined) => void -): UAAccountPropertyView & UAAccountPropertyViewSetters => { - const flattenedViewsRequest = useFlattenedViews() - - const getAccountByID = useCallback( - (id: string | undefined) => { - if ( - flattenedViewsRequest.status !== RequestStatus.Successful || - id === undefined - ) { - return undefined - } - return flattenedViewsRequest.flattenedViews.find( - flattenedView => flattenedView.account?.id === id - )?.account - }, - [flattenedViewsRequest] - ) - - const [ - account, - setAccountID, - ] = useKeyedHydratedPersistantObject( - `${prefix}-account` as StorageKey, - queryParamKeys.Account, - getAccountByID - ) - - const getPropertyByID = useCallback( - (id: string | undefined) => { - if ( - flattenedViewsRequest.status !== RequestStatus.Successful || - id === undefined - ) { - return undefined - } - return flattenedViewsRequest.flattenedViews.find( - flattenedView => flattenedView.property?.id === id - )?.property - }, - [flattenedViewsRequest] - ) - - const [ - property, - setPropertyID, - ] = useKeyedHydratedPersistantObject( - `${prefix}-property` as StorageKey, - queryParamKeys.Property, - getPropertyByID - ) - - const getViewByID = useCallback( - (id: string | undefined) => { - if ( - flattenedViewsRequest.status !== RequestStatus.Successful || - id === undefined - ) { - return undefined - } - return flattenedViewsRequest.flattenedViews.find( - flattenedView => flattenedView.view?.id === id - )?.view - }, - [flattenedViewsRequest] - ) - - const [view, setViewID] = useKeyedHydratedPersistantObject( - `${prefix}-view` as StorageKey, - queryParamKeys.View, - getViewByID, - onSetView - ) - - return { account, setAccountID, property, setPropertyID, view, setViewID } -} - -export default useAccountPropertyView diff --git a/src/components/ViewSelector/useAccountSummaries.ts b/src/components/ViewSelector/useAccountSummaries.ts deleted file mode 100644 index 8c117605..00000000 --- a/src/components/ViewSelector/useAccountSummaries.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { StorageKey } from "@/constants" -import useCached from "@/hooks/useCached" -import { Requestable, RequestStatus } from "@/types" -import { AccountSummary, ProfileSummary, WebPropertySummary } from "@/types/ua" -import moment from "moment" -import { useCallback, useMemo } from "react" - -import { useSelector } from "react-redux" - -interface Successful { - accountSummaries: AccountSummary[] - propertySummaries: WebPropertySummary[] - profileSummaries: ProfileSummary[] -} - -const useAccountSummaries = ( - accountSummary?: AccountSummary, - propertySummary?: WebPropertySummary -): Requestable => { - const gapi = useSelector((state: AppState) => state.gapi) - - const managementAPI = useMemo(() => { - return gapi?.client?.analytics?.management - }, [gapi]) - - const requestAccountSummaries = useCallback(async (): Promise< - AccountSummary[] | undefined - > => { - if (managementAPI === undefined) { - throw new Error( - "invalid invariant - fetchAccounts should never be called with an undefined managementAPI" - ) - } - const response = await managementAPI.accountSummaries.list({}) - return response.result.items - }, [managementAPI]) - - const requestReady = useMemo(() => managementAPI !== undefined, [ - managementAPI, - ]) - - const accountSummariesRequest = useCached( - StorageKey.uaAccounts, - requestAccountSummaries, - moment.duration(5, "minutes"), - requestReady - ) - - const accountFilter = useCallback( - (a: AccountSummary) => { - if (accountSummary === undefined) { - return false - } - return a.id === accountSummary.id - }, - [accountSummary] - ) - - const propertyFilter = useCallback( - (p: WebPropertySummary) => { - if (propertySummary === undefined) { - return false - } - return propertySummary.id === p.id - }, - [propertySummary] - ) - - return useMemo(() => { - switch (accountSummariesRequest.status) { - case RequestStatus.Successful: { - const accountSummaries = accountSummariesRequest.value || [] - const propertySummaries = accountSummaries - .filter(accountFilter) - .flatMap(a => a.webProperties || []) - const profileSummaries = propertySummaries - .filter(propertyFilter) - .flatMap(p => p.profiles || []) - return { - status: accountSummariesRequest.status, - accountSummaries, - propertySummaries, - profileSummaries, - } - } - case RequestStatus.Failed: { - console.log({ accountSummariesRequest }) - return { - status: accountSummariesRequest.status, - error: accountSummariesRequest.error, - } - } - default: - return { status: accountSummariesRequest.status } - } - }, [accountSummariesRequest, accountFilter, propertyFilter]) -} - -export default useAccountSummaries diff --git a/src/components/ViewSelector/useFlattenedViews.ts b/src/components/ViewSelector/useFlattenedViews.ts deleted file mode 100644 index 36751c87..00000000 --- a/src/components/ViewSelector/useFlattenedViews.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Requestable, RequestStatus } from "@/types" -import { useCallback, useMemo } from "react" -import { - AccountSummary, - WebPropertySummary, - UAAccountPropertyView, -} from "../ViewSelector/useAccountPropertyView" -import useAccountSummaries from "./useAccountSummaries" - -interface Successful { - flattenedViews: UAAccountPropertyView[] -} - -const useFlattenedViews = ( - accountSummary?: AccountSummary, - propertySummary?: WebPropertySummary, - filter?: (fv: UAAccountPropertyView) => boolean -): Requestable => { - const accountSummariesRequest = useAccountSummaries() - - const filterFlattened = useCallback( - (flattenedView: UAAccountPropertyView) => { - if (filter && filter(flattenedView) === false) { - return false - } - return accountSummary === undefined - ? true - : accountSummary.id === flattenedView.account?.id - ? propertySummary === undefined - ? true - : propertySummary.id === flattenedView.property?.id - : false - }, - [accountSummary, propertySummary, filter] - ) - - return useMemo(() => { - switch (accountSummariesRequest.status) { - case RequestStatus.Successful: { - const accountSummaries = accountSummariesRequest.accountSummaries - - const flattenedViews = accountSummaries - .flatMap(summary => { - const account = { ...summary } - - const properties = summary.webProperties || [] - if (properties.length === 0) { - return { account } - } - return properties.flatMap(propertySummary => { - const property = { ...propertySummary } - - const profiles = propertySummary.profiles || [] - if (profiles.length === 0) { - return { account, property } - } - return profiles.map(profile => ({ - view: profile, - property, - account, - })) - }) - }) - .filter(filterFlattened) - return { status: accountSummariesRequest.status, flattenedViews } - } - default: - return { status: accountSummariesRequest.status } - } - }, [accountSummariesRequest, filterFlattened]) -} - -export default useFlattenedViews diff --git a/src/components/ga4/EventBuilder/index.spec.tsx b/src/components/ga4/EventBuilder/index.spec.tsx index 7a1619c5..16596010 100644 --- a/src/components/ga4/EventBuilder/index.spec.tsx +++ b/src/components/ga4/EventBuilder/index.spec.tsx @@ -107,19 +107,13 @@ describe("Event Builder", () => { // This test is somewhat likely to break if we add/remove events & // event categories so if it's broken, it's probably fine to just // change the expected values. - const ecInput = within(eventCategory).getByRole("textbox") + const ecInput = within(eventCategory).getByRole("combobox") eventCategory.focus() - renderer.fireEvent.change(ecInput, { target: { value: "" } }) - renderer.fireEvent.keyDown(eventCategory, { key: "ArrowDown" }) - renderer.fireEvent.keyDown(eventCategory, { key: "ArrowDown" }) - renderer.fireEvent.keyDown(eventCategory, { key: "Enter" }) + renderer.fireEvent.change(ecInput, { target: { value: "All apps" } }) - const enInput = within(eventName).getByRole("textbox") + const enInput = within(eventName).getByRole("combobox") eventCategory.focus() - renderer.fireEvent.change(enInput, { target: { value: "" } }) - renderer.fireEvent.keyDown(eventName, { key: "ArrowDown" }) - renderer.fireEvent.keyDown(eventName, { key: "ArrowDown" }) - renderer.fireEvent.keyDown(eventName, { key: "Enter" }) + renderer.fireEvent.change(enInput, { target: { value: "select_content" } }) await userEvent.type(timestampMicros, "1234", { delay: 1 }) nonPersonalizedAds.click() @@ -138,7 +132,7 @@ describe("Event Builder", () => { expect(payload).toHaveTextContent(/"user_id":"my_user_id"/) expect(payload).toHaveTextContent(/"timestamp_micros":"1234"/) expect(payload).toHaveTextContent(/"non_personalized_ads":true/) - expect(payload).toHaveTextContent(/"name":"add_shipping_info"/) + expect(payload).toHaveTextContent(/"name":"select_content"/) }) }) describe("for gtag switch", () => { @@ -187,19 +181,13 @@ describe("Event Builder", () => { // This test is somewhat likely to break if we add/remove events & // event categories so if it's broken, it's probably fine to just // change the expected values. - const ecInput = within(eventCategory).getByRole("textbox") - eventCategory.focus() - renderer.fireEvent.change(ecInput, { target: { value: "" } }) - renderer.fireEvent.keyDown(eventCategory, { key: "ArrowDown" }) - renderer.fireEvent.keyDown(eventCategory, { key: "ArrowDown" }) - renderer.fireEvent.keyDown(eventCategory, { key: "Enter" }) + const ecInput = within(eventCategory).getByRole("combobox") + //eventCategory.focus() + renderer.fireEvent.change(ecInput, { target: { value: "All apps" } }) - const enInput = within(eventName).getByRole("textbox") - eventCategory.focus() - renderer.fireEvent.change(enInput, { target: { value: "" } }) - renderer.fireEvent.keyDown(eventName, { key: "ArrowDown" }) - renderer.fireEvent.keyDown(eventName, { key: "ArrowDown" }) - renderer.fireEvent.keyDown(eventName, { key: "Enter" }) + const enInput = within(eventName).getByRole("combobox") + //eventCategory.focus() + renderer.fireEvent.change(enInput, { target: { value: "select_content" } }) await userEvent.type( timestampMicros, @@ -220,7 +208,7 @@ describe("Event Builder", () => { expect(payload).toHaveTextContent(/"user_id":"my_user_id"/) expect(payload).toHaveTextContent(/"timestamp_micros":"1234"/) expect(payload).toHaveTextContent(/"non_personalized_ads":true/) - expect(payload).toHaveTextContent(/"name":"add_shipping_info"/) + expect(payload).toHaveTextContent(/"name":"select_content"/) }) }) }) diff --git a/src/components/ga4/EventBuilder/index.tsx b/src/components/ga4/EventBuilder/index.tsx index 3d826819..aa185437 100644 --- a/src/components/ga4/EventBuilder/index.tsx +++ b/src/components/ga4/EventBuilder/index.tsx @@ -104,20 +104,20 @@ const Root = styled('div')(( })); export enum Label { - APISecret = "api_secret", + APISecret = "api secret", - FirebaseAppID = "firebase_app_id", - AppInstanceID = "app_instance_id", + FirebaseAppID = "firebase app id", + AppInstanceID = "app instance id", - MeasurementID = "measurement_id", - ClientID = "client_id", + MeasurementID = "measurement id", + ClientID = "client id", - UserId = "user_id", + UserId = "user id", - EventCategory = "event_category", - EventName = "event_name", - TimestampMicros = "timestamp_micros", - NonPersonalizedAds = "non_personalized_ads", + EventCategory = "event category", + EventName = "event name", + TimestampMicros = "timestamp micros", + NonPersonalizedAds = "non personalized ads", Payload = "payload", @@ -251,7 +251,7 @@ const EventBuilder: React.FC = () => { return ( Overview - + The GA4 Event Builder allows you to create, validate, and send events using the {ga4MeasurementProtocol}. @@ -361,7 +361,7 @@ const EventBuilder: React.FC = () => { onChange={setUserId} /> { - useFirebase && ( + <> {
    - ) + } { useTextBox && <> - - {useFirebase ? ( - - ) : ( - - )} - { { !useTextBox &&
    - - {useFirebase ? ( - <> - - - - ) : ( - <> - - - - )} - + data-testid={Label.EventCategory} @@ -599,13 +498,7 @@ const EventBuilder: React.FC = () => { variant="outlined" helperText={ <> - The name of the event. See{" "} - - {type} - {" "} - on devsite. + The name of the event. } /> @@ -640,15 +533,6 @@ const EventBuilder: React.FC = () => { helpText={ <> Check to indicate events should not be used for personalized ads. - See{" "} - - non_personalized_ads - {" "} - on devsite. } > diff --git a/src/pages/account-explorer.tsx b/src/pages/account-explorer.tsx deleted file mode 100644 index d79b5e68..00000000 --- a/src/pages/account-explorer.tsx +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" -import Layout from "@/components/Layout" -import AccountExplorer from "@/components/AccountExplorer" - -interface Props { - location: { pathname: string } -} - -export default (props: Props) => { - return ( - - - - ) -} diff --git a/src/pages/dimensions-metrics-explorer.tsx b/src/pages/dimensions-metrics-explorer.tsx deleted file mode 100644 index 8e9d4156..00000000 --- a/src/pages/dimensions-metrics-explorer.tsx +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import Layout from "@/components/Layout" -import DimensionsMetricsExplorer from "@/components/DimensionsMetricsExplorer" - -interface Props { - location: { pathname: string } -} - -export default (props: Props) => { - return ( - - - - ) -} diff --git a/src/pages/ga4/enhanced-ecommerce/cart.tsx b/src/pages/ga4/enhanced-ecommerce/cart.tsx index dc84d6fa..d20a1e49 100644 --- a/src/pages/ga4/enhanced-ecommerce/cart.tsx +++ b/src/pages/ga4/enhanced-ecommerce/cart.tsx @@ -17,7 +17,6 @@ import * as React from "react" import Layout from "@/components/Layout" import {Header} from "@/components/ga4/EnhancedEcommerce/header"; import {Footer} from "@/components/ga4/EnhancedEcommerce/footer"; -import {LineItem} from "@/components/ga4/EnhancedEcommerce/line-item"; import {StoreContext} from '@/components/ga4/EnhancedEcommerce/store-context'; import {collapseColumn, emptyStateContainer, emptyStateHeading, grandTotal, imageHeader, labelColumn, productHeader, summary, table, title, totals, wrap,} from "./cart.module.css" @@ -80,9 +79,6 @@ export default (props: Props) => { - {lineItems.map((item) => ( - - ))} diff --git a/src/pages/hit-builder.tsx b/src/pages/hit-builder.tsx deleted file mode 100644 index 99d9910d..00000000 --- a/src/pages/hit-builder.tsx +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import Layout from "@/components/Layout" -import HitBuilder from "@/components/HitBuilder" - -interface Props { - location: { pathname: string } -} - -export default (props: Props) => { - return ( - - - - ) -} diff --git a/src/pages/query-explorer.tsx b/src/pages/query-explorer.tsx deleted file mode 100644 index adf553ee..00000000 --- a/src/pages/query-explorer.tsx +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import Layout from "@/components/Layout" -import QueryExplorer from "@/components/QueryExplorer" - -interface Props { - location: { pathname: string } -} - -export default (props: Props) => { - return ( - - - - ) -} diff --git a/src/pages/request-composer/cohort.tsx b/src/pages/request-composer/cohort.tsx deleted file mode 100644 index d863d857..00000000 --- a/src/pages/request-composer/cohort.tsx +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import Layout from "@/components/Layout" -import RequestComposer, { - RequestComposerType, -} from "@/components/RequestComposer" - -interface Props { - location: { pathname: string } -} - -export default (props: Props) => { - return ( - - - - ) -} diff --git a/src/pages/request-composer/index.tsx b/src/pages/request-composer/index.tsx deleted file mode 100644 index 12f8640e..00000000 --- a/src/pages/request-composer/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import Layout from "@/components/Layout" -import RequestComposer, { - RequestComposerType, -} from "@/components/RequestComposer" - -interface Props { - location: { pathname: string } -} - -export default (props: Props) => { - return ( - - - - ) -} diff --git a/src/pages/request-composer/metric-expression.tsx b/src/pages/request-composer/metric-expression.tsx deleted file mode 100644 index 892f7495..00000000 --- a/src/pages/request-composer/metric-expression.tsx +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import Layout from "@/components/Layout" -import RequestComposer, { - RequestComposerType, -} from "@/components/RequestComposer" - -interface Props { - location: { pathname: string } -} - -export default (props: Props) => { - return ( - - - - ) -} diff --git a/src/pages/request-composer/pivot.tsx b/src/pages/request-composer/pivot.tsx deleted file mode 100644 index e59033b3..00000000 --- a/src/pages/request-composer/pivot.tsx +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import * as React from "react" - -import Layout from "@/components/Layout" -import RequestComposer, { - RequestComposerType, -} from "@/components/RequestComposer" - -interface Props { - location: { pathname: string } -} - -export default (props: Props) => { - return ( - - - - ) -}