From 0b6e645b44b40cc69a01a4fed5445a00277b5a4b Mon Sep 17 00:00:00 2001 From: Uku Taht Date: Fri, 30 Oct 2020 10:49:41 +0200 Subject: [PATCH] Rename metadata -> properties (#390) --- assets/js/dashboard/filters.js | 4 +- assets/js/dashboard/query.js | 2 +- .../js/dashboard/stats/conversions/index.js | 6 +-- .../{meta-breakdown.js => prop-breakdown.js} | 38 +++++++++---------- lib/plausible/stats/clickhouse.ex | 16 ++++---- .../controllers/api/external_controller.ex | 2 +- .../controllers/api/stats_controller.ex | 10 ++--- lib/plausible_web/router.ex | 2 +- priv/tracker/js/analytics.js | 2 +- priv/tracker/js/plausible.hash.js | 2 +- priv/tracker/js/plausible.js | 2 +- tracker/src/plausible.js | 3 ++ 12 files changed, 46 insertions(+), 43 deletions(-) rename assets/js/dashboard/stats/conversions/{meta-breakdown.js => prop-breakdown.js} (68%) diff --git a/assets/js/dashboard/filters.js b/assets/js/dashboard/filters.js index a7399a05a9..9e7e9ef15c 100644 --- a/assets/js/dashboard/filters.js +++ b/assets/js/dashboard/filters.js @@ -7,7 +7,7 @@ function filterText(key, value, query) { if (key === "goal") { return Completed goal {value} } - if (key === "meta") { + if (key === "props") { const [metaKey, metaValue] = Object.entries(value)[0] const eventName = query.filters["goal"] ? query.filters["goal"] : 'event' return {eventName}.{metaKey} is {metaValue} @@ -49,7 +49,7 @@ function filterText(key, value, query) { function renderFilter(history, [key, value], query) { function removeFilter() { let newQuery = removeQueryParam(location.search, key) - if (key === 'goal') { newQuery = removeQueryParam(newQuery, 'meta') } + if (key === 'goal') { newQuery = removeQueryParam(newQuery, 'props') } history.push({search: newQuery}) } diff --git a/assets/js/dashboard/query.js b/assets/js/dashboard/query.js index bd8200ddcf..155f77e132 100644 --- a/assets/js/dashboard/query.js +++ b/assets/js/dashboard/query.js @@ -24,7 +24,7 @@ export function parseQuery(querystring, site) { to: q.get('to') ? parseUTCDate(q.get('to')) : undefined, filters: { 'goal': q.get('goal'), - 'meta': JSON.parse(q.get('meta')), + 'props': JSON.parse(q.get('props')), 'source': q.get('source'), 'utm_medium': q.get('utm_medium'), 'utm_source': q.get('utm_source'), diff --git a/assets/js/dashboard/stats/conversions/index.js b/assets/js/dashboard/stats/conversions/index.js index 9d50c5aa4e..f131bafd61 100644 --- a/assets/js/dashboard/stats/conversions/index.js +++ b/assets/js/dashboard/stats/conversions/index.js @@ -3,7 +3,7 @@ import { Link } from 'react-router-dom' import Bar from '../bar' import MoreLink from '../more-link' -import MetaBreakdown from './meta-breakdown' +import PropBreakdown from './prop-breakdown' import numberFormatter from '../../number-formatter' import * as api from '../../api' @@ -45,7 +45,7 @@ export default class Conversions extends React.Component { } renderGoal(goal) { - const renderMeta = this.props.query.filters['goal'] == goal.name && goal.meta_keys + const renderProps = this.props.query.filters['goal'] == goal.name && goal.prop_names return (
@@ -59,7 +59,7 @@ export default class Conversions extends React.Component { {numberFormatter(goal.total_count)}
- { renderMeta && } + { renderProps && } ) } diff --git a/assets/js/dashboard/stats/conversions/meta-breakdown.js b/assets/js/dashboard/stats/conversions/prop-breakdown.js similarity index 68% rename from assets/js/dashboard/stats/conversions/meta-breakdown.js rename to assets/js/dashboard/stats/conversions/prop-breakdown.js index 00f4b9c429..bbfc8d7a15 100644 --- a/assets/js/dashboard/stats/conversions/meta-breakdown.js +++ b/assets/js/dashboard/stats/conversions/prop-breakdown.js @@ -5,39 +5,39 @@ import Bar from '../bar' import numberFormatter from '../../number-formatter' import * as api from '../../api' -export default class MetaBreakdown extends React.Component { +export default class PropertyBreakdown extends React.Component { constructor(props) { super(props) - let metaKey = props.goal.meta_keys[0] - this.storageKey = 'goalMetaTab__' + props.site.domain + props.goal.name + let propKey = props.goal.prop_names[0] + this.storageKey = 'goalPropTab__' + props.site.domain + props.goal.name const storedKey = window.localStorage[this.storageKey] - if (props.goal.meta_keys.includes(storedKey)) { - metaKey = storedKey + if (props.goal.prop_names.includes(storedKey)) { + propKey = storedKey } - if (props.query.filters['meta']) { - metaKey = Object.keys(props.query.filters['meta'])[0] + if (props.query.filters['props']) { + propKey = Object.keys(props.query.filters['props'])[0] } this.state = { loading: true, - metaKey: metaKey + propKey: propKey } } componentDidMount() { - this.fetchMetaBreakdown() + this.fetchPropBreakdown() } - fetchMetaBreakdown() { + fetchPropBreakdown() { if (this.props.query.filters['goal']) { - api.get(`/api/stats/${encodeURIComponent(this.props.site.domain)}/meta-breakdown/${encodeURIComponent(this.state.metaKey)}`, this.props.query) + api.get(`/api/stats/${encodeURIComponent(this.props.site.domain)}/property/${encodeURIComponent(this.state.propKey)}`, this.props.query) .then((res) => this.setState({loading: false, breakdown: res})) } } - renderMetadataValue(value) { + renderPropValue(value) { const query = new URLSearchParams(window.location.search) - query.set('meta', JSON.stringify({[this.state.metaKey]: value.name})) + query.set('props', JSON.stringify({[this.state.propKey]: value.name})) return (
@@ -55,26 +55,26 @@ export default class MetaBreakdown extends React.Component { ) } - changeMetaKey(newKey) { + changePropKey(newKey) { window.localStorage[this.storageKey] = newKey - this.setState({metaKey: newKey, loading: true}, this.fetchMetaBreakdown) + this.setState({propKey: newKey, loading: true}, this.fetchPropBreakdown) } renderBody() { if (this.state.loading) { return
} else { - return this.state.breakdown.map((metaValue) => this.renderMetadataValue(metaValue)) + return this.state.breakdown.map((propValue) => this.renderPropValue(propValue)) } } renderPill(key) { - const isActive = this.state.metaKey === key + const isActive = this.state.propKey === key if (isActive) { return
  • {key}
  • } else { - return
  • {key}
  • + return
  • {key}
  • } } @@ -84,7 +84,7 @@ export default class MetaBreakdown extends React.Component {
    Breakdown by:
      - { this.props.goal.meta_keys.map(this.renderPill.bind(this)) } + { this.props.goal.prop_names.map(this.renderPill.bind(this)) }
    { this.renderBody() } diff --git a/lib/plausible/stats/clickhouse.ex b/lib/plausible/stats/clickhouse.ex index f707de5a21..7aa8e3b277 100644 --- a/lib/plausible/stats/clickhouse.ex +++ b/lib/plausible/stats/clickhouse.ex @@ -597,7 +597,7 @@ defmodule Plausible.Stats.Clickhouse do ClickhouseRepo.exists?(from e in "events", where: e.domain == ^site.domain) end - def all_seen_metadata_keys(site, %Query{filters: %{"meta" => meta}} = query) when is_map(meta) do + def all_props(site, %Query{filters: %{"props" => meta}} = query) when is_map(meta) do [{key, val}] = meta |> Enum.into([]) if val == "(none)" do @@ -614,7 +614,7 @@ defmodule Plausible.Stats.Clickhouse do end end - def all_seen_metadata_keys(site, query) do + def all_props(site, query) do ClickhouseRepo.all( from e in base_query_w_sessions_bare(site, query), inner_lateral_join: meta in fragment("meta as m"), @@ -625,7 +625,7 @@ defmodule Plausible.Stats.Clickhouse do end) end - def metadata_breakdown(site, %Query{filters: %{"meta" => meta}} = query, key) when is_map(meta) do + def property_breakdown(site, %Query{filters: %{"props" => meta}} = query, key) when is_map(meta) do [{_key, val}] = meta |> Enum.into([]) if val == "(none)" do @@ -653,7 +653,7 @@ defmodule Plausible.Stats.Clickhouse do end end - def metadata_breakdown(site, query, key) do + def property_breakdown(site, query, key) do none = ClickhouseRepo.all( from e in base_query_w_sessions(site, query), where: fragment("not has(meta.key, ?)", ^key), @@ -858,8 +858,8 @@ defmodule Plausible.Stats.Clickhouse do q end - if query.filters["meta"] do - [{key, val}] = query.filters["meta"] |> Enum.into([]) + if query.filters["props"] do + [{key, val}] = query.filters["props"] |> Enum.into([]) if val == "(none)" do from( @@ -1070,8 +1070,8 @@ defmodule Plausible.Stats.Clickhouse do q end - q = if query.filters["meta"] do - [{key, val}] = query.filters["meta"] |> Enum.into([]) + q = if query.filters["props"] do + [{key, val}] = query.filters["props"] |> Enum.into([]) if val == "(none)" do from( diff --git a/lib/plausible_web/controllers/api/external_controller.ex b/lib/plausible_web/controllers/api/external_controller.ex index 20762e5106..2d1e2be40b 100644 --- a/lib/plausible_web/controllers/api/external_controller.ex +++ b/lib/plausible_web/controllers/api/external_controller.ex @@ -117,7 +117,7 @@ defmodule PlausibleWeb.Api.ExternalController do end defp parse_meta(params) do - raw_meta = params["m"] || params["meta"] + raw_meta = params["m"] || params["meta"] || params["p"] || params["props"] if raw_meta do Jason.decode!(raw_meta) else diff --git a/lib/plausible_web/controllers/api/stats_controller.ex b/lib/plausible_web/controllers/api/stats_controller.ex index 14d48db17e..f19f1b91bd 100644 --- a/lib/plausible_web/controllers/api/stats_controller.ex +++ b/lib/plausible_web/controllers/api/stats_controller.ex @@ -36,7 +36,7 @@ defmodule PlausibleWeb.Api.StatsController do end defp fetch_top_stats(site, %Query{filters: %{"goal" => goal}} = query) when is_binary(goal) do - total_filter = Map.merge(query.filters, %{"goal" => nil, "meta" => nil}) + total_filter = Map.merge(query.filters, %{"goal" => nil, "props" => nil}) prev_query = Query.shift_back(query) unique_visitors = Stats.unique_visitors(site, %{query | filters: total_filter}) prev_unique_visitors = Stats.unique_visitors(site, %{prev_query | filters: total_filter}) @@ -260,18 +260,18 @@ defmodule PlausibleWeb.Api.StatsController do def conversions(conn, params) do site = conn.assigns[:site] query = Query.from(site.timezone, params) - metadata_keys = Stats.all_seen_metadata_keys(site, query) + prop_names = Stats.all_props(site, query) conversions = Stats.goal_conversions(site, query) - |> Enum.map(fn goal -> Map.put(goal, :meta_keys, metadata_keys[goal[:name]]) end) + |> Enum.map(fn goal -> Map.put(goal, :prop_names, prop_names[goal[:name]]) end) json(conn, conversions) end - def meta_breakdown(conn, params) do + def prop_breakdown(conn, params) do site = conn.assigns[:site] query = Query.from(site.timezone, params) - json(conn, Stats.metadata_breakdown(site, query, params["meta_key"])) + json(conn, Stats.property_breakdown(site, query, params["prop_name"])) end def current_visitors(conn, _) do diff --git a/lib/plausible_web/router.ex b/lib/plausible_web/router.ex index 23569aa0f2..d59fb545eb 100644 --- a/lib/plausible_web/router.ex +++ b/lib/plausible_web/router.ex @@ -59,7 +59,7 @@ defmodule PlausibleWeb.Router do get "/:domain/operating-systems", StatsController, :operating_systems get "/:domain/screen-sizes", StatsController, :screen_sizes get "/:domain/conversions", StatsController, :conversions - get "/:domain/meta-breakdown/:meta_key", StatsController, :meta_breakdown + get "/:domain/property/:prop_name", StatsController, :prop_breakdown end scope "/api", PlausibleWeb do diff --git a/priv/tracker/js/analytics.js b/priv/tracker/js/analytics.js index e53ae0c111..f874ee003c 100644 --- a/priv/tracker/js/analytics.js +++ b/priv/tracker/js/analytics.js @@ -1 +1 @@ -!function(i,r){"use strict";var o=i.location,s=i.document,e=s.querySelector('[src*="'+r+'"]'),l=e&&e.getAttribute("data-domain"),t=!1;function n(e,t){if(/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/.test(o.hostname)||"file:"===o.protocol)return console.warn("Ignoring event on localhost");var n={};n.n=e,n.u=o.href,n.d=l,n.r=s.referrer||null,n.w=i.innerWidth,console.log(t),t&&t.meta&&(n.m=JSON.stringify(t.meta));var a=new XMLHttpRequest;a.open("POST",r+"/api/event",!0),a.setRequestHeader("Content-Type","text/plain"),a.send(JSON.stringify(n)),a.onreadystatechange=function(){4==a.readyState&&t&&t.callback&&t.callback()}}function a(){n("pageview")}try{var c,p=i.history;p.pushState&&(c=p.pushState,p.pushState=function(){c.apply(this,arguments),a()},i.addEventListener("popstate",a));var u=i.plausible&&i.plausible.q||[];i.plausible=n;for(var d=0;d"); \ No newline at end of file +!function(i,r){"use strict";var s=i.location,o=i.document,e=o.querySelector('[src*="'+r+'"]'),l=e&&e.getAttribute("data-domain"),t=!1;function n(e,t){if(/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/.test(s.hostname)||"file:"===s.protocol)return console.warn("Ignoring event on localhost");var n={};n.n=e,n.u=s.href,n.d=l,n.r=o.referrer||null,n.w=i.innerWidth,t&&t.meta&&(n.m=JSON.stringify(t.meta)),t&&t.props&&(n.p=JSON.stringify(t.props));var a=new XMLHttpRequest;a.open("POST",r+"/api/event",!0),a.setRequestHeader("Content-Type","text/plain"),a.send(JSON.stringify(n)),a.onreadystatechange=function(){4==a.readyState&&t&&t.callback&&t.callback()}}function a(){n("pageview")}try{var p,c=i.history;c.pushState&&(p=c.pushState,c.pushState=function(){p.apply(this,arguments),a()},i.addEventListener("popstate",a));var u=i.plausible&&i.plausible.q||[];i.plausible=n;for(var d=0;d"); \ No newline at end of file diff --git a/priv/tracker/js/plausible.hash.js b/priv/tracker/js/plausible.hash.js index d67c0818fa..a78921c2ef 100644 --- a/priv/tracker/js/plausible.hash.js +++ b/priv/tracker/js/plausible.hash.js @@ -1 +1 @@ -!function(i,r){"use strict";var s=i.location,o=i.document,e=o.querySelector('[src*="'+r+'"]'),l=e&&e.getAttribute("data-domain"),t=!1;function n(e,t){if(/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/.test(s.hostname)||"file:"===s.protocol)return console.warn("Ignoring event on localhost");var n={};n.n=e,n.u=s.href,n.d=l,n.r=o.referrer||null,n.w=i.innerWidth,console.log(t),t&&t.meta&&(n.m=JSON.stringify(t.meta)),n.h=1;var a=new XMLHttpRequest;a.open("POST",r+"/api/event",!0),a.setRequestHeader("Content-Type","text/plain"),a.send(JSON.stringify(n)),a.onreadystatechange=function(){4==a.readyState&&t&&t.callback&&t.callback()}}function a(){n("pageview")}try{var c,p=i.history;p.pushState&&(c=p.pushState,p.pushState=function(){c.apply(this,arguments),a()},i.addEventListener("popstate",a)),i.addEventListener("hashchange",a);var u=i.plausible&&i.plausible.q||[];i.plausible=n;for(var h=0;h"); \ No newline at end of file +!function(i,r){"use strict";var s=i.location,o=i.document,e=o.querySelector('[src*="'+r+'"]'),l=e&&e.getAttribute("data-domain"),t=!1;function n(e,t){if(/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/.test(s.hostname)||"file:"===s.protocol)return console.warn("Ignoring event on localhost");var n={};n.n=e,n.u=s.href,n.d=l,n.r=o.referrer||null,n.w=i.innerWidth,t&&t.meta&&(n.m=JSON.stringify(t.meta)),t&&t.props&&(n.p=JSON.stringify(t.props)),n.h=1;var a=new XMLHttpRequest;a.open("POST",r+"/api/event",!0),a.setRequestHeader("Content-Type","text/plain"),a.send(JSON.stringify(n)),a.onreadystatechange=function(){4==a.readyState&&t&&t.callback&&t.callback()}}function a(){n("pageview")}try{var c,p=i.history;p.pushState&&(c=p.pushState,p.pushState=function(){c.apply(this,arguments),a()},i.addEventListener("popstate",a)),i.addEventListener("hashchange",a);var u=i.plausible&&i.plausible.q||[];i.plausible=n;for(var h=0;h"); \ No newline at end of file diff --git a/priv/tracker/js/plausible.js b/priv/tracker/js/plausible.js index e53ae0c111..f874ee003c 100644 --- a/priv/tracker/js/plausible.js +++ b/priv/tracker/js/plausible.js @@ -1 +1 @@ -!function(i,r){"use strict";var o=i.location,s=i.document,e=s.querySelector('[src*="'+r+'"]'),l=e&&e.getAttribute("data-domain"),t=!1;function n(e,t){if(/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/.test(o.hostname)||"file:"===o.protocol)return console.warn("Ignoring event on localhost");var n={};n.n=e,n.u=o.href,n.d=l,n.r=s.referrer||null,n.w=i.innerWidth,console.log(t),t&&t.meta&&(n.m=JSON.stringify(t.meta));var a=new XMLHttpRequest;a.open("POST",r+"/api/event",!0),a.setRequestHeader("Content-Type","text/plain"),a.send(JSON.stringify(n)),a.onreadystatechange=function(){4==a.readyState&&t&&t.callback&&t.callback()}}function a(){n("pageview")}try{var c,p=i.history;p.pushState&&(c=p.pushState,p.pushState=function(){c.apply(this,arguments),a()},i.addEventListener("popstate",a));var u=i.plausible&&i.plausible.q||[];i.plausible=n;for(var d=0;d"); \ No newline at end of file +!function(i,r){"use strict";var s=i.location,o=i.document,e=o.querySelector('[src*="'+r+'"]'),l=e&&e.getAttribute("data-domain"),t=!1;function n(e,t){if(/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/.test(s.hostname)||"file:"===s.protocol)return console.warn("Ignoring event on localhost");var n={};n.n=e,n.u=s.href,n.d=l,n.r=o.referrer||null,n.w=i.innerWidth,t&&t.meta&&(n.m=JSON.stringify(t.meta)),t&&t.props&&(n.p=JSON.stringify(t.props));var a=new XMLHttpRequest;a.open("POST",r+"/api/event",!0),a.setRequestHeader("Content-Type","text/plain"),a.send(JSON.stringify(n)),a.onreadystatechange=function(){4==a.readyState&&t&&t.callback&&t.callback()}}function a(){n("pageview")}try{var p,c=i.history;c.pushState&&(p=c.pushState,c.pushState=function(){p.apply(this,arguments),a()},i.addEventListener("popstate",a));var u=i.plausible&&i.plausible.q||[];i.plausible=n;for(var d=0;d"); \ No newline at end of file diff --git a/tracker/src/plausible.js b/tracker/src/plausible.js index aa5265374f..fc2b7481ce 100644 --- a/tracker/src/plausible.js +++ b/tracker/src/plausible.js @@ -20,6 +20,9 @@ if (options && options.meta) { payload.m = JSON.stringify(options.meta) } + if (options && options.props) { + payload.p = JSON.stringify(options.props) + } {{#if hashMode}} payload.h = 1 {{/if}}