Add welcome dashboard

- Add a stats overview API to aggregate global stats
- Add bizcharts to the project to render visualisations
- WIP: Add stats widgets and visualisations to the dashboard
This commit is contained in:
Kailash Nadh 2018-11-06 15:14:26 +05:30
parent 31e180089e
commit 9511a78d91
5 changed files with 349 additions and 20 deletions

View file

@ -5,6 +5,7 @@
"dependencies": {
"antd": "^3.6.5",
"axios": "^0.18.0",
"bizcharts": "^3.2.5-beta.4",
"dayjs": "^1.7.5",
"react": "^16.4.1",
"react-app-rewire-less": "^2.1.3",

View file

@ -1,5 +1,6 @@
import { Button, Col, Form, Icon, Input, Modal, notification, Popconfirm, Row, Select, Spin, Table, Tag, Tooltip } from "antd"
import { Col, Row, notification, Card, Tooltip, Icon } from "antd"
import React from "react";
import { Chart, Axis, Geom, Tooltip as BizTooltip } from 'bizcharts';
import * as cs from "./constants"
@ -8,6 +9,8 @@ class Dashboard extends React.PureComponent {
stats: null
}
campaignTypes = ["running", "finished", "paused", "draft", "scheduled", "cancelled"]
componentDidMount = () => {
this.props.pageTitle("Dashboard")
@ -17,17 +20,97 @@ class Dashboard extends React.PureComponent {
notification["error"]({ message: "Error", description: e.message })
})
}
orZero(v) {
return v ? v : 0
}
render() {
return (
<section className = "dashboard">
<h1>Welcome</h1>
<hr />
{ this.state.stats &&
<div className="stats">
<Row>
<Col span={ 12 }>
<h1></h1>
<Col span={ 16 }>
<Row gutter={ 24 }>
<Col span={ 8 }>
<Card title="Active subscribers" bordered={ false }>
<h1 className="count">{ this.orZero(this.state.stats.subscribers.enabled) }</h1>
</Card>
</Col>
<Col span={ 8 }>
<Card title="Blacklisted subscribers" bordered={ false }>
<h1 className="count">{ this.orZero(this.state.stats.subscribers.blacklisted) }</h1>
</Card>
</Col>
<Col span={ 8 }>
<Card title="Orphaned subscribers" bordered={ false }>
<h1 className="count">{ this.orZero(this.state.stats.orphan_subscribers) }</h1>
</Card>
</Col>
</Row>
</Col>
<Col span={ 6 } offset={ 2 }>
<Row gutter={ 24 }>
<Col span={ 12 }>
<Card title="Public lists" bordered={ false }>
<h1 className="count">{ this.orZero(this.state.stats.lists.public) }</h1>
</Card>
</Col>
<Col span={ 12 }>
<Card title="Private lists" bordered={ false }>
<h1 className="count">{ this.orZero(this.state.stats.lists.private) }</h1>
</Card>
</Col>
</Row>
</Col>
</Row>
<hr />
<Row>
<Col span={ 16 }>
<Row gutter={ 24 }>
<Col span={ 12 }>
<Card title="Campaign views (last 3 months)" bordered={ false }>
<h1 className="count">
{ this.state.stats.campaign_views.reduce((total, v) => total + v.count, 0) }
{' '}
views
</h1>
<Chart height={ 220 } padding={ [0, 0, 0, 0] } data={ this.state.stats.campaign_views } forceFit>
<BizTooltip crosshairs={{ type : "y" }} />
<Geom type="area" position="date*count" size={ 0 } color="#7f2aff" />
<Geom type='point' position="date*count" size={ 0 } />
</Chart>
</Card>
</Col>
<Col span={ 12 }>
<Card title="Link clicks (last 3 months)" bordered={ false }>
<h1 className="count">
{ this.state.stats.link_clicks.reduce((total, v) => total + v.count, 0) }
{' '}
clicks
</h1>
<Chart height={ 220 } padding={ [0, 0, 0, 0] } data={ this.state.stats.link_clicks } forceFit>
<BizTooltip crosshairs={{ type : "y" }} />
<Geom type="area" position="date*count" size={ 0 } color="#7f2aff" />
<Geom type='point' position="date*count" size={ 0 } />
</Chart>
</Card>
</Col>
</Row>
</Col>
<Col span={ 6 } offset={ 2 }>
<Card title="Campaigns" bordered={ false } className="campaign-counts">
{ this.campaignTypes.map((key, count) =>
<Row key={ `stats-campaigns-${ key }` }>
<Col span={ 18 }><h1 className="name">{ key }</h1></Col>
<Col span={ 6 }><h1 className="count">{ count }</h1></Col>
</Row>
)}
</Card>
</Col>
</Row>
</div>

View file

@ -44,11 +44,14 @@ body {
}
.content-body {
background: #fff;
padding: 24px;
min-height: 90vh;
}
section.content {
padding: 24px;
background: #fff;
}
.logo {
padding: 30px;
}
@ -65,6 +68,11 @@ body {
width: 20px;
}
.ant-card-head-title {
font-size: .85em !important;
color: #999 !important;
}
.hidden {
display: none;
}
@ -83,6 +91,14 @@ td .ant-tag {
margin-top: 5px;
}
/* Dashboard */
.dashboard {
margin: 24px;
}
.dashboard .campaign-counts .name {
text-transform: capitalize;
}
/* Templates */
.wysiwyg {
padding: 30px;

View file

@ -2,6 +2,75 @@
# yarn lockfile v1
"@antv/adjust@~0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@antv/adjust/-/adjust-0.1.0.tgz#c4bce8ba0aef7cd5b3bf271f75f434c07bd215a0"
dependencies:
"@antv/util" "~1.3.1"
"@antv/attr@~0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@antv/attr/-/attr-0.1.0.tgz#68734b0557d9392645e947342acc8fca370d4a56"
dependencies:
"@antv/util" "~1.3.1"
"@antv/component@~0.2.0":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@antv/component/-/component-0.2.1.tgz#e3ef27fcd0aa0f6a76859a63c7a2578a365920bf"
dependencies:
"@antv/attr" "~0.1.0"
"@antv/g" "~3.3.3"
"@antv/util" "~1.3.1"
wolfy87-eventemitter "~5.1.0"
"@antv/coord@~0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@antv/coord/-/coord-0.1.0.tgz#48a80ae36d07552f96657e7f8095227c63f0c0a9"
dependencies:
"@antv/util" "~1.3.1"
"@antv/g2@3.3.3":
version "3.3.3"
resolved "https://registry.yarnpkg.com/@antv/g2/-/g2-3.3.3.tgz#da997eb6422437d0827cbc26e184e455c06944b1"
dependencies:
"@antv/adjust" "~0.1.0"
"@antv/attr" "~0.1.0"
"@antv/component" "~0.2.0"
"@antv/coord" "~0.1.0"
"@antv/g" "~3.3.4"
"@antv/scale" "~0.1.0"
"@antv/util" "~1.3.1"
venn.js "~0.2.20"
wolfy87-eventemitter "~5.1.0"
"@antv/g@~3.3.3", "@antv/g@~3.3.4":
version "3.3.4"
resolved "https://registry.yarnpkg.com/@antv/g/-/g-3.3.4.tgz#46cb6ae5fe0b6e1937f6ab384318d97a737385ad"
dependencies:
"@antv/gl-matrix" "~2.7.1"
"@antv/util" "~1.3.1"
d3-ease "~1.0.3"
d3-interpolate "~1.1.5"
d3-timer "~1.0.6"
wolfy87-eventemitter "~5.1.0"
"@antv/gl-matrix@^2.7.1", "@antv/gl-matrix@~2.7.1":
version "2.7.1"
resolved "https://registry.yarnpkg.com/@antv/gl-matrix/-/gl-matrix-2.7.1.tgz#acb8e37f7ab3df01345aba4372d7942be42eba14"
"@antv/scale@~0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@antv/scale/-/scale-0.1.0.tgz#2b5459a100f97aac04781376d53904ccab18aab7"
dependencies:
"@antv/util" "~1.3.1"
fecha "~2.3.3"
"@antv/util@~1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@antv/util/-/util-1.3.1.tgz#30a34b201ff9126ec0d58c72c8166a9c3e644ccd"
dependencies:
"@antv/gl-matrix" "^2.7.1"
"@babel/helper-module-imports@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d"
@ -1215,6 +1284,15 @@ binary-extensions@^1.0.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
bizcharts@^3.2.5-beta.4:
version "3.2.5-beta.4"
resolved "https://registry.yarnpkg.com/bizcharts/-/bizcharts-3.2.5-beta.4.tgz#4f27e62c3d4a9a5c49a29c54978e4f1f42ae4d1a"
dependencies:
"@antv/g2" "3.3.3"
invariant "^2.2.2"
prop-types "^15.6.0"
warning "^3.0.0"
block-stream@*:
version "0.0.9"
resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
@ -1572,7 +1650,7 @@ center-align@^0.1.1:
align-text "^0.1.3"
lazy-cache "^1.0.3"
chalk@1.1.3, chalk@^1.1.3:
chalk@1.1.3, chalk@^1.1.1, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
dependencies:
@ -1944,6 +2022,10 @@ content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
contour_plot@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/contour_plot/-/contour_plot-0.0.1.tgz#475870f032b8e338412aa5fc507880f0bf495c77"
convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
@ -2195,6 +2277,49 @@ cyclist@~0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
d3-color@1:
version "1.2.3"
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.2.3.tgz#6c67bb2af6df3cc8d79efcc4d3a3e83e28c8048f"
d3-dispatch@1:
version "1.0.5"
resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.5.tgz#e25c10a186517cd6c82dd19ea018f07e01e39015"
d3-ease@1, d3-ease@~1.0.3:
version "1.0.5"
resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.5.tgz#8ce59276d81241b1b72042d6af2d40e76d936ffb"
d3-interpolate@1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.3.2.tgz#417d3ebdeb4bc4efcc8fd4361c55e4040211fd68"
dependencies:
d3-color "1"
d3-interpolate@~1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.1.6.tgz#2cf395ae2381804df08aa1bf766b7f97b5f68fb6"
dependencies:
d3-color "1"
d3-selection@^1.0.2, d3-selection@^1.1.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.3.2.tgz#6e70a9df60801c8af28ac24d10072d82cbfdf652"
d3-timer@1, d3-timer@~1.0.6:
version "1.0.9"
resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.9.tgz#f7bb8c0d597d792ff7131e1c24a36dd471a471ba"
d3-transition@^1.0.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.1.3.tgz#3a435b05ce9cef9524fe0d38121cfb6905331ca6"
dependencies:
d3-color "1"
d3-dispatch "1"
d3-ease "1"
d3-interpolate "1"
d3-selection "^1.1.0"
d3-timer "1"
d@1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
@ -2243,7 +2368,7 @@ decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
deep-equal@^1.0.1:
deep-equal@^1.0.1, deep-equal@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
@ -2293,7 +2418,7 @@ define-property@^2.0.2:
is-descriptor "^1.0.2"
isobject "^3.0.1"
defined@^1.0.0:
defined@^1.0.0, defined@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
@ -2623,7 +2748,7 @@ error-ex@^1.2.0:
dependencies:
is-arrayish "^0.2.1"
es-abstract@^1.7.0:
es-abstract@^1.5.0, es-abstract@^1.7.0:
version "1.12.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165"
dependencies:
@ -3142,6 +3267,10 @@ fbjs@^0.8.0, fbjs@^0.8.15, fbjs@^0.8.16, fbjs@^0.8.9:
setimmediate "^1.0.5"
ua-parser-js "^0.7.18"
fecha@~2.3.3:
version "2.3.3"
resolved "http://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
figgy-pudding@^3.0.0, figgy-pudding@^3.1.0, figgy-pudding@^3.4.1, figgy-pudding@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
@ -3265,12 +3394,28 @@ flush-write-stream@^1.0.0:
inherits "^2.0.1"
readable-stream "^2.0.4"
fmin@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/fmin/-/fmin-0.0.2.tgz#59bbb40d43ffdc1c94cd00a568c41f95f1973017"
dependencies:
contour_plot "^0.0.1"
json2module "^0.0.3"
rollup "^0.25.8"
tape "^4.5.1"
uglify-js "^2.6.2"
follow-redirects@^1.0.0, follow-redirects@^1.3.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291"
dependencies:
debug "^3.1.0"
for-each@~0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
dependencies:
is-callable "^1.1.3"
for-in@^1.0.1, for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@ -3394,7 +3539,7 @@ fstream@^1.0.0, fstream@^1.0.2:
mkdirp ">=0.5 0"
rimraf "2"
function-bind@^1.1.1:
function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@ -3664,7 +3809,7 @@ has-values@^1.0.0:
is-number "^3.0.0"
kind-of "^4.0.0"
has@^1.0.1:
has@^1.0.1, has@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
dependencies:
@ -4716,6 +4861,12 @@ json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
json2module@^0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/json2module/-/json2module-0.0.3.tgz#00fb5f4a9b7adfc3f0647c29cb17bcd1979be9b2"
dependencies:
rw "^1.3.2"
json2mq@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a"
@ -5337,7 +5488,7 @@ minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
@ -5913,6 +6064,10 @@ object-hash@^1.1.4:
version "1.3.0"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.0.tgz#76d9ba6ff113cf8efc0d996102851fe6723963e2"
object-inspect@~1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b"
object-keys@^1.0.8:
version "1.0.12"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2"
@ -7786,6 +7941,12 @@ resolve@^1.3.2, resolve@^1.5.0:
dependencies:
path-parse "^1.0.5"
resolve@~1.7.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3"
dependencies:
path-parse "^1.0.5"
restore-cursor@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
@ -7793,6 +7954,12 @@ restore-cursor@^2.0.0:
onetime "^2.0.0"
signal-exit "^3.0.2"
resumer@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759"
dependencies:
through "~2.3.4"
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
@ -7831,6 +7998,14 @@ rmc-feedback@^2.0.0:
babel-runtime "6.x"
classnames "^2.2.5"
rollup@^0.25.8:
version "0.25.8"
resolved "http://registry.npmjs.org/rollup/-/rollup-0.25.8.tgz#bf6ce83b87510d163446eeaa577ed6a6fc5835e0"
dependencies:
chalk "^1.1.1"
minimist "^1.2.0"
source-map-support "^0.3.2"
run-async@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
@ -7843,6 +8018,10 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
rw@^1.3.2:
version "1.3.3"
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
rx-lite-aggregates@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be"
@ -8183,6 +8362,12 @@ source-map-resolve@^0.5.0:
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-support@^0.3.2:
version "0.3.3"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.3.3.tgz#34900977d5ba3f07c7757ee72e73bb1a9b53754f"
dependencies:
source-map "0.1.32"
source-map-support@^0.4.15:
version "0.4.18"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f"
@ -8193,6 +8378,12 @@ source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
source-map@0.1.32:
version "0.1.32"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266"
dependencies:
amdefine ">=0.0.4"
source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
@ -8372,6 +8563,14 @@ string-width@^1.0.1, string-width@^1.0.2:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
string.prototype.trim@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea"
dependencies:
define-properties "^1.1.2"
es-abstract "^1.5.0"
function-bind "^1.0.2"
string_decoder@^1.0.0, string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
@ -8512,6 +8711,24 @@ tapable@^0.2.7:
version "0.2.8"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"
tape@^4.5.1:
version "4.9.1"
resolved "https://registry.yarnpkg.com/tape/-/tape-4.9.1.tgz#1173d7337e040c76fbf42ec86fcabedc9b3805c9"
dependencies:
deep-equal "~1.0.1"
defined "~1.0.0"
for-each "~0.3.3"
function-bind "~1.1.1"
glob "~7.1.2"
has "~1.0.3"
inherits "~2.0.3"
minimist "~1.2.0"
object-inspect "~1.6.0"
resolve "~1.7.1"
resumer "~0.0.0"
string.prototype.trim "~1.1.2"
through "~2.3.8"
tar@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
@ -8575,7 +8792,7 @@ through2@^2.0.0:
readable-stream "^2.1.5"
xtend "~4.0.1"
"through@>=2.2.7 <3", through@^2.3.6:
"through@>=2.2.7 <3", through@^2.3.6, through@~2.3.4, through@~2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@ -8716,7 +8933,7 @@ uglify-js@3.4.x, uglify-js@^3.0.13:
commander "~2.16.0"
source-map "~0.6.1"
uglify-js@^2.6, uglify-js@^2.8.29:
uglify-js@^2.6, uglify-js@^2.6.2, uglify-js@^2.8.29:
version "2.8.29"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
dependencies:
@ -8942,6 +9159,14 @@ vendors@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.2.tgz#7fcb5eef9f5623b156bcea89ec37d63676f21801"
venn.js@~0.2.20:
version "0.2.20"
resolved "https://registry.yarnpkg.com/venn.js/-/venn.js-0.2.20.tgz#3f0e50cc75cba1f58692a8a32f67bd7aaf1aa6fa"
dependencies:
d3-selection "^1.0.2"
d3-transition "^1.0.1"
fmin "0.0.2"
verror@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
@ -9161,6 +9386,10 @@ window-size@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
wolfy87-eventemitter@~5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/wolfy87-eventemitter/-/wolfy87-eventemitter-5.1.0.tgz#35c1ac0dd1ac0c15e35d981508fc22084a13a011"
wordwrap@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"

View file

@ -384,29 +384,29 @@ INSERT INTO link_clicks (campaign_id, subscriber_id, link_id)
-- name: get-dashboard-stats
WITH lists AS (
SELECT JSON_AGG(ROW_TO_JSON(row)) FROM (SELECT type, COUNT(id) AS num FROM lists GROUP BY type) row
SELECT JSON_OBJECT_AGG(type, num) FROM (SELECT type, COUNT(id) AS num FROM lists GROUP BY type) row
),
subs AS (
SELECT JSON_AGG(ROW_TO_JSON(row)) FROM (SELECT status, COUNT(id) AS num FROM subscribers GROUP by status) row
SELECT JSON_OBJECT_AGG(status, num) FROM (SELECT status, COUNT(id) AS num FROM subscribers GROUP by status) row
),
orphans AS (
SELECT COUNT(id) FROM subscribers LEFT JOIN subscriber_lists ON (subscribers.id = subscriber_lists.subscriber_id)
WHERE subscriber_lists.subscriber_id IS NULL
),
camps AS (
SELECT JSON_AGG(ROW_TO_JSON(row)) FROM (SELECT status, COUNT(id) AS num FROM campaigns GROUP by status) row
SELECT JSON_OBJECT_AGG(status, num) FROM (SELECT status, COUNT(id) AS num FROM campaigns GROUP by status) row
),
clicks AS (
-- Clicks by day for the last 3 months
SELECT JSON_AGG(ROW_TO_JSON(row))
FROM (SELECT COUNT(*) AS num, created_at::DATE as date
FROM (SELECT COUNT(*) AS count, created_at::DATE as date
FROM link_clicks GROUP by date ORDER BY date DESC LIMIT 100
) row
),
views AS (
-- Views by day for the last 3 months
SELECT JSON_AGG(ROW_TO_JSON(row))
FROM (SELECT COUNT(*) AS views, created_at::DATE as date
FROM (SELECT COUNT(*) AS count, created_at::DATE as date
FROM campaign_views GROUP by date ORDER BY date DESC LIMIT 100
) row
)