mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-29 00:10:52 +00:00
Fix nip04 messages not having a members field, Improve person search
This commit is contained in:
parent
6c902b7e8f
commit
04b3772231
@ -26,6 +26,8 @@
|
|||||||
- [x] Fix initial message when opening conversation from a listing
|
- [x] Fix initial message when opening conversation from a listing
|
||||||
- [x] Support frequency value in `price` tag for nip 99
|
- [x] Support frequency value in `price` tag for nip 99
|
||||||
- [x] Show all replies exands notes inline rather than opening the note
|
- [x] Show all replies exands notes inline rather than opening the note
|
||||||
|
- [x] Fix nip04 messages not having a members field
|
||||||
|
- [x] Improve person search
|
||||||
|
|
||||||
# 0.4.0
|
# 0.4.0
|
||||||
|
|
||||||
|
@ -73,7 +73,8 @@
|
|||||||
let collapsed = depth === 0
|
let collapsed = depth === 0
|
||||||
let ctx = uniqBy(prop("id"), context)
|
let ctx = uniqBy(prop("id"), context)
|
||||||
let showEntire = anchor === getIdOrAddress(event)
|
let showEntire = anchor === getIdOrAddress(event)
|
||||||
let interactive = !anchor || !showEntire
|
|
||||||
|
const interactive = !anchor || !showEntire
|
||||||
|
|
||||||
const onClick = e => {
|
const onClick = e => {
|
||||||
const target = (e.detail?.target || e.target) as HTMLElement
|
const target = (e.detail?.target || e.target) as HTMLElement
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
uniq(Tags.from(parent).type("p").values().all().concat(parent.pubkey)),
|
uniq(Tags.from(parent).type("p").values().all().concat(parent.pubkey)),
|
||||||
)
|
)
|
||||||
|
|
||||||
setTimeout(() => compose.write(draft))
|
setTimeout(() => compose.write(draft), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
const bypassNsecWarning = () => {
|
const bypassNsecWarning = () => {
|
||||||
|
@ -34,6 +34,9 @@ projections.addHandler(30078, async e => {
|
|||||||
const channel = $channels.get(id)
|
const channel = $channels.get(id)
|
||||||
|
|
||||||
$channels.set(id, {
|
$channels.set(id, {
|
||||||
|
relays: [],
|
||||||
|
members: [],
|
||||||
|
messages: [],
|
||||||
...channel,
|
...channel,
|
||||||
last_checked: Math.max(ts, channel?.last_checked || 0),
|
last_checked: Math.max(ts, channel?.last_checked || 0),
|
||||||
})
|
})
|
||||||
@ -55,12 +58,7 @@ const handleMessage = async e => {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const $channel =
|
const $channel = channels.key(channelId).get()
|
||||||
channels.key(channelId).get() ||
|
|
||||||
({
|
|
||||||
id: channelId,
|
|
||||||
members: pubkeys,
|
|
||||||
} as Channel)
|
|
||||||
|
|
||||||
const relays = $channel?.relays || []
|
const relays = $channel?.relays || []
|
||||||
const messages = $channel?.messages || []
|
const messages = $channel?.messages || []
|
||||||
@ -90,10 +88,12 @@ const handleMessage = async e => {
|
|||||||
e = {...e, content: await nip04.decryptAsUser(e.content, other)}
|
e = {...e, content: await nip04.decryptAsUser(e.content, other)}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updates = {
|
const updates: Channel = {
|
||||||
...$channel,
|
...$channel,
|
||||||
|
id: channelId,
|
||||||
relays: uniq([...tags.relays().all(), ...relays]),
|
relays: uniq([...tags.relays().all(), ...relays]),
|
||||||
messages: uniqBy(prop("id"), [e, ...messages]),
|
messages: uniqBy(prop("id"), [e, ...messages]),
|
||||||
|
members: pubkeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.pubkey === pubkey) {
|
if (e.pubkey === pubkey) {
|
||||||
|
@ -165,6 +165,7 @@ export class IndexedDBAdapter {
|
|||||||
readonly max: number,
|
readonly max: number,
|
||||||
readonly sort?: (xs: any[]) => any[],
|
readonly sort?: (xs: any[]) => any[],
|
||||||
readonly filter?: (x: any) => boolean,
|
readonly filter?: (x: any) => boolean,
|
||||||
|
readonly migrate?: (xs: any[]) => any[],
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getIndexedDBConfig() {
|
getIndexedDBConfig() {
|
||||||
@ -177,10 +178,12 @@ export class IndexedDBAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async initialize(storage: Storage) {
|
async initialize(storage: Storage) {
|
||||||
const {key, store, filter} = this
|
const {key, store} = this
|
||||||
const data = await storage.db.getAll(key)
|
const data = await storage.db.getAll(key)
|
||||||
|
const filter = this.filter || identity
|
||||||
|
const migrate = this.migrate || identity
|
||||||
|
|
||||||
store.set(data.filter(filter || identity))
|
store.set(migrate(data.filter(filter)))
|
||||||
|
|
||||||
store.subscribe(
|
store.subscribe(
|
||||||
throttle(randomInt(3000, 5000), async <T>(rows: T) => {
|
throttle(randomInt(3000, 5000), async <T>(rows: T) => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import {prop, sortBy} from "ramda"
|
import {Tags} from 'paravel'
|
||||||
|
import {prop, uniq, sortBy} from "ramda"
|
||||||
import {Storage, LocalStorageAdapter, IndexedDBAdapter, sortByPubkeyWhitelist} from "./core"
|
import {Storage, LocalStorageAdapter, IndexedDBAdapter, sortByPubkeyWhitelist} from "./core"
|
||||||
import {_lists} from "./lists"
|
import {_lists} from "./lists"
|
||||||
import {people} from "./people"
|
import {people} from "./people"
|
||||||
@ -34,6 +35,15 @@ const setAdapter = {
|
|||||||
load: a => new Set(a || []),
|
load: a => new Set(a || []),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nip 04 channels weren't getting members set
|
||||||
|
const migrateChannels = channels => {
|
||||||
|
return channels.map(c => {
|
||||||
|
c.members = uniq(c.members.concat(c.messages?.flatMap(m => Tags.from(m).pubkeys().all().concat(m.pubkey))))
|
||||||
|
|
||||||
|
return c
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const storage = new Storage(9, [
|
export const storage = new Storage(9, [
|
||||||
new LocalStorageAdapter("pubkey", pubkey),
|
new LocalStorageAdapter("pubkey", pubkey),
|
||||||
new LocalStorageAdapter("sessions", sessions),
|
new LocalStorageAdapter("sessions", sessions),
|
||||||
@ -51,7 +61,7 @@ export const storage = new Storage(9, [
|
|||||||
),
|
),
|
||||||
new IndexedDBAdapter("people", people, 5000, sortByPubkeyWhitelist(prop("last_fetched"))),
|
new IndexedDBAdapter("people", people, 5000, sortByPubkeyWhitelist(prop("last_fetched"))),
|
||||||
new IndexedDBAdapter("relays", relays, 1000, sortBy(prop("count"))),
|
new IndexedDBAdapter("relays", relays, 1000, sortBy(prop("count"))),
|
||||||
new IndexedDBAdapter("channels", channels, 1000, sortBy(prop("last_checked"))),
|
new IndexedDBAdapter("channels", channels, 1000, sortBy(prop("last_checked")), null, migrateChannels),
|
||||||
new IndexedDBAdapter("groups", groups, 1000, sortBy(prop("count"))),
|
new IndexedDBAdapter("groups", groups, 1000, sortBy(prop("count"))),
|
||||||
new IndexedDBAdapter("groupAlerts", groupAlerts, 30, sortBy(prop("created_at"))),
|
new IndexedDBAdapter("groupAlerts", groupAlerts, 30, sortBy(prop("created_at"))),
|
||||||
new IndexedDBAdapter("groupRequests", groupRequests, 100, sortBy(prop("created_at"))),
|
new IndexedDBAdapter("groupRequests", groupRequests, 100, sortBy(prop("created_at"))),
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import {defaultTo, filter} from "ramda"
|
import Fuse from "fuse.js"
|
||||||
|
import {doPipe} from "hurdak"
|
||||||
|
import {defaultTo, map, filter, sortBy} from "ramda"
|
||||||
|
import {derived} from "src/engine/core/utils"
|
||||||
|
import {pubkey} from "src/engine/session/state"
|
||||||
import {user} from "src/engine/session/derived"
|
import {user} from "src/engine/session/derived"
|
||||||
|
import type {Person} from "./model"
|
||||||
import {people} from "./state"
|
import {people} from "./state"
|
||||||
import {personHasName, getPeopleSearch, getMutes, getFollows, getNetwork} from "./utils"
|
import {personHasName, getFollowsWhoFollow, primeWotCaches, getWotScore, getMutes, getFollows, getNetwork} from "./utils"
|
||||||
|
|
||||||
export const peopleWithName = people.derived(filter(personHasName))
|
export const peopleWithName = people.derived(filter(personHasName))
|
||||||
|
|
||||||
export const searchPeople = peopleWithName.derived(getPeopleSearch)
|
|
||||||
|
|
||||||
export const derivePerson = pubkey => people.key(pubkey).derived(defaultTo({pubkey}))
|
export const derivePerson = pubkey => people.key(pubkey).derived(defaultTo({pubkey}))
|
||||||
|
|
||||||
export const mutes = user.derived(getMutes)
|
export const mutes = user.derived(getMutes)
|
||||||
@ -18,3 +21,35 @@ export const network = user.derived(getNetwork)
|
|||||||
export const deriveMuted = (value: string) => mutes.derived(s => s.has(value))
|
export const deriveMuted = (value: string) => mutes.derived(s => s.has(value))
|
||||||
|
|
||||||
export const deriveFollowing = (pubkey: string) => follows.derived(s => s.has(pubkey))
|
export const deriveFollowing = (pubkey: string) => follows.derived(s => s.has(pubkey))
|
||||||
|
|
||||||
|
export const searchPeople = derived(
|
||||||
|
[pubkey, peopleWithName.throttle(300)],
|
||||||
|
([$pubkey, $peopleWithName]: [string, Person[]]): ((term: string) => Person[]) => {
|
||||||
|
primeWotCaches($pubkey)
|
||||||
|
|
||||||
|
const options = $peopleWithName.map(p => ({person: p, score: getWotScore($pubkey, p.pubkey)}))
|
||||||
|
|
||||||
|
const fuse = new Fuse(options, {
|
||||||
|
keys: [
|
||||||
|
"person.profile.name",
|
||||||
|
"person.profile.display_name",
|
||||||
|
{name: "person.profile.nip05", weight: 0.5},
|
||||||
|
{name: "person.profile.about", weight: 0.1},
|
||||||
|
],
|
||||||
|
threshold: 0.3,
|
||||||
|
shouldSort: false,
|
||||||
|
includeScore: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
return (term: string) => {
|
||||||
|
if (!term) {
|
||||||
|
return sortBy(item => -item.score, options).map(item => item.person)
|
||||||
|
}
|
||||||
|
|
||||||
|
return doPipe(fuse.search(term), [
|
||||||
|
sortBy((r: any) => (r.score - 1) * Math.sqrt(Math.max(0, r.item.score))),
|
||||||
|
map((r: any) => r.item.person),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import {nip19} from "nostr-tools"
|
import {nip19} from "nostr-tools"
|
||||||
|
import {throttle} from "throttle-debounce"
|
||||||
import {fromNostrURI, cached} from "paravel"
|
import {fromNostrURI, cached} from "paravel"
|
||||||
import {uniq, join, nth, last} from "ramda"
|
import {uniq, join, nth, last} from "ramda"
|
||||||
import {Fetch, tryFunc, createMapOf, ellipsize, switcherFn} from "hurdak"
|
import {Fetch, tryFunc, createMapOf, ellipsize, switcherFn} from "hurdak"
|
||||||
import {fuzzy, createBatcher, pushToKey} from "src/util/misc"
|
import {createBatcher, pushToKey} from "src/util/misc"
|
||||||
import {dufflepud} from "src/engine/session/utils"
|
import {dufflepud} from "src/engine/session/utils"
|
||||||
import {getPubkeyHints} from "src/engine/relays/utils"
|
import {getPubkeyHints} from "src/engine/relays/utils"
|
||||||
import type {Person, Handle} from "./model"
|
import type {Person, Handle} from "./model"
|
||||||
@ -58,17 +59,6 @@ export const displayHandle = (handle: Handle) =>
|
|||||||
|
|
||||||
export const displayPubkey = (pubkey: string) => displayPerson(getPersonWithDefault(pubkey))
|
export const displayPubkey = (pubkey: string) => displayPerson(getPersonWithDefault(pubkey))
|
||||||
|
|
||||||
export const getPeopleSearch = $people =>
|
|
||||||
fuzzy($people, {
|
|
||||||
keys: [
|
|
||||||
"profile.name",
|
|
||||||
"profile.display_name",
|
|
||||||
{name: "profile.nip05", weight: 0.5},
|
|
||||||
{name: "about", weight: 0.1},
|
|
||||||
],
|
|
||||||
threshold: 0.3,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const getMutedPubkeys = $person => ($person?.mutes || []).map(nth(1)) as string[]
|
export const getMutedPubkeys = $person => ($person?.mutes || []).map(nth(1)) as string[]
|
||||||
|
|
||||||
export const getMutes = $person => new Set(getMutedPubkeys($person))
|
export const getMutes = $person => new Set(getMutedPubkeys($person))
|
||||||
@ -116,7 +106,7 @@ export const getFollowsWhoMute = cached({
|
|||||||
getFollowedPubkeys(people.key(pk).get()).filter(pk => isMuting(people.key(pk).get(), tpk)),
|
getFollowedPubkeys(people.key(pk).get()).filter(pk => isMuting(people.key(pk).get(), tpk)),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const primeWotCaches = pk => {
|
export const primeWotCaches = throttle(3000, pk => {
|
||||||
const mutes = {}
|
const mutes = {}
|
||||||
const follows = {}
|
const follows = {}
|
||||||
|
|
||||||
@ -153,7 +143,7 @@ export const primeWotCaches = pk => {
|
|||||||
getFollowsWhoFollow.cache.set(getFollowsWhoFollow.getKey([pk, person.pubkey]), [])
|
getFollowsWhoFollow.cache.set(getFollowsWhoFollow.getKey([pk, person.pubkey]), [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
export const getWotScore = (pk, tpk) => {
|
export const getWotScore = (pk, tpk) => {
|
||||||
if (!people.key(pk).exists()) {
|
if (!people.key(pk).exists()) {
|
||||||
|
@ -19,11 +19,15 @@
|
|||||||
let input, suggestions, popover
|
let input, suggestions, popover
|
||||||
let focused = Boolean(autofocus)
|
let focused = Boolean(autofocus)
|
||||||
|
|
||||||
$: suggestions?.setData(term ? search(term).slice(0, 10) : defaultOptions)
|
$: {
|
||||||
|
suggestions?.setData(term ? search(term).slice(0, 10) : defaultOptions)
|
||||||
|
}
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (!focused || !term) {
|
if (!focused || !term) {
|
||||||
popover?.hide()
|
popover?.hide()
|
||||||
|
} else {
|
||||||
|
popover?.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (popover) {
|
if (popover) {
|
||||||
|
Loading…
Reference in New Issue
Block a user