Skip to content

Commit

Permalink
Merge pull request #15 from blockades/search-and-show
Browse files Browse the repository at this point in the history
Search and show
  • Loading branch information
Kieran Gibb authored Jul 2, 2019
2 parents f17b0d9 + 16ed092 commit 1697a5d
Show file tree
Hide file tree
Showing 11 changed files with 342 additions and 31 deletions.
72 changes: 41 additions & 31 deletions src/components/AddPeer.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
const { h, resolve } = require('mutant')
const { h, Value, computed, resolve } = require('mutant')
const addSuggest = require('suggest-box')
const { isFeedId } = require('ssb-ref')
const { isFeedId } = require('ssb-ref')

module.exports = function AddPeer (props = {}, children = []) {
const {
peers,
selected,
suggest,
secrets = Value(),
max = 1,
placeholder = '',
onChange = console.log,
onSubmit = console.log,
canClear = false
} = props

var theSecrets = secrets()

const state = {
peers,
selected,
min: 0,
max,
isEmpty: true
}

const input = h('input', { placeholder })
suggestify(input, suggest, state, ({ state, link, name, e }) => {
addRecp({ state, link, name }, (err) => {
suggestify(input, suggest, state, (e) => {
var matched = e.detail

select({ state, matched }, (err) => {
if (err) console.error(err)

e.target.value = ''
Expand All @@ -32,7 +37,7 @@ module.exports = function AddPeer (props = {}, children = []) {
})

input.addEventListener('keydown', (e) => {
if (state.peers.getLength() >= max && !isBackspace(e)) {
if (state.selected.getLength() >= max && !isBackspace(e)) {
e.preventDefault()
return false
}
Expand All @@ -43,7 +48,7 @@ module.exports = function AddPeer (props = {}, children = []) {
state.isEmpty = wasEmpty && e.target.value.length === 0

if (isFeedId(e.target.value)) {
addRecp({ state, link: e.target.value }, (err) => {
select({ state, link: e.target.value }, (err) => {
if (err) console.error(err)

e.target.value = ''
Expand All @@ -52,8 +57,8 @@ module.exports = function AddPeer (props = {}, children = []) {
return
}

if (isBackspace(e) && state.isEmpty && state.peers.getLength() > state.min) {
peers.pop()
if (isBackspace(e) && state.isEmpty && state.selected.getLength() > state.min) {
selected.pop()
onChange()
}

Expand All @@ -67,42 +72,47 @@ module.exports = function AddPeer (props = {}, children = []) {
}, [
input,
canClear ? h('i.fa.fa-times', {
'ev-click': (e) => state.peers.set([]),
'ev-click': (e) => state.selected.set([]),
'style': { 'cursor': 'pointer' },
'title': 'Clear'
}) : h('div'),
...children
])
}

function suggestify (input, suggest, state, callback) {
// TODO use a legit module to detect whether ready
if (!input.parentElement) return setTimeout(() => suggestify(input, suggest, state, callback), 100)
function suggestify (input, suggest, state, callback) {
if (!input.parentElement) return setTimeout(() => suggestify(input, suggest, state, callback), 100)

addSuggest(input, (inputText, cb) => {
if (state.peers.getLength() >= state.max) return
// TODO - tell the user they're only allowed 6 (or 7?!) people in a message
addSuggest(input, (inputText, cb) => {
if (state.selected.getLength() >= state.max) return

if (isFeedId(inputText)) return
// suggest mention not needed, handled by eventListener above
if (isFeedId(inputText)) return

const searchTerm = inputText.replace(/^@/, '')
suggest.about(searchTerm, cb)
}, {cls: 'PatchSuggest'})
if (inputText.match(/^@/)) {
const searchTerm = inputText.replace(/^@/, '')
suggest.about(searchTerm, cb)
} else {
secrets = resolve(theSecrets)
if (!secrets) return

input.addEventListener('suggestselect', (e) => {
const { id: link, title: name } = e.detail
callback({ state, link, name, e })
})
var secrets = secrets
.filter(secret => secret.name.startsWith(inputText))
.map(s => Object.assign(s, { title: s.name, subtitle: s.createdAt, value: s.id }))

if (secrets.length) cb(null, secrets)
}
}, {cls: 'PatchSuggest'})

input.addEventListener('suggestselect', callback)
}
}

function addRecp ({ state, link, name }, cb) {
const isAlreadyPresent = resolve(state.peers).find(r => r === link || r.link === link)
function select ({ state, matched }, cb) {
const isAlreadyPresent = resolve(state.selected).find(r => r === matched.link || r.link === matched.link)
if (isAlreadyPresent) return cb(new Error('can only add each peer once'))

if (state.peers.getLength() >= state.max) return cb(new Error(`cannot add any more peers, already at max (${state.max})`))
if (state.selected.getLength() >= state.max) return cb(new Error(`cannot add any more selected, already at max (${state.max})`))

state.peers.push({ link, name })
state.selected.push(matched)
cb(null)
}

Expand Down
11 changes: 11 additions & 0 deletions src/components/NavBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ const Minimize = require('../components/Minimize')

const { isSettingsNamespace } = require('../routes')

const Search = require('./Search')

module.exports = function NavBar (props = {}, children = []) {
const {
routeTo,
goBack,
request,
suggest,
secrets,
myId
} = props

Expand All @@ -38,6 +41,14 @@ module.exports = function NavBar (props = {}, children = []) {
}
})
])
]),
h('section.bottom', [
Search({
suggest,
secrets,
routeTo,
myId
})
])
])

Expand Down
28 changes: 28 additions & 0 deletions src/components/Search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const { h, Array: MutantArray, resolve } = require('mutant')

const { isFeedId } = require('ssb-ref')
const AddPeer = require('./AddPeer')

module.exports = function Search (props = {}, children = []) {
const { suggest, secrets, routeTo, myId } = props
const state = {
selected: MutantArray([])
}

return h('div.search', [
h('i.fa.fa-search.fa-lg'),
AddPeer({
suggest,
secrets,
selected: state.selected,
max: 1,
canClear: false,
onSubmit: () => {
const record = resolve(state.selected)[0]
if (record.id === myId) routeTo({ path: `/settings/account` })
else if (isFeedId(record.id)) routeTo({ path: `/peers/${record.id}`, peer: { id: record.id } })
else routeTo({ path: `/secrets/${record.id}`, secret: record })
}
}, [ h('div') ])
])
}
7 changes: 7 additions & 0 deletions src/components/Search.mcss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
div.search {
display: grid
grid-template-columns: auto 1fr auto
justify-content: center
align-items: center
grid-gap: 0.5rem
}
9 changes: 9 additions & 0 deletions src/router/sync/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ exports.needs = nest({
'views.secrets.new.custodians': 'first',
'views.secrets.new.trust': 'first',
'views.secrets.new.submit': 'first',
'views.peers.show': 'first',
'views.shards.show': 'first',
'views.settings.account.index': 'first',
'views.settings.network.index': 'first',
})
Expand All @@ -32,6 +34,9 @@ const {
SecretsNewTrustPath,
SecretsNewSubmitPath,

ShardsShowPath,
PeersShowPath,

SettingsIndexPath,
SettingsAccountIndexPath,
SettingsNetworkIndexPath
Expand All @@ -42,6 +47,8 @@ exports.create = (api) => {
const {
root,
secrets,
shards,
peers,
settings,
layouts
} = api.views
Expand All @@ -56,6 +63,8 @@ exports.create = (api) => {
[ SecretsNewCustodiansPath, { view: secrets.new.custodians } ],
[ SecretsNewTrustPath, { view: secrets.new.trust } ],
[ SecretsNewSubmitPath, { view: secrets.new.submit } ],
[ PeersShowPath, { view: peers.show } ],
[ ShardsShowPath, { view: shards.show } ],
[ SettingsIndexPath, { view: settings.account.index, layout: layouts.settings } ],
[ SettingsAccountIndexPath, { view: settings.account.index, layout: layouts.settings } ],
[ SettingsNetworkIndexPath, { view: settings.network.index, layout: layouts.settings } ]
Expand Down
6 changes: 6 additions & 0 deletions src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const SecretsNewSubmitPath = (request) => (
request.state.quorum && request.state.peers && request.path === `/secrets/new/submit`
)

const PeersShowPath = (request) => request.peer && request.path === `/peers/${request.peer.id}`
const ShardsShowPath = (request) => request.shard && request.path === `/shards/${request.shard.id}`

const SettingsIndexPath = (request) => request.path === `/settings`
const SettingsAccountIndexPath = (request) => request.path === `/settings/account`
const SettingsNetworkIndexPath = (request) => request.path === `/settings/network`
Expand All @@ -43,6 +46,9 @@ module.exports = {
SecretsNewTrustPath,
SecretsNewSubmitPath,

PeersShowPath,
ShardsShowPath,

SettingsIndexPath,
SettingsAccountIndexPath,
SettingsNetworkIndexPath,
Expand Down
2 changes: 2 additions & 0 deletions src/views/layouts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ exports.needs = nest({
'router.sync.goTo': 'first',
'router.sync.goBack': 'first',
'about.async.suggest': 'first',
'app.actions.secrets.fetch': 'first',
'keys.sync.id': 'first'
})

Expand All @@ -21,6 +22,7 @@ exports.create = (api) => {
routeTo: api.router.sync.goTo,
goBack: api.router.sync.goBack,
suggest: { about: api.about.async.suggest },
secrets: api.app.actions.secrets.fetch,
myId: api.keys.sync.id(),
request
}),
Expand Down
64 changes: 64 additions & 0 deletions src/views/peers/show.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const nest = require('depnest')
const { h, computed, Value } = require('mutant')

const Avatar = require('../../components/Avatar')
const Backward = require('../../components/Backward')

exports.gives = nest('views.peers.show')

exports.needs = nest({
'app.actions.shards.fetch': 'first',
'router.sync.goTo': 'first',
'router.sync.goBack': 'first',
'about.obs.imageUrl': 'first',
'about.obs.name': 'first'
})

exports.create = (api) => {
return nest('views.peers.show', peersShow)

// This design isn't right. I've put together something to show for the moment.
// %%TODO%%: Redesign the peersShow interface and the shardsShow interface

function peersShow (request, children = []) {
const state = {
id: request.peer.id
}

return h('Peers -show', [
Backward({ routeTo: api.router.sync.goBack }),
h('div.container', [
h('section.profile', [
h('div.left', [
Avatar({
id: state.id,
imageUrl: api.about.obs.imageUrl,
size: 6
})
]),
h('div.right', [
h('p', 'Shards you hold belonging to: '),
h('div.name', [ h('strong', api.about.obs.name(state.id)) ])
])
]),
computed(api.app.actions.shards.fetch(), (shards) => {
if (!shards.length) return h('i.fa.fa-spinner.fa-pulse.fa-2x')

const peer = shards.find(s => s.id === state.id)

if (!peer) return h('section', [ h('p', `You don't hold any shards for this person`) ])
else return peer.shards.map((shard) => {
return h('section.shard', { title: shard.root, 'ev-click': () => api.router.sync.goTo({ path: `/shards/${shard.id}`, shard: { ...shard, peerId: peer.id } }) }, [
h('div.left', [
h('div.sentAt', shard.sentAt)
]),
h('div.right', [
h('div.state', shard.state)
])
])
})
})
])
])
}
}
Loading

0 comments on commit 1697a5d

Please sign in to comment.