git ssb

16+

Dominic / patchbay



Commit 99b8a9a471f85c47bbb7f32dc108e456f881b14d

Merge branch 'master' into opinionate

Dominic Tarr committed on 11/11/2016, 4:29:22 PM
Parent: 9275fb674485193b85f4e7852ab00e1908d0c514
Parent: 40d9f59631c75631748ae50f24992ad6f2d515c3

Files changed

index.jschanged
modules_basic/invite.jschanged
modules_basic/search-box.jschanged
modules_basic/setup.jschanged
modules_basic/thread.jschanged
modules_core/tabs.jschanged
modules_extra/git.jschanged
modules_extra/index.jschanged
modules_extra/network.jschanged
modules_extra/theme.jsdeleted
package.jsonchanged
plugs.jschanged
style.csschanged
util.jschanged
basic.jsadded
index.jsView
@@ -3,7 +3,4 @@
33 require('./modules_basic'),
44 require('./modules_extra')
55 ).plugs.app[0]()
66
7-
8-
9-
modules_basic/invite.jsView
@@ -7,44 +7,24 @@
77 var Progress = require('hyperprogress')
88
99 var plugs = require('../plugs')
1010 var sbot_publish = plugs.first(exports.sbot_publish = [])
11 +var sbot_gossip_connect = plugs.first(exports.sbot_gossip_connect = [])
1112 var follower_of = plugs.first(exports.follower_of = [])
1213
13-
14-//check that invite is
15-// ws:...~shs:key:seed
16-function parseMultiServerInvite (invite) {
17- var redirect = invite.split('#')
18- if(!redirect.length) return null
19-
20- var parts = redirect[0].split('~')
21- .map(function (e) { return e.split(':') })
22-
23- if(parts.length !== 2) return null
24- if(!/^(net|wss?)$/.test(parts[0][0])) return null
25- if(parts[1][0] !== 'shs') return null
26- if(parts[1].length !== 3) return null
27- var p2 = invite.split(':')
28- p2.pop()
29-
30- return {
31- invite: redirect[0],
32- remote: p2.join(':'),
33- key: '@'+parts[1][1]+'.ed25519',
34- redirect: '#' + redirect.slice(1).join('#')
35- }
36-}
37-
3814 exports.invite_parse = function (invite) {
39- return parseMultiServerInvite(invite)
15 + return ref.parseInvite(invite)
4016 }
4117
4218 exports.invite_accept = function (invite, onProgress, cb) {
4319 var data = exports.invite_parse(invite)
4420 if(!data) return cb(new Error('not a valid invite code:' + invite))
4521
4622 onProgress('connecting...')
23 +
24 + sbot_gossip_connect(data.remote, function (err) {
25 + if(err) console.log(err)
26 + })
4727
4828 ssbClient(null, {
4929 remote: data.invite,
5030 manifest: { invite: {use: 'async'}, getAddress: 'async' }
@@ -82,9 +62,9 @@
8262 }
8363
8464 exports.screen_view = function (invite) {
8565
86- var data = parseMultiServerInvite(invite)
66 + var data = ref.parseInvite(invite)
8767 if(!data) return
8868
8969 var progress = Progress(4)
9070
@@ -125,4 +105,8 @@
125105
126106 return div
127107 }
128108
109 +
110 +
111 +
112 +
modules_basic/search-box.jsView
@@ -11,9 +11,9 @@
1111
1212 //TODO: this list should be generated from plugs
1313 var builtinTabs = [
1414 '/public', '/private', '/notifications',
15- '/network', '/query', '/theme', '/versions'
15 + '/network', '/query', '/versions'
1616 ].map(function (name) {
1717 return {
1818 title: name,
1919 value: name,
modules_basic/setup.jsView
@@ -39,34 +39,41 @@
3939 )
4040 }
4141
4242 function invite_form () {
43- var status = h('span')
4443 var accept = h('button', 'enter code', {disabled: true, onclick: function () {
4544 invite_accept(input.value, function (msg) {
4645 status.textContent = msg
4746 }, function (err) {
4847 if(err) {
49- status.textContent = 'error:'+err.message
48 + accept.textContent = 'error:'+(err.message || err.stack || error.type)
5049 console.error(err)
5150 }
52- else
53- status.textContent = 'success!'
51 + else {
52 + input.value = ''
53 + accept.textContent = 'success!'
54 + }
5455 })
5556 }})
56- var input = h('input', {placeholder: 'invite code', oninput: function () {
57- console.log(invite_parse(input.value))
58- if(!invite_parse(input.value)) {
57 +
58 + function parseInput () {
59 + if(!input.value) {
5960 accept.disabled = true
61 + accept.textContent = 'enter code'
62 + }
63 + else if(!invite_parse(input.value)) {
64 + accept.disabled = true
6065 accept.textContent = 'invalid code'
6166 }
6267 else {
6368 accept.disabled = false
6469 accept.textContent = 'accept'
6570 }
66- }})
71 + }
6772
68- return h('div.invite-form', status, input, accept)
73 + var input = h('input.wide', {placeholder: 'invite code', oninput: parseInput, onchange: parseInput})
74 +
75 + return h('div.invite-form.row', input, accept)
6976 }
7077
7178 exports.progress_bar = function () {
7279 var liquid = h('div.hyperprogress__liquid', '.')
@@ -89,9 +96,9 @@
8996 //when you join the network, I want this to show as people follow you.
9097 //that could be when a pub accepts the invite, or when a local peer accepts.
9198
9299 exports.setup_joined_network = function (id) {
93- var followers = h('div')
100 + var followers = h('div.column')
94101 var label = h('label', 'not connected to a network')
95102 var joined = h('div.setup__joined', label,followers)
96103
97104 pull(
@@ -118,22 +125,21 @@
118125
119126
120127 var status = h('span')
121128 var invite = h('input', {placeholder: 'invite code'})
122- return h('div.column',
129 + return h('div.scroller', h('div.scroller__wrapper',
123130 h('h1', 'welcome to patchbay!'),
124131 h('div',
125132 'please choose avatar image and name',
126133 avatar_edit(id)
127134 ),
128135 h('h2', 'join network'),
129- 'invite code',
130136 invite_form(),
131137 //show avatars of anyone on the same local network.
132138 //show realtime changes in your followers, especially for local.
133139
134140 exports.progress_bar(),
135141 exports.setup_joined_network(require('../keys').id)
136- )
142 + ))
137143 }
138144
139145
modules_basic/thread.jsView
@@ -68,9 +68,9 @@
6868 )
6969 )
7070
7171 message_name(id, function (err, name) {
72- div.id = name
72 + div.title = name
7373 })
7474
7575 pull(
7676 sbot_links({
modules_core/tabs.jsView
@@ -67,8 +67,9 @@
6767 saved = ['/public', '/private', '/notifications']
6868
6969 saved.forEach(function (path) {
7070 var el = screen_view(path)
71 + if(!el) return
7172 el.id = el.id || path
7273 if (!el) return
7374 el.scroll = keyscroll(el.querySelector('.scroller__content'))
7475 if(el) tabs.add(el, false, false)
modules_extra/git.jsView
@@ -14,50 +14,47 @@
1414 var sbot_get = plugs.first(exports.sbot_get = [])
1515 var getAvatar = require('ssb-avatar')
1616 var avatar_name = plugs.first(exports.avatar_name = [])
1717 var markdown = plugs.first(exports.markdown = [])
18 +var KVGraph = require('kvgraph')
19 +var mergeRepo = require('ssb-git/merge')
1820
1921 var self_id = require('../keys').id
2022
2123 function shortRefName(ref) {
2224 return ref.replace(/^refs\/(heads|tags)\//, '')
2325 }
2426
2527 function getRefs(msg) {
26- var refs = {}
27- var commitTitles = {}
28- return pull(
28 + var updates = new KVGraph('key')
29 + var _cb, _refs
30 + pull(
2931 sbot_links({
3032 reverse: true,
31- source: msg.value.author,
33 + // source: msg.value.author,
3234 dest: msg.key,
3335 rel: 'repo',
3436 values: true
3537 }),
36- pull.map(function (link) {
37- var refUpdates = link.value.content.refs || {}
38- var commits = link.value.content.commits
39- if(commits) {
40- for(var i = 0; i < commits.length; i++) {
41- var commit = commits[i]
42- if(commit && commit.sha1 && commit.title) {
43- commitTitles[commit.sha1] = commit.title
44- }
45- }
38 + pull.drain(function (link) {
39 + if (link.value.content.type === 'git-update') {
40 + updates.add(link)
4641 }
47- return Object.keys(refUpdates).reverse().map(function (ref) {
48- if(refs[ref]) return
49- refs[ref] = true
50- var rev = refUpdates[ref]
51- if(!rev) return
52- return {
53- name: ref,
54- rev: rev,
55- link: link,
56- title: commitTitles[rev],
57- }
58- }).filter(Boolean)
59- }),
42 + }, function (err) {
43 + var refs = updates.reduceRight(mergeRepo).refs
44 + var cb = _cb
45 + if (cb) delete _cb, cb(err, refs)
46 + else _refs = refs
47 + })
48 + )
49 +
50 + return pull(
51 + function fn(end, cb) {
52 + if (end || fn.ended) cb(true)
53 + fn.ended = true
54 + if (_refs) cb(_refs)
55 + else _cb = cb
56 + },
6057 pull.flatten()
6158 )
6259 }
6360
@@ -194,15 +191,22 @@
194191 this.parentNode.replaceChild(pullRequestForm(msg), this)
195192 }}, 'New Pull Request…')))
196193
197194 pull(getRefs(msg), pull.drain(function (ref) {
198- var parts = /^refs\/(heads|tags)\/(.*)$/.exec(ref.name) || []
195 + var name = ref.realname || ref.name
196 + var author = ref.link && ref.link.value.author
197 + var parts = /^refs\/(heads|tags)\/(.*)$/.exec(name) || []
198 + var shortName = parts[2]
199199 var t
200200 if(parts[1] === 'heads') t = branchesT
201201 else if(parts[1] === 'tags') t = tagsT
202202 if(t) t.append(h('tr',
203- h('td', parts[2]),
204- h('td', h('code', ref.rev)),
203 + h('td', shortName,
204 + ref.conflict ? [
205 + h('br'),
206 + h('a', {href: '#'+author}, avatar_name(author))
207 + ] : ''),
208 + h('td', h('code', ref.hash)),
205209 h('td', messageTimestampLink(ref.link))))
206210 }, function (err) {
207211 if(err) console.error(err)
208212 }))
@@ -288,9 +292,10 @@
288292 }) : null
289293 ]
290294 }
291295
292- if(c.type === 'issue-edit') {
296 + if(c.type === 'issue-edit'
297 + || (c.type === 'post' && c.text === '')) {
293298 return h('div',
294299 c.issue ? renderIssueEdit(c) : null,
295300 c.issues ? c.issues.map(renderIssueEdit) : null)
296301 }
@@ -368,9 +373,9 @@
368373 if(full) {
369374 var updated = new Date(ref.link.value.timestamp)
370375 label = branch +
371376 ' · ' + human(updated) +
372- ' · ' + ref.rev.substr(1, 8) +
377 + ' · ' + ref.hash.substr(1, 8) +
373378 (ref.title ? ' · "' + ref.title + '"' : '')
374379 }
375380 return h('option', {value: branch}, label)
376381 }))
modules_extra/index.jsView
@@ -10,8 +10,8 @@
1010 "query.js": require('./query.js'),
1111 "raw.js": require('./raw.js'),
1212 "search.js": require('./search'),
1313 "split.js": require('./split.js'),
14- "theme.js": require('./theme.js'),
1514 "versions.js": require('./versions.js')
1615 }
1716
17 +
modules_extra/network.jsView
@@ -37,9 +37,9 @@
3737
3838 //pub is running scuttlebot < 8
3939 //have connected sucessfully
4040 function isLegacy (peer) {
41- return /connect/.test(peer.state) || (peer.duration && peer.duration.mean > 0 && !isLongterm(peer))
41 + return /connect/.test(peer.state) || (peer.duration && peer.duration.mean) > 0 && !isLongterm(peer)
4242 }
4343
4444 //tried to connect, but failed.
4545 function isInactive (e) {
@@ -142,7 +142,7 @@
142142
143143 })()
144144
145145 return h('div.column.scroll-y', ol)
146-
147146 }
148147
148 +
modules_extra/theme.jsView
@@ -1,167 +1,0 @@
1-var h = require('hyperscript')
2-var pull = require('pull-stream')
3-var plugs = require('../plugs')
4-var cat = require('pull-cat')
5-
6-var sbot_links2 = plugs.first(exports.sbot_links2 = [])
7-var avatar_name = plugs.first(exports.avatar_name = [])
8-var blob_url = require('../plugs').first(exports.blob_url = [])
9-
10-var defaultTheme = {
11- id: '&JFa42U6HtPm9k+s+AmpDIAoTJJI/PzoRC/J/WCfduDY=.sha256',
12- name: 'patchbay-minimal.css'
13-}
14-
15-var next = 'undefined' === typeof setImmediate ? setTimeout : setImmediate
16-
17-if('undefined' !== typeof document)
18- var link = document.head.appendChild(h('link', {rel: 'stylesheet'}))
19-
20-var activeTheme
21-
22-function useTheme(id) {
23- activeTheme = id
24- link.href = id ? blob_url(id) : ''
25- var forms = [].slice.call(document.querySelectorAll('.themes__form'))
26- forms.forEach(updateForm)
27-
28- var radios = [].slice.call(document.querySelectorAll('input[type=radio]'))
29- radios.forEach(function (radio) {
30- radio.checked = (radio.value === activeTheme)
31- })
32-}
33-
34-function useSavedTheme() {
35- //enable setting "NONE" as your theme, and having that persist.
36- useTheme(localStorage.themeId == null ? defaultTheme.id : localStorage.themeId)
37-}
38-
39-next(useSavedTheme)
40-
41-function themes() {
42- return cat([
43- pull.values([
44- {
45- id: '',
46- name: 'none',
47- feed: ''
48- },
49- defaultTheme,
50- ]),
51- pull(
52- sbot_links2({
53- query: [
54- {$filter: {rel: ['mentions', {$prefix: 'patchbay-'}]}},
55- {$filter: {dest: {$prefix: '&'}}},
56- {$map: {id: 'dest', feed: 'source', name: ['rel', 1]}}
57- ],
58- live: true,
59- sync: false,
60- }),
61- pull.filter(function (link) {
62- return /\.css$/.test(link.name)
63- })
64- )
65- ])
66-}
67-
68-function onRadioClick(e) {
69- if (this.checked) useTheme(this.value)
70-}
71-
72-function updateForm(form) {
73- var same = localStorage.themeId === activeTheme
74- form.querySelector('.themes__id').value = activeTheme
75- form.querySelector('.themes__reset').disabled = same
76- form.querySelector('.themes__submit').disabled = same
77- return form
78-}
79-
80-function renderTheme(link) {
81- return h('div.theme',
82- h('input', {type: 'radio', name: 'theme',
83- value: link.id, onclick: onRadioClick,
84- checked: link.id === activeTheme
85- }),
86- link.id ? h('a', {href: '#'+link.id}, link.name) : link.name, ' ',
87- link.feed ? h('a', {href: '#'+link.feed}, avatar_name(link.feed)) : ''
88- )
89-}
90-
91-function insertAfter(parentNode, newNode, referenceNode) {
92- var nextSibling = referenceNode && referenceNode.nextSibling
93- if (nextSibling) parentNode.insertBefore(newNode, nextSibling)
94- else parentNode.appendChild(newNode)
95-}
96-
97-function theme_view() {
98- var themeInput
99- var themesList = h('form.themes__list')
100- var themesPerFeed = {/* feedid: {blobid||name: theme} */}
101-
102- pull(
103- themes(),
104- pull.drain(function (theme) {
105- var map = themesPerFeed[theme.feed] || (themesPerFeed[theme.feed] = {})
106- // replace old theme
107- var prevByName = map[theme.name]
108- var prevById = map[theme.id]
109- theme.el = renderTheme(theme)
110- map[theme.name] = theme
111- map[theme.id] = theme
112- if (prevById) {
113- // remove theme which is having its id reused
114- themesList.removeChild(prevById.el)
115- // prevById.el.appendChild(document.createTextNode(' (renamed)'))
116- if (prevById === prevByName) {
117- prevByName = null
118- }
119- }
120- if (prevByName) {
121- // update theme
122- if (prevByName.id === localStorage.themeId
123- || prevByName.id === activeTheme) {
124- // keep old version because the user is still using it
125- prevByName.el.appendChild(document.createTextNode(' (old)'))
126- insertAfter(themesList, theme.el, prevByName.el)
127- } else {
128- // replace old version
129- themesList.replaceChild(theme.el, prevByName.el)
130- }
131- } else {
132- // show new theme
133- themesList.appendChild(theme.el)
134- }
135- }, function (err) {
136- if (err) console.error(err)
137- })
138- )
139-
140- return h('div.column.scroll-y', h('div',
141- updateForm(h('form.themes__form', {onsubmit: onsubmit, onreset: onreset},
142- themeInput = h('input.themes__id', {placeholder: 'theme id',
143- value: link.href}), ' ',
144- h('input.themes__reset', {type: 'reset'}), ' ',
145- h('input.themes__submit', {type: 'submit', value: 'Save'}))),
146- themesList
147- ))
148-
149- function onsubmit(e) {
150- e.preventDefault()
151- useTheme(localStorage.themeId = themeInput.value)
152- }
153-
154- function onreset(e) {
155- e.preventDefault()
156- useSavedTheme()
157- }
158-}
159-
160-exports.menu_items = function () {
161- return h('a', {href:'#/theme'}, '/theme')
162-}
163-
164-exports.screen_view = function (path) {
165- if(path === '/theme') return theme_view()
166-}
167-
package.jsonView
@@ -1,8 +1,8 @@
11 {
22 "name": "patchbay",
33 "description": "a pluggable patchwork",
4- "version": "3.5.0",
4 + "version": "4.1.0",
55 "homepage": "https://github.com/dominictarr/patchbay",
66 "repository": {
77 "type": "git",
88 "url": "git://github.com/dominictarr/patchbay.git"
@@ -20,8 +20,9 @@
2020 "hyperprogress": "0.1.0",
2121 "hyperscript": "^1.4.7",
2222 "hypertabs": "^2.2.0",
2323 "is-visible": "^2.0.4",
24 + "kvgraph": "^0.1.0",
2425 "map-filter-reduce": "^3.0.1",
2526 "mime-types": "^2.1.11",
2627 "moment": "^2.13.0",
2728 "open-external": "^0.1.1",
@@ -40,13 +41,15 @@
4041 "ssb-avatar": "^0.2.0",
4142 "ssb-client": "^4.0.3",
4243 "ssb-config": "^2.1.1",
4344 "ssb-feed": "^2.2.1",
45 + "ssb-git": "^0.4.1",
4446 "ssb-keys": "^6.1.0",
4547 "ssb-links": "^2.0.0",
4648 "ssb-markdown": "^3.0.0",
4749 "ssb-mentions": "^0.1.0",
4850 "ssb-query": "^0.1.1",
51 + "ssb-ref": "^2.6.2",
4952 "ssb-sort": "^1.0.0",
5053 "ssb-ws": "^0.6.2",
5154 "suggest-box": "^2.2.1",
5255 "text-node-searcher": "^1.1.0",
@@ -63,6 +66,4 @@
6366 "author": "Dominic Tarr <dominic.tarr@gmail.com> (http://dominictarr.com)",
6467 "license": "MIT"
6568 }
6669
67-
68-
plugs.jsView
@@ -17,7 +17,4 @@
1717 }
1818 }
1919
2020
21-
22-
23-
style.cssView
@@ -68,8 +68,12 @@
6868 white-space: pre-wrap;
6969 word-wrap: break-word;
7070 }
7171
72 +.wide {
73 + width: 100%;
74 +}
75 +
7276 p {
7377 margin-top: .35ex;
7478 }
7579
@@ -365,19 +369,8 @@
365369 .error {
366370 background: red;
367371 }
368372
369-/* themes */
370-
371-.theme {
372- margin-left: 1ex;
373-}
374-
375-.themes__form {
376- margin: 1ex;
377-}
378-
379-
380373 /* tabs */
381374
382375 .header {
383376 background: #f5f5f5;
@@ -447,4 +440,15 @@
447440
448441 .screen {
449442 background: #f5f5f5
450443 }
444 +
445 +/* progress bar */
446 +
447 +.hyperprogress__bar {
448 + background: darkgrey;
449 +}
450 +.hyperprogress__liquid {
451 + background: lightblue;
452 +}
453 +
454 +
util.jsView
@@ -48,7 +48,4 @@
4848 }
4949
5050
5151
52-
53-
54-
basic.jsView
@@ -1,0 +1,6 @@
1 +require('depject')(
2 + require('./modules_core'),
3 + require('./modules_basic')
4 +).plugs.app[0]()
5 +
6 +

Built with git-ssb-web