Skip to content

Commit

Permalink
display warning icons in the dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertJoonas authored and zoldar committed May 23, 2024
1 parent 3cfcab7 commit a727f44
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 65 deletions.
3 changes: 2 additions & 1 deletion assets/js/dashboard/stats/behaviours/conversions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CR_METRIC } from '../reports/metrics';
import ListReport from '../reports/list';

export default function Conversions(props) {
const { site, query } = props
const { site, query, afterFetchData } = props

function fetchConversions() {
return api.get(url.apiPath(site, '/conversions'), query, { limit: 9 })
Expand All @@ -23,6 +23,7 @@ export default function Conversions(props) {
return (
<ListReport
fetchData={fetchConversions}
afterFetchData={afterFetchData}
getFilterFor={getFilterFor}
keyLabel="Goal"
onClick={props.onGoalFilterClick}
Expand Down
9 changes: 5 additions & 4 deletions assets/js/dashboard/stats/behaviours/goal-conversions.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function specialTitleWhenGoalFilter(query, defaultTitle) {
}

function SpecialPropBreakdown(props) {
const { site, query, prop } = props
const { site, query, prop, afterFetchData } = props

function fetchData() {
return api.get(url.apiPath(site, `/custom-prop-values/${prop}`), query)
Expand All @@ -55,6 +55,7 @@ function SpecialPropBreakdown(props) {
return (
<ListReport
fetchData={fetchData}
afterFetchData={afterFetchData}
getFilterFor={getFilterFor}
keyLabel={prop}
metrics={[
Expand All @@ -73,12 +74,12 @@ function SpecialPropBreakdown(props) {
}

export default function GoalConversions(props) {
const {site, query} = props
const {site, query, afterFetchData} = props

const specialGoal = getSpecialGoal(query)
if (specialGoal) {
return <SpecialPropBreakdown site={site} query={props.query} prop={specialGoal.prop} />
return <SpecialPropBreakdown site={site} query={props.query} prop={specialGoal.prop} afterFetchData={afterFetchData} />
} else {
return <Conversions site={site} query={props.query} onGoalFilterClick={props.onGoalFilterClick}/>
return <Conversions site={site} query={props.query} onGoalFilterClick={props.onGoalFilterClick} afterFetchData={afterFetchData} />
}
}
20 changes: 15 additions & 5 deletions assets/js/dashboard/stats/behaviours/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Menu, Transition } from '@headlessui/react'
import { ChevronDownIcon } from '@heroicons/react/20/solid'
import classNames from 'classnames'
import * as storage from '../../util/storage'

import ImportedQueryUnsupportedWarning from '../imported-query-unsupported-warning'
import GoalConversions, { specialTitleWhenGoalFilter } from './goal-conversions'
import Properties from './props'
import { FeatureSetupNotice } from '../../components/notice'
Expand Down Expand Up @@ -48,6 +48,8 @@ export default function Behaviours(props) {

const [showingPropsForGoalFilter, setShowingPropsForGoalFilter] = useState(false)

const [importedQueryUnsupported, setImportedQueryUnsupported] = useState(false)

const onGoalFilterClick = useCallback((e) => {
const goalName = e.target.innerHTML
const isSpecialGoal = Object.keys(SPECIAL_GOALS).includes(goalName)
Expand Down Expand Up @@ -170,9 +172,14 @@ export default function Behaviours(props) {
)
}

function afterFetchGoalData(apiResponse) {
const unsupportedQuery = apiResponse.skip_imported_reason === 'unsupported_query'
setImportedQueryUnsupported(unsupportedQuery && !isRealtime())
}

function renderConversions() {
if (site.hasGoals) {
return <GoalConversions site={site} query={query} onGoalFilterClick={onGoalFilterClick} />
return <GoalConversions site={site} query={query} onGoalFilterClick={onGoalFilterClick} afterFetchData={afterFetchGoalData}/>
}
else if (adminAccess) {
return (
Expand Down Expand Up @@ -330,9 +337,12 @@ export default function Behaviours(props) {
<div className="items-start justify-between block w-full mt-6 md:flex">
<div className="w-full p-4 bg-white rounded shadow-xl dark:bg-gray-825">
<div className="flex justify-between w-full">
<h3 className="font-bold dark:text-gray-100">
{sectionTitle() + (isRealtime() ? ' (last 30min)' : '')}
</h3>
<div className="flex gap-x-1">
<h3 className="font-bold dark:text-gray-100">
{sectionTitle() + (isRealtime() ? ' (last 30min)' : '')}
</h3>
<ImportedQueryUnsupportedWarning condition={mode === CONVERSIONS && importedQueryUnsupported}/>
</div>
{tabs()}
</div>
{renderContent()}
Expand Down
38 changes: 27 additions & 11 deletions assets/js/dashboard/stats/devices/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import ListReport from '../reports/list'
import * as api from '../../api'
import * as url from '../../util/url'
import { VISITORS_METRIC, PERCENTAGE_METRIC, maybeWithCR } from '../reports/metrics';
import ImportedQueryUnsupportedWarning from '../imported-query-unsupported-warning';

function Browsers({ query, site }) {
function Browsers({ query, site, afterFetchData }) {
function fetchData() {
return api.get(url.apiPath(site, '/browsers'), query)
}
Expand All @@ -21,6 +22,7 @@ function Browsers({ query, site }) {
return (
<ListReport
fetchData={fetchData}
afterFetchData={afterFetchData}
getFilterFor={getFilterFor}
keyLabel="Browser"
metrics={maybeWithCR([VISITORS_METRIC, PERCENTAGE_METRIC], query)}
Expand All @@ -29,7 +31,7 @@ function Browsers({ query, site }) {
)
}

function BrowserVersions({ query, site }) {
function BrowserVersions({ query, site, afterFetchData }) {
function fetchData() {
return api.get(url.apiPath(site, '/browser-versions'), query)
}
Expand All @@ -47,6 +49,7 @@ function BrowserVersions({ query, site }) {
return (
<ListReport
fetchData={fetchData}
afterFetchData={afterFetchData}
getFilterFor={getFilterFor}
keyLabel="Browser version"
metrics={maybeWithCR([VISITORS_METRIC, PERCENTAGE_METRIC], query)}
Expand All @@ -56,7 +59,7 @@ function BrowserVersions({ query, site }) {

}

function OperatingSystems({ query, site }) {
function OperatingSystems({ query, site, afterFetchData }) {
function fetchData() {
return api.get(url.apiPath(site, '/operating-systems'), query)
}
Expand All @@ -71,6 +74,7 @@ function OperatingSystems({ query, site }) {
return (
<ListReport
fetchData={fetchData}
afterFetchData={afterFetchData}
getFilterFor={getFilterFor}
keyLabel="Operating system"
metrics={maybeWithCR([VISITORS_METRIC, PERCENTAGE_METRIC], query)}
Expand All @@ -79,7 +83,7 @@ function OperatingSystems({ query, site }) {
)
}

function OperatingSystemVersions({ query, site }) {
function OperatingSystemVersions({ query, site, afterFetchData }) {
function fetchData() {
return api.get(url.apiPath(site, '/operating-system-versions'), query)
}
Expand All @@ -97,6 +101,7 @@ function OperatingSystemVersions({ query, site }) {
return (
<ListReport
fetchData={fetchData}
afterFetchData={afterFetchData}
getFilterFor={getFilterFor}
keyLabel="Operating System Version"
metrics={maybeWithCR([VISITORS_METRIC, PERCENTAGE_METRIC], query)}
Expand All @@ -106,7 +111,7 @@ function OperatingSystemVersions({ query, site }) {

}

function ScreenSizes({ query, site }) {
function ScreenSizes({ query, site, afterFetchData }) {
function fetchData() {
return api.get(url.apiPath(site, '/screen-sizes'), query)
}
Expand All @@ -125,6 +130,7 @@ function ScreenSizes({ query, site }) {
return (
<ListReport
fetchData={fetchData}
afterFetchData={afterFetchData}
getFilterFor={getFilterFor}
keyLabel="Screen size"
metrics={maybeWithCR([VISITORS_METRIC, PERCENTAGE_METRIC], query)}
Expand Down Expand Up @@ -161,27 +167,34 @@ export default function Devices(props) {
const tabKey = `deviceTab__${site.domain}`
const storedTab = storage.getItem(tabKey)
const [mode, setMode] = useState(storedTab || 'browser')
const [importedQueryUnsupported, setImportedQueryUnsupported] = useState(false)

function switchTab(mode) {
storage.setItem(tabKey, mode)
setMode(mode)
}

function afterFetchData(apiResponse) {
const unsupportedQuery = apiResponse.skip_imported_reason === 'unsupported_query'
const isRealtime = query.period === 'realtime'
setImportedQueryUnsupported(unsupportedQuery && !isRealtime)
}

function renderContent() {
switch (mode) {
case 'browser':
if (isFilteringOnFixedValue(query, 'browser')) {
return <BrowserVersions site={site} query={query} />
return <BrowserVersions site={site} query={query} afterFetchData={afterFetchData} />
}
return <Browsers site={site} query={query} />
return <Browsers site={site} query={query} afterFetchData={afterFetchData} />
case 'os':
if (isFilteringOnFixedValue(query, 'os')) {
return <OperatingSystemVersions site={site} query={query} />
return <OperatingSystemVersions site={site} query={query} afterFetchData={afterFetchData} />
}
return <OperatingSystems site={site} query={query} />
return <OperatingSystems site={site} query={query} afterFetchData={afterFetchData} />
case 'size':
default:
return <ScreenSizes site={site} query={query} />
return <ScreenSizes site={site} query={query} afterFetchData={afterFetchData} />
}
}

Expand Down Expand Up @@ -211,7 +224,10 @@ export default function Devices(props) {
return (
<div>
<div className="flex justify-between w-full">
<h3 className="font-bold dark:text-gray-100">Devices</h3>
<div className="flex gap-x-1">
<h3 className="font-bold dark:text-gray-100">Devices</h3>
<ImportedQueryUnsupportedWarning condition={importedQueryUnsupported}/>
</div>
<div className="flex text-xs font-medium text-gray-500 dark:text-gray-400 space-x-2">
{renderPill('Browser', 'browser')}
{renderPill('OS', 'os')}
Expand Down
14 changes: 14 additions & 0 deletions assets/js/dashboard/stats/imported-query-unsupported-warning.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import { ExclamationCircleIcon } from '@heroicons/react/24/outline'

export default function ImportedQueryUnsupportedWarning({condition}) {
if (condition) {
return (
<span tooltip="Imported data is excluded due to applied filters">
<ExclamationCircleIcon className="w-6 h-6" />
</span>
)
} else {
return null
}
}
37 changes: 26 additions & 11 deletions assets/js/dashboard/stats/locations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import {apiPath, sitePath} from '../../util/url'
import ListReport from '../reports/list'
import { VISITORS_METRIC, maybeWithCR } from '../reports/metrics';
import { getFiltersByKeyPrefix } from '../../util/filters';
import ImportedQueryUnsupportedWarning from '../imported-query-unsupported-warning';

function Countries({query, site, onClick}) {
function Countries({query, site, onClick, afterFetchData}) {
function fetchData() {
return api.get(apiPath(site, '/countries'), query, { limit: 9 })
}
Expand All @@ -29,6 +30,7 @@ function Countries({query, site, onClick}) {
return (
<ListReport
fetchData={fetchData}
afterFetchData={afterFetchData}
getFilterFor={getFilterFor}
onClick={onClick}
keyLabel="Country"
Expand All @@ -41,7 +43,7 @@ function Countries({query, site, onClick}) {
)
}

function Regions({query, site, onClick}) {
function Regions({query, site, onClick, afterFetchData}) {
function fetchData() {
return api.get(apiPath(site, '/regions'), query, {limit: 9})
}
Expand All @@ -61,6 +63,7 @@ function Regions({query, site, onClick}) {
return (
<ListReport
fetchData={fetchData}
afterFetchData={afterFetchData}
getFilterFor={getFilterFor}
onClick={onClick}
keyLabel="Region"
Expand All @@ -73,7 +76,7 @@ function Regions({query, site, onClick}) {
)
}

function Cities({query, site}) {
function Cities({query, site, afterFetchData}) {
function fetchData() {
return api.get(apiPath(site, '/cities'), query, {limit: 9})
}
Expand All @@ -93,6 +96,7 @@ function Cities({query, site}) {
return (
<ListReport
fetchData={fetchData}
afterFetchData={afterFetchData}
getFilterFor={getFilterFor}
keyLabel="City"
metrics={maybeWithCR([VISITORS_METRIC], query)}
Expand All @@ -116,10 +120,12 @@ export default class Locations extends React.Component {
super(props)
this.onCountryFilter = this.onCountryFilter.bind(this)
this.onRegionFilter = this.onRegionFilter.bind(this)
this.afterFetchData = this.afterFetchData.bind(this)
this.tabKey = `geoTab__${ props.site.domain}`
const storedTab = storage.getItem(this.tabKey)
this.state = {
mode: storedTab || 'map'
mode: storedTab || 'map',
importedQueryUnsupported: false
}
}

Expand Down Expand Up @@ -156,17 +162,23 @@ export default class Locations extends React.Component {
this.setMode('cities')()
}

afterFetchData(apiResponse) {
const unsupportedQuery = apiResponse.skip_imported_reason === 'unsupported_query'
const isRealtime = this.props.query.period === 'realtime'
this.setState({importedQueryUnsupported: unsupportedQuery && !isRealtime})
}

renderContent() {
switch(this.state.mode) {
case "cities":
return <Cities site={this.props.site} query={this.props.query} />
return <Cities site={this.props.site} query={this.props.query} afterFetchData={this.afterFetchData} />
case "regions":
return <Regions onClick={this.onRegionFilter} site={this.props.site} query={this.props.query} />
return <Regions onClick={this.onRegionFilter} site={this.props.site} query={this.props.query} afterFetchData={this.afterFetchData} />
case "countries":
return <Countries onClick={this.onCountryFilter('countries')} site={this.props.site} query={this.props.query} />
return <Countries onClick={this.onCountryFilter('countries')} site={this.props.site} query={this.props.query} afterFetchData={this.afterFetchData} />
case "map":
default:
return <CountriesMap onClick={this.onCountryFilter('map')} site={this.props.site} query={this.props.query}/>
return <CountriesMap onClick={this.onCountryFilter('map')} site={this.props.site} query={this.props.query} afterFetchData={this.afterFetchData} />
}
}

Expand Down Expand Up @@ -197,9 +209,12 @@ export default class Locations extends React.Component {
return (
<div>
<div className="w-full flex justify-between">
<h3 className="font-bold dark:text-gray-100">
{labelFor[this.state.mode] || 'Locations'}
</h3>
<div className="flex gap-x-1">
<h3 className="font-bold dark:text-gray-100">
{labelFor[this.state.mode] || 'Locations'}
</h3>
<ImportedQueryUnsupportedWarning condition={this.state.importedQueryUnsupported} />
</div>
<div className="flex text-xs font-medium text-gray-500 dark:text-gray-400 space-x-2">
{ this.renderPill('Map', 'map') }
{ this.renderPill('Countries', 'countries') }
Expand Down
4 changes: 4 additions & 0 deletions assets/js/dashboard/stats/locations/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ class Countries extends React.Component {
fetchCountries() {
return api.get(`/api/stats/${encodeURIComponent(this.props.site.domain)}/countries`, this.props.query, {limit: 300})
.then((response) => {
if (this.props.afterFetchData) {
this.props.afterFetchData(response)
}

this.setState({loading: false, countries: response.results})
})
}
Expand Down
Loading

0 comments on commit a727f44

Please sign in to comment.