diff --git a/CHANGELOG.md b/CHANGELOG.md index c42fb4b8..283f67bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), #### Fixed * [#243](https://github.com/shlinkio/shlink-web-client/issues/243) Fixed loading state and resetting on short URL creation form. +* [#239](https://github.com/shlinkio/shlink-web-client/issues/239) Fixed how user agents are parsed, reducing false results. ## 2.3.1 - 2020-02-08 diff --git a/package-lock.json b/package-lock.json index 45ce16c2..bec22699 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3460,6 +3460,11 @@ "resolved": "https://registry.npmjs.org/bottlejs/-/bottlejs-1.7.2.tgz", "integrity": "sha512-voMPQ+g8/4GBiDE5lp43fgfoBn7Q5fZI7k3ye8ErrPoHzuuRS0Gff9lZYeyalh86uz5P304iZ14wNAM+3TZguQ==" }, + "bowser": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz", + "integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA==" + }, "boxen": { "version": "1.3.0", "resolved": "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz", diff --git a/package.json b/package.json index 9041a0eb..669cf8fd 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "axios": "^0.19.0", "bootstrap": "^4.3.1", "bottlejs": "^1.7.2", + "bowser": "^2.9.0", "chart.js": "^2.8.0", "classnames": "^2.2.6", "compare-versions": "^3.5.1", diff --git a/src/utils/helpers/visits.js b/src/utils/helpers/visits.js index 754cbb19..8f5b9e8d 100644 --- a/src/utils/helpers/visits.js +++ b/src/utils/helpers/visits.js @@ -1,51 +1,29 @@ +import bowser from 'bowser'; import { hasValue } from '../utils'; const DEFAULT = 'Others'; +const BROWSERS_WHITELIST = [ + 'Android Browser', + 'Chrome', + 'Chromium', + 'Firefox', + 'Internet Explorer', + 'Microsoft Edge', + 'Opera', + 'Safari', + 'Samsung Internet for Android', + 'Vivaldi', + 'WeChat', +]; -export const osFromUserAgent = (userAgent) => { +export const parseUserAgent = (userAgent) => { if (!hasValue(userAgent)) { - return DEFAULT; + return { browser: DEFAULT, os: DEFAULT }; } - const lowerUserAgent = userAgent.toLowerCase(); + const { browser: { name: browser }, os: { name: os } } = bowser.parse(userAgent); - switch (true) { - case lowerUserAgent.includes('linux'): - return 'Linux'; - case lowerUserAgent.includes('windows'): - return 'Windows'; - case lowerUserAgent.includes('mac'): - return 'MacOS'; - case lowerUserAgent.includes('mobi'): - return 'Mobile'; - default: - return DEFAULT; - } -}; - -export const browserFromUserAgent = (userAgent) => { - if (!hasValue(userAgent)) { - return DEFAULT; - } - - const lowerUserAgent = userAgent.toLowerCase(); - - switch (true) { - case lowerUserAgent.includes('opera') || lowerUserAgent.includes('opr'): - return 'Opera'; - case lowerUserAgent.includes('firefox'): - return 'Firefox'; - case lowerUserAgent.includes('chrome'): - return 'Chrome'; - case lowerUserAgent.includes('safari'): - return 'Safari'; - case lowerUserAgent.includes('edg'): - return 'Microsoft Edge'; - case lowerUserAgent.includes('msie'): - return 'Internet Explorer'; - default: - return DEFAULT; - } + return { os: os || DEFAULT, browser: browser && BROWSERS_WHITELIST.includes(browser) ? browser : DEFAULT }; }; export const extractDomain = (url) => { diff --git a/src/visits/GraphCard.js b/src/visits/GraphCard.js index 7cccf30d..f42b3184 100644 --- a/src/visits/GraphCard.js +++ b/src/visits/GraphCard.js @@ -24,12 +24,16 @@ const generateGraphData = (title, isBarChart, labels, data, highlightedData) => data, backgroundColor: isBarChart ? 'rgba(70, 150, 229, 0.4)' : [ '#97BBCD', - '#DCDCDC', '#F7464A', '#46BFBD', '#FDB45C', '#949FB1', - '#4D5360', + '#57A773', + '#414066', + '#08B2E3', + '#B6C454', + '#DCDCDC', + '#463730', ], borderColor: isBarChart ? 'rgba(70, 150, 229, 1)' : 'white', borderWidth: 2, @@ -47,6 +51,14 @@ const generateGraphData = (title, isBarChart, labels, data, highlightedData) => const dropLabelIfHidden = (label) => label.startsWith('hidden') ? '' : label; +const determineHeight = (isBarChart, labels) => { + if (!isBarChart && labels.length > 8) { + return 200; + } + + return isBarChart && labels.length > 20 ? labels.length * 8 : null; +}; + const renderGraph = (title, isBarChart, stats, max, highlightedStats, onClick) => { const hasHighlightedStats = highlightedStats && Object.keys(highlightedStats).length > 0; const Component = isBarChart ? HorizontalBar : Doughnut; @@ -84,7 +96,7 @@ const renderGraph = (title, isBarChart, stats, max, highlightedStats, onClick) = }), }; const graphData = generateGraphData(title, isBarChart, labels, data, highlightedData); - const height = isBarChart && labels.length > 20 ? labels.length * 8 : null; + const height = determineHeight(isBarChart, labels); // Provide a key based on the height, so that every time the dataset changes, a new graph is rendered return ( diff --git a/src/visits/ShortUrlVisits.js b/src/visits/ShortUrlVisits.js index 1a057279..0d279ae2 100644 --- a/src/visits/ShortUrlVisits.js +++ b/src/visits/ShortUrlVisits.js @@ -198,7 +198,7 @@ const ShortUrlVisits = ({ processStatsFromVisits, normalizeVisits }, OpenMapModa