Commit a893a560b31905d216fdb21487f862a094bb7d6f
MVP workings stats on stats page
mix irving committed on 4/19/2018, 12:21:03 AMParent: 0dff233ce29767d6fc042cf4bf59dcecdb8b347d
Files changed
app/page/statsShow.js | changed |
app/page/statsShow.mcss | changed |
ssb-server-blog-stats.js | changed |
app/page/statsShow.js | ||
---|---|---|
@@ -1,7 +1,8 @@ | ||
1 | 1 | const nest = require('depnest') |
2 | -const { h, Value, Struct, Array: MutantArray, Dict, onceTrue, map, computed, dictToCollection } = require('mutant') | |
2 | +const { h, Value, Struct, Array: MutantArray, Dict, onceTrue, map, computed, dictToCollection, throttle } = require('mutant') | |
3 | 3 | const pull = require('pull-stream') |
4 | +const marksum = require('markdown-summary') | |
4 | 5 | |
5 | 6 | exports.gives = nest('app.page.statsShow') |
6 | 7 | |
7 | 8 | exports.needs = nest({ |
@@ -20,20 +21,20 @@ | ||
20 | 21 | }) |
21 | 22 | |
22 | 23 | var howFarBack = Value(0) |
23 | 24 | // stats show a moving window of 30 days |
24 | - const now = Date.now() | |
25 | 25 | const thirtyDays = 30 * 24 * 60 * 60 * 1000 |
26 | 26 | |
27 | 27 | // TODO |
28 | 28 | var range = computed([howFarBack], howFarBack => { |
29 | + const now = Date.now() | |
29 | 30 | return { |
30 | 31 | upper: now - howFarBack * thirtyDays, |
31 | 32 | lower: now - (howFarBack + 1) * thirtyDays |
32 | 33 | } |
33 | 34 | }) |
34 | 35 | |
35 | - var rangeComments = computed([dictToCollection(store.comments), range], (comments, range) => { | |
36 | + var rangeComments = computed([throttle(dictToCollection(store.comments), 1000), range], (comments, range) => { | |
36 | 37 | return comments |
37 | 38 | .map(c => c.value) |
38 | 39 | .reduce((n, sofar) => [...n, ...sofar], []) |
39 | 40 | .filter(msg => { |
@@ -41,9 +42,9 @@ | ||
41 | 42 | return ts >= range.lower && ts <= range.upper |
42 | 43 | }) |
43 | 44 | }) |
44 | 45 | |
45 | - var rangeLikes = computed([dictToCollection(store.likes), range], (likes, range) => { | |
46 | + var rangeLikes = computed([throttle(dictToCollection(store.likes), 1000), range], (likes, range) => { | |
46 | 47 | return likes |
47 | 48 | .map(c => c.value) |
48 | 49 | .reduce((n, sofar) => [...n, ...sofar], []) |
49 | 50 | .filter(msg => { |
@@ -97,10 +98,10 @@ | ||
97 | 98 | ]), |
98 | 99 | h('section.graph', [ |
99 | 100 | // TODO insert actual graph |
100 | 101 | h('div', [ |
101 | - h('div', [ 'Comments ', map(rangeComments, msg => [new Date(msg.value.timestamp).toDateString(), ' ']) ]), | |
102 | - h('div', [ 'Likes ', map(rangeLikes, msg => [new Date(msg.value.timestamp).toDateString(), ' ']) ]) | |
102 | + // h('div', [ 'Comments ', map(rangeComments, msg => [new Date(msg.value.timestamp).toDateString(), ' ']) ]), | |
103 | + // h('div', [ 'Likes ', map(rangeLikes, msg => [new Date(msg.value.timestamp).toDateString(), ' ']) ]) | |
103 | 104 | ]), |
104 | 105 | h('div', [ |
105 | 106 | h('a', { href: '#', 'ev-click': () => howFarBack.set(howFarBack() + 1) }, '< Prev 30 days'), |
106 | 107 | ' | ', |
@@ -115,11 +116,11 @@ | ||
115 | 116 | h('th.comment', 'Comments'), |
116 | 117 | h('th.likes', 'Likes') |
117 | 118 | ]) |
118 | 119 | ]), |
119 | - h('tbody', map(store.blogs, blog => h('tr.blog', [ | |
120 | + h('tbody', map(store.blogs, blog => h('tr.blog', { id: blog.key }, [ | |
120 | 121 | h('td.details', [ |
121 | - h('div.title', {}, blog.value.content.title), | |
122 | + h('div.title', {}, getTitle(blog)), | |
122 | 123 | h('a', |
123 | 124 | { |
124 | 125 | href: '#', |
125 | 126 | 'ev-click': viewBlog(blog) |
@@ -128,8 +129,9 @@ | ||
128 | 129 | ) |
129 | 130 | ]), |
130 | 131 | h('td.comments', computed(store.comments.get(blog.key), msgs => msgs ? msgs.length : 0)), |
131 | 132 | h('td.likes', computed(store.likes.get(blog.key), msgs => msgs ? msgs.length : 0)) |
133 | + // ]), { comparer: (a, b) => a === b })) | |
132 | 134 | ]))) |
133 | 135 | ]) |
134 | 136 | ]) |
135 | 137 | ]) |
@@ -139,8 +141,14 @@ | ||
139 | 141 | return () => api.history.sync.push(blog) |
140 | 142 | } |
141 | 143 | } |
142 | 144 | |
145 | +function getTitle (blog) { | |
146 | + if (blog.value.content.title) return blog.value.content.title | |
147 | + else if (blog.value.content.text) return marksum.title(blog.value.content.text) | |
148 | + else return blog.key | |
149 | +} | |
150 | + | |
143 | 151 | function fetchBlogs ({ server, store }) { |
144 | 152 | pull( |
145 | 153 | server.blogStats.readBlogs({ reverse: false }), |
146 | 154 | pull.drain(blog => { |
@@ -156,10 +164,10 @@ | ||
156 | 164 | if (!store.comments.has(blog.key)) store.comments.put(blog.key, MutantArray()) |
157 | 165 | |
158 | 166 | pull( |
159 | 167 | server.blogStats.readComments(blog), |
160 | - pull.drain(comment => { | |
161 | - store.comments.get(blog.key).push(comment) | |
168 | + pull.drain(msg => { | |
169 | + store.comments.get(blog.key).push(msg) | |
162 | 170 | // TODO remove my comments from count? |
163 | 171 | }) |
164 | 172 | ) |
165 | 173 | } |
@@ -168,10 +176,10 @@ | ||
168 | 176 | if (!store.likes.has(blog.key)) store.likes.put(blog.key, MutantArray()) |
169 | 177 | |
170 | 178 | pull( |
171 | 179 | server.blogStats.readLikes(blog), |
172 | - pull.drain(comment => { | |
173 | - store.likes.get(blog.key).push(comment) | |
180 | + pull.drain(msg => { | |
181 | + store.likes.get(blog.key).push(msg) | |
174 | 182 | // TODO this needs reducing... like + unlike are muddled in here |
175 | 183 | // find any thing by same author |
176 | 184 | // if exists - over-write or delete |
177 | 185 | }) |
app/page/statsShow.mcss | ||
---|---|---|
@@ -2,9 +2,9 @@ | ||
2 | 2 | div.content { |
3 | 3 | flex-grow: 0 |
4 | 4 | $backgroundPrimaryText |
5 | 5 | margin-top: 1rem |
6 | - width: 800px | |
6 | + width: 1000px | |
7 | 7 | |
8 | 8 | h1 { |
9 | 9 | font-size: .8rem |
10 | 10 | letter-spacing: 4px |
ssb-server-blog-stats.js | ||
---|---|---|
@@ -9,9 +9,9 @@ | ||
9 | 9 | const getCommentRoot = (msg) => get(msg, 'value.content.root') |
10 | 10 | const getLikeRoot = (msg) => get(msg, 'value.content.vote.link') |
11 | 11 | const getTimestamp = (msg) => get(msg, 'value.timestamp') |
12 | 12 | |
13 | -const FLUME_VIEW_VERSION = 5 | |
13 | +const FLUME_VIEW_VERSION = 1 | |
14 | 14 | |
15 | 15 | module.exports = { |
16 | 16 | name: 'blogStats', |
17 | 17 | version: 1, |
@@ -47,9 +47,9 @@ | ||
47 | 47 | var root |
48 | 48 | |
49 | 49 | switch (getType(msg)) { |
50 | 50 | case 'blog': |
51 | - if (isBlog(msg) && myBlog(msg)) return [['B', msg.key, getTimestamp(msg)]] | |
51 | + if (isBlog(msg) && isMyMsg(msg)) return [['B', msg.key, getTimestamp(msg)]] | |
52 | 52 | else return [] |
53 | 53 | |
54 | 54 | case 'vote': |
55 | 55 | // process.stdout.write('L') |
@@ -62,12 +62,13 @@ | ||
62 | 62 | // - all likes, on all things D: |
63 | 63 | // - likes AND unlikes |
64 | 64 | |
65 | 65 | case 'post': |
66 | - // process.stdout.write('C') | |
66 | + // process.stdout.write('POST ') | |
67 | 67 | root = getCommentRoot(msg) |
68 | - // TODO figure out how to only store likes I care about | |
69 | - if (root) return [['C', root, getTimestamp(msg)]] | |
68 | + // TODO figure out how to only store comments I care about | |
69 | + if (!root && isMyMsg(msg) && isPlog(msg)) return [['B', msg.key, getTimestamp(msg)]] | |
70 | + else if (root) return [['C', root, getTimestamp(msg)]] | |
70 | 71 | else return [] |
71 | 72 | |
72 | 73 | // Note this catches: |
73 | 74 | // - all comments, on all things D: |
@@ -76,8 +77,15 @@ | ||
76 | 77 | return [] |
77 | 78 | } |
78 | 79 | } |
79 | 80 | |
81 | + // a Plog is a Blog shaped Post | |
82 | + function isPlog (msg) { | |
83 | + // return false // Disable plogs | |
84 | + if (get(msg, 'value.content.text', '').length >= 3000) console.log(get(msg, 'value.content.text', '').length) | |
85 | + return get(msg, 'value.content.text', '').length >= 3000 | |
86 | + } | |
87 | + | |
80 | 88 | function readBlogs (options = {}) { |
81 | 89 | const query = Object.assign({}, { |
82 | 90 | gte: ['B', null, null], |
83 | 91 | // null is the 'minimum' structure in bytewise ordering |
@@ -98,11 +106,9 @@ | ||
98 | 106 | ) |
99 | 107 | } |
100 | 108 | |
101 | 109 | function readComments (blog, options = {}) { |
102 | - var key | |
103 | - if (isMsgRef(blog)) key = blog | |
104 | - else if (isMsgRef(blog.key) && isBlog(blog)) key = blog.key | |
110 | + var key = getBlogKey(blog) | |
105 | 111 | |
106 | 112 | const query = Object.assign({}, { |
107 | 113 | gt: ['C', key, null], |
108 | 114 | lt: ['C', key, undefined], |
@@ -116,11 +122,9 @@ | ||
116 | 122 | return view.read(query) |
117 | 123 | } |
118 | 124 | |
119 | 125 | function readLikes (blog, options = {}) { |
120 | - var key | |
121 | - if (isMsgRef(blog)) key = blog | |
122 | - else if (isMsgRef(blog.key) && isBlog(blog)) key = blog.key | |
126 | + var key = getBlogKey(blog) | |
123 | 127 | |
124 | 128 | const query = Object.assign({}, { |
125 | 129 | // gt: ['L', key, null], |
126 | 130 | // lt: ['L', key, undefined], // why doesn't this work? |
@@ -134,9 +138,15 @@ | ||
134 | 138 | |
135 | 139 | return view.read(query) |
136 | 140 | } |
137 | 141 | |
138 | - function myBlog (msg) { | |
142 | + function getBlogKey (blog) { | |
143 | + if (isMsgRef(blog)) return blog | |
144 | + // else if (isMsgRef(blog.key) && isBlog(blog)) return blog.key | |
145 | + else if (isMsgRef(blog.key) && (isBlog(blog) || isPlog(blog))) return blog.key | |
146 | + } | |
147 | + | |
148 | + function isMyMsg (msg) { | |
139 | 149 | return getAuthor(msg) === myKey |
140 | 150 | } |
141 | 151 | } |
142 | 152 | } |
Built with git-ssb-web