From 4c34de6c5c71eeca73fc091dfe05d473e1f85c69 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 9 Dec 2024 22:07:03 +0100 Subject: [PATCH] Feature/1001 proposal page (#1008) * feat: fetch from devhub-cache-api-rs.fly.dev * @Megha-Dev-19 WIP * wip * fmt * wip * events and devhub are ready to be reviewed * feat: infra proposals * fmt * feat: rfps infra * remove comments * fix: spelling * fix: spelling * replace all nearqueryapi in devhub related to proposals and rfps * devhub: simplemde, acceptedTerms, passing instance * fix: devhub * refactor events: deleted SimpleMDE and LinkedProposalsDropdown for both * test: replace all references of queryapi in tests * test: fix linkedProposals and simpleMDE test :) * test: skip discussions test for now * clean up SimpleMDE * infra: SimpleMDE, LinkedDropdown rfp + proposal, Proposal + Rfp.jsx, remove fetchgraphql from common * test: fix events test, 1. had to deploy events with new cors policy, 2. passing instance down to simplemde, 3. mock the test on the right api path. * test: infra -- fix: should show correct linked RFP to a proposal in feed page * test: infra -- fix: should create proposal and link an RFP * remove comments * test: @petersalomonsen fixed! * fmt * test: discussions test back in * test: skip discussions test * revert: changes to rfp comment test * initial commit 1002 * fmt * test for comparing local feed with production * add events committee feed components + by-sort component * fmt * compare links in prod and local * test: update events test * add events committee feed components + by-sort component * fmt * test: update events test * test: comment spec * test: included some test from pr 982 * revert commit * feat: simpleMDE to new api * fmt * feat: linkedproposaldropdown to new api * fmt * test: proposal autolink * fix spelling --------- Co-authored-by: Peter Salomonsen --- .../devhub/entity/proposal/AcceptedTerms.jsx | 69 +++++++++---------- .../entity/proposal/CommentsAndLogs.jsx | 2 +- .../widget/devhub/entity/proposal/Editor.jsx | 8 +-- .../devhub/entity/proposal/Proposal.jsx | 1 + .../feature/proposal-search/by-sort.jsx | 1 + .../widget/devhub/entity/proposal/Editor.jsx | 6 +- .../community/announcements.links.spec.js | 1 + .../tests/community/announcements.spec.js | 1 + .../tests/community/discussions.spec.js | 8 ++- .../tests/events/proposals.spec.js | 1 - .../tests/proposal/comment.spec.js | 2 +- 11 files changed, 53 insertions(+), 47 deletions(-) diff --git a/instances/devhub.near/widget/devhub/entity/proposal/AcceptedTerms.jsx b/instances/devhub.near/widget/devhub/entity/proposal/AcceptedTerms.jsx index 0686ddfae..c91ff7f84 100644 --- a/instances/devhub.near/widget/devhub/entity/proposal/AcceptedTerms.jsx +++ b/instances/devhub.near/widget/devhub/entity/proposal/AcceptedTerms.jsx @@ -6,47 +6,44 @@ State.init({ proposalBlockHeight: null, }); -const proposalId = props.proposalId; +const instance = props.instance ?? ""; -const QUERYAPI_ENDPOINT = `https://near-queryapi.api.pagoda.co/v1/graphql`; -const fetchGraphQL = (operationsDoc, operationName, variables) => { - return asyncFetch(QUERYAPI_ENDPOINT, { - method: "POST", - headers: { "x-hasura-role": "${REPL_INDEXER_HASURA_ROLE}" }, - body: JSON.stringify({ - query: operationsDoc, - variables: variables, - operationName: operationName, - }), - }); -}; +const { cacheUrl } = VM.require(`${instance}/widget/config.data`); -const queryName = "${REPL_PROPOSAL_FEED_INDEXER_QUERY_NAME}"; -const query = `query GetLatestSnapshot($offset: Int = 0, $limit: Int = 10, $where: ${queryName}_bool_exp = {}) { - ${queryName}( - offset: $offset - limit: $limit - order_by: {proposal_id: desc} - where: $where - ) { - block_height - } - }`; +const fetchAndSetProposalSnapshot = () => { + if (!props.proposalId) { + return; + } + asyncFetch(`${cacheUrl}/proposal/${props.proposalId}/snapshots`, { + method: "GET", + headers: { accept: "application/json" }, + }) + .then((response) => { + if (!response.ok) { + console.error(`Failed to fetch snapshots: ${response.status}`); + } + return response.body; + }) + .then((snapshots) => { + if (!Array.isArray(snapshots) || snapshots.length === 0) { + console.log("No snapshots found"); + return; + } -const variables = { - limit: 10, - offset, - where: { proposal_id: { _eq: proposalId } }, + // Get the most recent snapshot + const latestSnapshot = (snapshots || []).reduce((latest, current) => + current.block_height > latest.block_height ? current : latest + ); + + State.update({ proposalBlockHeight: latestSnapshot.block_height }); + }) + .catch((error) => { + console.error("Failed to fetch proposal snapshot:", error); + }); }; -fetchGraphQL(query, "GetLatestSnapshot", variables).then(async (result) => { - if (result.status === 200) { - if (result.body.data) { - const data = result.body.data?.[queryName]; - State.update({ proposalBlockHeight: data[0].block_height }); - } - } -}); +// Fetch snapshot data on component mount +fetchAndSetProposalSnapshot(); let acceptedTermsVersion = Near.block().header.height; diff --git a/instances/devhub.near/widget/devhub/entity/proposal/CommentsAndLogs.jsx b/instances/devhub.near/widget/devhub/entity/proposal/CommentsAndLogs.jsx index eadede46e..d64a89a89 100644 --- a/instances/devhub.near/widget/devhub/entity/proposal/CommentsAndLogs.jsx +++ b/instances/devhub.near/widget/devhub/entity/proposal/CommentsAndLogs.jsx @@ -334,7 +334,7 @@ const parseProposalKeyAndValue = (key, modifiedValue, originalValue) => { accepted ); diff --git a/instances/devhub.near/widget/devhub/entity/proposal/Editor.jsx b/instances/devhub.near/widget/devhub/entity/proposal/Editor.jsx index b5e7241da..0bd639451 100644 --- a/instances/devhub.near/widget/devhub/entity/proposal/Editor.jsx +++ b/instances/devhub.near/widget/devhub/entity/proposal/Editor.jsx @@ -516,7 +516,7 @@ useEffect(() => { } }, [props.transactionHashes]); -const DropdowntBtnContainer = styled.div` +const DropdownBtnContainer = styled.div` font-size: 13px; min-width: 150px; @@ -666,7 +666,7 @@ const SubmitBtn = () => { const selectedOption = btnOptions.find((i) => i.value === selectedStatus); return ( - +
{
)} -
+ ); }; @@ -909,7 +909,7 @@ const ConsentComponent = useMemo(() => { src={ "${REPL_DEVHUB}/widget/devhub.entity.proposal.AcceptedTerms" } - props={{ proposalId: proposalId, portal: "DevHub" }} + props={{ ...props, proposalId: proposalId, portal: "DevHub" }} /> and commit to honoring it diff --git a/instances/devhub.near/widget/devhub/entity/proposal/Proposal.jsx b/instances/devhub.near/widget/devhub/entity/proposal/Proposal.jsx index 8c2182381..8c92be1b0 100644 --- a/instances/devhub.near/widget/devhub/entity/proposal/Proposal.jsx +++ b/instances/devhub.near/widget/devhub/entity/proposal/Proposal.jsx @@ -939,6 +939,7 @@ return ( } props={{ ...props, + instance: props.instance, item: item, notifyAccountId: authorId, id: proposal.id, diff --git a/instances/devhub.near/widget/devhub/feature/proposal-search/by-sort.jsx b/instances/devhub.near/widget/devhub/feature/proposal-search/by-sort.jsx index 909d7f0e6..192361033 100644 --- a/instances/devhub.near/widget/devhub/feature/proposal-search/by-sort.jsx +++ b/instances/devhub.near/widget/devhub/feature/proposal-search/by-sort.jsx @@ -1,4 +1,5 @@ const options = [ + { label: "All", value: "" }, { label: "Most recent", value: "id_desc" }, // proposal_id desc { label: "Oldest", value: "id_asc" }, // proposal_id desc { label: "Recently updated", value: "ts_desc" }, // timestamp desc diff --git a/instances/events-committee.near/widget/devhub/entity/proposal/Editor.jsx b/instances/events-committee.near/widget/devhub/entity/proposal/Editor.jsx index 79c388ba4..a77c31975 100644 --- a/instances/events-committee.near/widget/devhub/entity/proposal/Editor.jsx +++ b/instances/events-committee.near/widget/devhub/entity/proposal/Editor.jsx @@ -520,7 +520,7 @@ useEffect(() => { } }, [props.transactionHashes]); -const DropdowntBtnContainer = styled.div` +const DropdownBtnContainer = styled.div` font-size: 13px; min-width: 150px; @@ -670,7 +670,7 @@ const SubmitBtn = () => { const selectedOption = btnOptions.find((i) => i.value === selectedStatus); return ( - +
{
)} -
+ ); }; diff --git a/playwright-tests/tests/community/announcements.links.spec.js b/playwright-tests/tests/community/announcements.links.spec.js index 46338b80b..5078d33e4 100644 --- a/playwright-tests/tests/community/announcements.links.spec.js +++ b/playwright-tests/tests/community/announcements.links.spec.js @@ -34,6 +34,7 @@ test.describe("Clipboard permissions", () => { return json; }); await page.route( + // TODO sunset "https://near-queryapi.api.pagoda.co/v1/graphql", async (route) => { const request = route.request(); diff --git a/playwright-tests/tests/community/announcements.spec.js b/playwright-tests/tests/community/announcements.spec.js index 66d336514..60fa0059c 100644 --- a/playwright-tests/tests/community/announcements.spec.js +++ b/playwright-tests/tests/community/announcements.spec.js @@ -122,6 +122,7 @@ test.describe("Don't ask again enabled", () => { /* // We can have this test when we can trust the indexer to be live, but it will fail if falling back to the social.index await page.route( + TODO sunset "https://near-queryapi.api.pagoda.co/v1/graphql", async (route) => { const request = route.request(); diff --git a/playwright-tests/tests/community/discussions.spec.js b/playwright-tests/tests/community/discussions.spec.js index 9a35362aa..2904623a2 100644 --- a/playwright-tests/tests/community/discussions.spec.js +++ b/playwright-tests/tests/community/discussions.spec.js @@ -30,6 +30,8 @@ test.describe("Wallet is connected", () => { }); // test uses an older transaction hash which doesn't return in RPC (so skipping for now, ticket #998) + // Created an issue to fix this test: https://github.com/NEAR-DevHub/neardevhub-bos/issues/991 + test.skip("should create a discussion when content matches", async ({ page, }) => { @@ -74,8 +76,12 @@ test.describe("Wallet is connected", () => { await discussionPostEditor.scrollIntoViewIfNeeded(); await discussionPostEditor.fill(socialdbpostcontent.text); - await page.getByTestId("post-btn").click(); + // Submit the discussion content + const postBtn = await page.getByTestId("post-btn"); + await postBtn.scrollIntoViewIfNeeded(); + await postBtn.click(); + // Navigate to the transaction confirmation page await page.goto( "/devhub.near/widget/app?page=community&handle=webassemblymusic&tab=discussions&transactionHashes=mi2a1KwagRFZhpqBNKhKaCTkHVj98J8tZnxSr1NpxSQ" ); diff --git a/playwright-tests/tests/events/proposals.spec.js b/playwright-tests/tests/events/proposals.spec.js index 3f9806faa..828867ac5 100644 --- a/playwright-tests/tests/events/proposals.spec.js +++ b/playwright-tests/tests/events/proposals.spec.js @@ -548,7 +548,6 @@ test.describe("Wallet is connected", () => { test.setTimeout(120000); await getCurrentBlockHeight(page); await page.goto(`/${account}/widget/app?page=create-proposal`); - await getCurrentBlockHeight(page); const delay_milliseconds_between_keypress_when_typing = 100; diff --git a/playwright-tests/tests/proposal/comment.spec.js b/playwright-tests/tests/proposal/comment.spec.js index a91f16c44..94fe016c1 100644 --- a/playwright-tests/tests/proposal/comment.spec.js +++ b/playwright-tests/tests/proposal/comment.spec.js @@ -13,7 +13,7 @@ test.afterEach( async ({ page }) => await page.unrouteAll({ behavior: "ignoreErrors" }) ); -test.describe("Wallet connected", () => { +test.describe("Wallet is connected", () => { test.use({ contextOptions: { permissions: ["clipboard-read", "clipboard-write"],