From d575f20476fb3f02d43f4c43b01386bec18d67ba Mon Sep 17 00:00:00 2001 From: Megha-Dev-19 <100185149+Megha-Dev-19@users.noreply.github.com> Date: Fri, 15 Nov 2024 16:25:24 +0530 Subject: [PATCH] add indexer --- .../aliases.mainnet.json | 3 +- .../molecule/LinkedProposalsDropdown.jsx | 98 ++---- .../components/molecule/LinkedRfpDropdown.jsx | 103 ++---- .../widget/components/molecule/SimpleMDE.jsx | 4 +- .../widget/components/proposals/Editor.jsx | 4 +- .../widget/components/proposals/Feed.jsx | 314 ++++++++---------- .../widget/components/proposals/Proposal.jsx | 83 ++--- .../widget/components/rfps/Feed.jsx | 186 +++++------ .../widget/components/rfps/Rfp.jsx | 131 +++----- 9 files changed, 374 insertions(+), 552 deletions(-) diff --git a/instances/treasury-templar.near/aliases.mainnet.json b/instances/treasury-templar.near/aliases.mainnet.json index 83048af46..3f28e7486 100644 --- a/instances/treasury-templar.near/aliases.mainnet.json +++ b/instances/treasury-templar.near/aliases.mainnet.json @@ -10,5 +10,6 @@ "REPL_RFP_INDEXER_QUERY_NAME": "polyprogrammist_near_devhub_ic_v1_rfp_snapshots", "REPL_PROPOSAL_FEED_INDEXER_QUERY_NAME": "polyprogrammist_near_devhub_ic_v1_proposals_with_latest_snapshot", "REPL_PROPOSAL_QUERY_NAME": "polyprogrammist_near_devhub_ic_v1_proposal_snapshots", - "REPL_INDEXER_HASURA_ROLE": "polyprogrammist_near" + "REPL_INDEXER_HASURA_ROLE": "polyprogrammist_near", + "REPL_CACHE_URL": "https://templar-cache-api-rs.fly.dev" } diff --git a/instances/treasury-templar.near/widget/components/molecule/LinkedProposalsDropdown.jsx b/instances/treasury-templar.near/widget/components/molecule/LinkedProposalsDropdown.jsx index 4c2b063cf..c75d689aa 100644 --- a/instances/treasury-templar.near/widget/components/molecule/LinkedProposalsDropdown.jsx +++ b/instances/treasury-templar.near/widget/components/molecule/LinkedProposalsDropdown.jsx @@ -11,19 +11,6 @@ const [selectedProposals, setSelectedProposals] = useState(linkedProposals); const [proposalsOptions, setProposalsOptions] = useState([]); const [searchProposalId, setSearchProposalId] = useState(""); -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 -) { - name - proposal_id -} -}`; - useEffect(() => { if (JSON.stringify(linkedProposals) !== JSON.stringify(selectedProposals)) { setSelectedProposals(linkedProposals); @@ -36,69 +23,38 @@ useEffect(() => { } }, [selectedProposals]); -function separateNumberAndText(str) { - const numberRegex = /\d+/; - - if (numberRegex.test(str)) { - const number = str.match(numberRegex)[0]; - const text = str.replace(numberRegex, "").trim(); - return { number: parseInt(number), text }; - } else { - return { number: null, text: str.trim() }; - } -} - -const buildWhereClause = () => { - let where = {}; - const { number, text } = separateNumberAndText(searchProposalId); +function searchProposals() { + const ENDPOINT = "${REPL_CACHE_URL}"; - if (number) { - where = { proposal_id: { _eq: number }, ...where }; - } - - if (text) { - where = { - _or: [ - { name: { _iregex: `${text}` } }, - { summary: { _iregex: `${text}` } }, - { description: { _iregex: `${text}` } }, - ], - ...where, - }; - } + let searchInput = encodeURI(searchProposalId); + let searchUrl = searchInput + ? `${ENDPOINT}/proposals/search/${searchInput}` + : `${ENDPOINT}/proposals`; - return where; -}; - -const fetchProposals = () => { - const FETCH_LIMIT = 30; - const variables = { - limit: FETCH_LIMIT, - offset: 0, - where: buildWhereClause(), - }; - if (typeof fetchGraphQL !== "function") { - return; - } - fetchGraphQL(query, "GetLatestSnapshot", variables).then(async (result) => { - if (result.status === 200) { - if (result.body.data) { - const proposalsData = result.body.data?.[queryName]; - const data = []; - for (const prop of proposalsData) { - data.push({ - label: "# " + prop.proposal_id + " : " + prop.name, - value: prop.proposal_id, - }); - } - setProposalsOptions(data); + return asyncFetch(searchUrl, { + method: "GET", + headers: { + accept: "application/json", + }, + }) + .then((result) => { + const proposalsData = result.body.records; + const data = []; + for (const prop of proposalsData) { + data.push({ + label: "# " + prop.proposal_id + " : " + prop.name, + value: prop.proposal_id, + }); } - } - }); -}; + setProposalsOptions(data); + }) + .catch((error) => { + console.log("Error searching cache api", error); + }); +} useEffect(() => { - fetchProposals(); + searchProposals(); }, [searchProposalId]); return ( diff --git a/instances/treasury-templar.near/widget/components/molecule/LinkedRfpDropdown.jsx b/instances/treasury-templar.near/widget/components/molecule/LinkedRfpDropdown.jsx index e80ea2a91..08d3ff11d 100644 --- a/instances/treasury-templar.near/widget/components/molecule/LinkedRfpDropdown.jsx +++ b/instances/treasury-templar.near/widget/components/molecule/LinkedRfpDropdown.jsx @@ -20,20 +20,6 @@ const [allRfpOptions, setAllRfpOptions] = useState([]); const [searchRFPId, setSearchRfpId] = useState(""); const [initialStateApplied, setInitialState] = useState(false); -const queryName = "${REPL_RFP_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: {rfp_id: desc} - where: $where - ) { - name - rfp_id - timeline - } - }`; - function separateNumberAndText(str) { const numberRegex = /\d+/; @@ -46,69 +32,48 @@ function separateNumberAndText(str) { } } -const buildWhereClause = () => { - // show only accepting submissions stage rfps - let where = {}; - const { number, text } = separateNumberAndText(searchRFPId); +function searchRfps() { + const ENDPOINT = "${REPL_CACHE_URL}"; + let searchInput = encodeURI(searchRFPId); + let searchUrl = searchInput + ? `${ENDPOINT}/rfps/search/${searchInput}` + : `${ENDPOINT}/rfps`; - if (number) { - where = { rfp_id: { _eq: number }, ...where }; - } - - if (text) { - where = { - _or: [ - { name: { _iregex: `${text}` } }, - { summary: { _iregex: `${text}` } }, - { description: { _iregex: `${text}` } }, - ], - ...where, - }; - } - - return where; -}; - -const fetchRfps = () => { - const FETCH_LIMIT = 30; - const variables = { - limit: FETCH_LIMIT, - offset: 0, - where: buildWhereClause(), - }; - if (typeof fetchGraphQL !== "function") { - return; - } - fetchGraphQL(query, "GetLatestSnapshot", variables).then(async (result) => { - if (result.status === 200) { - if (result.body.data) { - const rfpsData = result.body.data?.[queryName]; - const data = []; - const acceptingData = []; - for (const prop of rfpsData) { - const timeline = parseJSON(prop.timeline); - const label = "# " + prop.rfp_id + " : " + prop.name; - const value = prop.rfp_id; - if (timeline.status === RFP_TIMELINE_STATUS.ACCEPTING_SUBMISSIONS) { - acceptingData.push({ - label, - value, - }); - } - data.push({ + return asyncFetch(searchUrl, { + method: "GET", + headers: { + accept: "application/json", + }, + }) + .then((result) => { + const rfpsData = result.body.records; + const data = []; + const acceptingData = []; + for (const prop of rfpsData) { + const timeline = parseJSON(prop.timeline); + const label = "# " + prop.rfp_id + " : " + prop.name; + const value = prop.rfp_id; + if (timeline.status === RFP_TIMELINE_STATUS.ACCEPTING_SUBMISSIONS) { + acceptingData.push({ label, value, }); } - setAcceptingRfpsOption(acceptingData); - setAllRfpOptions(data); + data.push({ + label, + value, + }); } - } - }); -}; + setAcceptingRfpsOption(acceptingData); + setAllRfpOptions(data); + }) + .catch((error) => { + console.log("Error searching cache api", error); + }); +} useEffect(() => { - fetchRfps(); + searchRfps(); }, [searchRFPId]); useEffect(() => { diff --git a/instances/treasury-templar.near/widget/components/molecule/SimpleMDE.jsx b/instances/treasury-templar.near/widget/components/molecule/SimpleMDE.jsx index 0ae9f861f..959aeebee 100644 --- a/instances/treasury-templar.near/widget/components/molecule/SimpleMDE.jsx +++ b/instances/treasury-templar.near/widget/components/molecule/SimpleMDE.jsx @@ -29,8 +29,8 @@ const fontFamily = props.fontFamily ?? "sans-serif"; const alignToolItems = props.alignToolItems ?? "right"; const placeholder = props.placeholder ?? ""; const showAccountAutoComplete = props.showAutoComplete ?? false; -const showProposalIdAutoComplete = props.showProposalIdAutoComplete ?? false; -const showRfpIdAutoComplete = props.showRfpIdAutoComplete ?? false; +const showProposalIdAutoComplete = false; +const showRfpIdAutoComplete = false; const autoFocus = props.autoFocus ?? false; const proposalQueryName = "${REPL_PROPOSAL_FEED_INDEXER_QUERY_NAME}"; diff --git a/instances/treasury-templar.near/widget/components/proposals/Editor.jsx b/instances/treasury-templar.near/widget/components/proposals/Editor.jsx index 9d881f158..ab687a6cb 100644 --- a/instances/treasury-templar.near/widget/components/proposals/Editor.jsx +++ b/instances/treasury-templar.near/widget/components/proposals/Editor.jsx @@ -780,7 +780,7 @@ const onSubmit = ({ isDraft, isCancel }) => { const body = { proposal_body_version: "V1", linked_rfp: linkedRfp?.value, - category: "Infrastructure Committee", + category: "Templar", name: title, description: description, summary: summary, @@ -788,7 +788,7 @@ const onSubmit = ({ isDraft, isCancel }) => { requested_sponsorship_usd_amount: requestedSponsorshipAmount, requested_sponsorship_paid_in_currency: requestedSponsorshipToken.value, receiver_account: receiverAccount, - requested_sponsor: "infrastructure-committee.near", + requested_sponsor: "templar.sputnik-dao.near", supervisor: supervisor, timeline: isCancel ? { diff --git a/instances/treasury-templar.near/widget/components/proposals/Feed.jsx b/instances/treasury-templar.near/widget/components/proposals/Feed.jsx index d7516b9be..ea2b44513 100644 --- a/instances/treasury-templar.near/widget/components/proposals/Feed.jsx +++ b/instances/treasury-templar.near/widget/components/proposals/Feed.jsx @@ -9,7 +9,6 @@ const { rfpFeedIndexerQueryName, availableCategoryOptions, proposalFeedIndexerQueryName, - indexerHasuraRole, isDevhub, isInfra, isEvents, @@ -268,14 +267,18 @@ const getProposal = (proposal_id) => { }); }; -const FeedPage = () => { - const QUERYAPI_ENDPOINT = `https://near-queryapi.api.pagoda.co/v1/graphql`; +const getRfp = (rfp_id) => { + return Near.asyncView(contract, "get_rfp", { + rfp_id, + }); +}; +const FeedPage = () => { State.init({ data: [], author: "", stage: "", - sort: "", + sort: "id_desc", category: "", input: "", loading: false, @@ -285,114 +288,6 @@ const FeedPage = () => { currentlyDisplaying: 0, }); - const query = `query GetLatestSnapshot($offset: Int = 0, $limit: Int = 20, $where: ${proposalFeedIndexerQueryName}_bool_exp = {}) { - ${proposalFeedIndexerQueryName}( - offset: $offset - limit: $limit - order_by: {proposal_id: desc} - where: $where - ) { - author_id - block_height - name - category - summary - editor_id - proposal_id - ts - timeline - views - labels - linked_rfp - } - ${proposalFeedIndexerQueryName}_aggregate( - order_by: {proposal_id: desc} - where: $where - ) { - aggregate { - count - } - } - }`; - - const rfpQuery = `query GetLatestSnapshot($offset: Int = 0, $limit: Int = 20, $where: ${rfpFeedIndexerQueryName}_bool_exp = {}) { - ${rfpFeedIndexerQueryName}( - offset: $offset - limit: $limit - order_by: {rfp_id: desc} - where: $where - ) { - name - rfp_id - } - }`; - - function fetchGraphQL(operationsDoc, operationName, variables) { - return asyncFetch(QUERYAPI_ENDPOINT, { - method: "POST", - headers: { "x-hasura-role": indexerHasuraRole }, - body: JSON.stringify({ - query: operationsDoc, - variables: variables, - operationName: operationName, - }), - }); - } - - function separateNumberAndText(str) { - const numberRegex = /\d+/; - - if (numberRegex.test(str)) { - const number = str.match(numberRegex)[0]; - const text = str.replace(numberRegex, "").trim(); - return { number: parseInt(number), text }; - } else { - return { number: null, text: str.trim() }; - } - } - - const buildWhereClause = () => { - let where = {}; - if (state.author) { - where = { author_id: { _eq: state.author }, ...where }; - } - - if (state.category) { - if (isInfra || isEvents) { - where = { labels: { _contains: state.category }, ...where }; - } else { - where = { category: { _eq: state.category }, ...where }; - } - } - - if (state.stage) { - // timeline is stored as jsonb - where = { - timeline: { _cast: { String: { _regex: `${state.stage}` } } }, - ...where, - }; - } - if (state.input) { - const { number, text } = separateNumberAndText(state.input); - if (number) { - where = { proposal_id: { _eq: number }, ...where }; - } - - if (text) { - where = { - _or: [ - { name: { _iregex: `${text}` } }, - { summary: { _iregex: `${text}` } }, - { description: { _iregex: `${text}` } }, - ], - ...where, - }; - } - } - - return where; - }; - const makeMoreItems = () => { State.update({ makeMoreLoader: true }); fetchProposals(state.data.length); @@ -405,7 +300,86 @@ const FeedPage = () => { REJECTED: 1, }; - const fetchProposals = (offset) => { + function searchCacheApi() { + const ENDPOINT = "${REPL_CACHE_URL}"; + + let searchTerm = state.input; + let searchInput = encodeURI(searchTerm); + let searchUrl = searchInput + ? `${ENDPOINT}/proposals/search/${searchInput}` + : `${ENDPOINT}/proposals`; + + console.log(searchUrl); + return asyncFetch(searchUrl, { + method: "GET", + headers: { + accept: "application/json", + }, + }).catch((error) => { + console.log("Error searching cache api", error); + }); + } + + function searchProposals() { + if (state.loading) return; + State.update({ loading: true }); + + searchCacheApi().then((result) => { + console.log("result", result); + let data = result.body.records; + + const promises = data.map((item) => { + console.log("item.linked_rfp ", item.linked_rfp); + if (isNumber(item.linked_rfp)) { + // TODO fetch individual rfp's via the cache instead of RPC directly -> name & rfp_id + getRfp(item.linked_rfp).then((result) => { + console.log({ result }); + const rfpData = result.body.data; + return { ...item, rfpData: rfpData[0] }; + }); + } else { + return Promise.resolve(item); + } + }); + Promise.all(promises).then((res) => { + State.update({ aggregatedCount: result.body.total_records }); + fetchBlockHeights(res, offset); + }); + }); + } + + function fetchCacheApi(variables) { + const ENDPOINT = "${REPL_CACHE_URL}"; + console.log("Fetching endpoint", ENDPOINT); + console.log("Fetching cache api", variables); + + let fetchUrl = `${ENDPOINT}/proposals?order=${variables.order}&limit=${variables.limit}&offset=${variables.offset}`; + + if (variables.author_id) { + fetchUrl += `&filters.author_id=${variables.author_id}`; + } + if (variables.stage) { + fetchUrl += `&filters.stage=${variables.stage}`; + } + if (variables.category) { + if (isInfra || isEvents) { + fetchUrl += `&filters.labels=${variables.category}`; + } else { + fetchUrl += `&filters.category=${variables.category}`; + } + } + console.log("Fetching.. ", fetchUrl); + return asyncFetch(fetchUrl, { + method: "GET", + headers: { + accept: "application/json", + }, + }).catch((error) => { + console.log("Error fetching cache api", error); + }); + } + + function fetchProposals(offset) { if (!offset) { offset = 0; } @@ -413,36 +387,34 @@ const FeedPage = () => { State.update({ loading: true }); const FETCH_LIMIT = 20; const variables = { + order: state.sort, limit: FETCH_LIMIT, offset, - where: buildWhereClause(), + category: state.category ? encodeURIComponent(state.category) : "", + author_id: state.author ? encodeURIComponent(state.author) : "", + stage: state.stage ? encodeURIComponent(state.stage) : "", }; - fetchGraphQL(query, "GetLatestSnapshot", variables).then(async (result) => { - if (result.status === 200) { - if (result.body.data) { - const data = result.body.data[proposalFeedIndexerQueryName]; - const totalResult = - result.body.data[`${proposalFeedIndexerQueryName}_aggregate`]; - const promises = data.map((item) => { - if (isNumber(item.linked_rfp)) { - return fetchGraphQL(rfpQuery, "GetLatestSnapshot", { - where: { rfp_id: { _eq: item.linked_rfp } }, - }).then((result) => { - const rfpData = result.body.data?.[rfpFeedIndexerQueryName]; - return { ...item, rfpData: rfpData[0] }; - }); - } else { - return Promise.resolve(item); - } - }); - Promise.all(promises).then((res) => { - State.update({ aggregatedCount: totalResult.aggregate.count }); - fetchBlockHeights(res, offset); + fetchCacheApi(variables).then((result) => { + const body = result.body; + const promises = body.records.map((item) => { + console.log("item.linked_rfp ", item.linked_rfp); + if (isNumber(item.linked_rfp)) { + // TODO fetch individual rfp's via the cache instead of RPC directly -> name & rfp_id + getRfp(item.linked_rfp).then((result) => { + console.log({ result }); + const rfpData = body.data; + return { ...item, rfpData: rfpData[0] }; }); + } else { + return Promise.resolve(item); } - } + }); + Promise.all(promises).then((res) => { + State.update({ aggregatedCount: body.total_records }); + fetchBlockHeights(res, offset); + }); }); - }; + } useEffect(() => { State.update({ searchLoader: true }); @@ -454,12 +426,11 @@ const FeedPage = () => { ...new Set([...newItems, ...state.data].map((i) => JSON.stringify(i))), ].map((i) => JSON.parse(i)); // Sorting in the front end - if (state.sort === "proposal_id" || state.sort === "") { + if (state.sort === "id_desc" || state.sort === "") { items.sort((a, b) => b.proposal_id - a.proposal_id); - } else if (state.sort === "views") { - items.sort((a, b) => b.views - a.views); } + // Show the accepted once before showing rejected proposals items.sort((a, b) => { return statusOrder[a.timeline.status] - statusOrder[b.timeline.status]; }); @@ -468,43 +439,40 @@ const FeedPage = () => { }; const fetchBlockHeights = (data, offset) => { - let promises = data.map((item) => getProposal(item.proposal_id)); - Promise.all(promises).then((blockHeights) => { - data = data.map((item, index) => ({ - ...item, - timeline: JSON.parse(item.timeline), - social_db_post_block_height: - blockHeights[index].social_db_post_block_height, - })); - if (offset) { - let newData = mergeItems(data); - State.update({ - data: newData, - currentlyDisplaying: newData.length, - loading: false, - searchLoader: false, - makeMoreLoader: false, - }); - } else { - let sorted = [...data].sort((a, b) => { - return ( - statusOrder[a.timeline.status] - statusOrder[b.timeline.status] - ); - }); - State.update({ - data: sorted, - currentlyDisplaying: data.length, - loading: false, - searchLoader: false, - makeMoreLoader: false, - }); - } - }); + data = data.map((item, index) => ({ + ...item, + timeline: JSON.parse(item.timeline), + })); + if (offset) { + let newData = mergeItems(data); + State.update({ + data: newData, + currentlyDisplaying: newData.length, + loading: false, + searchLoader: false, + makeMoreLoader: false, + }); + } else { + let sorted = [...data].sort((a, b) => { + return statusOrder[a.timeline.status] - statusOrder[b.timeline.status]; + }); + State.update({ + data: sorted, + currentlyDisplaying: data.length, + loading: false, + searchLoader: false, + makeMoreLoader: false, + }); + } }; useEffect(() => { const handler = setTimeout(() => { - fetchProposals(); + if (state.input) { + searchProposals(); + } else { + fetchProposals(); + } }, 1000); return () => { diff --git a/instances/treasury-templar.near/widget/components/proposals/Proposal.jsx b/instances/treasury-templar.near/widget/components/proposals/Proposal.jsx index a0ad9ff03..826da378c 100644 --- a/instances/treasury-templar.near/widget/components/proposals/Proposal.jsx +++ b/instances/treasury-templar.near/widget/components/proposals/Proposal.jsx @@ -279,57 +279,38 @@ const proposal = Near.view( const [snapshotHistory, setSnapshotHistory] = useState([]); -const queryName = "${REPL_PROPOSAL_QUERY_NAME}"; -const query = `query GetLatestSnapshot($offset: Int = 0, $limit: Int = 10, $where: ${queryName}_bool_exp = {}) { - ${queryName}( - offset: $offset - limit: $limit - order_by: {ts: asc} - where: $where - ) { - editor_id - name - summary - description - ts - proposal_id - timeline - labels - linked_proposals - linked_rfp - requested_sponsorship_usd_amount - requested_sponsorship_paid_in_currency - receiver_account - requested_sponsor - supervisor - } -}`; - -const fetchSnapshotHistory = () => { - const variables = { - where: { proposal_id: { _eq: id } }, - }; - if (typeof fetchGraphQL !== "function") { - return; - } - fetchGraphQL(query, "GetLatestSnapshot", variables).then(async (result) => { - if (result.status === 200) { - if (result.body.data) { - const data = result.body.data?.[queryName]; - const history = data.map((item) => { - const proposalData = { - ...item, - timestamp: item.ts, - timeline: parseJSON(item.timeline), - }; - delete proposalData.ts; - return proposalData; - }); - setSnapshotHistory(history); - } - } - }); -}; +// need to fix it +function fetchSnapshotHistory() { + const ENDPOINT = "${REPL_CACHE_URL}"; + + let searchInput = encodeURI(id); + let searchUrl = `${ENDPOINT}/proposals/search/${searchInput}`; + + console.log(searchUrl); + return asyncFetch(searchUrl, { + method: "GET", + headers: { + accept: "application/json", + }, + }) + .catch((error) => { + console.log("Error searching cache api", error); + }) + .then((result) => { + console.log("result", result); + let data = result.body.records; + const history = data.map((item) => { + const proposalData = { + ...item, + timestamp: item.ts, + timeline: parseJSON(item.timeline), + }; + delete proposalData.ts; + return proposalData; + }); + setSnapshotHistory(history); + }); +} useEffect(() => { fetchSnapshotHistory(); diff --git a/instances/treasury-templar.near/widget/components/rfps/Feed.jsx b/instances/treasury-templar.near/widget/components/rfps/Feed.jsx index 9e1eebea0..dbad79366 100644 --- a/instances/treasury-templar.near/widget/components/rfps/Feed.jsx +++ b/instances/treasury-templar.near/widget/components/rfps/Feed.jsx @@ -1,7 +1,3 @@ -const { fetchGraphQL } = VM.require( - `${REPL_TREASURY_TEMPLAR}/widget/core.common` -); - const { href } = VM.require(`${REPL_DEVHUB}/widget/core.lib.url`); href || (href = () => {}); @@ -110,8 +106,6 @@ const Heading = styled.div` const rfpLabelOptions = getGlobalLabels(); const FeedItem = ({ rfp, index }) => { - const accountId = rfp.author_id; - const profile = Social.get(`${accountId}/profile/**`, "final"); // We will have to get the rfp from the contract to get the block height. const blockHeight = parseInt(rfp.social_db_post_block_height); const item = { @@ -229,7 +223,7 @@ const FeedPage = () => { data: [], cachedItems: {}, stage: "", - sort: "", + sort: "id_desc", label: "", input: "", loading: false, @@ -239,91 +233,77 @@ const FeedPage = () => { isFiltered: false, }); - const queryName = "${REPL_RFP_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: {rfp_id: desc} - where: $where - ) { - author_id - block_height - name - summary - editor_id - rfp_id - timeline - views - labels - submission_deadline - linked_proposals - } - ${queryName}_aggregate( - order_by: {rfp_id: desc} - where: $where - ) { - aggregate { - count + function searchCacheApi() { + console.log( + `search url: ${REPL_CACHE_URL}/rfps/search/${encodeURI(state.input)}` + ); + return asyncFetch( + `${REPL_CACHE_URL}/rfps/search/${encodeURI(state.input)}`, + { + method: "GET", + headers: { + accept: "application/json", + }, } - } - }`; - - function separateNumberAndText(str) { - const numberRegex = /\d+/; - - if (numberRegex.test(str)) { - const number = str.match(numberRegex)[0]; - const text = str.replace(numberRegex, "").trim(); - return { number: parseInt(number), text }; - } else { - return { number: null, text: str.trim() }; - } + ).catch((error) => { + console.log("Error searching cache api", error); + }); } - const buildWhereClause = () => { - let where = {}; + function searchRfps() { + if (state.loading) return; + State.update({ loading: true }); + + searchCacheApi().then((result) => { + console.log("search result", result); + let body = result.body; + const data = []; + const acceptingData = []; + for (const prop of body) { + const timeline = parseJSON(prop.timeline); + const label = "# " + prop.rfp_id + " : " + prop.name; + const value = prop.rfp_id; + if (timeline.status === RFP_TIMELINE_STATUS.ACCEPTING_SUBMISSIONS) { + acceptingData.push({ + label, + value, + }); + } + data.push({ + label, + value, + }); + } + setAcceptingRfpsOption(acceptingData); + setAllRfpOptions(data); + }); + } - if (state.label) { - where = { labels: { _contains: state.label }, ...where }; - } + function fetchCacheApi(variables) { + let fetchUrl = `${REPL_CACHE_URL}/rfps?order=${variables.order}&limit=${variables.limit}&offset=${variables.offset}`; - if (state.stage) { - // timeline is stored as jsonb - where = { - timeline: { _cast: { String: { _regex: `${state.stage}` } } }, - ...where, - }; + if (variables.stage) { + fetchUrl += `&filters.stage=${variables.stage}`; } - if (state.input) { - const { number, text } = separateNumberAndText(state.input); - if (number) { - where = { rfp_id: { _eq: number }, ...where }; - } - - if (text) { - where = { - _or: [ - { name: { _iregex: `${text}` } }, - { summary: { _iregex: `${text}` } }, - { description: { _iregex: `${text}` } }, - ], - ...where, - }; + if (variables.category) { + if (isInfra || isEvents) { + fetchUrl += `&filters.labels=${variables.category}`; + } else { + fetchUrl += `&filters.category=${variables.category}`; } } - State.update({ isFiltered: Object.keys(where).length > 0 }); - return where; - }; - const buildOrderByClause = () => { - /** - * TODO - * Most commented -> edit contract and indexer - * Unanswered -> 0 comments - */ - }; + State.update({ isFiltered: variables.category || variables.stage }); + + return asyncFetch(fetchUrl, { + method: "GET", + headers: { + accept: "application/json", + }, + }).catch((error) => { + console.log("Error fetching cache api", error); + }); + } const makeMoreItems = () => { if (state.aggregatedCount <= state.currentlyDisplaying) return; @@ -335,25 +315,21 @@ const FeedPage = () => { offset = 0; } if (state.loading) return; + State.update({ loading: true }); + const FETCH_LIMIT = 10; const variables = { + order: state.sort, limit: FETCH_LIMIT, offset, - where: buildWhereClause(), + category: state.category ? encodeURIComponent(state.category) : "", + stage: state.stage ? encodeURIComponent(state.stage) : "", }; - if (typeof fetchGraphQL !== "function") { - return; - } - fetchGraphQL(query, "GetLatestSnapshot", variables).then(async (result) => { - if (result.status === 200) { - if (result.body.data) { - const data = result.body.data?.[queryName]; - const totalResult = result.body.data?.[`${queryName}_aggregate`]; - State.update({ aggregatedCount: totalResult.aggregate.count }); - // Parse timeline - fetchBlockHeights(data, offset); - } - } + + fetchCacheApi(variables).then((result) => { + const body = result.body; + State.update({ aggregatedCount: body.total_records }); + fetchBlockHeights(body.records, offset); }); }; @@ -386,7 +362,21 @@ const FeedPage = () => { useEffect(() => { fetchRfps(); - }, [state.input, state.sort, state.label, state.stage]); + }, [state.sort, state.label, state.stage]); + + useEffect(() => { + const handler = setTimeout(() => { + if (state.input) { + searchRfps(); + } else { + fetchRfps(); + } + }, 1000); + + return () => { + clearTimeout(handler); + }; + }, [state.input]); const mergeItems = (newItems) => { const items = [ diff --git a/instances/treasury-templar.near/widget/components/rfps/Rfp.jsx b/instances/treasury-templar.near/widget/components/rfps/Rfp.jsx index 13f51ec56..f4b11fc2a 100644 --- a/instances/treasury-templar.near/widget/components/rfps/Rfp.jsx +++ b/instances/treasury-templar.near/widget/components/rfps/Rfp.jsx @@ -279,52 +279,38 @@ const rfp = Near.view("${REPL_TREASURY_TEMPLAR_CONTRACT}", "get_rfp", { rfp_id: parseInt(id), }); -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: {ts: asc} - where: $where - ) { - editor_id - name - summary - description - ts - rfp_id - timeline - labels - submission_deadline - linked_proposals - } -}`; - -const fetchSnapshotHistory = () => { - const variables = { - where: { rfp_id: { _eq: id } }, - }; - if (typeof fetchGraphQL !== "function") { - return; - } - fetchGraphQL(query, "GetLatestSnapshot", variables).then(async (result) => { - if (result.status === 200) { - if (result.body.data) { - const data = result.body.data?.[queryName]; - const history = data.map((item) => { - const rfpData = { - ...item, - timestamp: item.ts, - timeline: parseJSON(item.timeline), - }; - delete rfpData.ts; - return rfpData; - }); - setSnapshotHistory(history); - } - } - }); -}; +// need to fix it +function fetchSnapshotHistory() { + const ENDPOINT = "${REPL_CACHE_URL}"; + + let searchInput = encodeURI(id); + let searchUrl = `${ENDPOINT}/rfps/search/${searchInput}`; + + console.log(searchUrl); + return asyncFetch(searchUrl, { + method: "GET", + headers: { + accept: "application/json", + }, + }) + .catch((error) => { + console.log("Error searching cache api", error); + }) + .then((result) => { + console.log("result", result); + let data = result.body.records; + const history = data.map((item) => { + const rfpData = { + ...item, + timestamp: item.ts, + timeline: parseJSON(item.timeline), + }; + delete rfpData.ts; + return rfpData; + }); + setSnapshotHistory(history); + }); +} useEffect(() => { fetchSnapshotHistory(); @@ -410,45 +396,18 @@ useEffect(() => { }, [snapshot]); function fetchApprovedRfpProposals() { - const queryName = "${REPL_PROPOSAL_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 - ) { - proposal_id - name - timeline - } - }`; - - const FETCH_LIMIT = 50; - const variables = { - limit: FETCH_LIMIT, - offset, - where: { - proposal_id: { _in: rfp.snapshot.linked_proposals }, - }, - }; - if (typeof fetchGraphQL !== "function") { - return; - } - fetchGraphQL(query, "GetLatestSnapshot", variables).then(async (result) => { - if (result.status === 200) { - if (result.body.data) { - const data = result.body.data?.[queryName]; - const approved = []; - data.map((item) => { - const timeline = parseJSON(item.timeline); - if (PROPOSALS_APPROVED_STATUS_ARRAY.includes(timeline.status)) { - approved.push(item); - } - }); - setApprovedProposals(approved); + snapshot.linked_proposals.map((item) => { + Near.asyncView("${REPL_TREASURY_TEMPLAR_CONTRACT}", "get_proposal", { + proposal_id: item, + }).then((item) => { + const timeline = parseJSON(item.snapshot.timeline); + if (PROPOSALS_APPROVED_STATUS_ARRAY.includes(timeline.status)) { + setApprovedProposals([ + ...approvedProposals, + { proposal_id: item.id, ...item.snapshot }, + ]); } - } + }); }); } @@ -493,7 +452,9 @@ const accessControlInfo = const moderatorList = accessControlInfo?.members_list?.["team:moderators"]?.children; -fetchApprovedRfpProposals(); +useEffect(() => { + fetchApprovedRfpProposals(); +}, []); const SubmitProposalBtn = () => { return (