diff --git a/frontend/apps/desktop/src/app-comments.ts b/frontend/apps/desktop/src/app-comments.ts index 0ade133a..42fc3db6 100644 --- a/frontend/apps/desktop/src/app-comments.ts +++ b/frontend/apps/desktop/src/app-comments.ts @@ -19,11 +19,11 @@ export const commentsApi = t.router({ getCommentDrafts: t.procedure .input( z.object({ - docEid: z.string(), + docUid: z.string(), }), ) .query(({input}) => { - const result = commentDraftStore.get(`Doc-${input.docEid}`) + const result = commentDraftStore.get(`Doc-${input.docUid}`) if (!result) return [] const commentIds = Object.keys(result) return commentIds @@ -40,7 +40,7 @@ export const commentsApi = t.router({ createCommentDraft: t.procedure .input( z.object({ - targetDocEid: z.string(), + targetDocUid: z.string(), targetDocVersion: z.string(), targetCommentId: z.string().or(z.null()), blocks: z.array(z.any()).optional(), @@ -48,14 +48,14 @@ export const commentsApi = t.router({ ) .mutation(async ({input}) => { const draftId = Math.random().toString(36).slice(2) - const prevIndex = commentDraftStore.get(`Doc-${input.targetDocEid}`) || {} - commentDraftStore.set(`Doc-${input.targetDocEid}`, { + const prevIndex = commentDraftStore.get(`Doc-${input.targetDocUid}`) || {} + commentDraftStore.set(`Doc-${input.targetDocUid}`, { ...prevIndex, [draftId]: true, }) commentDraftStore.set(`Comment-${draftId}`, { blocks: input.blocks || [], - targetDocEid: input.targetDocEid, + targetDocUid: input.targetDocUid, targetDocVersion: input.targetDocVersion, targetCommentId: input.targetCommentId, }) @@ -82,7 +82,7 @@ export const commentsApi = t.router({ .input( z.object({ commentId: z.string(), - // targetDocEid: z.string(), + // targetDocUid: z.string(), }), ) .mutation(async ({input}) => { @@ -90,9 +90,9 @@ export const commentsApi = t.router({ const comment = commentDraftStore.get(`Comment-${commentId}`) if (!comment) throw new Error('Comment with this commentId not found') commentDraftStore.delete(`Comment-${commentId}`) - const index = commentDraftStore.get(`Doc-${comment.targetDocEid}`) + const index = commentDraftStore.get(`Doc-${comment.targetDocUid}`) if (!index) throw new Error('Comment index not found') - commentDraftStore.set(`Doc-${comment.targetDocEid}`, { + commentDraftStore.set(`Doc-${comment.targetDocUid}`, { ...index, [commentId]: undefined, }) diff --git a/frontend/apps/desktop/src/app-diagnosis.ts b/frontend/apps/desktop/src/app-diagnosis.ts index fff57471..ceea1ffa 100644 --- a/frontend/apps/desktop/src/app-diagnosis.ts +++ b/frontend/apps/desktop/src/app-diagnosis.ts @@ -35,7 +35,7 @@ export const diagnosisApi = t.router({ .mutation(async ({input}) => { const id = unpackHmId(input.draftId) if (!id) throw new Error('Invalid draftId') - const draftPath = draftFilePath(id.eid) + const draftPath = draftFilePath(id.uid) // @ts-ignore const logExist: boolean = await exists(draftPath) if (!logExist) { @@ -54,16 +54,16 @@ export const diagnosisApi = t.router({ .mutation(async ({input}) => { const id = unpackHmId(input.draftId) if (!id) throw new Error('Invalid draftId') - const draftPath = draftFilePath(id.eid) + const draftPath = draftFilePath(id.uid) await appendFile(draftPath, JSON.stringify(input.event) + '\n') - const pubFilePath = createPubFilePath(id.eid) + const pubFilePath = createPubFilePath(id.uid) await move(draftPath, pubFilePath) return pubFilePath }), openDraftLog: t.procedure.input(z.string()).mutation(async ({input}) => { const id = unpackHmId(input) if (!id) throw new Error('Invalid draftId') - await open(draftFilePath(id.eid)) + await open(draftFilePath(id.uid)) }), openDraftLogFolder: t.procedure.mutation(async () => { await open(`${userDataPath}/DraftLog`) diff --git a/frontend/apps/desktop/src/changes-list.tsx b/frontend/apps/desktop/src/changes-list.tsx index b4fb25a5..ee3bd82a 100644 --- a/frontend/apps/desktop/src/changes-list.tsx +++ b/frontend/apps/desktop/src/changes-list.tsx @@ -10,9 +10,9 @@ import {NavRoute} from '@/utils/routes' import {useNavigate} from '@/utils/useNavigate' import { Change, - createHmId, createPublicWebHmUrl, formattedDateLong, + packHmId, unpackHmId, } from '@shm/shared' import {hmId, UnpackedHypermediaId} from '@shm/shared/src/utils/entity-id-url' @@ -84,7 +84,7 @@ function ChangeItem({ const navigate = useNavigate() const openAccount = (e) => { e.stopPropagation() - navigate({key: 'document', id: hmId('a', change.author)}) + navigate({key: 'document', id: hmId('d', change.author)}) } const navRoute = useNavRoute() const isActive = new Set(activeVersion?.split('.') || []).has(change.id) @@ -124,7 +124,7 @@ function ChangeItem({ const gwUrl = useGatewayUrl() const publicWebUrl = parsedEntityId && - createPublicWebHmUrl(parsedEntityId?.type, parsedEntityId?.eid, { + createPublicWebHmUrl(parsedEntityId?.type, parsedEntityId?.uid, { version: change.id, hostname: gwUrl.data, }) @@ -146,9 +146,11 @@ function ChangeItem({ icon: ArrowUpRight, onPress: () => { open( - createHmId(parsedEntityId.type, parsedEntityId.eid, { - version: change.id, - }), + packHmId( + hmId(parsedEntityId.type, parsedEntityId.uid, { + version: change.id, + }), + ), true, ) }, diff --git a/frontend/apps/desktop/src/components/account-link-avatar.tsx b/frontend/apps/desktop/src/components/account-link-avatar.tsx index 2fc43a18..75e9d4bd 100644 --- a/frontend/apps/desktop/src/components/account-link-avatar.tsx +++ b/frontend/apps/desktop/src/components/account-link-avatar.tsx @@ -85,7 +85,7 @@ export function BaseAccountLinkAvatar({ e.preventDefault() e.stopPropagation() if (!accountId) return appError('No account ready to load') - navigate({key: 'document', id: hmId('a', accountId)}) + navigate({key: 'document', id: hmId('d', accountId)}) }} position="relative" height={size} diff --git a/frontend/apps/desktop/src/components/app-embeds.tsx b/frontend/apps/desktop/src/components/app-embeds.tsx index 7964d1ae..1db73025 100644 --- a/frontend/apps/desktop/src/components/app-embeds.tsx +++ b/frontend/apps/desktop/src/components/app-embeds.tsx @@ -11,11 +11,11 @@ import { EntityComponentProps, InlineEmbedComponentProps, UnpackedHypermediaId, - createHmId, formattedDateMedium, getBlockNodeById, getDocumentTitle, hmId, + packHmId, unpackHmId, useDocContentContext, } from '@shm/shared' @@ -80,7 +80,7 @@ function EmbedWrapper({ useEffect(() => { const val = - (routeParams?.documentId == unpackRef?.qid && + (routeParams?.documentId == unpackRef?.id && routeParams?.version == unpackRef?.version && comment) || false @@ -96,7 +96,7 @@ function EmbedWrapper({ routeParams?.documentId, routeParams?.version, comment, - unpackRef?.qid, + unpackRef?.id, unpackRef?.version, ]) @@ -424,7 +424,7 @@ export function EmbedDocContent(props: EntityComponentProps) { size="$2" icon={ArrowUpRightSquare} onPress={() => { - if (!props.qid) return + if (!props.id) return navigate({ key: 'document', id: props, @@ -439,7 +439,7 @@ export function EmbedDocContent(props: EntityComponentProps) { } export function EmbedDocumentCard(props: EntityComponentProps) { - const docId = props.type == 'd' ? createHmId('d', props.eid) : undefined + const docId = props.type == 'd' ? packHmId(hmId('d', props.uid)) : undefined const doc = useEntity(props) let textContent = useMemo(() => { if (doc.data?.document?.content) { @@ -472,13 +472,10 @@ export function EmbedAccount( props: EntityComponentProps, parentBlockId: string | null, ) { - const profile = useEntity(props) + const entity = useEntity(props) - if (profile.status == 'success') { - const account = - profile.data?.type === 'a' ? profile.data?.account : undefined - if (!account) return null - if (props.block?.attributes?.view == 'content' && profile.data) { + if (entity.status == 'success') { + if (props.block?.attributes?.view == 'content' && entity.data) { return } else if (props.block?.attributes?.view == 'card') { return ( @@ -511,9 +508,9 @@ export function EmbedAccount( } export function EmbedComment(props: EntityComponentProps) { - if (props?.type !== 'c') + if (props?.type !== 'comment') throw new Error('Invalid props as ref for EmbedComment') - const comment = useComment(createHmId('c', props.eid), { + const comment = useComment(hmId('comment', props.uid), { enabled: !!props, }) let embedBlocks = useMemo(() => { @@ -583,10 +580,8 @@ function AvatarComponent({accountId}: {accountId: string}) { } export function EmbedInline(props: InlineEmbedComponentProps) { - if (props?.type == 'a') { - return - } else if (props?.type == 'd') { - return + if (props?.type == 'd') { + return } else { console.error('Inline Embed Error', JSON.stringify(props)) return ?? @@ -594,7 +589,7 @@ export function EmbedInline(props: InlineEmbedComponentProps) { } function AccountInlineEmbed(props: InlineEmbedComponentProps) { - const accountId = props?.type == 'a' ? props.eid : undefined + const accountId = props?.type == 'd' ? props.uid : undefined if (!accountId) throw new Error('Invalid props at AccountInlineEmbed (accountId)') const accountQuery = useAccount_deprecated(accountId) @@ -602,7 +597,7 @@ function AccountInlineEmbed(props: InlineEmbedComponentProps) { return ( navigate({key: 'document', id: hmId('a', accountId)})} + onPress={() => navigate({key: 'document', id: hmId('d', accountId)})} > {(accountId && accountQuery.status == 'success' && @@ -612,9 +607,9 @@ function AccountInlineEmbed(props: InlineEmbedComponentProps) { ) } -function PublicationInlineEmbed(props: InlineEmbedComponentProps) { - const pubId = props?.type == 'd' ? props.qid : undefined - if (!pubId) throw new Error('Invalid props at PublicationInlineEmbed (pubId)') +function DocInlineEmbed(props: InlineEmbedComponentProps) { + const pubId = props?.type == 'd' ? props.id : undefined + if (!pubId) throw new Error('Invalid props at DocInlineEmbed (pubId)') const doc = useEntity(props) const navigate = useNavigate() return ( diff --git a/frontend/apps/desktop/src/components/citations.tsx b/frontend/apps/desktop/src/components/citations.tsx index de5cba4d..ba19cab4 100644 --- a/frontend/apps/desktop/src/components/citations.tsx +++ b/frontend/apps/desktop/src/components/citations.tsx @@ -64,7 +64,7 @@ function PublicationCitationItem({mention}: {mention: Mention}) { const docTextContent = useDocTextContent(doc.data?.document) const destRoute: DocumentRoute = { key: 'document', - documentId: unpackedSource!.qid, + documentId: unpackedSource!.id, versionId: mention.sourceBlob?.cid, blockId: mention.sourceContext, } @@ -149,7 +149,7 @@ function CommentCitationItem({mention}: {mention: Mention}) { if (commentTarget) { spawn({ key: 'document', - documentId: commentTarget.qid, + documentId: commentTarget.id, versionId: commentTarget.version || undefined, }) } diff --git a/frontend/apps/desktop/src/components/comments.tsx b/frontend/apps/desktop/src/components/comments.tsx index b1c266c0..79b08a4a 100644 --- a/frontend/apps/desktop/src/components/comments.tsx +++ b/frontend/apps/desktop/src/components/comments.tsx @@ -11,9 +11,10 @@ import { HMComment, StateStream, UnpackedHypermediaId, - createHmId, formattedDateMedium, getDocumentTitle, + hmId, + packHmId, serializeBlockRange, unpackHmId, } from '@shm/shared' @@ -49,11 +50,11 @@ import {WindowsLinuxWindowControls} from './window-controls' export function CommentGroup({ group, - targetDocEid, + targetDocUid, targetDocVersion, }: { group: CommentGroup - targetDocEid: string + targetDocUid: string targetDocVersion: string }) { const createComment = useCreateComment() @@ -81,7 +82,7 @@ export function CommentGroup({ label: 'Reply', icon: Reply, onPress: () => { - createComment(targetDocEid, targetDocVersion, comment.id) + createComment(targetDocUid, targetDocVersion, comment.id) }, }, { @@ -111,12 +112,14 @@ export function CommentGroup({ const quotingCommentId = unpackHmId(comment.id) if (!targetId || !quotingCommentId) return createComment( - targetDocEid, + targetDocUid, targetDocVersion, lastComment.id, - createHmId('c', quotingCommentId.eid, { - blockRef: blockId, - }), + packHmId( + hmId('comment', quotingCommentId.uid, { + blockRef: blockId, + }), + ), ) }} /> @@ -148,7 +151,7 @@ export function CommentGroup({ onPress={() => { const lastComment = group.comments.at(-1) if (!lastComment) return - createComment(targetDocEid, targetDocVersion, lastComment.id) + createComment(targetDocUid, targetDocVersion, lastComment.id) }} icon={Reply} > @@ -162,14 +165,14 @@ export function CommentGroup({ export function CommentThread({ targetCommentId, - targetDocEid, + targetDocUid, onReplyBlock, }: { targetCommentId: string - targetDocEid: string + targetDocUid: string onReplyBlock: (commentId: string, blockId: string) => void }) { - const thread = useCommentReplies(targetCommentId, targetDocEid) + const thread = useCommentReplies(targetCommentId, targetDocUid) return ( <> @@ -198,7 +201,7 @@ export function EntityCommentsAccessory({ activeVersion: string }) { const navigate = useNavigate() - const commentGroups = useDocumentCommentGroups(id.eid) + const commentGroups = useDocumentCommentGroups(id.uid) const createComment = trpc.comments.createCommentDraft.useMutation() return ( { createComment .mutateAsync({ - targetDocEid: id.eid, + targetDocUid: id.uid, targetDocVersion: activeVersion, targetCommentId: null, }) @@ -233,7 +236,7 @@ export function EntityCommentsAccessory({ ))} diff --git a/frontend/apps/desktop/src/components/contacts-prompt.tsx b/frontend/apps/desktop/src/components/contacts-prompt.tsx index 51dc67e8..cd976b30 100644 --- a/frontend/apps/desktop/src/components/contacts-prompt.tsx +++ b/frontend/apps/desktop/src/components/contacts-prompt.tsx @@ -35,7 +35,7 @@ function AddConnectionForm({ const [peerText, setPeer] = useState('') const daemonInfo = useDaemonInfo() const account = useMyAccount_deprecated() - const profile = useEntity(account ? hmId('a', account) : undefined) + const profile = useEntity(account ? hmId('d', account) : undefined) const deviceId = daemonInfo.data?.peerId const peerInfo = usePeerInfo(deviceId) console.log('peerInfo', peerInfo.data, deviceId) diff --git a/frontend/apps/desktop/src/components/copy-gateway-reference.tsx b/frontend/apps/desktop/src/components/copy-gateway-reference.tsx index 41074be4..966c6043 100644 --- a/frontend/apps/desktop/src/components/copy-gateway-reference.tsx +++ b/frontend/apps/desktop/src/components/copy-gateway-reference.tsx @@ -6,8 +6,9 @@ import { writeableStateStream, } from '@shm/shared' import { - createHmId, createPublicWebHmUrl, + hmId, + packHmId, } from '@shm/shared/src/utils/entity-id-url' import { Button, @@ -49,11 +50,10 @@ export function useCopyGatewayReference() { const pushOnCopy = usePushOnCopy() const push = usePushPublication() function onCopy(input: UnpackedHypermediaId) { - const publicUrl = createPublicWebHmUrl(input.type, input.eid, { + const publicUrl = createPublicWebHmUrl(input.type, input.uid, { version: input.version, blockRef: input.blockRef, blockRange: input.blockRange, - variants: input.variants, hostname: gatewayUrl.data, }) const [setIsPublished, isPublished] = @@ -63,7 +63,7 @@ export function useCopyGatewayReference() { fetchWebLinkMeta(publicUrl) .then((meta) => { // toast.success(JSON.stringify(meta)) - const destId = createHmId(input.type, input.eid) + const destId = packHmId(hmId(input.type, input.uid)) const correctId = meta?.hmId === destId const correctVersion = !input.version || meta?.hmVersion === input.version @@ -100,7 +100,7 @@ export function useCopyGatewayReference() { host={gatewayHost} isPublished={isPublished} pushingState={pushingState} - hmId={createHmId(input.type, input.eid)} + hmId={packHmId(input)} />, {duration: 8000}, ) @@ -216,7 +216,7 @@ export function PushToGatewayDialog({ onPress={() => { if (shouldDoAlways) setDoEveryTime('always') push - .mutateAsync(createHmId(input.type, input.eid)) + .mutateAsync(packHmId(input)) .then(() => { onClose() toast.success(`Pushed to ${input.host}`) diff --git a/frontend/apps/desktop/src/components/document-list-item.tsx b/frontend/apps/desktop/src/components/document-list-item.tsx index 2cb36367..c599ef0c 100644 --- a/frontend/apps/desktop/src/components/document-list-item.tsx +++ b/frontend/apps/desktop/src/components/document-list-item.tsx @@ -4,8 +4,9 @@ import { Document, HMAccount, HMDocument, - createHmId, getDocumentTitle, + hmId, + packHmId, } from '@shm/shared' import { ArrowUpRight, @@ -55,9 +56,11 @@ export const DocumentListItem = React.memo(function DocumentListItem({ const docHmId = docRoute?.id const docUrl = docHmId && docRoute - ? createHmId('d', docHmId.eid, { - version: docRoute.versionId, - }) + ? packHmId( + hmId('d', docHmId.uid, { + version: docRoute.versionId, + }), + ) : undefined const favorite = useFavorite(docUrl) @@ -89,13 +92,13 @@ export const DocumentListItem = React.memo(function DocumentListItem({ theme="yellow" zIndex="$zIndex.5" onPress={(e) => { - navigate( - { - key: 'draft', - id: hasDraft.id, - }, - e, - ) + // navigate( + // { + // key: 'draft', + // id: hasDraft.id, // todo use unpacked ID here + // }, + // e, + // ) }} size="$1" > diff --git a/frontend/apps/desktop/src/components/network-dialog.tsx b/frontend/apps/desktop/src/components/network-dialog.tsx index c484f3d3..b3ce8f52 100644 --- a/frontend/apps/desktop/src/components/network-dialog.tsx +++ b/frontend/apps/desktop/src/components/network-dialog.tsx @@ -151,7 +151,7 @@ const PeerRow = React.memo(function PeerRow({ function handlePress() { if (isSite && account?.profile?.alias) openUrl(account?.profile?.alias) else if (!isSite && account?.id) - spawn({key: 'document', id: hmId('a', account.id)}) + spawn({key: 'document', id: hmId('d', account.id)}) else toast.error('Could not open account') } function handleCopyPeerId() { diff --git a/frontend/apps/desktop/src/components/publish-draft-button.tsx b/frontend/apps/desktop/src/components/publish-draft-button.tsx index 76a9ac54..42877820 100644 --- a/frontend/apps/desktop/src/components/publish-draft-button.tsx +++ b/frontend/apps/desktop/src/components/publish-draft-button.tsx @@ -5,7 +5,7 @@ import {useNavRoute} from '@/utils/navigation' import {DraftRoute} from '@/utils/routes' import {useNavigate} from '@/utils/useNavigate' import {PlainMessage} from '@bufbuild/protobuf' -import {Document, hmId, unpackHmId} from '@shm/shared' +import {Document, hmId, packHmId} from '@shm/shared' import { AlertCircle, Button, @@ -29,34 +29,38 @@ export default function PublishDraftButton() { if (!draftRoute) throw new Error('DraftPublicationButtons requires draft route') const draftId = draftRoute.id - const unpackedDraftId = unpackHmId(draftRoute.id) - const draft = useDraft(draftRoute.id) - const prevEntity = useEntity( - unpackedDraftId?.type !== 'draft' ? unpackedDraftId : undefined, - ) + const packedDraftId = draftId ? packHmId(draftId) : undefined + const draft = useDraft(packedDraftId) + const prevEntity = useEntity(draftId?.type !== 'draft' ? draftId : undefined) const invalidate = useQueryInvalidator() const deleteDraft = trpc.drafts.delete.useMutation({ onSuccess: () => { invalidate(['trpc.drafts.get']) }, }) - const publish = usePublishDraft(grpcClient, draftRoute.id) + const publish = usePublishDraft(grpcClient, packedDraftId) function handlePublish() { - if (draft.data && unpackedDraftId) { + if (draft.data && draftId) { publish .mutateAsync({ draft: draft.data, previous: prevEntity.data?.document as | PlainMessage | undefined, - id: unpackedDraftId.type === 'draft' ? undefined : unpackedDraftId, + id: draftId.type === 'draft' ? undefined : draftId, }) .then(async (res) => { - const resultDocId = hmId('a', unpackedDraftId.eid) + const resultDocId = hmId('d', draftId.uid, {path: draftId.path}) if (draftId) - await deleteDraft.mutateAsync(draftId).catch((e) => { - console.error('Failed to delete draft', e) - }) + await deleteDraft + .mutateAsync(packHmId(draftId)) + .catch((e) => { + console.error('Failed to delete draft', e) + }) + .then(() => { + invalidate(['trpc.drafts.get']) // todo, invalidate the specific draft id + invalidate(['trpc.drafts.list']) + }) if (resultDocId) { navigate({key: 'document', id: resultDocId}) } else { diff --git a/frontend/apps/desktop/src/components/sidebar-base.tsx b/frontend/apps/desktop/src/components/sidebar-base.tsx index 49396c8e..64eea833 100644 --- a/frontend/apps/desktop/src/components/sidebar-base.tsx +++ b/frontend/apps/desktop/src/components/sidebar-base.tsx @@ -31,7 +31,6 @@ import { ArrowDownRight, ChevronDown, ChevronRight, - Contact, FileText, Hash, Search, @@ -366,7 +365,7 @@ export function MyAccountItem({ appError('Account has not loaded.') return } - onRoute({key: 'document', id: hmId('a', account.id)}) + onRoute({key: 'document', id: hmId('d', account.id)}) }} icon={ { return myAccount - ? ({key: 'document', id: hmId('a', myAccount)} as DocumentRoute) + ? ({key: 'document', id: hmId('d', myAccount)} as DocumentRoute) : null }, [myAccount]) const navigate = useNavigate() @@ -64,8 +56,8 @@ function _SidebarNeo() { isMyAccountDraftActive || (firstEntityRoute && firstEntityRoute.key === 'document' && - firstEntityRoute.id.type === 'a' && - firstEntityRoute.id.eid === myAccount) + firstEntityRoute.id.type === 'd' && + firstEntityRoute.id.uid === myAccount) // const [collapseMe, setCollapseMe] = useState(!isMyAccountActive) // const entityContents = useRouteEntities( // myAccountRoute ? [myAccountRoute, ...entityRoutes] : entityRoutes, @@ -197,12 +189,10 @@ export function getItemDetails( let icon: IconDefinition | undefined = undefined let isDraft = false if (!entity) return null - console.log(`== ~ entity.id:`, entity.id) - if (entity.id.type === 'a') { - name = getProfileName(entity.document) - icon = Contact + if (entity.id.type === 'd') { + name = getDocumentTitle(entity.document) + icon = FileText } - if (entity.id.type === 'draft') { name = '' icon = FilePen @@ -210,7 +200,6 @@ export function getItemDetails( } if (entity.id.path?.[0] != '') { - console.log('--- ENTITY WITH PATH', entity) name = getDocumentTitle(entity.document) icon = FileText } @@ -279,7 +268,7 @@ function ContextItems({ { if (route.key === 'draft') return @@ -670,19 +659,8 @@ function SidebarFavorites({ if (!collapse) { items = favorites.map((fav) => { const {key, url} = fav - if (key === 'account') { - return ( - - ) - } if (key === 'document') { - return ( - - ) + return } return null }) @@ -719,35 +697,7 @@ function SidebarFavorites({ ) } -function FavoriteAccountItem({ - url, - onNavigate, -}: { - url: string - onNavigate: (route: NavRoute) => void -}) { - const id = unpackHmId(url) - const route = useNavRoute() - const accountId = id?.eid - const {data} = useEntity(id) - if (!accountId) return null - return ( - { - onNavigate({key: 'document', id: hmId('a', accountId)}) - }} - title={getProfileName(data?.document)} - /> - ) -} - -function FavoritePublicationItem({ +function FavoriteItem({ url, onNavigate, }: { @@ -757,7 +707,7 @@ function FavoritePublicationItem({ const id = unpackHmId(url) const route = useNavRoute() const doc = useEntity(id) - const documentId = id?.qid + const documentId = id?.id if (!documentId) return null return ( { onNavigate({ diff --git a/frontend/apps/desktop/src/components/titlebar-common.tsx b/frontend/apps/desktop/src/components/titlebar-common.tsx index 3c4aef18..418c0c14 100644 --- a/frontend/apps/desktop/src/components/titlebar-common.tsx +++ b/frontend/apps/desktop/src/components/titlebar-common.tsx @@ -22,9 +22,10 @@ import { BlockRange, ExpandedBlockRange, HYPERMEDIA_ENTITY_TYPES, - createHmId, createPublicWebHmUrl, getDocumentTitle, + hmId, + packHmId, } from '@shm/shared' import { Back, @@ -107,9 +108,11 @@ export function DocOptionsButton() { }, ] const docUrl = route.id - ? createHmId('d', route.id.eid, { - version: route.id.version, - }) + ? packHmId( + hmId('d', route.id.uid, { + version: route.id.version, + }), + ) : null menuItems.push(useFavoriteMenuItem(docUrl)) @@ -129,21 +132,18 @@ function EditDocButton() { const myAccountIds = useMyAccountIds() const navigate = useNavigate() const draft = useDraft(route.id.id) - if (route.id.type === 'a' && !myAccountIds.data?.includes(route.id.eid)) { - return null - } if (route.tab !== 'home' && route.tab) return null const hasExistingDraft = !!draft.data return ( <> - + ) : null} @@ -490,8 +490,8 @@ function EmbedControl({ }, }, ]} - enterStyle={{ y: -10, opacity: 0 }} - exitStyle={{ y: -10, opacity: 0 }} + enterStyle={{y: -10, opacity: 0}} + exitStyle={{y: -10, opacity: 0}} elevate={true} > @@ -503,7 +503,7 @@ function EmbedControl({ handleBlockToDocument() }} title="Convert to Document Embed" - // icon={item.icon} + // icon={item.icon} /> ) : null} diff --git a/frontend/apps/desktop/src/editor/hyperlink-toolbar.tsx b/frontend/apps/desktop/src/editor/hyperlink-toolbar.tsx index fb7c8d4b..356ba16f 100644 --- a/frontend/apps/desktop/src/editor/hyperlink-toolbar.tsx +++ b/frontend/apps/desktop/src/editor/hyperlink-toolbar.tsx @@ -1,4 +1,4 @@ -import {createHmDocLink, unpackHmId} from '@shm/shared' +import {createHmDocLink_DEPRECATED, unpackHmId} from '@shm/shared' import { Button, Check, @@ -107,8 +107,8 @@ export function HypermediaLinkToolbar( key={_latest} value={_latest} onCheckedChange={(newValue) => { - let newUrl = createHmDocLink({ - documentId: unpackedRef?.qid, + let newUrl = createHmDocLink_DEPRECATED({ + documentId: unpackedRef?.id, version: unpackedRef?.version, blockRef: unpackedRef?.blockRef, variants: unpackedRef?.variants, diff --git a/frontend/apps/desktop/src/editor/mentions-plugin.tsx b/frontend/apps/desktop/src/editor/mentions-plugin.tsx index 8483fb67..1e336f27 100644 --- a/frontend/apps/desktop/src/editor/mentions-plugin.tsx +++ b/frontend/apps/desktop/src/editor/mentions-plugin.tsx @@ -88,7 +88,7 @@ function InlineEmbedNodeComponent(props: any) { export function MentionToken(props: {value: string; selected?: boolean}) { const unpackedRef = unpackHmId(props.value) - if (unpackedRef?.type == 'a') { + if (unpackedRef?.type == 'd') { // todo, remove and merge . this was removed when the id.type=d was removed return } else { @@ -104,11 +104,11 @@ function AccountMention({ unpackedRef: UnpackedHypermediaId selected?: boolean }) { - const account = useAccount_deprecated(unpackedRef.eid) + const account = useAccount_deprecated(unpackedRef.uid) return ( - @{account.data?.profile?.alias || unpackedRef.eid} + @{account.data?.profile?.alias || unpackedRef.uid} ) } @@ -130,7 +130,7 @@ function DocumentMention({ {doc.data?.document ? getDocumentTitle(doc.data.document) - : unpackedRef.qid} + : unpackedRef.id} ) } diff --git a/frontend/apps/desktop/src/editor/tiptap-extension-link/helpers/pasteHandler.ts b/frontend/apps/desktop/src/editor/tiptap-extension-link/helpers/pasteHandler.ts index 2d10e611..70ea8852 100644 --- a/frontend/apps/desktop/src/editor/tiptap-extension-link/helpers/pasteHandler.ts +++ b/frontend/apps/desktop/src/editor/tiptap-extension-link/helpers/pasteHandler.ts @@ -6,12 +6,13 @@ import { GRPCClient, StateStream, UnpackedHypermediaId, - createHmId, extractBlockRefOfUrl, + hmId, hmIdWithVersion, isHypermediaScheme, isPublicGatewayLink, normalizeHmId, + packHmId, unpackHmId, } from '@shm/shared' import {Editor} from '@tiptap/core' @@ -149,20 +150,17 @@ export function pasteHandler(options: PasteHandlerOptions): Plugin { return false } - if (selection.empty && unpackedHmId?.eid && unpackedHmId.type) { + if (selection.empty && unpackedHmId?.uid && unpackedHmId.type) { let tr = view.state.tr let pos = tr.selection.from - const normalizedHmUrl = createHmId( - unpackedHmId.type, - unpackedHmId.eid, - { + const normalizedHmUrl = packHmId( + hmId(unpackedHmId.type, unpackedHmId.uid, { blockRef: unpackedHmId.blockRef, blockRange: unpackedHmId.blockRange, version: unpackedHmId.version, - variants: unpackedHmId.variants, latest: unpackedHmId.latest, - }, + }), ) fetchEntityTitle(unpackedHmId, options.grpcClient) @@ -507,25 +505,13 @@ async function fetchEntityTitle( grpcClient: GRPCClient, ) { if (hmId.type == 'd') { - console.log('aa 1') - const doc = await grpcClient.documents.getDocument({ - documentId: hmId.qid, - version: hmId.version ? hmId.version : undefined, - }) - return { - title: doc.metadata?.name || null, - } - } else if (hmId.type == 'a') { - const profile = await grpcClient.documents.getProfileDocument({ - accountId: hmId.eid, - }) return { - title: profile.metadata?.name || null, + title: 'broken-title-code' || null, } - } else if (hmId.type == 'c') { + } else if (hmId.type == 'comment') { try { const comment = await grpcClient.comments.getComment({ - id: hmId.qid, + id: hmId.id, }) if (comment) { diff --git a/frontend/apps/desktop/src/models/accounts.ts b/frontend/apps/desktop/src/models/accounts.ts index b5c07de1..95bce619 100644 --- a/frontend/apps/desktop/src/models/accounts.ts +++ b/frontend/apps/desktop/src/models/accounts.ts @@ -5,7 +5,7 @@ import {queryKeys} from '@/models/query-keys' import {client, trpc} from '@/trpc' import {toPlainMessage} from '@bufbuild/protobuf' import {Code, ConnectError} from '@connectrpc/connect' -import {createHmId, GRPCClient, HMAccount, HMDraft, hmId} from '@shm/shared' +import {GRPCClient, HMAccount, HMDraft, hmId, packHmId} from '@shm/shared' import {useQueries, useQuery, UseQueryOptions} from '@tanstack/react-query' import {useEntities, useEntity} from './entities' import {useConnectedPeers} from './networking' @@ -59,7 +59,7 @@ export function useAllAccounts() { export function useAllAccountProfiles() { const allAccounts = useAllAccounts() const allProfiles = useEntities( - allAccounts.data?.accounts.map((a) => hmId('a', a.id)) || [], + allAccounts.data?.accounts.map((a) => hmId('d', a.id)) || [], {enabled: !!allAccounts.data}, ) return allProfiles.map((query) => { @@ -103,27 +103,11 @@ export function useDrafts(draftIds: string[]) { } export function useProfileWithDraft(accountId?: string) { - const profile = useEntity(accountId ? hmId('a', accountId) : undefined) - const draft = useDraft(accountId ? createHmId('a', accountId) : undefined) + const profile = useEntity(accountId ? hmId('d', accountId) : undefined) + const draft = useDraft(accountId ? packHmId(hmId('d', accountId)) : undefined) return {profile: profile.data?.document, draft: draft?.data} } -export function useProfilesWithDrafts(accountIds: string[]) { - const profiles = useEntities(accountIds.map((uid) => hmId('a', uid))) - const drafts = useDrafts(accountIds) - return accountIds.map((accountId, index) => { - const profile = profiles[index] - const draft = drafts[index] - if (profile.data?.type !== 'a') return null - return { - accountId, - account: profile.data?.account, - document: profile.data?.document, - draft: draft.data, - } - }) -} - export function queryDraft({ draftId, grpcClient, @@ -141,9 +125,6 @@ export function queryDraft({ if (!draftId) return null try { const draftReq = await client.drafts.get.query(draftId) - - console.log(`== ~ queryFn: ~ draft:`, draftReq) - draft = draftReq } catch (error) { const connectErr = ConnectError.from(error) diff --git a/frontend/apps/desktop/src/models/comments.ts b/frontend/apps/desktop/src/models/comments.ts index 34bbac66..f8a887e7 100644 --- a/frontend/apps/desktop/src/models/comments.ts +++ b/frontend/apps/desktop/src/models/comments.ts @@ -6,8 +6,10 @@ import {client, trpc} from '@/trpc' import { HMComment, HMCommentDraft, - createHmId, + UnpackedHypermediaId, fromHMBlock, + hmId, + packHmId, toHMBlock, unpackHmId, writeableStateStream, @@ -113,9 +115,9 @@ export function useCommentGroups( export function useCommentReplies( targetCommentId: string, - targetDocEid: string, + targetDocUid: string, ) { - const comments = useAllPublicationComments(targetDocEid) + const comments = useAllPublicationComments(targetDocUid) return useMemo(() => { let comment = comments.data?.find((c) => c.id === targetCommentId) const thread = [comment] @@ -138,7 +140,7 @@ export function useCommentDraft(commentId: string, opts?: UseQueryOptions) { } export function useComment( - commentId: string | null | undefined, + id: UnpackedHypermediaId | null | undefined, opts?: UseQueryOptions, ) { const grpcClient = useGRPCClient() @@ -157,27 +159,27 @@ export function useComment( }) } -export function useAllPublicationComments(docEid: string | undefined) { +export function useAllPublicationComments(docUid: string | undefined) { const grpcClient = useGRPCClient() return useQuery({ queryFn: async () => { - if (!docEid) return [] + if (!docUid) return [] let res = await grpcClient.comments.listComments({ - target: createHmId('d', docEid), + target: packHmId(hmId('d', docUid)), }) return res.comments as unknown as HMComment[] }, - enabled: !!docEid, + enabled: !!docUid, refetchInterval: 10_000, - queryKey: [queryKeys.PUBLICATION_COMMENTS, docEid], + queryKey: [queryKeys.PUBLICATION_COMMENTS, docUid], }) } export function useDocumentCommentGroups( - docEid: string | undefined, + docUid: string | undefined, commentId: string | null = null, ) { - const comments = useAllPublicationComments(docEid) + const comments = useAllPublicationComments(docUid) return useCommentGroups(comments.data, commentId) } @@ -220,7 +222,6 @@ export function useCommentEditor(opts: {onDiscard?: () => void} = {}) { const draft = initCommentDraft.current if (!readyEditor.current || !draft) return const editor = readyEditor.current - console.log('comment draft mmokay') const editorBlocks = toHMBlock(draft.blocks) editor.removeBlocks(editor.topLevelBlocks) editor.replaceBlocks(editor.topLevelBlocks, editorBlocks) @@ -302,7 +303,7 @@ export function useCommentEditor(opts: {onDiscard?: () => void} = {}) { throw new Error('no valid draft in route for getCommentDraft') initCommentDraft.current = draft streams.current.targetCommentId[0](draft.targetCommentId) - const docId = createHmId('d', draft.targetDocEid) + const docId = packHmId(hmId('d', draft.targetDocUid)) streams.current.targetDocId[0](docId) initDraft() }, @@ -319,7 +320,7 @@ export function useCommentEditor(opts: {onDiscard?: () => void} = {}) { // throw new Error('no valid draft in route for getCommentDraft') // initCommentDraft.current = draft // setTargetCommentId(draft.targetCommentId) - // setTargetDocId(createHmId('d', draft.targetDocEid)) + // setTargetDocId(packHmId(hmId('d', draft.targetDocUid))) // initDraft() // }) // }, [editCommentId]) @@ -347,7 +348,7 @@ export function useCommentEditor(opts: {onDiscard?: () => void} = {}) { ? unpackHmId(newComment.target) : null targetDocId && - invalidate([queryKeys.PUBLICATION_COMMENTS, targetDocId.eid]) + invalidate([queryKeys.PUBLICATION_COMMENTS, targetDocId.uid]) invalidate(['trpc.comments.getCommentDrafts']) invalidate([queryKeys.FEED_LATEST_EVENT]) invalidate([queryKeys.RESOURCE_FEED_LATEST_EVENT]) @@ -382,9 +383,11 @@ export function useCommentEditor(opts: {onDiscard?: () => void} = {}) { }) publishComment.mutate({ content: contentWithoutLastEmptyBlock, - targetDocId: createHmId('d', draft.targetDocEid, { - version: draft.targetDocVersion, - }), + targetDocId: packHmId( + hmId('d', draft.targetDocUid, { + version: draft.targetDocVersion, + }), + ), targetCommentId: draft.targetCommentId, }) } @@ -398,7 +401,9 @@ export function useCommentEditor(opts: {onDiscard?: () => void} = {}) { { type: 'embed', props: { - ref: createHmId('c', commentId.eid, {blockRef: blockId}), + ref: packHmId( + hmId('comment', commentId.uid, {blockRef: blockId}), + ), textAlignment: 'left', childrenType: 'group', }, @@ -435,7 +440,7 @@ export function useCreateComment() { const navigate = useNavigate() const createComment = trpc.comments.createCommentDraft.useMutation() return ( - targetDocEid: string, + targetDocUid: string, targetDocVersion: string, targetCommentId?: string, embedRef?: string, @@ -455,7 +460,7 @@ export function useCreateComment() { : [{type: 'paragraph', text: '', attributes: {}, children: []}] createComment .mutateAsync({ - targetDocEid, + targetDocUid, targetCommentId: targetCommentId || null, targetDocVersion, blocks: content, diff --git a/frontend/apps/desktop/src/models/documents.ts b/frontend/apps/desktop/src/models/documents.ts index 624890c4..1172ebec 100644 --- a/frontend/apps/desktop/src/models/documents.ts +++ b/frontend/apps/desktop/src/models/documents.ts @@ -18,7 +18,6 @@ import { HMDraft, UnpackedHypermediaId, fromHMBlock, - getParentIds, hmDocument, toHMBlock, unpackHmId, @@ -68,7 +67,7 @@ export function useDraftList() { } export function useDeleteDraft( - opts: UseMutationOptions, + opts?: UseMutationOptions, ) { const invalidate = useQueryInvalidator() const deleteDraft = trpc.drafts.delete.useMutation({ @@ -76,7 +75,7 @@ export function useDeleteDraft( onSuccess: (data, input, ctx) => { invalidate(['trpc.drafts.get', input]) invalidate(['trpc.drafts.list']) - opts.onSuccess?.(data, input, ctx) + opts?.onSuccess?.(data, input, ctx) }, }) return deleteDraft @@ -109,7 +108,6 @@ function extractRefs( } } children.forEach(extractRefsFromBlock) - // console.log('extractRefs', children, refs) return refs } @@ -159,7 +157,7 @@ export function getDefaultShortname( docId: string, ) { const unpackedId = unpackHmId(docId) - const idShortname = unpackedId ? unpackedId.eid.slice(0, 5).toLowerCase() : '' + const idShortname = unpackedId ? unpackedId.uid.slice(0, 5).toLowerCase() : '' const kebabName = docTitle ? pathNameify(docTitle) : idShortname const shortName = kebabName.length > 40 ? kebabName.substring(0, 40) : kebabName @@ -244,8 +242,8 @@ export function usePublishDraft( ) const publishedDoc = await grpcClient.documents.createDocumentChange({ signingKeyName, - namespace: id.eid, - path: id.path?.length ? `${id.path.join('/')}` : '', + namespace: id.uid, + path: id.path?.length ? `/${id.path.join('/')}` : '', changes: allChanges, }) @@ -259,13 +257,11 @@ export function usePublishDraft( } }, onSuccess: (result, variables, context) => { - const documentId = variables.id?.qid + const documentId = variables.id?.id opts?.onSuccess?.(result, variables, context) if (documentId) { invalidate([queryKeys.ENTITY, documentId]) - getParentIds(documentId).forEach((id) => { - invalidate([queryKeys.ENTITY, id]) - }) + invalidate([queryKeys.DOC_LIST_DIRECTORY, variables.id?.uid]) } }, }) @@ -507,12 +503,17 @@ export function useDraftEditor({id}: {id: string | undefined}) { event: {output: OutputFrom} }) => { if (event.output.id) { - replaceRoute({...route, id: event.output.id}) + const id = unpackHmId(event.output.id) + if (!id) throw new Error('Draft save resulted in invalid hm ID') + if (route.key !== 'draft') + throw new Error('Invalid route, draft expected.') + replaceRoute({...route, id}) } }, onSaveSuccess: function () { invalidate([queryKeys.DRAFT, id]) invalidate(['trpc.drafts.get']) + invalidate(['trpc.drafts.list']) invalidate([queryKeys.ENTITY, id]) }, }, @@ -707,12 +708,17 @@ export function usePushPublication() { export function useListDirectory(id: UnpackedHypermediaId) { const grpcClient = useGRPCClient() return useQuery({ - queryKey: [queryKeys.DOC_LIST_DIRECTORY, id.eid], + queryKey: [queryKeys.DOC_LIST_DIRECTORY, id.uid], queryFn: async () => { const res = await grpcClient.documents.listDocuments({ - namespace: id.eid, + namespace: id.uid, }) - const docs = res.documents.map(toPlainMessage) + const docs = res.documents + .map(toPlainMessage) + .filter((doc) => doc.path !== '') + .map((doc) => { + return {...doc, path: doc.path.slice(1).split('/')} + }) return docs }, }) @@ -1012,13 +1018,13 @@ function observeBlocks( export function useAccountDocuments(id?: UnpackedHypermediaId) { const grpcClient = useGRPCClient() return useQuery({ - queryKey: [queryKeys.ACCOUNT_DOCUMENTS, id?.eid], - enabled: !!id?.eid, + queryKey: [queryKeys.ACCOUNT_DOCUMENTS, id?.uid], + enabled: !!id?.uid, queryFn: async () => { - const namespace = id?.eid + const namespace = id?.uid if (!namespace) return {documents: []} const result = await grpcClient.documents.listDocuments({ - namespace: id?.eid, + namespace: id?.uid, }) const documents = result.documents.map((response) => toPlainMessage(response), diff --git a/frontend/apps/desktop/src/models/entities.ts b/frontend/apps/desktop/src/models/entities.ts index 1962fabb..31cb35f6 100644 --- a/frontend/apps/desktop/src/models/entities.ts +++ b/frontend/apps/desktop/src/models/entities.ts @@ -2,6 +2,7 @@ import {toPlainMessage} from '@bufbuild/protobuf' import { GRPCClient, HMEntityContent, + hmId, UnpackedHypermediaId, unpackHmId, } from '@shm/shared' @@ -36,13 +37,12 @@ export function useDeleteEntity( context, ) => { const hmId = unpackHmId(variables.id) - if (hmId?.type === 'a') { + if (hmId?.type === 'd') { invalidate([queryKeys.ENTITY, variables.id]) invalidate([queryKeys.ACCOUNT_DOCUMENTS]) - invalidate([queryKeys.DOCUMENT_LIST]) invalidate([queryKeys.LIST_ACCOUNTS]) - invalidate([queryKeys.ACCOUNT, hmId.eid]) - } else if (hmId?.type === 'c') { + invalidate([queryKeys.ACCOUNT, hmId.uid]) + } else if (hmId?.type === 'comment') { invalidate([queryKeys.ENTITY, variables.id]) invalidate([queryKeys.COMMENT, variables.id]) invalidate([queryKeys.PUBLICATION_COMMENTS]) @@ -88,11 +88,9 @@ export function useUndeleteEntity( if (hmId?.type === 'd') { invalidate([queryKeys.ENTITY, variables.id]) invalidate([queryKeys.ACCOUNT_DOCUMENTS]) - invalidate([queryKeys.DOCUMENT_LIST]) - } else if (hmId?.type === 'a') { invalidate([queryKeys.LIST_ACCOUNTS]) - invalidate([queryKeys.ACCOUNT, hmId.eid]) - } else if (hmId?.type === 'c') { + invalidate([queryKeys.ACCOUNT, hmId.uid]) + } else if (hmId?.type === 'comment') { invalidate([queryKeys.COMMENT, variables.id]) invalidate([queryKeys.PUBLICATION_COMMENTS]) } @@ -115,10 +113,9 @@ function getRouteBreadrumbRoutes( return route.id.path?.length ? route.id.path.map((path) => ({ ...route, - id: { - ...route.id, + id: hmId(route.id.type, route.id.uid, { path: [path], - }, + }), })) : [route] } @@ -133,7 +130,8 @@ export function useRouteBreadcrumbRoutes( route: NavRoute, ): Array { return useMemo(() => { - return getRouteBreadrumbRoutes(route) + const routes = getRouteBreadrumbRoutes(route) + return routes }, [route]) } @@ -154,15 +152,13 @@ export function queryEntity( return { ...options, enabled: options?.enabled ?? !!id, - queryKey: [queryKeys.ENTITY, id?.id, id?.version], + queryKey: [queryKeys.ENTITY, id?.id], queryFn: async (): Promise => { if (!id) return null - const {version} = id try { const document = await grpcClient.documents.getDocument({ - namespace: id.eid, - path: id.path?.length ? id.path.join('/') : '', - // version: version || undefined, + namespace: id.uid, + path: id.path?.length ? `/${id.path.join('/')}` : '', }) return {id, document: toPlainMessage(document)} } catch (e) { diff --git a/frontend/apps/desktop/src/models/favorites.ts b/frontend/apps/desktop/src/models/favorites.ts index 162d838b..fa75ccd4 100644 --- a/frontend/apps/desktop/src/models/favorites.ts +++ b/frontend/apps/desktop/src/models/favorites.ts @@ -28,8 +28,8 @@ export function useFavorites() { }) const accounts: string[] = [] unpackedIds?.forEach((id) => { - if (id?.type === 'a') { - accounts.push(id.eid) + if (id?.type === 'd') { + accounts.push(id.uid) } }) return { @@ -42,9 +42,9 @@ export function useFavorites() { const favoriteItems: FavoriteItem[] = [] favorites?.forEach((id, favoriteIndex) => { const url = favoriteUrls[favoriteIndex] - if (id?.type === 'a' && url) { + if (id?.type === 'd' && url) { const accountQ = accountsQuery.find( - (account) => account.data?.id === id.eid, + (account) => account.data?.id === id.uid, ) const account = accountQ?.data if (account) { @@ -52,7 +52,7 @@ export function useFavorites() { key: 'account', id, url, - accountId: id.qid, + accountId: id.id, account, }) } diff --git a/frontend/apps/desktop/src/models/feed.ts b/frontend/apps/desktop/src/models/feed.ts index 2f90adc5..8211356e 100644 --- a/frontend/apps/desktop/src/models/feed.ts +++ b/frontend/apps/desktop/src/models/feed.ts @@ -42,8 +42,8 @@ export function useFeedWithLatest(trustedOnly: boolean = false) { function feedFilterFromId(id?: string): PartialMessage { const hmId = id ? unpackHmId(id) : null return { - filterResource: !id || hmId?.type === 'a' ? undefined : [id], - filterUsers: hmId?.type === 'a' ? [hmId.eid] : undefined, + filterResource: !id || hmId?.type === 'd' ? undefined : [id], + filterUsers: hmId?.type === 'd' ? [hmId.uid] : undefined, } } export function useResourceFeedWithLatest(id?: string) { @@ -134,7 +134,7 @@ export function useFeed(trustedOnly: boolean = false) { const {eventTime} = event const id = unpackHmId(event.data.value.resource) updateCidTypes.set(event.data.value.cid, id?.type) - updateEids.set(event.data.value.cid, id?.eid) + updateEids.set(event.data.value.cid, id?.uid) if (id?.type === 'g') { groupUpdateCids.push(event.data.value.cid) groupUpdateTimes.set(event.data.value.cid, eventTime) @@ -154,7 +154,7 @@ export function useFeed(trustedOnly: boolean = false) { const contentItemId = unpackHmId(value) const time = groupUpdateTimes.get(cid) if (contentItemId?.type === 'd' && time) { - timeMap.set(`${contentItemId.eid}-${contentItemId.version}`, time) + timeMap.set(`${contentItemId.uid}-${contentItemId.version}`, time) } } } @@ -167,10 +167,10 @@ export function useFeed(trustedOnly: boolean = false) { if (event.data.value.blobType === 'KeyDelegation') return false if (event.data.value.blobType === 'Change') { const type = updateCidTypes.get(event.data.value.cid) - const eid = updateEids.get(event.data.value.cid) - if (eid && type === 'd') { + const uid = updateEids.get(event.data.value.cid) + if (uid && type === 'd') { const groupContentUpdateTime = timeMap.get( - `${eid}-${event.data.value.cid}`, + `${uid}-${event.data.value.cid}`, ) const groupUpdateTimeIsNear = !!groupContentUpdateTime && diff --git a/frontend/apps/desktop/src/models/query-keys.ts b/frontend/apps/desktop/src/models/query-keys.ts index 57d02e90..2af0cbbe 100644 --- a/frontend/apps/desktop/src/models/query-keys.ts +++ b/frontend/apps/desktop/src/models/query-keys.ts @@ -42,7 +42,7 @@ export const queryKeys = { // comments COMMENT: 'COMMENT', //, commentId: string - PUBLICATION_COMMENTS: 'PUBLICATION_COMMENTS', //, docEid: string + PUBLICATION_COMMENTS: 'PUBLICATION_COMMENTS', //, docUid: string // content-graph ENTITY_CITATIONS: 'ENTITY_CITATIONS', //, entityId: string diff --git a/frontend/apps/desktop/src/pages/_draft.tsx b/frontend/apps/desktop/src/pages/_draft.tsx deleted file mode 100644 index 270df761..00000000 --- a/frontend/apps/desktop/src/pages/_draft.tsx +++ /dev/null @@ -1,665 +0,0 @@ -import Footer from '@/components/footer' -import {MainWrapper} from '@/components/main-wrapper' -import {subscribeDraftFocus} from '@/draft-focusing' -import {BlockNoteEditor, getBlockInfoFromPos} from '@/editor' -import {useMyAccount_deprecated} from '@/models/accounts' -import {useDraftEditor} from '@/models/documents' -import {draftMachine} from '@/models/draft-machine' -import {useHasDevTools} from '@/models/experiments' -import {useGatewayUrl} from '@/models/gateway-settings' -import {trpc} from '@/trpc' -import { - chromiumSupportedImageMimeTypes, - chromiumSupportedVideoMimeTypes, - generateBlockId, - handleDragMedia, -} from '@/utils/media-drag' -import {useNavRoute} from '@/utils/navigation' -import {useOpenDraft} from '@/utils/open-draft' -import {DraftRoute} from '@/utils/routes' -import { - BlockRange, - ExpandedBlockRange, - StateStream, - blockStyles, - createPublicWebHmUrl, - formattedDateMedium, - unpackHmId, - useDocContentContext, - useHeadingMarginStyles, - useHeadingTextStyles, -} from '@shm/shared' -import { - Button, - Input, - SizableText, - Theme, - XStack, - YStack, - copyUrlToClipboardWithFeedback, - useStream, -} from '@shm/ui' -import {useSelector} from '@xstate/react' -import {useEffect, useRef, useState} from 'react' -import {ErrorBoundary, FallbackProps} from 'react-error-boundary' -import {HMEditorContainer, HyperMediaEditorView} from 'src/components/editor' -import {ActorRefFrom} from 'xstate' -import {AppDocContentProvider} from './document-content-provider' - -export default function DraftPage() { - let route = useNavRoute() - if (route.key != 'draft') throw new Error('DraftPage must have draft route') - const openDraft = useOpenDraft('replace') - const draftId = route.id! // TODO, clean this up when draftId != docId - const [isDragging, setIsDragging] = useState(false) - const importWebFile = trpc.webImporting.importWebFile.useMutation() - const gwUrl = useGatewayUrl() - // const fixedTitle = useFixedDraftTitle(route) - - // const isSaved = DraftStatusContext.useSelector((s) => s.matches('saved')) - - let data = useDraftEditor({ - id: route.draftId, - }) - - // const {shouldRebase, newVersion} = useDraftRebase({ - - // shouldCheck: - // (data.draft?.previousVersion && data.state.matches('ready')) || false, - // draft: data.draft, - // }) - - useEffect(() => { - return subscribeDraftFocus(draftId, (blockId: string) => { - if (data.editor) { - data.editor._tiptapEditor.commands.focus() - - data.editor.setTextCursorPosition(blockId, 'start') - } - }) - }, [data.editor, draftId]) - - // if (data.state.matches('ready')) { - if (data.editor.ready) { - return ( - window.location.reload()} - > - { - setIsDragging(true) - }} - onDragEnd={(event) => { - setIsDragging(false) - }} - onDragOver={(event) => { - setIsDragging(true) - event.preventDefault() - }} - onDrop={(event: DragEvent) => { - if (!isDragging) return - const dataTransfer = event.dataTransfer - - if (dataTransfer) { - const ttEditor = (data.editor as BlockNoteEditor)._tiptapEditor - const files: File[] = [] - - if (dataTransfer.files.length) { - for (let i = 0; i < dataTransfer.files.length; i++) { - files.push(dataTransfer.files[i]) - } - } else if (dataTransfer.items.length) { - for (let i = 0; i < dataTransfer.items.length; i++) { - const item = dataTransfer.items[i].getAsFile() - if (item) { - files.push(item) - } - } - } - - if (files.length > 0) { - const editorElement = document.getElementsByClassName( - 'mantine-Editor-root', - )[0] - const editorBoundingBox = editorElement.getBoundingClientRect() - const pos = ttEditor.view.posAtCoords({ - left: editorBoundingBox.left + editorBoundingBox.width / 2, - top: event.clientY, - }) - - let lastId: string - - // using reduce so files get inserted sequentially - files - .reduce((previousPromise, file, index) => { - return previousPromise.then(() => { - event.preventDefault() - event.stopPropagation() - - if (pos && pos.inside !== -1) { - return handleDragMedia(file).then((props) => { - if (!props) return false - - const {state} = ttEditor.view - let blockNode - const newId = generateBlockId() - - if (chromiumSupportedImageMimeTypes.has(file.type)) { - blockNode = { - id: newId, - type: 'image', - props: { - url: props.url, - name: props.name, - }, - } - } else if ( - chromiumSupportedVideoMimeTypes.has(file.type) - ) { - blockNode = { - id: newId, - type: 'video', - props: { - url: props.url, - name: props.name, - }, - } - } else { - blockNode = { - id: newId, - type: 'file', - props: { - ...props, - }, - } - } - - const blockInfo = getBlockInfoFromPos( - state.doc, - pos.pos, - ) - - if (index === 0) { - ;(data.editor as BlockNoteEditor).insertBlocks( - [blockNode], - blockInfo.id, - blockInfo.node.textContent ? 'after' : 'before', - ) - } else { - ;(data.editor as BlockNoteEditor).insertBlocks( - [blockNode], - lastId, - 'after', - ) - } - - lastId = newId - }) - } - }) - }, Promise.resolve()) - .then(() => true) - setIsDragging(false) - return true - } - setIsDragging(false) - return false - } - setIsDragging(false) - - return false - }} - > - - - {/* {shouldRebase ? ( - - - - - - - - A new version of this document was found. do you want to - base your changes on this new version? - - - - - - - - ) : null} */} - { - if (route.key != 'draft') - throw new Error('DraftPage must have draft route') - if (!route.draftId) - throw new Error('draft route draftId is missing') - const id = unpackHmId(route.draftId) - if (!id?.eid) - throw new Error( - 'eid could not be extracted from draft route', - ) - copyUrlToClipboardWithFeedback( - createPublicWebHmUrl('d', id.eid, { - blockRef: blockId, - blockRange, - hostname: gwUrl.data, - }), - 'Block', - ) - }} - importWebFile={importWebFile} - > - {/** TODO: Add the state when machine is ready */} - {/* {data.state.matches({ready: 'saveError'}) ? ( - - - - - - - - Oh No! Your draft is in a corrupt state. Need to - restore or reset :( - - - - {data.state.context.restoreTries == 0 ? ( - - - - ) : ( - - Restore failed - - )} - - - - - - - ) : null} */} - { - e.stopPropagation() - }} - // style={{border: '1px solid green'}} - > - {/* { - data.editor?._tiptapEditor?.commands?.focus?.('start') - }} - /> */} - - - {data.editor && data.editor.topLevelBlocks.length ? ( - - ) : null} - - - - - {draftId ? ( - - ) : null} - -
- - {data.draft?.updateTime && ( - - Last update: {formattedDateMedium(data.draft.updateTime)} - - )} - -
-
- ) - } - - if (data.state.matches('error')) { - return ( - - - - - Sorry, this drafts appears to be corrupt - - - - Well, this is embarrasing. for some reason we are not able to load - this draft due to a internal problem in the draft changes. TODO. - - - - - - - - - ) - } - - // console.log('=== DATA', data.state.value) - - // if (data.state.matches('waiting')) { - // return - // } - - return null -} - -function applyTitleResize(target: HTMLTextAreaElement) { - // without this, the scrollHeight doesn't shrink, so when the user deletes a long title it doesnt shrink back - target.style.height = '' - - // here is the actual auto-resize - target.style.height = `${target.scrollHeight}px` -} - -export function useFixedDraftTitle(route: DraftRoute) { - const myAccount = useMyAccount_deprecated() - - let fixedTitle: string | undefined = undefined - if (route.isProfileDocument) { - const myAlias = myAccount.data?.profile?.alias - fixedTitle = myAlias ? `${myAlias} Home` : 'My Account Home' - } - return fixedTitle -} - -export function DraftTitleInput({ - fixedTitle, - onEnter, - draftActor, - disabled = false, -}: { - fixedTitle?: string - onEnter: () => void - draftActor: ActorRefFrom - disabled?: boolean -}) { - const {textUnit, layoutUnit} = useDocContentContext() - let headingTextStyles = useHeadingTextStyles(1, textUnit) - const title = useSelector(draftActor, (s) => s.context.draft?.title || '') - - const input = useRef(null) - const headingMarginStyles = useHeadingMarginStyles(2, layoutUnit) - - useEffect(() => { - // handle the initial size of the title - const target = input.current - if (!target) return - applyTitleResize(target) - }, [input.current]) - - useEffect(() => { - if (fixedTitle) return - const target = input.current - if (!target) return - if (target.value !== title) { - // handle cases where the model has a different title. this happens when pasting multiline text into the title - target.value = title || '' - applyTitleResize(target) - } - }, [title, fixedTitle]) - - useEffect(() => { - handleResize() - - window.addEventListener('resize', handleResize) - return () => { - window.removeEventListener('resize', handleResize) - } - - function handleResize() { - // handle the resize size of the title, responsive size may be changed - const target = input.current - if (!target) return - applyTitleResize(target) - } - }, [input.current]) - - return ( - - { - if (e.nativeEvent.key == 'Enter') { - e.preventDefault() - onEnter() - } - }} - size="$9" - readOnly={!!fixedTitle} - borderRadius="$1" - borderWidth={0} - overflow="hidden" // trying to hide extra content that flashes when pasting multi-line text into the title - flex={1} - backgroundColor="$color2" - fontWeight="bold" - fontFamily="$body" - onChange={(e) => { - applyTitleResize(e.target as HTMLTextAreaElement) - }} - outlineColor="transparent" - borderColor="transparent" - paddingLeft={9.6} - defaultValue={fixedTitle || title?.trim() || ''} // this is still a controlled input because of the value comparison in useLayoutEffect - // value={title} - onChangeText={(title) => { - // TODO: change title here - draftActor.send({type: 'CHANGE', title}) - }} - placeholder="Untitled Document" - {...headingTextStyles} - padding={0} - /> - - ) -} - -function DraftDevTools({ - draftId, - editorState, -}: { - draftId: string - editorState: StateStream -}) { - const hasDevTools = useHasDevTools() - const openDraft = trpc.diagnosis.openDraftLog.useMutation() - const [debugValue, setShowValue] = useState(false) - const editorValue = useStream(editorState) - if (!hasDevTools) return null - return ( - - - - - - {debugValue && ( - - {JSON.stringify(editorValue, null, 2)} - - )} - - ) -} - -function DraftError({ - documentId, - error, - resetErrorBoundary, -}: FallbackProps & {documentId: string}) { - return ( - - - - Error loading Draft (Document Id: {documentId}) - - - {JSON.stringify(error)} - - - - - ) -} diff --git a/frontend/apps/desktop/src/pages/comment-draft.tsx b/frontend/apps/desktop/src/pages/comment-draft.tsx index ef6ce199..bf2957c7 100644 --- a/frontend/apps/desktop/src/pages/comment-draft.tsx +++ b/frontend/apps/desktop/src/pages/comment-draft.tsx @@ -1,29 +1,29 @@ -import { getBlockInfoFromPos } from '@/editor' -import { StateStream, unpackHmId } from '@shm/shared' -import { Button, ChevronUp, SizableText, YStack, useStream } from '@shm/ui' +import {getBlockInfoFromPos} from '@/editor' +import {StateStream, unpackHmId} from '@shm/shared' +import {Button, ChevronUp, SizableText, YStack, useStream} from '@shm/ui' import { CommentPageTitlebarWithDocId, CommentPresentation, CommentThread, } from '@/components/comments' -import { useDeleteCommentDraftDialog } from '@/components/delete-comment-draft-dialog' -import { MainWrapperStandalone } from '@/components/main-wrapper' -import { useComment, useCommentEditor } from '@/models/comments' +import {useDeleteCommentDraftDialog} from '@/components/delete-comment-draft-dialog' +import {MainWrapperStandalone} from '@/components/main-wrapper' +import {useComment, useCommentEditor} from '@/models/comments' import { chromiumSupportedImageMimeTypes, chromiumSupportedVideoMimeTypes, generateBlockId, handleDragMedia, } from '@/utils/media-drag' -import { useEffect, useState } from 'react' -import { XStack } from 'tamagui' +import {useEffect, useState} from 'react' +import {XStack} from 'tamagui' -import { useNavRoute } from '@/utils/navigation' -import { useNavigate } from '@/utils/useNavigate' -import { HMEditorContainer, HyperMediaEditorView } from 'src/components/editor' +import {useNavRoute} from '@/utils/navigation' +import {useNavigate} from '@/utils/useNavigate' +import {HMEditorContainer, HyperMediaEditorView} from 'src/components/editor' import './comment-draft.css' -import { AppDocContentProvider } from './document-content-provider' +import {AppDocContentProvider} from './document-content-provider' function CommitBar({ onSubmit, @@ -94,14 +94,14 @@ function TargetComment({ {route.showThread && comment.data?.repliedComment ? ( ) : comment.data?.repliedComment ? (