diff --git a/bobbin/crates/ingest/src/lib.rs b/bobbin/crates/ingest/src/lib.rs index 1999ab72..86616a12 100644 --- a/bobbin/crates/ingest/src/lib.rs +++ b/bobbin/crates/ingest/src/lib.rs @@ -1090,7 +1090,9 @@ async fn prepare_record( debug!("record-typed frame missing payload, skipping"); return PendingOp::Noop; }; - if !record.collection.as_ref().starts_with(TANGLED_PREFIX) && !record.collection.as_ref().starts_with(ORG_TANGLED_PREFIX) { + if !record.collection.as_ref().starts_with(TANGLED_PREFIX) + && !record.collection.as_ref().starts_with(ORG_TANGLED_PREFIX) + { return PendingOp::Noop; } // hydrant only announces an identity when it changes, so nothing tells us diff --git a/bobbin/crates/types/src/edges.rs b/bobbin/crates/types/src/edges.rs index 415b8326..421a5b7e 100644 --- a/bobbin/crates/types/src/edges.rs +++ b/bobbin/crates/types/src/edges.rs @@ -8,11 +8,11 @@ use jacquard_common::types::tid::Tid; use jacquard_common::{BosStr, DefaultStr}; use crate::ids::{SubjectRef, nsid_static}; +use crate::org_tangled::feed::subscription::Subscription; use crate::sh_tangled::actor::profile::Profile; use crate::sh_tangled::feed::comment::Comment as FeedCommentRecord; use crate::sh_tangled::feed::reaction::Reaction; use crate::sh_tangled::feed::star::Star; -use crate::org_tangled::feed::subscription::Subscription; use crate::sh_tangled::git::ref_update::RefUpdate; use crate::sh_tangled::graph::follow::Follow; use crate::sh_tangled::graph::vouch::Vouch; diff --git a/deliberi/bobbin.go b/deliberi/bobbin.go index 8736132e..76e9d365 100644 --- a/deliberi/bobbin.go +++ b/deliberi/bobbin.go @@ -10,8 +10,8 @@ import ( "github.com/bluesky-social/indigo/atproto/syntax" indigoxrpc "github.com/bluesky-social/indigo/xrpc" - "tangled.org/core/api/tangled" "tangled.org/core/api/org_tangled" + "tangled.org/core/api/tangled" ) type recipientResolver interface { diff --git a/web/src/lib/api/graph.ts b/web/src/lib/api/graph.ts index 9262f337..8570633e 100644 --- a/web/src/lib/api/graph.ts +++ b/web/src/lib/api/graph.ts @@ -90,7 +90,10 @@ export const deleteStar = async (agent: OAuthUserAgent, rkey: string): Promise => { +export const createSubscription = async ( + agent: OAuthUserAgent, + repoDid: string +): Promise => { const { uri } = await createRecord(agent, SUBSCRIPTION_COLLECTION, { $type: SUBSCRIPTION_COLLECTION, subject: { @@ -106,7 +109,10 @@ export const deleteSubscription = async (agent: OAuthUserAgent, rkey: string): P await deleteRecord(agent, SUBSCRIPTION_COLLECTION, rkey); }; -export const createEntitySubscription = async (agent: OAuthUserAgent, entityUri: string): Promise => { +export const createEntitySubscription = async ( + agent: OAuthUserAgent, + entityUri: string +): Promise => { const { uri } = await createRecord(agent, SUBSCRIPTION_COLLECTION, { $type: SUBSCRIPTION_COLLECTION, subject: { diff --git a/web/src/lib/api/moderation.ts b/web/src/lib/api/moderation.ts index a616d876..2b0c2a21 100644 --- a/web/src/lib/api/moderation.ts +++ b/web/src/lib/api/moderation.ts @@ -13,7 +13,8 @@ type KnownOf = T extends string ? (string extends T ? never : T) : never; export type KnownReasonType = KnownOf; export type ReportSubject = - { kind: "account"; did: string } | { kind: "record"; uri: string; cid: string }; + | { kind: "account"; did: string } + | { kind: "record"; uri: string; cid: string }; export interface ReportInput { subject: ReportSubject; diff --git a/web/src/lib/api/notifications.ts b/web/src/lib/api/notifications.ts index fb2ff53d..4b0f2dd5 100644 --- a/web/src/lib/api/notifications.ts +++ b/web/src/lib/api/notifications.ts @@ -94,10 +94,7 @@ export const markEntityNotificationsRead = ( entityAt: string ): Promise => authedPost(ctx, MARK_ENTITY_READ, { entityAt }).then(() => undefined); - -export const getUnreadCount = ( - ctx: DeliberiContext -): Promise<{ count: number }> => +export const getUnreadCount = (ctx: DeliberiContext): Promise<{ count: number }> => authedGet(ctx, GET_UNREAD); const subjectFromUri = ( @@ -122,19 +119,11 @@ export const hydrateNotifications = async ( const repoDids = [...new Set(items.map((n) => n.repoDid).filter((d): d is string => !!d))]; - const issueUris = [ - ...new Set(items.map((n) => n.issueAt).filter((u): u is string => !!u)) - ]; - const pullUris = [ - ...new Set(items.map((n) => n.pullAt).filter((u): u is string => !!u)) - ]; + const issueUris = [...new Set(items.map((n) => n.issueAt).filter((u): u is string => !!u))]; + const pullUris = [...new Set(items.map((n) => n.pullAt).filter((u): u is string => !!u))]; const [actorDocs, repoList, issueList, pullList] = await Promise.all([ - Promise.all( - actorDids.map((did) => - resolveMiniDoc(ctx, did).catch(() => null) - ) - ), + Promise.all(actorDids.map((did) => resolveMiniDoc(ctx, did).catch(() => null))), repoDids.length > 0 ? getReposByRepoDids(ctx, repoDids).catch(() => ({ items: [] })) : Promise.resolve({ items: [] }), diff --git a/web/src/lib/api/pullCompose.ts b/web/src/lib/api/pullCompose.ts index 59242061..5c32ef2f 100644 --- a/web/src/lib/api/pullCompose.ts +++ b/web/src/lib/api/pullCompose.ts @@ -144,12 +144,14 @@ export const loadCompose = async (args: { (item) => item.value.source?.startsWith("at://") && item.value.repoDid ) - .map((item): ForkOption => ({ - uri: item.uri, - repoDid: item.value.repoDid as string, - name: repoNameOf(item), - knot: item.value.knot - })) + .map( + (item): ForkOption => ({ + uri: item.uri, + repoDid: item.value.repoDid as string, + name: repoNameOf(item), + knot: item.value.knot + }) + ) ) .catch(() => [] as ForkOption[]) : Promise.resolve([] as ForkOption[]) diff --git a/web/src/lib/api/pullDiff.ts b/web/src/lib/api/pullDiff.ts index 391f4d61..a24750c9 100644 --- a/web/src/lib/api/pullDiff.ts +++ b/web/src/lib/api/pullDiff.ts @@ -74,7 +74,8 @@ export interface PullDiffFile { // rebased in memory for that one request, reachable by no ref, so its text can // only arrive inlined on the payload export type ContentsSource = - { inlineOld?: false; oldRef: string; newRef: string } | { inlineOld: true; newRef: string }; + | { inlineOld?: false; oldRef: string; newRef: string } + | { inlineOld: true; newRef: string }; export interface PullDiff { files: PullDiffFile[]; diff --git a/web/src/lib/components/notifications/mock.ts b/web/src/lib/components/notifications/mock.ts index 573d0bac..9cdb4848 100644 --- a/web/src/lib/components/notifications/mock.ts +++ b/web/src/lib/components/notifications/mock.ts @@ -22,7 +22,10 @@ const subjectUri = (kind: "issue" | "pull", number: string) => `at://did:plc:mock/sh.tangled.repo.${kind}/${number}`; export const notifications: NotificationSummary[] = [ - { uri: `at://mock/notif/${1}`, id: 1, type: "user_mentioned", + { + uri: `at://mock/notif/${1}`, + id: 1, + type: "user_mentioned", read: false, createdAt: ago(4), actor: alice, @@ -32,8 +35,12 @@ export const notifications: NotificationSummary[] = [ uri: subjectUri("pull", "214"), number: "214", title: "spindle: retry a workflow after a knot timeout" - } }, - { uri: `at://mock/notif/${2}`, id: 2, type: "pull_created", + } + }, + { + uri: `at://mock/notif/${2}`, + id: 2, + type: "pull_created", read: false, createdAt: ago(26), actor: bob, @@ -43,13 +50,21 @@ export const notifications: NotificationSummary[] = [ uri: subjectUri("pull", "213"), number: "213", title: "web: port the notifications page to svelte" - } }, - { uri: `at://mock/notif/${3}`, id: 3, type: "repo_starred", + } + }, + { + uri: `at://mock/notif/${3}`, + id: 3, + type: "repo_starred", read: false, createdAt: ago(51), actor: carol, - repo: core }, - { uri: `at://mock/notif/${4}`, id: 4, type: "issue_commented", + repo: core + }, + { + uri: `at://mock/notif/${4}`, + id: 4, + type: "issue_commented", read: true, createdAt: ago(190), actor: dave, @@ -59,12 +74,20 @@ export const notifications: NotificationSummary[] = [ uri: subjectUri("issue", "87"), number: "87", title: "packfile upload stalls on large repositories" - } }, - { uri: `at://mock/notif/${5}`, id: 5, type: "followed", + } + }, + { + uri: `at://mock/notif/${5}`, + id: 5, + type: "followed", read: false, createdAt: ago(320), - actor: dave }, - { uri: `at://mock/notif/${6}`, id: 6, type: "issue_assigned", + actor: dave + }, + { + uri: `at://mock/notif/${6}`, + id: 6, + type: "issue_assigned", read: true, createdAt: ago(60 * 26), actor: alice, @@ -74,8 +97,12 @@ export const notifications: NotificationSummary[] = [ uri: subjectUri("issue", "402"), number: "402", title: "settings: the email tab drops its drill-down" - } }, - { uri: `at://mock/notif/${7}`, id: 7, type: "pull_merged", + } + }, + { + uri: `at://mock/notif/${7}`, + id: 7, + type: "pull_merged", read: true, createdAt: ago(60 * 30), actor: bob, @@ -85,12 +112,20 @@ export const notifications: NotificationSummary[] = [ uri: subjectUri("pull", "208"), number: "208", title: "appview: resolve handles inside the timeline feed" - } }, - { uri: `at://mock/notif/${8}`, id: 8, type: "followed", + } + }, + { + uri: `at://mock/notif/${8}`, + id: 8, + type: "followed", read: true, createdAt: ago(60 * 40), - actor: carol }, - { uri: `at://mock/notif/${9}`, id: 9, type: "issue_created", + actor: carol + }, + { + uri: `at://mock/notif/${9}`, + id: 9, + type: "issue_created", read: false, createdAt: ago(60 * 55), actor: carol, @@ -100,8 +135,12 @@ export const notifications: NotificationSummary[] = [ uri: subjectUri("issue", "91"), number: "91", title: "git hooks reject a push with no error message" - } }, - { uri: `at://mock/notif/${10}`, id: 10, type: "pull_closed", + } + }, + { + uri: `at://mock/notif/${10}`, + id: 10, + type: "pull_closed", read: true, createdAt: ago(60 * 24 * 5), actor: dave, @@ -111,13 +150,21 @@ export const notifications: NotificationSummary[] = [ uri: subjectUri("pull", "199"), number: "199", title: "drop the legacy avatar worker" - } }, - { uri: `at://mock/notif/${11}`, id: 11, type: "repo_starred", + } + }, + { + uri: `at://mock/notif/${11}`, + id: 11, + type: "repo_starred", read: true, createdAt: ago(60 * 24 * 6), actor: alice, - repo: knot }, - { uri: `at://mock/notif/${12}`, id: 12, type: "issue_closed", + repo: knot + }, + { + uri: `at://mock/notif/${12}`, + id: 12, + type: "issue_closed", read: true, createdAt: ago(60 * 24 * 9), actor: bob, @@ -127,8 +174,12 @@ export const notifications: NotificationSummary[] = [ uri: subjectUri("issue", "377"), number: "377", title: "dark mode inverts the button group seam" - } }, - { uri: `at://mock/notif/${13}`, id: 13, type: "pull_commented", + } + }, + { + uri: `at://mock/notif/${13}`, + id: 13, + type: "pull_commented", read: true, createdAt: ago(60 * 24 * 12), actor: alice, @@ -138,8 +189,12 @@ export const notifications: NotificationSummary[] = [ uri: subjectUri("pull", "64"), number: "64", title: "knot: verify the owner signature before a fetch" - } }, - { uri: `at://mock/notif/${14}`, id: 14, type: "issue_reopen", + } + }, + { + uri: `at://mock/notif/${14}`, + id: 14, + type: "issue_reopen", read: true, createdAt: ago(60 * 24 * 15), actor: carol, @@ -149,8 +204,12 @@ export const notifications: NotificationSummary[] = [ uri: subjectUri("issue", "311"), number: "311", title: "pipelines tab shows a stale workflow status" - } }, - { uri: `at://mock/notif/${15}`, id: 15, type: "pull_unassigned", + } + }, + { + uri: `at://mock/notif/${15}`, + id: 15, + type: "pull_unassigned", read: true, createdAt: ago(60 * 24 * 21), actor: bob, @@ -160,5 +219,6 @@ export const notifications: NotificationSummary[] = [ uri: subjectUri("pull", "180"), number: "180", title: "camo: cache remote images for a week" - } } + } + } ]; diff --git a/web/src/lib/components/reaction/reactions.ts b/web/src/lib/components/reaction/reactions.ts index 5e099c2b..b4eceb3f 100644 --- a/web/src/lib/components/reaction/reactions.ts +++ b/web/src/lib/components/reaction/reactions.ts @@ -85,7 +85,7 @@ export function upsertViewerReaction( const next = exists ? groups.map((g) => (g.kind === kind ? withViewerReaction(g, viewerHandle, rkey) : g)) : [...groups, { kind, count: 1, users: [viewerHandle], isReacted: true, viewerRkey: rkey }]; - return ORDERED_REACTION_KINDS.filter((k) => next.some((g) => g.kind === k)).map((k) => - next.find((g) => g.kind === k)! + return ORDERED_REACTION_KINDS.filter((k) => next.some((g) => g.kind === k)).map( + (k) => next.find((g) => g.kind === k)! ); } diff --git a/web/src/lib/oauth-client-metadata.json b/web/src/lib/oauth-client-metadata.json index e6f6ec3b..9df36d2f 100644 --- a/web/src/lib/oauth-client-metadata.json +++ b/web/src/lib/oauth-client-metadata.json @@ -2,17 +2,10 @@ "client_id": "https://tangled.org/oauth-client-metadata.json", "client_name": "Tangled", "client_uri": "https://tangled.org", - "redirect_uris": [ - "https://tangled.org/oauth/callback" - ], + "redirect_uris": ["https://tangled.org/oauth/callback"], "scope": "atproto repo:sh.tangled.actor.profile repo:org.tangled.feed.subscription repo:sh.tangled.feed.comment repo:sh.tangled.feed.reaction repo:sh.tangled.feed.star repo:sh.tangled.graph.follow repo:sh.tangled.graph.vouch repo:sh.tangled.knot repo:sh.tangled.knot.member repo:sh.tangled.label.definition repo:sh.tangled.label.op repo:sh.tangled.publicKey repo:sh.tangled.repo repo:sh.tangled.repo.artifact repo:sh.tangled.repo.collaborator repo:sh.tangled.repo.issue repo:sh.tangled.repo.issue.comment repo:sh.tangled.repo.issue.state repo:sh.tangled.repo.pull repo:sh.tangled.repo.pull.comment repo:sh.tangled.repo.pull.status repo:sh.tangled.spindle repo:sh.tangled.spindle.member repo:sh.tangled.string blob:*/* rpc:sh.tangled.graph.listNetworkVouches?aud=* rpc:sh.tangled.knot.addMember?aud=* rpc:sh.tangled.knot.removeMember?aud=* rpc:sh.tangled.ci.triggerPipeline?aud=* rpc:sh.tangled.ci.cancelPipeline?aud=* rpc:sh.tangled.repo.addCollaborator?aud=* rpc:sh.tangled.repo.addSecret?aud=* rpc:sh.tangled.repo.create?aud=* rpc:sh.tangled.repo.delete?aud=* rpc:sh.tangled.repo.deleteBranch?aud=* rpc:sh.tangled.repo.forkStatus?aud=* rpc:sh.tangled.repo.forkSync?aud=* rpc:sh.tangled.repo.hiddenRef?aud=* rpc:sh.tangled.repo.listSecrets?aud=* rpc:sh.tangled.repo.merge?aud=* rpc:sh.tangled.repo.mergeCheck?aud=* rpc:sh.tangled.repo.removeCollaborator?aud=* rpc:sh.tangled.repo.removeSecret?aud=* rpc:sh.tangled.repo.setDefaultBranch?aud=* rpc:org.tangled.temp.notification.getPreferences?aud=* rpc:org.tangled.temp.notification.updatePreferences?aud=* rpc:org.tangled.temp.notification.getUnreadCount?aud=* rpc:org.tangled.temp.notification.listNotifications?aud=* rpc:org.tangled.temp.notification.markAllRead?aud=* rpc:org.tangled.temp.notification.markEntityRead?aud=* rpc:org.tangled.temp.notification.updateSeen?aud=* rpc:org.tangled.temp.account.listEmails?aud=* rpc:org.tangled.temp.account.deleteEmail?aud=* rpc:org.tangled.temp.account.setPrimaryEmail?aud=* rpc:org.tangled.temp.account.addEmail?aud=* rpc:org.tangled.temp.account.verifyEmail?aud=* rpc:org.tangled.temp.site.getDomainClaim?aud=* rpc:org.tangled.temp.site.claimDomain?aud=* rpc:org.tangled.temp.site.releaseDomain?aud=* rpc:org.tangled.temp.search.searchCode?aud=* rpc:sh.tangled.git.keepCommit?aud=* rpc:sh.tangled.git.mergeCommit?aud=* rpc:com.atproto.moderation.createReport?aud=*", - "grant_types": [ - "authorization_code", - "refresh_token" - ], - "response_types": [ - "code" - ], + "grant_types": ["authorization_code", "refresh_token"], + "response_types": ["code"], "token_endpoint_auth_method": "none", "application_type": "web", "dpop_bound_access_tokens": true diff --git a/web/src/routes/[handle]/+layout.ts b/web/src/routes/[handle]/+layout.ts index 73b3755b..dbaf1a85 100644 --- a/web/src/routes/[handle]/+layout.ts +++ b/web/src/routes/[handle]/+layout.ts @@ -80,14 +80,15 @@ export const load: LayoutLoad = async (event) => { const followPromise = stream(resolved.then(({ viewerFollowRkey }) => viewerFollowRkey)); const profilePromise = stream( - resolved.then(({ identity }): Promise => - getProfile(ctx, identity.did) - .then((view) => view.value) - .catch((cause) => { - if (cause instanceof ClientResponseError && httpStatusFor(cause) === 404) - return null; - return toHttpError(cause, "Could not load profile"); - }) + resolved.then( + ({ identity }): Promise => + getProfile(ctx, identity.did) + .then((view) => view.value) + .catch((cause) => { + if (cause instanceof ClientResponseError && httpStatusFor(cause) === 404) + return null; + return toHttpError(cause, "Could not load profile"); + }) ) ); diff --git a/web/src/routes/[handle]/[repo]/+layout.ts b/web/src/routes/[handle]/[repo]/+layout.ts index a62a2490..6ca7dc17 100644 --- a/web/src/routes/[handle]/[repo]/+layout.ts +++ b/web/src/routes/[handle]/[repo]/+layout.ts @@ -120,12 +120,14 @@ export const load: LayoutLoad = async (event) => { forks: repoDid ? count(ctx, "sh.tangled.repo.countForks", repoDid).catch(() => null) : Promise.resolve(null) - }).then((stats): RepoCounts => ({ - stars: stats.stars?.count ?? 0, - issues: stats.issues?.count ?? 0, - pulls: stats.pulls?.count ?? 0, - forks: stats.forks?.count ?? 0 - })); + }).then( + (stats): RepoCounts => ({ + stars: stats.stars?.count ?? 0, + issues: stats.issues?.count ?? 0, + pulls: stats.pulls?.count ?? 0, + forks: stats.forks?.count ?? 0 + }) + ); }) ); diff --git a/web/src/routes/notifications/+page.ts b/web/src/routes/notifications/+page.ts index f7be72f9..469a801c 100644 --- a/web/src/routes/notifications/+page.ts +++ b/web/src/routes/notifications/+page.ts @@ -5,7 +5,8 @@ export const load: PageLoad = async (event) => { const parent = await event.parent(); const read: ReadFilter = event.url.searchParams.get("read") === "unread" ? "unread" : "inbox"; const requested = event.url.searchParams.get("category"); - const category: CategoryFilter = requested === "work" || requested === "social" ? requested : "all"; + const category: CategoryFilter = + requested === "work" || requested === "social" ? requested : "all"; return { readFilter: read,