Skip to content

Refactors remaining linking routes #12123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions libs/model/src/aggregates/thread/DeleteLinks.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Command } from '@hicommonwealth/core';
import * as schemas from '@hicommonwealth/schemas';
import { models } from '../../database';
import { authThread, mustExist } from '../../middleware';

export function DeleteLinks(): Command<typeof schemas.DeleteLinks> {
return {
...schemas.DeleteLinks,
auth: [authThread({ roles: ['admin'], author: true })],
secure: true,
body: async ({ payload }) => {
const { thread_id, links } = payload;

const thread = await models.Thread.findOne({
where: { id: thread_id },
});
mustExist('Thread', thread);

const keep =
thread.links?.length || 0 > 0
? thread.links!.filter((link) => {
return !links.some(
(l) =>
l.source === link.source && l.identifier === link.identifier,
);
})
: [];

if (keep.length !== thread.links?.length || 0) {
thread.links = keep;
await thread.save();
}

const updated = await models.Thread.findOne({
where: { id: thread_id },
include: [
{ model: models.Address, as: 'Address' },
{ model: models.Address, as: 'collaborators' },
{ model: models.Topic, as: 'topic' },
],
});
return updated!.toJSON();
},
};
}
39 changes: 39 additions & 0 deletions libs/model/src/aggregates/thread/GetLinks.query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Query } from '@hicommonwealth/core';
import * as schemas from '@hicommonwealth/schemas';
import { Op } from 'sequelize';
import { models } from '../../database';
import { mustExist } from '../../middleware';

export function GetLinks(): Query<typeof schemas.GetLinks> {
return {
...schemas.GetLinks,
auth: [],
secure: false,
body: async ({ payload }) => {
const { thread_id, link_source, link_identifier } = payload;

if (thread_id) {
const thread = await models.Thread.findOne({
where: { id: thread_id },
});
mustExist('Thread', thread);
return { links: thread.links || undefined };
}

if (link_source && link_identifier) {
const threads = await models.Thread.findAll({
where: {
links: {
[Op.contains]: [
{ source: link_source, identifier: link_identifier },
],
},
},
});
return { threads: threads.map((t) => ({ id: t.id!, title: t.title })) };
}

return {};
},
};
}
2 changes: 2 additions & 0 deletions libs/model/src/aggregates/thread/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
export * from './AddLinks.command';
export * from './CreateThread.command';
export * from './CreateThreadReaction.command';
export * from './DeleteLinks.command';
export * from './DeleteThread.command';
export * from './GetActiveThreads.query';
export * from './GetLinks.query';
export * from './GetThreadCount.query';
export * from './GetThreads.query';
export * from './GetThreadsByIds.query';
Expand Down
9 changes: 9 additions & 0 deletions libs/schemas/src/commands/thread.schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,12 @@ export const AddLinks = {
}),
context: ThreadContext,
};

export const DeleteLinks = {
input: z.object({
thread_id: PG_INT,
links: z.array(Link),
}),
output: Thread,
context: ThreadContext,
};
21 changes: 21 additions & 0 deletions libs/schemas/src/queries/thread.schemas.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { LinkSource } from '@hicommonwealth/shared';
import { ZodType, z } from 'zod';
import {
Address,
Comment,
CommentVersionHistory,
ContestManager,
Link,
ProfileTags,
Thread,
ThreadVersionHistory,
Expand Down Expand Up @@ -335,3 +337,22 @@ export const SearchThreads = {
results: z.array(ThreadView),
}),
};

export const GetLinks = {
input: z.object({
thread_id: PG_INT.optional(),
link_source: z.nativeEnum(LinkSource).optional(),
link_identifier: z.string().optional(),
}),
output: z.object({
links: z.array(Link).optional(),
threads: z
.array(
z.object({
id: PG_INT,
title: z.string(),
}),
)
.optional(),
}),
};
Original file line number Diff line number Diff line change
@@ -1,45 +1,13 @@
import { useMutation } from '@tanstack/react-query';
import axios from 'axios';
import Thread, { Link } from 'models/Thread';
import { SERVER_URL } from 'state/api/config';
import { userStore } from '../../ui/user';
import { Thread, ThreadView } from 'models/Thread';
import { trpc } from 'utils/trpcClient';
import { updateThreadInAllCaches } from './helpers/cache';

interface DeleteThreadLinksProps {
communityId: string;
threadId: number;
links: Link[];
}

const deleteThreadLinks = async ({
threadId,
links,
}: DeleteThreadLinksProps): Promise<Thread> => {
const response = await axios.delete(`${SERVER_URL}/linking/deleteLinks`, {
data: {
thread_id: threadId,
links,
jwt: userStore.getState().jwt,
},
});

return new Thread(response.data.result);
};

interface DeleteThreadLinksMutationProps {
communityId: string;
threadId: number;
}

const useDeleteThreadLinksMutation = ({
communityId,
threadId,
}: DeleteThreadLinksMutationProps) => {
return useMutation({
mutationFn: deleteThreadLinks,
onSuccess: async (updatedThread) => {
updateThreadInAllCaches(communityId, threadId, updatedThread);
return updatedThread;
const useDeleteThreadLinksMutation = () => {
return trpc.thread.deleteLinks.useMutation({
onSuccess: (updated) => {
const thread = new Thread(updated as ThreadView);
updateThreadInAllCaches(updated.community_id, updated.id!, thread);
return updated;
},
});
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,22 @@
import type { Link } from '@hicommonwealth/shared';
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { ApiEndpoints, SERVER_URL } from 'state/api/config';
import { userStore } from '../../ui/user';
import { trpc } from 'utils/trpcClient';

const THREAD_STALE_TIME = 5000; // 5 seconds

interface GetThreadsByLinkProps {
communityId: string;
link: Link;
enabled: boolean;
}

const getThreadsByLink = async ({
link,
}: GetThreadsByLinkProps): Promise<{ id: number; title: string }[]> => {
const response = await axios.post(`${SERVER_URL}/linking/getLinks`, {
link,
jwt: userStore.getState().jwt,
});

return response.data.result.threads;
};

// Gets all threads associated with a link(ie all threads linked to 1 proposal)
const useGetThreadsByLinkQuery = ({
communityId,
link,
enabled,
}: GetThreadsByLinkProps) => {
return useQuery({
// TODO: we are not updating cache here, because the response looks like this
// {
// "status": "Success",
// "result": {
// "threads": [
// {
// "id": 7872,
// "title": "DRC%20-%20Remove%20stkDYDX%20from%20LP%20Rewards%20Formulas"
// }
// ]
// }
// }
// decide if we need to cache this?? -- atm it looks like we dont have to
// eslint-disable-next-line @tanstack/query/exhaustive-deps
queryKey: [
ApiEndpoints.FETCH_THREADS,
communityId,
'byLink',
link.source,
link.identifier,
],
queryFn: () => getThreadsByLink({ communityId, link, enabled }),
staleTime: THREAD_STALE_TIME,
enabled: enabled,
});
const useGetThreadsByLinkQuery = ({ link, enabled }: GetThreadsByLinkProps) => {
return trpc.thread.getLinks.useQuery(
{ link_source: link.source, link_identifier: link.identifier },
{
staleTime: THREAD_STALE_TIME,
enabled: enabled,
},
);
};

export default useGetThreadsByLinkQuery;
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,7 @@ export const ThreadUpdateProposalStatusModal = ({
});

const { mutateAsync: addThreadLinks } = useAddThreadLinksMutation();

const { mutateAsync: deleteThreadLinks } = useDeleteThreadLinksMutation({
communityId: app.activeChainId() || '',
threadId: thread.id,
});
const { mutateAsync: deleteThreadLinks } = useDeleteThreadLinksMutation();

const { trackAnalytics } =
useBrowserAnalyticsTrack<MixpanelCommunityInteractionEventPayload>({
Expand Down Expand Up @@ -158,15 +154,14 @@ export const ThreadUpdateProposalStatusModal = ({
.then(({ toDelete, links }) => {
if (toDelete.length > 0) {
return deleteThreadLinks({
communityId: app.activeChainId() || '',
threadId: thread.id,
thread_id: thread.id,
links: toDelete.map((sn) => ({
source: LinkSource.Snapshot,
identifier: String(sn.id),
})),
}).then((updatedThread) => {
// eslint-disable-next-line no-param-reassign
links = updatedThread.links;
links = updatedThread.links || [];
return links;
});
} else {
Expand Down Expand Up @@ -207,15 +202,14 @@ export const ThreadUpdateProposalStatusModal = ({
.then(({ toDelete, links }) => {
if (toDelete.length > 0) {
return deleteThreadLinks({
communityId: app.activeChainId() || '',
threadId: thread.id,
thread_id: thread.id,
links: toDelete.map(({ identifier }) => ({
source: LinkSource.Proposal,
identifier: String(identifier),
})),
}).then((updatedThread) => {
// eslint-disable-next-line no-param-reassign
links = updatedThread.links;
links = updatedThread.links || [];
return links;
});
} else {
Expand Down Expand Up @@ -251,8 +245,7 @@ export const ThreadUpdateProposalStatusModal = ({
const handleRemoveProposal = () => {
try {
deleteThreadLinks({
communityId: app.activeChainId() || '',
threadId: thread.id,
thread_id: thread.id,
links: [
{
source: LinkSource.Snapshot,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { notifyError } from '../../controllers/app/notifications';
import { getAddedAndDeleted } from '../../helpers/threads';
import type Thread from '../../models/Thread';
import { LinkSource } from '../../models/Thread';
import app from '../../state';
import {
useAddThreadLinksMutation,
useDeleteThreadLinksMutation,
Expand Down Expand Up @@ -33,13 +32,8 @@ export const LinkedThreadModal = ({
const [tempLinkedThreads, setTempLinkedThreads] =
useState<Array<Thread>>(initialLinkedThreads);

const communityId = app.activeChainId() || '';
const { mutateAsync: addThreadLinks } = useAddThreadLinksMutation();

const { mutateAsync: deleteThreadLinks } = useDeleteThreadLinksMutation({
communityId,
threadId: thread.id,
});
const { mutateAsync: deleteThreadLinks } = useDeleteThreadLinksMutation();

const handleSaveChanges = async () => {
const { toAdd, toDelete } = getAddedAndDeleted(
Expand All @@ -61,14 +55,13 @@ export const LinkedThreadModal = ({
}
if (toDelete.length) {
const updatedThread = await deleteThreadLinks({
communityId,
threadId: thread.id,
thread_id: thread.id,
links: toDelete.map((el) => ({
source: LinkSource.Thread,
identifier: String(el.id),
})),
});
links = updatedThread.links;
links = updatedThread.links || [];
}
onModalClose();
// @ts-expect-error <StrictNullChecks/>
Expand Down
Loading
Loading