Something went wrong. Try again.
Monorepo for Tangled
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131import type { BobbinContext } from "$lib/api/client";import { INVALID_HANDLE } from "$lib/api/identity";import { listIssues } from "$lib/api/issue";import { listPulls } from "$lib/api/records";import { searchActorsTypeahead } from "$lib/api/search";import { rkeyFromUri } from "$lib/api/uri";import type { TicketState } from "$lib/components/repo/tickets/TicketStatePill.svelte";import type { MentionPerson } from "$lib/components/ui/mentionPeople";
export interface UserSuggestion { kind: "user"; key: string; did: string; handle: string; insert: string;}
export interface TicketSuggestion { kind: "ticket"; key: string; isPull: boolean; state: TicketState; title: string; rkey: string; createdAt: string; insert: string;}
export type Suggestion = UserSuggestion | TicketSuggestion;
export interface TicketRepo { did: string; url: string;}
const SUGGESTION_LIMIT = 8;const RECOMMENDATION_LIMIT = 5;const TICKET_FETCH_LIMIT = 100;
export const suggestUsers = async ( ctx: BobbinContext, query: string, signal: AbortSignal): Promise<UserSuggestion[]> => { if (query === "") return []; const { actors } = await searchActorsTypeahead( ctx, { q: query, limit: SUGGESTION_LIMIT }, { signal } ); return actors.map((actor) => userSuggestion(actor.did, actor.handle));};
const userSuggestion = (did: string, handle: string): UserSuggestion => ({ kind: "user", key: did, did, handle, insert: `@${handle} `});
export const recommendUsers = ( people: MentionPerson[], exclude: string | undefined): UserSuggestion[] => { const seen = new Set(exclude ? [exclude] : []); const picked: UserSuggestion[] = []; for (const { did, handle } of people) { if (!handle || handle === INVALID_HANDLE || seen.has(did)) continue; seen.add(did); picked.push(userSuggestion(did, handle)); if (picked.length === RECOMMENDATION_LIMIT) break; } return picked;};
export const recommendPeople = async ( known: MentionPerson[], members: () => Promise<MentionPerson[]>, exclude: string | undefined): Promise<UserSuggestion[]> => { const participants = recommendUsers(known, exclude); if (participants.length >= RECOMMENDATION_LIMIT) return participants; const others = await members().catch(() => []); return recommendUsers([...known, ...others], exclude);};
const ticket = ( repo: TicketRepo, isPull: boolean, item: { uri: string; state: string; value: { title: string; createdAt: string } }): TicketSuggestion => { const rkey = rkeyFromUri(item.uri); const state: TicketState = item.state === "closed" || (isPull && item.state === "merged") ? item.state : "open"; return { kind: "ticket", key: item.uri, isPull, state, title: item.value.title, rkey, createdAt: item.value.createdAt, insert: `[#${rkey}](${repo.url}/${isPull ? "pulls" : "issues"}/${item.uri}) ` };};
export const loadTickets = async ( ctx: BobbinContext, repo: TicketRepo): Promise<TicketSuggestion[]> => { const [issues, pulls] = await Promise.all([ listIssues(ctx, repo.did, { limit: TICKET_FETCH_LIMIT }), listPulls(ctx, repo.did, { limit: TICKET_FETCH_LIMIT }) ]); return [ ...issues.items.map((item) => ticket(repo, false, item)), ...pulls.items.map((item) => ticket(repo, true, item)) ].sort((a, b) => b.createdAt.localeCompare(a.createdAt));};
export const filterTickets = (tickets: TicketSuggestion[], query: string): TicketSuggestion[] => { const needle = query.toLowerCase(); return tickets .filter( (ticket) => ticket.rkey.startsWith(needle) || ticket.title.toLowerCase().includes(needle) ) .slice(0, SUGGESTION_LIMIT);};