Don't use localStorage when the browser doesn't support it (#971)

* Wrap localStorage with support checks

* Add changelog
This commit is contained in:
Uku Taht 2021-04-28 11:31:10 +03:00 committed by GitHub
parent 6319e7f29d
commit 255b4b2325
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 52 additions and 11 deletions

View File

@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
### Fixed
- Fix weekly report time range plausible/analytics#951
- Make sure embedded dashboards can run when user has blocked third-party cookies plausible/analytics#971
### Removed
- Removes AppSignal monitoring package

View File

@ -1,6 +1,7 @@
import React from 'react'
import { Link, withRouter } from 'react-router-dom'
import {formatDay, formatMonthYYYY, nowForSite, parseUTCDate} from './date'
import * as storage from './storage'
const PERIODS = ['realtime', 'day', 'month', '7d', '30d', '6mo', '12mo', 'custom']
@ -10,9 +11,9 @@ export function parseQuery(querystring, site) {
const periodKey = `period__${ site.domain}`
if (PERIODS.includes(period)) {
if (period !== 'custom' && period !== 'realtime') window.localStorage[periodKey] = period
} else if (window.localStorage[periodKey]) {
period = window.localStorage[periodKey]
if (period !== 'custom' && period !== 'realtime') storage.setItem(periodKey, period)
} else if (storage.getItem(periodKey)) {
period = storage.getItem(periodKey)
} else {
period = '30d'
}

View File

@ -1,6 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom'
import * as storage from '../../storage'
import Bar from '../bar'
import numberFormatter from '../../number-formatter'
import * as api from '../../api'
@ -10,7 +11,7 @@ export default class PropertyBreakdown extends React.Component {
super(props)
let propKey = props.goal.prop_names[0]
this.storageKey = 'goalPropTab__' + props.site.domain + props.goal.name
const storedKey = window.localStorage[this.storageKey]
const storedKey = storage.getItem(this.storageKey)
if (props.goal.prop_names.includes(storedKey)) {
propKey = storedKey
}
@ -70,7 +71,7 @@ export default class PropertyBreakdown extends React.Component {
}
changePropKey(newKey) {
window.localStorage[this.storageKey] = newKey
storage.setItem(this.storageKey, newKey)
this.setState({propKey: newKey, loading: true}, this.fetchPropBreakdown)
}

View File

@ -1,6 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom'
import * as storage from '../../storage'
import LazyLoader from '../../lazy-loader'
import Browsers from './browsers'
import OperatingSystems from './operating-systems'
@ -117,7 +118,7 @@ export default class Devices extends React.Component {
constructor(props) {
super(props)
this.tabKey = 'deviceTab__' + props.site.domain
const storedTab = window.localStorage[this.tabKey]
const storedTab = storage.getItem(this.tabKey)
this.state = {
mode: storedTab || 'size'
}
@ -135,7 +136,7 @@ export default class Devices extends React.Component {
setMode(mode) {
return () => {
window.localStorage[this.tabKey] = mode
storage.setItem(this.tabKey, mode)
this.setState({mode})
}
}

View File

@ -1,6 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom'
import * as storage from '../../storage'
import Visits from './pages'
import EntryPages from './entry-pages'
import ExitPages from './exit-pages'
@ -16,7 +17,7 @@ export default class Pages extends React.Component {
constructor(props) {
super(props)
this.tabKey = 'pageTab__' + props.site.domain
const storedTab = window.localStorage[this.tabKey]
const storedTab = storage.getItem(this.tabKey)
this.state = {
mode: storedTab || 'pages'
}
@ -34,7 +35,7 @@ export default class Pages extends React.Component {
setMode(mode) {
return () => {
window.localStorage[this.tabKey] = mode
storage.setItem(this.tabKey, mode)
this.setState({mode})
}
}

View File

@ -2,6 +2,7 @@ import React from 'react';
import { Link } from 'react-router-dom'
import FlipMove from 'react-flip-move';
import * as storage from '../../storage'
import FadeIn from '../../fade-in'
import Bar from '../bar'
import MoreLink from '../more-link'
@ -210,7 +211,7 @@ export default class SourceList extends React.Component {
constructor(props) {
super(props)
this.tabKey = 'sourceTab__' + props.site.domain
const storedTab = window.localStorage[this.tabKey]
const storedTab = storage.getItem(this.tabKey)
this.state = {
tab: storedTab || 'all'
}
@ -218,7 +219,7 @@ export default class SourceList extends React.Component {
setTab(tab) {
return () => {
window.localStorage[this.tabKey] = tab
storage.setItem(this.tabKey, tab)
this.setState({tab})
}
}

View File

@ -0,0 +1,35 @@
// This module checks if localStorage is available and uses it for persistent frontend storage
// if possible. Localstorage can be blocked by browsers when people block third-party cookies and
// the dashboard is running in embedded mode. In those cases, store stuff in a regular object instead.
const memStore = {}
// https://stackoverflow.com/a/16427747
function testLocalStorageAvailability(){
try {
const testItem = 'test';
localStorage.setItem(testItem, testItem);
localStorage.removeItem(testItem);
return true;
} catch(e) {
return false;
}
}
const isLocalStorageAvailable = testLocalStorageAvailability()
export function setItem(key, value) {
if (isLocalStorageAvailable) {
window.localStorage.setItem(key, value)
} else {
memStore[key] = value
}
}
export function getItem(key) {
if (isLocalStorageAvailable) {
return window.localStorage.getItem(key)
} else {
return memStore[key]
}
}