From 01fcb2c1830a0b01469ef3d65f61eb0a40699be6 Mon Sep 17 00:00:00 2001 From: Megha <100185149+Megha-Dev-19@users.noreply.github.com> Date: Tue, 30 Jul 2024 20:50:54 +0530 Subject: [PATCH 1/3] add `.tg` to near account checks (#911) --- .../widget/devhub/entity/proposal/AccountInput.jsx | 5 ++++- .../widget/devhub/entity/proposal/VerificationStatus.jsx | 3 ++- .../widget/devhub/entity/proposal/AccountInput.jsx | 5 ++++- .../widget/devhub/entity/proposal/VerificationStatus.jsx | 3 ++- .../widget/components/molecule/AccountInput.jsx | 5 ++++- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/instances/devhub.near/widget/devhub/entity/proposal/AccountInput.jsx b/instances/devhub.near/widget/devhub/entity/proposal/AccountInput.jsx index 40b79c175..d8938766f 100644 --- a/instances/devhub.near/widget/devhub/entity/proposal/AccountInput.jsx +++ b/instances/devhub.near/widget/devhub/entity/proposal/AccountInput.jsx @@ -25,7 +25,10 @@ useEffect(() => { useEffect(() => { const handler = setTimeout(() => { - const valid = account.length === 64 || (account ?? "").includes(".near"); + const valid = + account.length === 64 || + (account ?? "").includes(".near") || + (account ?? "").includes(".tg"); setValidAccount(valid); setAutoComplete(!valid); }, 100); diff --git a/instances/devhub.near/widget/devhub/entity/proposal/VerificationStatus.jsx b/instances/devhub.near/widget/devhub/entity/proposal/VerificationStatus.jsx index 85133cf17..e7cf4377d 100644 --- a/instances/devhub.near/widget/devhub/entity/proposal/VerificationStatus.jsx +++ b/instances/devhub.near/widget/devhub/entity/proposal/VerificationStatus.jsx @@ -12,7 +12,8 @@ const SuccessImg = useEffect(() => { if ( receiverAccount.length === 64 || - (receiverAccount ?? "").includes(".near") + (receiverAccount ?? "").includes(".near") || + (receiverAccount ?? "").includes(".tg") ) { useCache( () => diff --git a/instances/events-committee.near/widget/devhub/entity/proposal/AccountInput.jsx b/instances/events-committee.near/widget/devhub/entity/proposal/AccountInput.jsx index 6bec25240..b8b4d23d2 100644 --- a/instances/events-committee.near/widget/devhub/entity/proposal/AccountInput.jsx +++ b/instances/events-committee.near/widget/devhub/entity/proposal/AccountInput.jsx @@ -24,7 +24,10 @@ useEffect(() => { useEffect(() => { const handler = setTimeout(() => { - const valid = account.length === 64 || (account ?? "").includes(".near"); + const valid = + account.length === 64 || + (account ?? "").includes(".near") || + (account ?? "").includes(".tg"); setValidAccount(valid); setAutoComplete(!valid); }, 100); diff --git a/instances/events-committee.near/widget/devhub/entity/proposal/VerificationStatus.jsx b/instances/events-committee.near/widget/devhub/entity/proposal/VerificationStatus.jsx index d3b4547af..a33a0181a 100644 --- a/instances/events-committee.near/widget/devhub/entity/proposal/VerificationStatus.jsx +++ b/instances/events-committee.near/widget/devhub/entity/proposal/VerificationStatus.jsx @@ -12,7 +12,8 @@ const SuccessImg = useEffect(() => { if ( receiverAccount.length === 64 || - (receiverAccount ?? "").includes(".near") + (receiverAccount ?? "").includes(".near") || + (receiverAccount ?? "").includes(".tg") ) { useCache( () => diff --git a/instances/infrastructure-committee.near/widget/components/molecule/AccountInput.jsx b/instances/infrastructure-committee.near/widget/components/molecule/AccountInput.jsx index 1e821eb56..06c1fd99a 100644 --- a/instances/infrastructure-committee.near/widget/components/molecule/AccountInput.jsx +++ b/instances/infrastructure-committee.near/widget/components/molecule/AccountInput.jsx @@ -23,7 +23,10 @@ useEffect(() => { useEffect(() => { const handler = setTimeout(() => { - const valid = account.length === 64 || (account ?? "").includes(".near"); + const valid = + account.length === 64 || + (account ?? "").includes(".near") || + (account ?? "").includes(".tg"); setValidAccount(valid); setAutoComplete(!valid); }, 100); From 698a8dcafe014b831a0cad212b46da3687bbeb91 Mon Sep 17 00:00:00 2001 From: Peter Salomonsen Date: Thu, 1 Aug 2024 16:25:37 +0200 Subject: [PATCH 2/3] share link with clean url for community announcements (#907) * playwright test for share link for community announcement * copy feed/post components from near into devhub to change share URL * handle direct links to the post widget * fallback to social index should use the new post widget * announcements should scroll into view * show page url in test for video * wait for elements to be loaded before scrolling into view * separate script file for scrolling posts into view, that can also be referenced by the contract. * highlight linked announcement --- .devcontainer/post-create.sh | 1 + .../devhub/components/organism/Feed.jsx | 10 +- .../components/organism/Feed/NearQueryApi.jsx | 6 +- .../components/organism/Feed/Posts/Feed.jsx | 93 ++++ .../components/organism/Feed/Posts/Post.jsx | 493 ++++++++++++++++++ .../devhub/entity/community/Announcements.jsx | 4 + .../devhub.near/widget/devhub/page/addon.jsx | 1 + .../widget/devhub/page/community/index.jsx | 4 + .../community/announcements.links.spec.js | 141 +++++ playwright-tests/tests/proposal/links.spec.js | 25 +- scripts/dev-gateway.mjs | 8 +- scripts/web4browserclient.js | 27 + 12 files changed, 785 insertions(+), 28 deletions(-) create mode 100644 instances/devhub.near/widget/devhub/components/organism/Feed/Posts/Feed.jsx create mode 100644 instances/devhub.near/widget/devhub/components/organism/Feed/Posts/Post.jsx create mode 100644 playwright-tests/tests/community/announcements.links.spec.js create mode 100644 scripts/web4browserclient.js diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh index 03eab4394..e995342b2 100755 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/post-create.sh @@ -1,4 +1,5 @@ #!/bin/bash +curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/near-cli-rs/releases/latest/download/near-cli-rs-installer.sh | sh npm install curl --proto '=https' --tlsv1.2 -LsSf https://github.com/mpeterdev/bos-loader/releases/download/v0.7.1/bos-loader-v0.7.1-installer.sh | sh diff --git a/instances/devhub.near/widget/devhub/components/organism/Feed.jsx b/instances/devhub.near/widget/devhub/components/organism/Feed.jsx index 2293bd7f6..f585f35de 100644 --- a/instances/devhub.near/widget/devhub/components/organism/Feed.jsx +++ b/instances/devhub.near/widget/devhub/components/organism/Feed.jsx @@ -102,12 +102,16 @@ return ( return ( } props={{ accountId: item.accountId, blockHeight: item.blockHeight, filteredAccountIds: filteredAccountIds, + page: props.page, + handle: props.handle, + tab: props.tab, + highlight: props.highlight, }} /> ); @@ -118,6 +122,10 @@ return ( src={`${REPL_DEVHUB}/widget/devhub.components.organism.Feed.NearQueryApi`} props={{ GRAPHQL_ENDPOINT, + page: props.page, + handle: props.handle, + tab: props.tab, + highlight: props.highlight, filteredAccountIds: filteredAccountIds, showFlagAccountFeature: showFlagAccountFeature, onNewUnseenPosts: props.onNewUnseenPosts, diff --git a/instances/devhub.near/widget/devhub/components/organism/Feed/NearQueryApi.jsx b/instances/devhub.near/widget/devhub/components/organism/Feed/NearQueryApi.jsx index 0781048ac..d6148e755 100644 --- a/instances/devhub.near/widget/devhub/components/organism/Feed/NearQueryApi.jsx +++ b/instances/devhub.near/widget/devhub/components/organism/Feed/NearQueryApi.jsx @@ -258,8 +258,12 @@ if (!initialized && sort) { return ( <> { diff --git a/instances/devhub.near/widget/devhub/components/organism/Feed/Posts/Feed.jsx b/instances/devhub.near/widget/devhub/components/organism/Feed/Posts/Feed.jsx new file mode 100644 index 000000000..48741897c --- /dev/null +++ b/instances/devhub.near/widget/devhub/components/organism/Feed/Posts/Feed.jsx @@ -0,0 +1,93 @@ +const GRAPHQL_ENDPOINT = + props.GRAPHQL_ENDPOINT || "https://near-queryapi.api.pagoda.co"; +const loadMorePosts = props.loadMorePosts; +const hasMore = props.hasMore || false; +const posts = props.posts || []; + +const Post = styled.div` + border-bottom: 1px solid #eceef0; + padding: 24px 0 12px; + @media (max-width: 1024px) { + padding: 12px 0 0; + } +`; + +const TextLink = styled("Link")` + font-weight: 600; +`; + +const renderItem = (item) => { + if (item.accounts_liked.length !== 0) { + item.accounts_liked = JSON.parse(item.accounts_liked); + } + + if (item.content.includes("repost")) { + const repostData = JSON.parse(item.content); + const fullPath = repostData[0].value.item.path.split("/"); + item.repostData = { + reposted_by: item.account_id, + reposted_content: JSON.parse(item.content), + original_post_accountId: fullPath[0], + original_post_blockHeight: repostData[0].value.item.blockHeight, + }; + } + return ( + + + + ); +}; + +if (posts.length === 0 && !props.isLoading) { + return ( +
+ Build your feed by finding + + people to follow + +
+ ); +} + +const renderedItems = posts.map(renderItem); + +return ( + + +); diff --git a/instances/devhub.near/widget/devhub/components/organism/Feed/Posts/Post.jsx b/instances/devhub.near/widget/devhub/components/organism/Feed/Posts/Post.jsx new file mode 100644 index 000000000..384cb1fa3 --- /dev/null +++ b/instances/devhub.near/widget/devhub/components/organism/Feed/Posts/Post.jsx @@ -0,0 +1,493 @@ +const GRAPHQL_ENDPOINT = + props.GRAPHQL_ENDPOINT || "https://near-queryapi.api.pagoda.co"; +let accountId = props.accountId; +let blockHeight = + props.blockHeight === "now" ? "now" : parseInt(props.blockHeight); +const verifications = props.verifications; +const blockTimestamp = props.blockTimestamp; +const notifyAccountId = accountId; +let postUrl; + +if (props.page) { + postUrl = `https://${REPL_DEVHUB}.page/${props.page}${ + props.handle ? `/${props.handle}${props.tab ? `/${props.tab}` : ""}` : "" + }`; +} else { + postUrl = `https://${REPL_DEVHUB}.page/${REPL_DEVHUB}/widget/devhub.components.organism.Feed.Posts.Post`; +} +postUrl += `?accountId=${accountId}&blockHeight=${blockHeight}`; + +const showFlagAccountFeature = props.showFlagAccountFeature; +const profile = props.profile; +let repostedByProfile = null; +let repostedByProfileUrl = null; +const parsedContent = props.content + ? typeof props.content === "string" + ? JSON.parse(props.content) + : props.content + : undefined; + +State.init({ + hasBeenFlaggedOptimistic: false, + hasBeenFlagged: false, + showToast: false, + flaggedMessage: { header: "", detail: "" }, + postExists: true, + comments: props.comments ?? undefined, + content: parsedContent, + likes: props.likes ?? undefined, +}); + +const repostData = props.repostData || null; + +if (repostData || props.isRepost) { + accountId = repostData.original_post_accountId || props.accountId; + blockHeight = repostData.original_post_blockHeight || props.blockHeight; + repostedByProfile = Social.get( + `${repostData.reposted_by || props.repostedBy}/profile/**`, + "final" + ); + repostedByProfileUrl = `/near/widget/ProfilePage?accountId=${ + repostData.reposted_by || props.repostedBy + }`; + postUrl = `https://near.org/s/rp?a=${accountId}&b=${blockHeight}&rb=${ + repostData.reposted_by || props.repostedBy + }`; +} + +const edits = []; // Social.index('edit', { accountId, blockHeight }, { limit: 1, order: "desc", accountId }) + +const item = { + type: "social", + path: `${accountId}/post/main`, + blockHeight, +}; + +const toggleEdit = () => { + State.update({ editPost: !state.editPost }); +}; + +// Load post if contents and comments are not passed in +if (!state.content || !state.comments || !state.likes) { + const postsQuery = ` +query IndexerQuery { + dataplatform_near_social_feed_posts( + order_by: {block_height: desc} + where: {_and: {block_height: {_eq: ${blockHeight}}, account_id: {_eq: "${accountId}"}}} + ) { + account_id + block_height + block_timestamp + content + receipt_id + accounts_liked + comments(order_by: {block_height: asc}) { + account_id + block_height + block_timestamp + content + } + } +} +`; + + function fetchGraphQL(operationsDoc, operationName, variables) { + return asyncFetch(`${GRAPHQL_ENDPOINT}/v1/graphql`, { + method: "POST", + headers: { "x-hasura-role": "dataplatform_near" }, + body: JSON.stringify({ + query: operationsDoc, + variables: variables, + operationName: operationName, + }), + }); + } + + fetchGraphQL(postsQuery, "IndexerQuery", {}).then((result) => { + if (result.status === 200) { + if (result.body.data) { + const posts = result.body.data.dataplatform_near_social_feed_posts; + if (posts.length > 0) { + const post = posts[0]; + let content = JSON.parse(post.content); + if (post.accounts_liked.length !== 0) { + if (typeof post.accounts_liked === "string") { + post.accounts_liked = JSON.parse(post.accounts_liked); + } + } + const comments = post.comments; + State.update({ + content: content, + comments: comments, + likes: post.accounts_liked, + }); + } else { + State.update({ + postExists: false, + }); + } + } + } + }); + + if (state.postExists == false) { + return "Post does not exist"; + } + return "loading..."; +} + +const Post = styled.div` + position: relative; + &::before { + content: ""; + display: block; + position: absolute; + left: 19px; + top: 52px; + bottom: 12px; + width: 2px; + background: #eceef0; + } +`; + +const Header = styled.div` + margin-bottom: 0; + display: inline-flex; +`; + +const Body = styled.div` + padding-left: 52px; + padding-bottom: 1px; +`; + +const Content = styled.div` + img { + display: block; + max-width: 100%; + max-height: 80vh; + margin: 0 0 12px; + } +`; + +const Text = styled.p` + display: block; + margin: 0; + font-size: 14px; + line-height: 20px; + font-weight: 400; + color: #687076; + white-space: nowrap; +`; + +const Actions = styled.div` + display: flex; + align-items: center; + gap: 12px; + margin: -6px -6px 6px; +`; + +const Comments = styled.div` + > div > div:first-child { + padding-top: 12px; + } +`; +const CommentWrapper = styled.div` + > div:first-child { + > a:first-child { + display: inline-flex; + margin-bottom: 24px; + font-size: 14px; + line-height: 20px; + color: #687076; + outline: none; + font-weight: 600; + + &:hover, + &:focus { + color: #687076; + text-decoration: underline; + } + } + } +`; + +const TextLink = styled("Link")` + display: inline block; + margin: 0; + font-size: 14px; + line-height: 18px; + color: ${(p) => (p.$bold ? "#11181C !important" : "#687076 !important")}; + font-weight: ${(p) => (p.$bold ? "600" : "400")}; + font-size: ${(p) => (p.$small ? "12px" : "14px")}; + overflow: ${(p) => (p.$ellipsis ? "hidden" : "visible")}; + text-overflow: ${(p) => (p.$ellipsis ? "ellipsis" : "unset")}; + white-space: nowrap; + outline: none; + + &:focus, + &:hover { + text-decoration: underline; + } +`; + +const TagsWrapper = styled.div` + padding-top: 4px; +`; + +const optimisticallyHideItem = (message) => { + State.update({ + hasBeenFlaggedOptimistic: true, + showToast: true, + flaggedMessage: message, + }); +}; +const resolveHideItem = (message) => { + State.update({ + hasBeenFlagged: true, + showToast: true, + flaggedMessage: message, + }); +}; +const cancelHideItem = () => { + State.update({ + hasBeenFlaggedOptimistic: false, + showToast: false, + flaggedMessage: { header: "", detail: "" }, + }); +}; + +const renderComment = (a) => { + return ( +
+ +
+ ); +}; + +const renderedComments = state.comments.map(renderComment); + +const addNewCommentFn = (newComment) => { + State.update(state.comments.push(newComment)); +}; + +const highlight = + props.highlight?.accountId === accountId && + props.highlight?.blockHeight === `${blockHeight}`; + +return ( + <> + {state.showToast && ( + { + State.update({ showToast: false }); + }, + duration: 5000, + }} + /> + )} + {!state.hasBeenFlagged && ( + + <> + {repostData || isRepost ? ( + +
+ reposted by{" "} + + @{repostData.reposted_by} + + {tags.length > 0 && ( + + + + )} +
+ + ), + placement: props.overlayPlacement, + verifications, + showFlagAccountFeature, + }} + /> + ) : null} + +
+
+
+ + + + + + {false && edits.length > 0 && ( + ・ Edited + )} + + ), + showFlagAccountFeature, + }} + /> +
+
+
+ +
+
+
+
+ + {!state.hasBeenFlaggedOptimistic && ( + + {state.content && ( + + {state.content.text && !state.editPost && ( + + )} + + {state.editPost && ( +
+ +
+ )} + + {state.content.image && ( + + )} +
+ )} + + {blockHeight !== "now" && ( + + + + State.update({ showReply: !state.showReply }), + }} + /> + + + + + )} + {state.showReply && ( +
+ State.update({ showReply: false }), + newAddedComment: addNewCommentFn, + }} + /> +
+ )} + {renderedComments && ( + + {renderedComments} + + )} + + )} +
+ )} + +); diff --git a/instances/devhub.near/widget/devhub/entity/community/Announcements.jsx b/instances/devhub.near/widget/devhub/entity/community/Announcements.jsx index 77f06eb39..1a05bfe95 100644 --- a/instances/devhub.near/widget/devhub/entity/community/Announcements.jsx +++ b/instances/devhub.near/widget/devhub/entity/community/Announcements.jsx @@ -169,6 +169,10 @@ return ( diff --git a/playwright-tests/tests/community/announcements.links.spec.js b/playwright-tests/tests/community/announcements.links.spec.js new file mode 100644 index 000000000..29063ce81 --- /dev/null +++ b/playwright-tests/tests/community/announcements.links.spec.js @@ -0,0 +1,141 @@ +import { test, expect } from "@playwright/test"; +import { pauseIfVideoRecording, showPageURLInTest } from "../../testUtils.js"; +import { mockDefaultTabs } from "../../util/addons.js"; +import { mockSocialIndexResponses } from "../../util/socialapi.js"; + +test.beforeEach(async ({ page }) => { + await page.route("http://localhost:20000/", async (route) => { + await mockDefaultTabs(route); + }); +}); + +test.afterEach( + async ({ page }) => await page.unrouteAll({ behavior: "ignoreErrors" }) +); + +test.describe("Clipboard permissions", () => { + test.use({ + contextOptions: { + permissions: ["clipboard-read", "clipboard-write"], + }, + }); + + const cleanUrlForAnnouncementsTest = async ({ page, lag }) => { + let socialIndexBlockHeight; + await mockSocialIndexResponses(page, ({ requestPostData, json }) => { + if ( + requestPostData && + requestPostData.action === "post" && + requestPostData.key === "main" + ) { + socialIndexBlockHeight = json[0].blockHeight; + } + return json; + }); + await page.route( + "https://near-queryapi.api.pagoda.co/v1/graphql", + async (route) => { + const request = route.request(); + const requestPostData = request.postDataJSON(); + + if ( + requestPostData?.query.includes( + "dataplatform_near_social_feed_posts" + ) && + requestPostData?.query.match("{[ \n]*block_height[ \n]*}") !== null + ) { + const response = await route.fetch(); + const json = await response.json(); + json.data.dataplatform_near_social_feed_posts[0].block_height = + socialIndexBlockHeight - lag; + await route.fulfill({ json }); + } else { + await route.continue(); + } + } + ); + await page.goto( + "/devhub.near/widget/app?page=community&handle=webassemblymusic&tab=announcements" + ); + const copyUrlButton = await page + .locator('[data-component="near/widget/CopyUrlButton"]') + .first(); + await expect(copyUrlButton).toBeVisible({ timeout: 10000 }); + await copyUrlButton.hover(); + await expect(await page.getByText("Copy URL to clipboard")).toBeVisible(); + await copyUrlButton.click(); + + const linkUrlFromClipboard = await page.evaluate( + "navigator.clipboard.readText()" + ); + + expect(linkUrlFromClipboard).toEqual( + "https://devhub.near.page/community/webassemblymusic/announcements?accountId=webassemblymusic.community.devhub.near&blockHeight=116026696" + ); + await pauseIfVideoRecording(page); + await page.goto(linkUrlFromClipboard); + + await showPageURLInTest(page); + await expect(await page.getByText("WebAssembly Music")).toBeVisible({ + timeout: 10000, + }); + }; + + test("should share clean URL for announcements, using indexer ( no lag )", async ({ + page, + }) => { + await cleanUrlForAnnouncementsTest({ page, lag: 0 }); + }); + + test("should share clean URL for announcements, using fallback ( big lag )", async ({ + page, + }) => { + await cleanUrlForAnnouncementsTest({ page, lag: 1_000_000 }); + }); + + test("should handle direct links to the post widget", async ({ page }) => { + const directUrlPath = + "/devhub.near/widget/devhub.components.organism.Feed.Posts.Post?accountId=webassemblymusic.community.devhub.near&blockHeight=115859669"; + await page.goto(directUrlPath); + + const copyUrlButton = await page + .locator('[data-component="near/widget/CopyUrlButton"]') + .first(); + await expect(copyUrlButton).toBeVisible({ timeout: 10000 }); + await copyUrlButton.hover(); + await expect(await page.getByText("Copy URL to clipboard")).toBeVisible(); + await copyUrlButton.click(); + + const linkUrlFromClipboard = await page.evaluate( + "navigator.clipboard.readText()" + ); + + expect(linkUrlFromClipboard).toEqual( + "https://devhub.near.page" + directUrlPath + ); + }); + + test("announcement should scroll into view and be highlighted", async ({ + page, + }) => { + await page.goto( + "/devhub.near/widget/app?page=community&handle=webassemblymusic&tab=announcements&accountId=webassemblymusic.community.devhub.near&blockHeight=112244156" + ); + await showPageURLInTest(page); + + const viewer = await page.locator("near-social-viewer"); + const announcementElement = await viewer.locator( + "css=div#webassemblymusiccommunitydevhubnear112244156" + ); + await expect(announcementElement).toBeVisible({ timeout: 10000 }); + + await expect(announcementElement).toContainText( + "WebAssembly Music is the concept of storing a full length track of music in a tiny file" + ); + await expect(announcementElement).toBeInViewport({ timeout: 10000 }); + await expect(announcementElement).toHaveCSS( + "border", + "2px solid rgb(0, 0, 0)" + ); + }); +}); diff --git a/playwright-tests/tests/proposal/links.spec.js b/playwright-tests/tests/proposal/links.spec.js index a2c512f4b..98f0694b0 100644 --- a/playwright-tests/tests/proposal/links.spec.js +++ b/playwright-tests/tests/proposal/links.spec.js @@ -52,32 +52,9 @@ test.describe("share links", () => { await page.goto( "/devhub.near/widget/app?page=proposal&id=127&accountId=theori.near&blockHeight=121684702" ); - await page.evaluate(() => { - (async function () { - const urlSearchParams = new URLSearchParams(location.search); - const accountId = urlSearchParams.get("accountId"); - const blockHeight = urlSearchParams.get("blockHeight"); - if (accountId && blockHeight) { - for (let n = 0; n < 20; n++) { - const linkElementSelector = `#${accountId.replace( - /[^a-z0-9]/g, - "" - )}${blockHeight}`; - - const linkElement = document.querySelector(linkElementSelector); - if (linkElement) { - linkElement.scrollIntoView(); - console.log("scrolled into view"); - break; - } - await new Promise((resolve) => setTimeout(() => resolve(), 500)); - } - } - })(); - }); const viewer = await page.locator("near-social-viewer"); const commentElement = await viewer.locator("css=div#theorinear121684702"); - await expect(commentElement).toBeVisible(); + await expect(commentElement).toBeVisible({ timeout: 10000 }); await expect(commentElement).toBeInViewport({ timeout: 10000 }); }); diff --git a/scripts/dev-gateway.mjs b/scripts/dev-gateway.mjs index ee0b025de..899e7ae95 100644 --- a/scripts/dev-gateway.mjs +++ b/scripts/dev-gateway.mjs @@ -2,7 +2,7 @@ import httpServer from "http-server"; import path from "path"; import { spawn } from "child_process"; import { homedir, tmpdir } from "os"; -import { readFile, writeFile, cp } from "fs/promises"; +import { readFile, writeFile, cp, copyFile } from "fs/promises"; import { rpcProxy } from "./rpc-cache-proxy.mjs"; const instanceName = process.argv[process.argv.length - 1]; @@ -17,6 +17,8 @@ await cp( statingWebHostinFolder, { recursive: true } ); +const web4browserclientFileName = 'web4browserclient.js'; +await copyFile(new URL(web4browserclientFileName, import.meta.url), `${statingWebHostinFolder}/${web4browserclientFileName}`); const replaceRpc = async (htmlfile) => { const indexHtmlFilePath = `${statingWebHostinFolder}/${htmlfile}`; @@ -24,7 +26,9 @@ const replaceRpc = async (htmlfile) => { let indexHtmlData = await readFile(indexHtmlFilePath, "utf8"); indexHtmlData = indexHtmlData.replace( "", - '' + ` + + ` ); await writeFile(indexHtmlFilePath, indexHtmlData, "utf8"); }; diff --git a/scripts/web4browserclient.js b/scripts/web4browserclient.js new file mode 100644 index 000000000..86ff929f7 --- /dev/null +++ b/scripts/web4browserclient.js @@ -0,0 +1,27 @@ +/** + * This file is loaded by the web4 gateway to scroll linked posts into view. + */ + +(async function () { + const urlSearchParams = new URLSearchParams(location.search); + const accountId = urlSearchParams.get("accountId"); + const blockHeight = urlSearchParams.get("blockHeight"); + if (accountId && blockHeight) { + for (let n = 0; n < 20; n++) { + const linkElementSelector = `#${accountId.replace( + /[^a-z0-9]/g, + "" + )}${blockHeight}`; + + const linkElement = document.querySelector(linkElementSelector); + const loadingElement = document.querySelector( + 'span.spinner-grow-sm[role="status"]' + ); + if (loadingElement === null && linkElement !== null) { + linkElement.scrollIntoView(); + break; + } + await new Promise((resolve) => setTimeout(() => resolve(), 500)); + } + } +})(); From 4af0f4d621d9f46ecaede390ba9e1bbb8f702682 Mon Sep 17 00:00:00 2001 From: Peter Salomonsen Date: Mon, 5 Aug 2024 07:09:30 +0200 Subject: [PATCH 3/3] feat: gateway for all instances (#913) * feat: gateway for all instances * replace all references to http://localhost:2000 with MOCK_RPC_URL remove modifySocialNearGetRPCResponsesInsteadOfGettingWidgetsFromBOSLoader ( not needed when RPC proxy handles this ) mock RPC request must check on path, would not work on origin * transaction submit RPC intercept must still check with https://rpc.mainnet.near.org * no need for bosloader flags. need longer timeout for scrolling into view when no cache * longer timeout is needed to wait for comment element to be visible * don't check for bos loader environment * longer timeout waiting for comment button remove posthog from aliases in events/infrastructure * must import MOCK_RPC_URL * import MOCK_RPC_URL * import MOCK_RPC_URL * add timeouts when running without rpc cache * without cache, don't use empty functions when waiting for vm.require, rather wait for them to be loaded * wait for label options to be available * wait for labels to appear * remove unused scripts * replace posthog api key in aliases file before creating replacement script * remove console.log --- .../workflows/deploy-prod-mainnet-devhub.yml | 3 +- instances/devhub.near/aliases.mainnet.json | 3 +- .../entity/addon/github/Configurator.jsx | 7 +- package.json | 4 +- .../wallet-connected-admin.json | 4 - ...ted-chain-abstraction-community-admin.json | 4 - .../wallet-connected-community-admin.json | 4 - .../wallet-connected-moderator.json | 4 - ...et-connected-not-kyc-verified-account.json | 4 - .../wallet-connected-peter.json | 4 - .../storage-states/wallet-connected.json | 4 - .../storage-states/wallet-not-connected.json | 12 +- .../storage-states/wallet-permissioned.json | 4 - .../blog/blogv2.admin.dontaskagain.spec.js | 3 +- .../tests/blog/blogv2.admin.spec.js | 3 +- .../tests/blog/blogv2.search.spec.js | 3 +- .../tests/blog/blogv2.settings.spec.js | 3 +- playwright-tests/tests/blog/blogv2.spec.js | 3 +- .../tests/community/addons.spec.js | 5 +- .../community/announcements.links.spec.js | 8 +- .../tests/community/announcements.spec.js | 3 +- .../tests/community/community.spec.js | 8 +- .../tests/community/discussions.spec.js | 13 +- .../tests/community/sharelinks.spec.js | 2 +- .../tests/events/proposals.spec.js | 14 +- .../tests/infrastructure/rfp.spec.js | 4 - .../tests/other/bosloaderenvironment.spec.js | 20 --- .../tests/other/feed.dontaskagain.spec.js | 14 -- .../tests/proposal/comment.spec.js | 6 +- playwright-tests/tests/proposal/links.spec.js | 8 +- .../tests/proposal/proposals.spec.js | 18 +- playwright-tests/tests/sunset/create.spec.js | 21 +++ playwright-tests/tests/sunset/feed.spec.js | 10 +- playwright-tests/tests/sunset/funding.spec.js | 19 +- playwright-tests/util/bos-loader.js | 44 ----- playwright-tests/util/rpcmock.js | 2 +- playwright-tests/util/transaction.js | 5 +- playwright.config.js | 21 +-- ...eate-static-hosting-web-gateway-folder.mjs | 31 ++++ scripts/deploy_preview_environment.sh | 8 - scripts/dev-gateway.mjs | 77 -------- scripts/rpc-cache-proxy.mjs | 170 ------------------ scripts/web4browserclient.js | 2 +- 43 files changed, 140 insertions(+), 469 deletions(-) delete mode 100644 playwright-tests/tests/other/bosloaderenvironment.spec.js delete mode 100644 playwright-tests/util/bos-loader.js create mode 100644 scripts/create-static-hosting-web-gateway-folder.mjs delete mode 100755 scripts/deploy_preview_environment.sh delete mode 100644 scripts/dev-gateway.mjs delete mode 100644 scripts/rpc-cache-proxy.mjs diff --git a/.github/workflows/deploy-prod-mainnet-devhub.yml b/.github/workflows/deploy-prod-mainnet-devhub.yml index b9a4eeff0..9467be12e 100644 --- a/.github/workflows/deploy-prod-mainnet-devhub.yml +++ b/.github/workflows/deploy-prod-mainnet-devhub.yml @@ -17,7 +17,8 @@ jobs: - name: Set replacements id: set_replacements run: | - echo "replacements=$(jq -r '[to_entries[] | .["find"] = "${" + .key + "}" | .["replace"] = .value | del(.key, .value), {"find": "${REPL_POSTHOG_API_KEY}", "replace": "'${{ secrets.POSTHOG_API_KEY }}'"}]' aliases.mainnet.json | tr -d "\n\r")" >> $GITHUB_OUTPUT + jq '.REPL_POSTHOG_API_KEY = "${{ secrets.POSTHOG_API_KEY }}"' aliases.mainnet.json > temp.aliases.mainnet.json && mv temp.aliases.mainnet.json aliases.mainnet.json + echo "replacements=$(jq -r '[to_entries[] | .["find"] = "${" + .key + "}" | .["replace"] = .value | del(.key, .value)]' aliases.mainnet.json | tr -d "\n\r")" >> $GITHUB_OUTPUT - name: Replace placeholders uses: flcdrg/replace-multiple-action@v1 diff --git a/instances/devhub.near/aliases.mainnet.json b/instances/devhub.near/aliases.mainnet.json index 081dab138..e153b8a83 100644 --- a/instances/devhub.near/aliases.mainnet.json +++ b/instances/devhub.near/aliases.mainnet.json @@ -9,5 +9,6 @@ "REPL_SOCIAL_CONTRACT": "social.near", "REPL_RPC_URL": "https://rpc.mainnet.near.org", "REPL_PROPOSAL_FEED_INDEXER_QUERY_NAME": "polyprogrammist_near_devhub_prod_v1_proposals_with_latest_snapshot", - "REPL_INDEXER_HASURA_ROLE": "polyprogrammist_near" + "REPL_INDEXER_HASURA_ROLE": "polyprogrammist_near", + "REPL_POSTHOG_API_KEY": "01234567890123456789012345678901234567890123456" } diff --git a/instances/devhub.near/widget/devhub/entity/addon/github/Configurator.jsx b/instances/devhub.near/widget/devhub/entity/addon/github/Configurator.jsx index 34b8197cd..e812302d0 100644 --- a/instances/devhub.near/widget/devhub/entity/addon/github/Configurator.jsx +++ b/instances/devhub.near/widget/devhub/entity/addon/github/Configurator.jsx @@ -10,10 +10,6 @@ const { uuid, withUUIDIndex } = VM.require( "${REPL_DEVHUB}/widget/core.lib.uuid" ); -uuid || (uuid = () => {}); -withUUIDIndex || (withUUIDIndex = () => {}); -useQuery || (useQuery = () => {}); - const AttractableDiv = styled.div` box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; transition: box-shadow 0.6s; @@ -105,8 +101,7 @@ function isValidGitHubRepoLink(url) { const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { const data = kanbanBoards ? Object.values(kanbanBoards)?.[0] : {}; - - if (!data) { + if (!data || !withUUIDIndex || !useQuery || !uuid) { return (