Search
Search

Transaction: 7Rf8Fqd...aNE8

Receiver
Status
Succeeded
Transaction Fee
0.00193 
Deposit Value
0 
Gas Used
19 Tgas
Attached Gas
300 Tgas
Created
July 09, 2024 at 9:03:03pm
Hash
7Rf8FqdHSa4X77Q9jBnBNs9ykegyqyPHZS4DcQr6aNE8

Actions

Called method: 'set' in contract: social.near
Arguments:
{ "data": { "dev-queryapi.dataplatform.near": { "widget": { "QueryApi.Editor": { "": "const path = props.path || \"query-api-editor\";\nconst tab = props.tab || \"\";\nconst activeView = props.activeView || \"editor\";\nlet accountId = props.accountId || context.accountId;\nlet externalAppUrl = `https://queryapi-frontend-vcqilefdcq-ew.a.run.app/${path}?accountId=${accountId}`;\n\nif (props.indexerName) {\n externalAppUrl += `&indexerName=${props.indexerName}`;\n}\nconst initialViewHeight = 1000;\n\nconst initialPayload = {\n height: Near.block(\"optimistic\").header.height,\n selectedTab: tab,\n activeView,\n currentUserAccountId: context.accountId,\n};\n\nconst registerFunctionHandler = (request, response) => {\n const gas = 200000000000000;\n const { indexerName, code, schema, startBlock, contractFilter, forkedFrom } =\n request.payload;\n\n const jsonFilter = `{\"indexer_rule_kind\":\"Action\",\"matching_rule\":{\"rule\":\"ACTION_ANY\",\"affected_account_id\":\"${contractFilter || \"social.near\"}\",\"status\":\"SUCCESS\"}}`\n\n Near.call(\n `dev-queryapi.dataplatform.near`,\n \"register\",\n {\n function_name: indexerName,\n code,\n schema,\n start_block: startBlock,\n rule: {\n kind: \"ACTION_ANY\",\n affected_account_id: contractFilter,\n status: \"SUCCESS\"\n },\n ...(forkedFrom && { forked_from: forkedFrom }),\n },\n gas\n );\n};\n\nlet deleteIndexer = (request) => {\n const { indexerName } = request.payload;\n const gas = 200000000000000;\n Near.call(\n `dev-queryapi.dataplatform.near`,\n \"remove_indexer_function\",\n {\n function_name: indexerName,\n },\n gas\n );\n};\n\n/**\n * Request Handlers here\n */\nconst requestHandler = (request, response) => {\n switch (request.type) {\n case \"register-function\":\n registerFunctionHandler(request, response);\n break;\n case \"delete-indexer\":\n deleteIndexer(request, response);\n break;\n case \"default\":\n console.log(\"default case\");\n }\n};\n\n// NearSocialBridgeCore widget is the core that makes all the \"magic\" happens\nreturn (\n <Widget\n src={\"wendersonpires.near/widget/NearSocialBridgeCore\"}\n props={{\n externalAppUrl,\n path,\n initialViewHeight,\n initialPayload,\n requestHandler,\n }}\n />\n);\n", "metadata": { "description": "Helper widget for QueryApi.Dashboard. Loads QueryAPI's React App which allows you to edit indexers inside the browser", "image": {}, "name": "Editor", "tags": { "indexers": "", "data-platform": "", "react": "" } } }, "QueryApi.Dashboard": { "": "const accountId = context.accountId;\nconst [selected_accountId, selected_indexerName] = props.selectedIndexerPath\n ? props.selectedIndexerPath.split(\"/\")\n : [undefined, undefined];\n\nconst activeTab = props.view == \"create-new-indexer\" ? \"create-new-indexer\" : props.selectedIndexerPath ? \"indexer\" : \"explore\"\nconst activeIndexerView = props.activeIndexerView ?? \"editor\";\nconst limit = 7;\nlet totalIndexers = 0;\n\nState.init({\n activeTab: activeTab,\n activeIndexerView: activeIndexerView,\n my_indexers: [],\n all_indexers: [],\n selected_indexer: undefined,\n selected_account: undefined,\n});\n\nconst Subheading = styled.h2`\n display: block;\n margin: 0;\n font-size: 14px;\n line-height: 20px;\n color: ${(p) => (p.bold ? \"#11181C !important\" : \"#687076 !important\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"visible\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"unset\")};\n white-space: nowrap;\n outline: none;\n`;\n\nconst Editor = styled.div`\n`;\nconst Status = styled.div`\n`;\n\nconst Wrapper = styled.div`\n margin-inline: 12px;\n margin-top: calc(var(--body-top-padding) * -1);\n`;\n\nconst NavBarLogo = styled.a`\n padding-top: 0.3125rem;\n padding-bottom: 0.3125rem;\n margin-right: .01rem;\n font-size: 1.25rem;\n text-decoration: none;\n white-space: nowrap;\n`;\nconst Main = styled.div`\n display: block;\n`;\n\nconst Section = styled.div`\n padding-top: 0px;\n border-left: none;\n border-right: none;\n display: ${(p) => (p.active ? \"block\" : \"none\")};\n margin: ${(p) => (p.negativeMargin ? \"0 -12px\" : \"0\")};\n`;\n\nconst Tabs = styled.div`\n display: none;\n height: 48px;\n background: #f8f9fa;\n border-top: 1px solid #eceef0;\n border-bottom: 1px solid #eceef0;\n margin-bottom: ${(p) => (p.noMargin ? \"0\" : p.halfMargin ? \"24px\" : \"24px\")};\n\n display: flex;\n margin-left: -12px;\n margin-right: -12px;\n\n button {\n flex: 1;\n }\n`;\nconst Content = styled.div`\n background-color: #f7f7f7;\n padding: 2em;\n border-radius: 5px;\n`;\n\nconst Title = styled.h1`\n font-size: 1.5em;\n text-align: center;\n color: palevioletred;\n`;\n\nconst TabsButton = styled.button`\n font-weight: 600;\n font-size: 14px;\n line-height: 16px;\n padding: 0 12px;\n position: relative;\n color: ${(p) => (p.selected ? \"#11181C\" : \"#687076\")};\n background: none;\n border: none;\n outline: none;\n &:hover {\n color: #11181c;\n }\n\n &::after {\n content: \"\";\n display: ${(p) => (p.selected ? \"block\" : \"none\")};\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #0091ff;\n }\n`;\nconst H2 = styled.h2`\n font-size: 19px;\n line-height: 22px;\n color: #11181c;\n margin: 0 0 8px;\n`;\nconst Card = styled.div`\n border-radius: 12px;\n background: #fff;\n border: ${(div) => (div.selected ? \"1px solid black\" : \"1px solid #eceef0\")};\n box-shadow: 0px 1px 3px rgba(16, 24, 40, 0.1),\n 0px 1px 2px rgba(16, 24, 40, 0.06);\n`;\n\nconst CardBody = styled.div`\n padding: 16px;\n display: flex;\n gap: 16px;\n align-items: center;\n\n > * {\n min-width: 0;\n }\n`;\n\nconst CardFooter = styled.div`\n display: flex;\n justify-content: space-around;\n flex-wrap: wrap;\n gap: 4px;\n padding: 16px;\n border-top: 1px solid #eceef0;\n`;\n\nconst TextLink = styled.a`\n display: block;\n margin: 0;\n font-size: 14px;\n line-height: 20px;\n color: ${(p) => (p.bold ? \"#11181C !important\" : \"#687076 !important\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"visible\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"unset\")};\n white-space: nowrap;\n outline: none;\n\n &:focus,\n &:hover {\n text-decoration: underline;\n }\n`;\n\nconst Thumbnail = styled.a`\n display: block;\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n border: 1px solid #eceef0;\n border-radius: 8px;\n overflow: hidden;\n outline: none;\n transition: border-color 200ms;\n\n &:focus,\n &:hover {\n border-color: #d0d5dd;\n }\n\n img {\n object-fit: cover;\n width: 100%;\n height: 100%;\n }\n`;\n\nconst CardWrapper = styled.div`\n margin: 0 0 16px;\n`;\n\nconst sharedButtonStyles = `\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n margin-bottom: 12px;\n height: 32px;\n border-radius: 6px;\n font-weight: 600;\n font-size: 12px;\n line-height: 15px;\n text-align: center;\n cursor: pointer;\n\n &:hover,\n &:focus {\n text-decoration: none;\n outline: none;\n }\n\n i {\n color: #7E868C;\n }\n\n .bi-16 {\n font-size: 16px;\n }\n`;\n\nconst Button = styled.button`\n ${sharedButtonStyles}\n color: ${(p) => (p.primary ? \"#fff\" : \"#11181C\")} !important;\n background: ${(p) => (p.primary ? \"#0091FF\" : \"#FBFCFD\")};\n border: ${(p) => (p.primary ? \"none\" : \"1px solid #D7DBDF\")};\n\n &:hover,\n &:focus {\n background: ${(p) => (p.primary ? \"#0484e5\" : \"#ECEDEE\")};\n }\n`;\n\nconst ButtonLink = styled.a`\n ${sharedButtonStyles}\n color: ${(p) => {\n if (p.primary) return \"#fff\";\n else if (p.danger) return \"#fff\";\n else return \"#11181C\";\n }} !important;\n background: ${(p) => {\n if (p.primary) return \"#0091FF\";\n else if (p.danger) return \"#dc3545\";\n else return \"#FBFCFD\";\n }};\n border: ${(p) => (p.primary ? \"none\" : \"1px solid #D7DBDF\")};\n\n &:hover,\n &:focus {\n background: ${(p) => {\n if (p.primary) return \"#0484e5\";\n else if (p.danger) return \"#b22b38\";\n else return \"#ECEDEE\";\n }}\n`;\n\nconst SignUpLink = styled.a`\n --blue: RGBA(13, 110, 253, 1);\n display: ${({ hidden }) => (hidden ? \"none\" : \"inline-block\")};\n font-size: 14px;\n cursor: pointer;\n color: var(--blue);\n text-decoration: none;\n margin-left: 0.1em;\n padding: 0;\n white-space: nowrap;\n\n &:hover {\n color: var(--blue);\n text-decoration: none;\n }\n\n &:visited {\n color: var(--blue);\n text-decoration: none;\n }\n`;\n// TODO fix activeTab\n// const previousSelectedTab = Storage.privateGet(\"queryapi:activeTab\");\n// if (previousSelectedTab && previousSelectedTab !== state.activeTab) {\n// State.update({\n// activeTab: previousSelectedTab,\n// });\n// }\n\nconst selectTab = (tabName) => {\n Storage.privateSet(\"queryapi:activeTab\", tabName);\n State.update({\n activeTab: tabName,\n });\n};\n\nconst selectIndexerPage = (viewName) => {\n Storage.privateSet(\"queryapi:activeIndexerTabView\", viewName);\n State.update({\n activeIndexerView: viewName,\n });\n};\nconst indexerView = (accountId, indexerName) => {\n const editUrl = `https://dev.near.org/dev-queryapi.dataplatform.near/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}`;\n const statusUrl = `https://dev.near.org/dev-queryapi.dataplatform.near/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}&view=indexer&activeIndexerView=status`;\n const playgroundLink = `https://cloud.hasura.io/public/graphiql?endpoint=https://near-queryapi.dev.api.pagoda.co/v1/graphql&header=x-hasura-role%3A${accountId.replaceAll(\n \".\",\n \"_\"\n )}`;\n\n return (\n <Card>\n <CardBody>\n <Thumbnail>\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n image: metadata.image,\n fallbackUrl:\n \"https://upload.wikimedia.org/wikipedia/commons/8/86/Database-icon.svg\",\n alt: \"Near QueryApi indexer\",\n }}\n />\n </Thumbnail>\n\n <div>\n <TextLink as=\"a\" bold ellipsis>\n {indexerName}\n </TextLink>\n <TextLink as=\"a\" ellipsis>\n @{accountId}\n </TextLink>\n </div>\n </CardBody>\n\n <CardFooter className=\"flex justify-center items-center\">\n <ButtonLink onClick={() => selectIndexerPage(\"status\")}>\n View Status\n </ButtonLink>\n <ButtonLink primary onClick={() => selectIndexerPage(\"editor\")}>\n {accountId === context.accountId ? \"Edit Indexer\" : \"View Indexer\"}\n </ButtonLink>\n <ButtonLink href={playgroundLink} target=\"_blank\">\n View In Playground\n </ButtonLink>\n </CardFooter>\n </Card>\n );\n};\n\nreturn (\n <Wrapper negativeMargin={state.activeTab === \"explore\"}>\n <Tabs>\n <TabsButton\n type=\"button\"\n onClick={() => selectTab(\"explore\")}\n selected={state.activeTab === \"explore\"}\n >\n Explore Indexers\n </TabsButton>\n {state.activeTab == \"create-new-indexer\" && (\n <TabsButton\n type=\"button\"\n onClick={() => selectTab(\"create-new-indexer\")}\n selected={state.activeTab === \"create-new-indexer\"}\n >\n Create New Indexer\n </TabsButton>\n )}\n\n {props.selectedIndexerPath && (\n <>\n <TabsButton\n type=\"button\"\n onClick={() => selectTab(\"indexer\")}\n selected={state.activeTab === \"indexer\"}\n >\n Indexer ({props.selectedIndexerPath})\n </TabsButton>\n </>\n )}\n </Tabs>\n <Main>\n <Section active={state.activeTab === \"explore\"}>\n <NavBarLogo\n href={`https://dev.near.org/dev-queryapi.dataplatform.near/widget/QueryApi.App`}\n title=\"QueryApi\"\n onClick={() => selectTab(\"explore\")}\n >\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n className: \"d-inline-block align-text-top me-2\",\n image: metadata.image,\n style: { height: \"24px\" },\n fallbackUrl:\n \"https://upload.wikimedia.org/wikipedia/commons/8/86/Database-icon.svg\",\n alt: \"the queryapi logo\",\n }}\n />\n QueryApi\n </NavBarLogo>\n\n <SignUpLink target=\"_blank\" href={`https://docs.near.org/build/data-infrastructure/query-api/intro`}>\n (Documentation)\n </SignUpLink>\n <div>\n <ButtonLink\n href={`/dev-queryapi.dataplatform.near/widget/QueryApi.App/?view=create-new-indexer`}\n style={{ \"margin-top\": \"10px\" }}\n onClick={() => {\n State.update({\n activeTab: \"create-new-indexer\",\n selected_indexer: \"\",\n });\n selectTab(\"create-new-indexer\");\n }}\n >\n Create New Indexer\n </ButtonLink>\n {state.my_indexers.length > 0 && (\n <H2>\n {accountId}'s Indexers\n <span>({state.my_indexers.length})</span>\n </H2>\n )}\n <Widget\n src={`dev-queryapi.dataplatform.near/widget/QueryApi.IndexerExplorer`}\n />\n </div>\n </Section>\n <Section\n negativeMargin\n primary\n active={state.activeTab === \"create-new-indexer\"}\n >\n {state.activeTab === \"create-new-indexer\" && (\n <div>\n <Widget\n src={`dev-queryapi.dataplatform.near/widget/QueryApi.Editor`}\n props={{\n indexerName:\n selected_indexerName ?? state.indexers[0].indexerName,\n accountId: selected_accountId ?? state.indexers[0].accountId,\n path: \"create-new-indexer\",\n }}\n />\n </div>\n )}\n </Section>\n <Section negativeMargin primary active={state.activeTab === \"indexer\"}>\n <Editor>\n {state.indexers.length > 0 &&\n (state.selected_indexer != undefined ? (\n <H2>{state.selected_indexer}</H2>\n ) : (\n <H2>{`${state.indexers[0].accountId}/${state.indexers[0].indexerName}`}</H2>\n ))}\n <Widget\n src={`dev-queryapi.dataplatform.near/widget/QueryApi.Editor`}\n props={{\n indexerName:\n selected_indexerName ?? state.indexers[0].indexerName,\n accountId: selected_accountId ?? state.indexers[0].accountId,\n path: \"query-api-editor\",\n tab: props.tab,\n activeView: state.activeIndexerView\n }}\n />\n </Editor>\n {state.activeTab === \"create-new-indexer\" && (\n <div>\n {state.indexers.length > 0 &&\n (state.selected_indexer != undefined ? (\n <H2>{state.selected_indexer}</H2>\n ) : (\n <H2>{`${state.indexers[0].accountId}/${state.indexers[0].indexerName}`}</H2>\n ))}\n <Widget\n src={`dev-queryapi.dataplatform.near/widget/QueryApi.Editor`}\n props={{\n indexerName:\n selected_indexerName ?? state.indexers[0].indexerName,\n accountId: selected_accountId ?? state.indexers[0].accountId,\n path: \"create-new-indexer\",\n }}\n />\n </div>\n )}\n </Section>\n </Main>\n </Wrapper>\n);\n", "metadata": { "description": "Main dashboard for Near QueryAPI which allows you to seamlessly create, manage, and discover indexers", "image": {}, "name": "Near QueryAPI Dashboard", "tags": {} } }, "QueryApi.IndexerStatus": { "": "//props indexer_name\nconst indexer_name = props.indexer_name;\n\nconst LIMIT = 20;\nconst accountId = props.accountId || context.accountId;\n\nconst H2 = styled.h2`\n font-size: 19px;\n line-height: 22px;\n color: #11181c;\n margin: 0 0 24px;\n`;\nconst Title = styled.h1`\n font-size: 1.5em;\n text-align: center;\n color: black;\n`;\nconst SmallTitle = styled.h3`\n color: black;\n font-weight: 600;\n font-size: 18px;\n line-height: 15px;\n text-transform: uppercase;\n\n @media (max-width: 770px) {\n margin-bottom: 16px;\n }\n`;\nconst TableElement = styled.td`\n word-wrap: break-word;\n font-family: \"Roboto Mono\", monospace;\n font-size: 11px;\n background-color: rgb(255, 255, 255);\n color: rgb(32, 33, 36);\n`;\nconst Subheading = styled.h2`\n display: block;\n margin: 0;\n font-size: 14px;\n line-height: 10px;\n color: ${(p) => (p.bold ? \"#11181C !important\" : \"#687076 !important\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"visible\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"unset\")};\n white-space: nowrap;\n outline: none;\n`;\nconst Card = styled.div`\n border-radius: 12px;\n background: #fff;\n border: ${(div) => (div.selected ? \"1px solid black\" : \"1px solid #eceef0\")};\n box-shadow: 0px 1px 3px rgba(16, 24, 40, 0.1),\n 0px 1px 2px rgba(16, 24, 40, 0.06);\n`;\n\nconst CardBody = styled.div`\n padding: 16px;\n display: flex;\n gap: 16px;\n align-items: center;\n flex-direction: column;\n > * {\n min-width: 0;\n }\n`;\n\nconst CardFooter = styled.div`\n display: flex;\n justify-content: space-around;\n flex-wrap: wrap;\n gap: 16px;\n padding: 16px;\n border-top: 1px solid #eceef0;\n`;\n\nconst TextLink = styled.a`\n display: block;\n margin: 0;\n font-size: 14px;\n line-height: 20px;\n color: ${(p) => (p.bold ? \"#11181C !important\" : \"#687076 !important\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"visible\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"unset\")};\n white-space: nowrap;\n outline: none;\n\n &:focus,\n &:hover {\n text-decoration: underline;\n }\n`;\n\nif (!indexer_name) return \"missing indexer_name\";\n\nState.init({\n logs: [],\n state: [],\n indexer_res: [],\n indexer_resCount: 0,\n logsCount: 0,\n stateCount: 0,\n indexer_resPage: 0,\n logsPage: 0,\n statePage: 0,\n});\n\nlet graphQLEndpoint = `https://near-queryapi.dev.api.pagoda.co`;\n\nfunction fetchGraphQL(operationsDoc, operationName, variables) {\n return asyncFetch(`${graphQLEndpoint}/v1/graphql`, {\n method: \"POST\",\n headers: {\n \"x-hasura-role\": \"append\"\n },\n body: JSON.stringify({\n query: operationsDoc,\n variables: variables,\n operationName: operationName,\n }),\n });\n}\n\nconst createGraphQLLink = () => {\n const queryLink = `https://cloud.hasura.io/public/graphiql?endpoint=${graphQLEndpoint}/v1/graphql&query=query+IndexerQuery+%7B%0A++indexer_state%28where%3A+%7Bfunction_name%3A+%7B_eq%3A+%22function_placeholder%22%7D%7D%29+%7B%0A++++function_name%0A++++current_block_height%0A++%7D%0A++indexer_log_entries%28%0A++++where%3A+%7Bfunction_name%3A+%7B_eq%3A+%22function_placeholder%22%7D%7D%0A++++order_by%3A+%7B+timestamp%3A+desc%7D%0A++%29+%7B%0A++++function_name%0A++++id%0A++++message%0A++++timestamp%0A++%7D%0A%7D%0A`;\n return queryLink.replaceAll(\n \"function_placeholder\",\n `${accountId}/${indexer_name}`\n );\n};\n\nconst accountName = accountId.replaceAll(\".\", \"_\");\nconst sanitizedFunctionName = indexer_name;\nconst fullFunctionName = accountName + \"_\" + sanitizedFunctionName;\nconst logsDoc = `\n query QueryLogs($offset: Int) {\n indexer_log_entries(order_by: {timestamp: desc}, limit: ${LIMIT}, offset: $offset, where: {function_name: {_eq: \"${accountId}/${indexer_name}\"}}) {\n block_height\n message\n timestamp\n }\n indexer_log_entries_aggregate(where: {function_name: {_eq: \"${accountId}/${indexer_name}\"}}) {\n aggregate {\n count\n }\n }\n }\n`;\n\nconst indexerStateDoc = `\n query IndexerState($offset: Int) {\n indexer_state(limit: ${LIMIT}, offset: $offset, where: {function_name: {_eq: \"${accountId}/${indexer_name}\"}}) {\n status\n function_name\n current_block_height\n current_historical_block_height\n }\n }\n`;\n\nif (!state.initialFetch) {\n State.update({\n logs: [],\n state: [],\n indexer_res: [],\n indexer_resCount: 0,\n logsCount: 0,\n stateCount: 0,\n indexer_resPage: 0,\n logsPage: 0,\n statePage: 0,\n })\n fetchGraphQL(logsDoc, \"QueryLogs\", {\n offset: state.logsPage * LIMIT,\n }).then((result) => {\n if (result.status === 200) {\n State.update({\n logs: result.body.data[`indexer_log_entries`],\n logsCount:\n result.body.data[`indexer_log_entries_aggregate`].aggregate.count,\n });\n }\n });\n\n fetchGraphQL(indexerStateDoc, \"IndexerState\", {\n offset: 0,\n }).then((result) => {\n if (result.status === 200) {\n if (result.body.data.indexer_state.length == 1) {\n State.update({\n state: result.body.data.indexer_state,\n stateCount: result.body.data.indexer_state_aggregate.aggregate.count,\n });\n }\n }\n });\n State.update({ initialFetch: true });\n}\nconst onLogsPageChange = (page) => {\n page = page - 1;\n if (page === state.logsPage) {\n console.log(`Selected the same page number as before: ${pageNumber}`);\n return;\n }\n try {\n fetchGraphQL(logsDoc, \"QueryLogs\", { offset: page * LIMIT }).then(\n (result) => {\n if (result.status === 200) {\n State.update({\n logs: result.body.data.indexer_log_entries,\n logsCount:\n result.body.data.indexer_log_entries_aggregate.aggregate.count,\n });\n }\n }\n );\n } catch (e) {\n console.log(\"error:\", e);\n }\n State.update({ logsPage: page, currentPage: page });\n};\n\nconst onIndexerResPageChange = (page) => {\n page = page - 1;\n if (page === state.indexer_resPage) {\n console.log(`Selected the same page number as before: ${pageNumber}`);\n return;\n }\n\n try {\n fetchGraphQL(IndexerStorageDoc, \"IndexerStorage\", {\n offset: page * LIMIT,\n }).then((result) => {\n if (result.status === 200) {\n State.update({\n indexer_res: result.body.data.indexer_storage,\n indexer_resCount:\n result.body.data.indexer_storage_aggregate.aggregate.count,\n });\n }\n });\n } catch (e) {\n console.log(\"error:\", e);\n }\n State.update({ indexer_resPage: page, currentPage: page });\n};\n\nreturn (\n <>\n <Card>\n <Title className=\"p-3\">\n Indexer Status\n <TextLink href={createGraphQLLink()} target=\"_blank\">\n GraphQL Playground\n <i className=\"bi bi-box-arrow-up-right\"></i>\n </TextLink>\n </Title>\n\n <CardBody>\n <SmallTitle>Indexer State </SmallTitle>\n {state.state.length > 0 ? (\n <div class=\"table-responsive mt-3\">\n <table\n class=\"table-striped table\"\n style={{\n padding: \"30px\",\n \"table-layout\": \"fixed\",\n }}\n >\n <thead>\n <tr>\n <th>Function Name</th>\n <th>Current Block Height</th>\n <th>Current Historical Block Height</th>\n <th>Status</th>\n </tr>\n </thead>\n <tbody>\n {state.state.map((x) => (\n <tr>\n <TableElement>{x.function_name}</TableElement>\n <TableElement>{x.current_block_height}</TableElement>\n <TableElement>\n {x.current_historical_block_height}\n </TableElement>\n <TableElement>{x.status}</TableElement>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ) : (\n <Subheading> No data to show... </Subheading>\n )}\n <SmallTitle> Indexer Logs</SmallTitle>\n {state.logs.length > 0 ? (\n <div>\n <div class=\"table-responsive mt-3\">\n <table\n class=\"table-striped table\"\n style={{\n padding: \"30px\",\n \"table-layout\": \"fixed\",\n }}\n >\n <thead>\n <tr>\n <th style={{ width: \"20%\" }}>Block Height</th>\n <th style={{ width: \"20%\" }}>Timestamp</th>\n <th style={{ width: \"80%\" }}>Message</th>\n </tr>\n </thead>\n <tbody>\n {state.logs.map((x) => (\n <tr>\n <TableElement>{x.block_height}</TableElement>\n <TableElement>{x.timestamp}</TableElement>\n <TableElement>{x.message}</TableElement>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <Widget\n src=\"roshaan.near/widget/Paginate-fork\"\n props={{\n siblingCount: 1,\n totalCount: state.logsCount,\n pageSize: LIMIT,\n onPageChange: onLogsPageChange,\n currentPage: state.logsPage,\n }}\n />\n </div>\n ) : (\n <Subheading> No data to show... </Subheading>\n )}\n </CardBody>\n <CardFooter></CardFooter>\n </Card>\n </>\n);\n", "metadata": { "description": "Helper widget for QueryApi.Dashboard to display Indexer Status", "image": {}, "name": "Indexer Status", "tags": { "data-platform": "", "indexers": "" } } } } } } }

Transaction Execution Plan

Convert Transaction To Receipt
Gas Burned:
367 Ggas
Tokens Burned:
0.00004 
Receipt:
Predecessor ID:
Receiver ID:
Gas Burned:
18 Tgas
Tokens Burned:
0.0019 
Called method: 'set' in contract: social.near
Arguments:
{ "data": { "dev-queryapi.dataplatform.near": { "widget": { "QueryApi.Editor": { "": "const path = props.path || \"query-api-editor\";\nconst tab = props.tab || \"\";\nconst activeView = props.activeView || \"editor\";\nlet accountId = props.accountId || context.accountId;\nlet externalAppUrl = `https://queryapi-frontend-vcqilefdcq-ew.a.run.app/${path}?accountId=${accountId}`;\n\nif (props.indexerName) {\n externalAppUrl += `&indexerName=${props.indexerName}`;\n}\nconst initialViewHeight = 1000;\n\nconst initialPayload = {\n height: Near.block(\"optimistic\").header.height,\n selectedTab: tab,\n activeView,\n currentUserAccountId: context.accountId,\n};\n\nconst registerFunctionHandler = (request, response) => {\n const gas = 200000000000000;\n const { indexerName, code, schema, startBlock, contractFilter, forkedFrom } =\n request.payload;\n\n const jsonFilter = `{\"indexer_rule_kind\":\"Action\",\"matching_rule\":{\"rule\":\"ACTION_ANY\",\"affected_account_id\":\"${contractFilter || \"social.near\"}\",\"status\":\"SUCCESS\"}}`\n\n Near.call(\n `dev-queryapi.dataplatform.near`,\n \"register\",\n {\n function_name: indexerName,\n code,\n schema,\n start_block: startBlock,\n rule: {\n kind: \"ACTION_ANY\",\n affected_account_id: contractFilter,\n status: \"SUCCESS\"\n },\n ...(forkedFrom && { forked_from: forkedFrom }),\n },\n gas\n );\n};\n\nlet deleteIndexer = (request) => {\n const { indexerName } = request.payload;\n const gas = 200000000000000;\n Near.call(\n `dev-queryapi.dataplatform.near`,\n \"remove_indexer_function\",\n {\n function_name: indexerName,\n },\n gas\n );\n};\n\n/**\n * Request Handlers here\n */\nconst requestHandler = (request, response) => {\n switch (request.type) {\n case \"register-function\":\n registerFunctionHandler(request, response);\n break;\n case \"delete-indexer\":\n deleteIndexer(request, response);\n break;\n case \"default\":\n console.log(\"default case\");\n }\n};\n\n// NearSocialBridgeCore widget is the core that makes all the \"magic\" happens\nreturn (\n <Widget\n src={\"wendersonpires.near/widget/NearSocialBridgeCore\"}\n props={{\n externalAppUrl,\n path,\n initialViewHeight,\n initialPayload,\n requestHandler,\n }}\n />\n);\n", "metadata": { "description": "Helper widget for QueryApi.Dashboard. Loads QueryAPI's React App which allows you to edit indexers inside the browser", "image": {}, "name": "Editor", "tags": { "indexers": "", "data-platform": "", "react": "" } } }, "QueryApi.Dashboard": { "": "const accountId = context.accountId;\nconst [selected_accountId, selected_indexerName] = props.selectedIndexerPath\n ? props.selectedIndexerPath.split(\"/\")\n : [undefined, undefined];\n\nconst activeTab = props.view == \"create-new-indexer\" ? \"create-new-indexer\" : props.selectedIndexerPath ? \"indexer\" : \"explore\"\nconst activeIndexerView = props.activeIndexerView ?? \"editor\";\nconst limit = 7;\nlet totalIndexers = 0;\n\nState.init({\n activeTab: activeTab,\n activeIndexerView: activeIndexerView,\n my_indexers: [],\n all_indexers: [],\n selected_indexer: undefined,\n selected_account: undefined,\n});\n\nconst Subheading = styled.h2`\n display: block;\n margin: 0;\n font-size: 14px;\n line-height: 20px;\n color: ${(p) => (p.bold ? \"#11181C !important\" : \"#687076 !important\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"visible\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"unset\")};\n white-space: nowrap;\n outline: none;\n`;\n\nconst Editor = styled.div`\n`;\nconst Status = styled.div`\n`;\n\nconst Wrapper = styled.div`\n margin-inline: 12px;\n margin-top: calc(var(--body-top-padding) * -1);\n`;\n\nconst NavBarLogo = styled.a`\n padding-top: 0.3125rem;\n padding-bottom: 0.3125rem;\n margin-right: .01rem;\n font-size: 1.25rem;\n text-decoration: none;\n white-space: nowrap;\n`;\nconst Main = styled.div`\n display: block;\n`;\n\nconst Section = styled.div`\n padding-top: 0px;\n border-left: none;\n border-right: none;\n display: ${(p) => (p.active ? \"block\" : \"none\")};\n margin: ${(p) => (p.negativeMargin ? \"0 -12px\" : \"0\")};\n`;\n\nconst Tabs = styled.div`\n display: none;\n height: 48px;\n background: #f8f9fa;\n border-top: 1px solid #eceef0;\n border-bottom: 1px solid #eceef0;\n margin-bottom: ${(p) => (p.noMargin ? \"0\" : p.halfMargin ? \"24px\" : \"24px\")};\n\n display: flex;\n margin-left: -12px;\n margin-right: -12px;\n\n button {\n flex: 1;\n }\n`;\nconst Content = styled.div`\n background-color: #f7f7f7;\n padding: 2em;\n border-radius: 5px;\n`;\n\nconst Title = styled.h1`\n font-size: 1.5em;\n text-align: center;\n color: palevioletred;\n`;\n\nconst TabsButton = styled.button`\n font-weight: 600;\n font-size: 14px;\n line-height: 16px;\n padding: 0 12px;\n position: relative;\n color: ${(p) => (p.selected ? \"#11181C\" : \"#687076\")};\n background: none;\n border: none;\n outline: none;\n &:hover {\n color: #11181c;\n }\n\n &::after {\n content: \"\";\n display: ${(p) => (p.selected ? \"block\" : \"none\")};\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #0091ff;\n }\n`;\nconst H2 = styled.h2`\n font-size: 19px;\n line-height: 22px;\n color: #11181c;\n margin: 0 0 8px;\n`;\nconst Card = styled.div`\n border-radius: 12px;\n background: #fff;\n border: ${(div) => (div.selected ? \"1px solid black\" : \"1px solid #eceef0\")};\n box-shadow: 0px 1px 3px rgba(16, 24, 40, 0.1),\n 0px 1px 2px rgba(16, 24, 40, 0.06);\n`;\n\nconst CardBody = styled.div`\n padding: 16px;\n display: flex;\n gap: 16px;\n align-items: center;\n\n > * {\n min-width: 0;\n }\n`;\n\nconst CardFooter = styled.div`\n display: flex;\n justify-content: space-around;\n flex-wrap: wrap;\n gap: 4px;\n padding: 16px;\n border-top: 1px solid #eceef0;\n`;\n\nconst TextLink = styled.a`\n display: block;\n margin: 0;\n font-size: 14px;\n line-height: 20px;\n color: ${(p) => (p.bold ? \"#11181C !important\" : \"#687076 !important\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"visible\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"unset\")};\n white-space: nowrap;\n outline: none;\n\n &:focus,\n &:hover {\n text-decoration: underline;\n }\n`;\n\nconst Thumbnail = styled.a`\n display: block;\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n border: 1px solid #eceef0;\n border-radius: 8px;\n overflow: hidden;\n outline: none;\n transition: border-color 200ms;\n\n &:focus,\n &:hover {\n border-color: #d0d5dd;\n }\n\n img {\n object-fit: cover;\n width: 100%;\n height: 100%;\n }\n`;\n\nconst CardWrapper = styled.div`\n margin: 0 0 16px;\n`;\n\nconst sharedButtonStyles = `\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n margin-bottom: 12px;\n height: 32px;\n border-radius: 6px;\n font-weight: 600;\n font-size: 12px;\n line-height: 15px;\n text-align: center;\n cursor: pointer;\n\n &:hover,\n &:focus {\n text-decoration: none;\n outline: none;\n }\n\n i {\n color: #7E868C;\n }\n\n .bi-16 {\n font-size: 16px;\n }\n`;\n\nconst Button = styled.button`\n ${sharedButtonStyles}\n color: ${(p) => (p.primary ? \"#fff\" : \"#11181C\")} !important;\n background: ${(p) => (p.primary ? \"#0091FF\" : \"#FBFCFD\")};\n border: ${(p) => (p.primary ? \"none\" : \"1px solid #D7DBDF\")};\n\n &:hover,\n &:focus {\n background: ${(p) => (p.primary ? \"#0484e5\" : \"#ECEDEE\")};\n }\n`;\n\nconst ButtonLink = styled.a`\n ${sharedButtonStyles}\n color: ${(p) => {\n if (p.primary) return \"#fff\";\n else if (p.danger) return \"#fff\";\n else return \"#11181C\";\n }} !important;\n background: ${(p) => {\n if (p.primary) return \"#0091FF\";\n else if (p.danger) return \"#dc3545\";\n else return \"#FBFCFD\";\n }};\n border: ${(p) => (p.primary ? \"none\" : \"1px solid #D7DBDF\")};\n\n &:hover,\n &:focus {\n background: ${(p) => {\n if (p.primary) return \"#0484e5\";\n else if (p.danger) return \"#b22b38\";\n else return \"#ECEDEE\";\n }}\n`;\n\nconst SignUpLink = styled.a`\n --blue: RGBA(13, 110, 253, 1);\n display: ${({ hidden }) => (hidden ? \"none\" : \"inline-block\")};\n font-size: 14px;\n cursor: pointer;\n color: var(--blue);\n text-decoration: none;\n margin-left: 0.1em;\n padding: 0;\n white-space: nowrap;\n\n &:hover {\n color: var(--blue);\n text-decoration: none;\n }\n\n &:visited {\n color: var(--blue);\n text-decoration: none;\n }\n`;\n// TODO fix activeTab\n// const previousSelectedTab = Storage.privateGet(\"queryapi:activeTab\");\n// if (previousSelectedTab && previousSelectedTab !== state.activeTab) {\n// State.update({\n// activeTab: previousSelectedTab,\n// });\n// }\n\nconst selectTab = (tabName) => {\n Storage.privateSet(\"queryapi:activeTab\", tabName);\n State.update({\n activeTab: tabName,\n });\n};\n\nconst selectIndexerPage = (viewName) => {\n Storage.privateSet(\"queryapi:activeIndexerTabView\", viewName);\n State.update({\n activeIndexerView: viewName,\n });\n};\nconst indexerView = (accountId, indexerName) => {\n const editUrl = `https://dev.near.org/dev-queryapi.dataplatform.near/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}`;\n const statusUrl = `https://dev.near.org/dev-queryapi.dataplatform.near/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}&view=indexer&activeIndexerView=status`;\n const playgroundLink = `https://cloud.hasura.io/public/graphiql?endpoint=https://near-queryapi.dev.api.pagoda.co/v1/graphql&header=x-hasura-role%3A${accountId.replaceAll(\n \".\",\n \"_\"\n )}`;\n\n return (\n <Card>\n <CardBody>\n <Thumbnail>\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n image: metadata.image,\n fallbackUrl:\n \"https://upload.wikimedia.org/wikipedia/commons/8/86/Database-icon.svg\",\n alt: \"Near QueryApi indexer\",\n }}\n />\n </Thumbnail>\n\n <div>\n <TextLink as=\"a\" bold ellipsis>\n {indexerName}\n </TextLink>\n <TextLink as=\"a\" ellipsis>\n @{accountId}\n </TextLink>\n </div>\n </CardBody>\n\n <CardFooter className=\"flex justify-center items-center\">\n <ButtonLink onClick={() => selectIndexerPage(\"status\")}>\n View Status\n </ButtonLink>\n <ButtonLink primary onClick={() => selectIndexerPage(\"editor\")}>\n {accountId === context.accountId ? \"Edit Indexer\" : \"View Indexer\"}\n </ButtonLink>\n <ButtonLink href={playgroundLink} target=\"_blank\">\n View In Playground\n </ButtonLink>\n </CardFooter>\n </Card>\n );\n};\n\nreturn (\n <Wrapper negativeMargin={state.activeTab === \"explore\"}>\n <Tabs>\n <TabsButton\n type=\"button\"\n onClick={() => selectTab(\"explore\")}\n selected={state.activeTab === \"explore\"}\n >\n Explore Indexers\n </TabsButton>\n {state.activeTab == \"create-new-indexer\" && (\n <TabsButton\n type=\"button\"\n onClick={() => selectTab(\"create-new-indexer\")}\n selected={state.activeTab === \"create-new-indexer\"}\n >\n Create New Indexer\n </TabsButton>\n )}\n\n {props.selectedIndexerPath && (\n <>\n <TabsButton\n type=\"button\"\n onClick={() => selectTab(\"indexer\")}\n selected={state.activeTab === \"indexer\"}\n >\n Indexer ({props.selectedIndexerPath})\n </TabsButton>\n </>\n )}\n </Tabs>\n <Main>\n <Section active={state.activeTab === \"explore\"}>\n <NavBarLogo\n href={`https://dev.near.org/dev-queryapi.dataplatform.near/widget/QueryApi.App`}\n title=\"QueryApi\"\n onClick={() => selectTab(\"explore\")}\n >\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n className: \"d-inline-block align-text-top me-2\",\n image: metadata.image,\n style: { height: \"24px\" },\n fallbackUrl:\n \"https://upload.wikimedia.org/wikipedia/commons/8/86/Database-icon.svg\",\n alt: \"the queryapi logo\",\n }}\n />\n QueryApi\n </NavBarLogo>\n\n <SignUpLink target=\"_blank\" href={`https://docs.near.org/build/data-infrastructure/query-api/intro`}>\n (Documentation)\n </SignUpLink>\n <div>\n <ButtonLink\n href={`/dev-queryapi.dataplatform.near/widget/QueryApi.App/?view=create-new-indexer`}\n style={{ \"margin-top\": \"10px\" }}\n onClick={() => {\n State.update({\n activeTab: \"create-new-indexer\",\n selected_indexer: \"\",\n });\n selectTab(\"create-new-indexer\");\n }}\n >\n Create New Indexer\n </ButtonLink>\n {state.my_indexers.length > 0 && (\n <H2>\n {accountId}'s Indexers\n <span>({state.my_indexers.length})</span>\n </H2>\n )}\n <Widget\n src={`dev-queryapi.dataplatform.near/widget/QueryApi.IndexerExplorer`}\n />\n </div>\n </Section>\n <Section\n negativeMargin\n primary\n active={state.activeTab === \"create-new-indexer\"}\n >\n {state.activeTab === \"create-new-indexer\" && (\n <div>\n <Widget\n src={`dev-queryapi.dataplatform.near/widget/QueryApi.Editor`}\n props={{\n indexerName:\n selected_indexerName ?? state.indexers[0].indexerName,\n accountId: selected_accountId ?? state.indexers[0].accountId,\n path: \"create-new-indexer\",\n }}\n />\n </div>\n )}\n </Section>\n <Section negativeMargin primary active={state.activeTab === \"indexer\"}>\n <Editor>\n {state.indexers.length > 0 &&\n (state.selected_indexer != undefined ? (\n <H2>{state.selected_indexer}</H2>\n ) : (\n <H2>{`${state.indexers[0].accountId}/${state.indexers[0].indexerName}`}</H2>\n ))}\n <Widget\n src={`dev-queryapi.dataplatform.near/widget/QueryApi.Editor`}\n props={{\n indexerName:\n selected_indexerName ?? state.indexers[0].indexerName,\n accountId: selected_accountId ?? state.indexers[0].accountId,\n path: \"query-api-editor\",\n tab: props.tab,\n activeView: state.activeIndexerView\n }}\n />\n </Editor>\n {state.activeTab === \"create-new-indexer\" && (\n <div>\n {state.indexers.length > 0 &&\n (state.selected_indexer != undefined ? (\n <H2>{state.selected_indexer}</H2>\n ) : (\n <H2>{`${state.indexers[0].accountId}/${state.indexers[0].indexerName}`}</H2>\n ))}\n <Widget\n src={`dev-queryapi.dataplatform.near/widget/QueryApi.Editor`}\n props={{\n indexerName:\n selected_indexerName ?? state.indexers[0].indexerName,\n accountId: selected_accountId ?? state.indexers[0].accountId,\n path: \"create-new-indexer\",\n }}\n />\n </div>\n )}\n </Section>\n </Main>\n </Wrapper>\n);\n", "metadata": { "description": "Main dashboard for Near QueryAPI which allows you to seamlessly create, manage, and discover indexers", "image": {}, "name": "Near QueryAPI Dashboard", "tags": {} } }, "QueryApi.IndexerStatus": { "": "//props indexer_name\nconst indexer_name = props.indexer_name;\n\nconst LIMIT = 20;\nconst accountId = props.accountId || context.accountId;\n\nconst H2 = styled.h2`\n font-size: 19px;\n line-height: 22px;\n color: #11181c;\n margin: 0 0 24px;\n`;\nconst Title = styled.h1`\n font-size: 1.5em;\n text-align: center;\n color: black;\n`;\nconst SmallTitle = styled.h3`\n color: black;\n font-weight: 600;\n font-size: 18px;\n line-height: 15px;\n text-transform: uppercase;\n\n @media (max-width: 770px) {\n margin-bottom: 16px;\n }\n`;\nconst TableElement = styled.td`\n word-wrap: break-word;\n font-family: \"Roboto Mono\", monospace;\n font-size: 11px;\n background-color: rgb(255, 255, 255);\n color: rgb(32, 33, 36);\n`;\nconst Subheading = styled.h2`\n display: block;\n margin: 0;\n font-size: 14px;\n line-height: 10px;\n color: ${(p) => (p.bold ? \"#11181C !important\" : \"#687076 !important\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"visible\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"unset\")};\n white-space: nowrap;\n outline: none;\n`;\nconst Card = styled.div`\n border-radius: 12px;\n background: #fff;\n border: ${(div) => (div.selected ? \"1px solid black\" : \"1px solid #eceef0\")};\n box-shadow: 0px 1px 3px rgba(16, 24, 40, 0.1),\n 0px 1px 2px rgba(16, 24, 40, 0.06);\n`;\n\nconst CardBody = styled.div`\n padding: 16px;\n display: flex;\n gap: 16px;\n align-items: center;\n flex-direction: column;\n > * {\n min-width: 0;\n }\n`;\n\nconst CardFooter = styled.div`\n display: flex;\n justify-content: space-around;\n flex-wrap: wrap;\n gap: 16px;\n padding: 16px;\n border-top: 1px solid #eceef0;\n`;\n\nconst TextLink = styled.a`\n display: block;\n margin: 0;\n font-size: 14px;\n line-height: 20px;\n color: ${(p) => (p.bold ? \"#11181C !important\" : \"#687076 !important\")};\n font-weight: ${(p) => (p.bold ? \"600\" : \"400\")};\n font-size: ${(p) => (p.small ? \"12px\" : \"14px\")};\n overflow: ${(p) => (p.ellipsis ? \"hidden\" : \"visible\")};\n text-overflow: ${(p) => (p.ellipsis ? \"ellipsis\" : \"unset\")};\n white-space: nowrap;\n outline: none;\n\n &:focus,\n &:hover {\n text-decoration: underline;\n }\n`;\n\nif (!indexer_name) return \"missing indexer_name\";\n\nState.init({\n logs: [],\n state: [],\n indexer_res: [],\n indexer_resCount: 0,\n logsCount: 0,\n stateCount: 0,\n indexer_resPage: 0,\n logsPage: 0,\n statePage: 0,\n});\n\nlet graphQLEndpoint = `https://near-queryapi.dev.api.pagoda.co`;\n\nfunction fetchGraphQL(operationsDoc, operationName, variables) {\n return asyncFetch(`${graphQLEndpoint}/v1/graphql`, {\n method: \"POST\",\n headers: {\n \"x-hasura-role\": \"append\"\n },\n body: JSON.stringify({\n query: operationsDoc,\n variables: variables,\n operationName: operationName,\n }),\n });\n}\n\nconst createGraphQLLink = () => {\n const queryLink = `https://cloud.hasura.io/public/graphiql?endpoint=${graphQLEndpoint}/v1/graphql&query=query+IndexerQuery+%7B%0A++indexer_state%28where%3A+%7Bfunction_name%3A+%7B_eq%3A+%22function_placeholder%22%7D%7D%29+%7B%0A++++function_name%0A++++current_block_height%0A++%7D%0A++indexer_log_entries%28%0A++++where%3A+%7Bfunction_name%3A+%7B_eq%3A+%22function_placeholder%22%7D%7D%0A++++order_by%3A+%7B+timestamp%3A+desc%7D%0A++%29+%7B%0A++++function_name%0A++++id%0A++++message%0A++++timestamp%0A++%7D%0A%7D%0A`;\n return queryLink.replaceAll(\n \"function_placeholder\",\n `${accountId}/${indexer_name}`\n );\n};\n\nconst accountName = accountId.replaceAll(\".\", \"_\");\nconst sanitizedFunctionName = indexer_name;\nconst fullFunctionName = accountName + \"_\" + sanitizedFunctionName;\nconst logsDoc = `\n query QueryLogs($offset: Int) {\n indexer_log_entries(order_by: {timestamp: desc}, limit: ${LIMIT}, offset: $offset, where: {function_name: {_eq: \"${accountId}/${indexer_name}\"}}) {\n block_height\n message\n timestamp\n }\n indexer_log_entries_aggregate(where: {function_name: {_eq: \"${accountId}/${indexer_name}\"}}) {\n aggregate {\n count\n }\n }\n }\n`;\n\nconst indexerStateDoc = `\n query IndexerState($offset: Int) {\n indexer_state(limit: ${LIMIT}, offset: $offset, where: {function_name: {_eq: \"${accountId}/${indexer_name}\"}}) {\n status\n function_name\n current_block_height\n current_historical_block_height\n }\n }\n`;\n\nif (!state.initialFetch) {\n State.update({\n logs: [],\n state: [],\n indexer_res: [],\n indexer_resCount: 0,\n logsCount: 0,\n stateCount: 0,\n indexer_resPage: 0,\n logsPage: 0,\n statePage: 0,\n })\n fetchGraphQL(logsDoc, \"QueryLogs\", {\n offset: state.logsPage * LIMIT,\n }).then((result) => {\n if (result.status === 200) {\n State.update({\n logs: result.body.data[`indexer_log_entries`],\n logsCount:\n result.body.data[`indexer_log_entries_aggregate`].aggregate.count,\n });\n }\n });\n\n fetchGraphQL(indexerStateDoc, \"IndexerState\", {\n offset: 0,\n }).then((result) => {\n if (result.status === 200) {\n if (result.body.data.indexer_state.length == 1) {\n State.update({\n state: result.body.data.indexer_state,\n stateCount: result.body.data.indexer_state_aggregate.aggregate.count,\n });\n }\n }\n });\n State.update({ initialFetch: true });\n}\nconst onLogsPageChange = (page) => {\n page = page - 1;\n if (page === state.logsPage) {\n console.log(`Selected the same page number as before: ${pageNumber}`);\n return;\n }\n try {\n fetchGraphQL(logsDoc, \"QueryLogs\", { offset: page * LIMIT }).then(\n (result) => {\n if (result.status === 200) {\n State.update({\n logs: result.body.data.indexer_log_entries,\n logsCount:\n result.body.data.indexer_log_entries_aggregate.aggregate.count,\n });\n }\n }\n );\n } catch (e) {\n console.log(\"error:\", e);\n }\n State.update({ logsPage: page, currentPage: page });\n};\n\nconst onIndexerResPageChange = (page) => {\n page = page - 1;\n if (page === state.indexer_resPage) {\n console.log(`Selected the same page number as before: ${pageNumber}`);\n return;\n }\n\n try {\n fetchGraphQL(IndexerStorageDoc, \"IndexerStorage\", {\n offset: page * LIMIT,\n }).then((result) => {\n if (result.status === 200) {\n State.update({\n indexer_res: result.body.data.indexer_storage,\n indexer_resCount:\n result.body.data.indexer_storage_aggregate.aggregate.count,\n });\n }\n });\n } catch (e) {\n console.log(\"error:\", e);\n }\n State.update({ indexer_resPage: page, currentPage: page });\n};\n\nreturn (\n <>\n <Card>\n <Title className=\"p-3\">\n Indexer Status\n <TextLink href={createGraphQLLink()} target=\"_blank\">\n GraphQL Playground\n <i className=\"bi bi-box-arrow-up-right\"></i>\n </TextLink>\n </Title>\n\n <CardBody>\n <SmallTitle>Indexer State </SmallTitle>\n {state.state.length > 0 ? (\n <div class=\"table-responsive mt-3\">\n <table\n class=\"table-striped table\"\n style={{\n padding: \"30px\",\n \"table-layout\": \"fixed\",\n }}\n >\n <thead>\n <tr>\n <th>Function Name</th>\n <th>Current Block Height</th>\n <th>Current Historical Block Height</th>\n <th>Status</th>\n </tr>\n </thead>\n <tbody>\n {state.state.map((x) => (\n <tr>\n <TableElement>{x.function_name}</TableElement>\n <TableElement>{x.current_block_height}</TableElement>\n <TableElement>\n {x.current_historical_block_height}\n </TableElement>\n <TableElement>{x.status}</TableElement>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ) : (\n <Subheading> No data to show... </Subheading>\n )}\n <SmallTitle> Indexer Logs</SmallTitle>\n {state.logs.length > 0 ? (\n <div>\n <div class=\"table-responsive mt-3\">\n <table\n class=\"table-striped table\"\n style={{\n padding: \"30px\",\n \"table-layout\": \"fixed\",\n }}\n >\n <thead>\n <tr>\n <th style={{ width: \"20%\" }}>Block Height</th>\n <th style={{ width: \"20%\" }}>Timestamp</th>\n <th style={{ width: \"80%\" }}>Message</th>\n </tr>\n </thead>\n <tbody>\n {state.logs.map((x) => (\n <tr>\n <TableElement>{x.block_height}</TableElement>\n <TableElement>{x.timestamp}</TableElement>\n <TableElement>{x.message}</TableElement>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <Widget\n src=\"roshaan.near/widget/Paginate-fork\"\n props={{\n siblingCount: 1,\n totalCount: state.logsCount,\n pageSize: LIMIT,\n onPageChange: onLogsPageChange,\n currentPage: state.logsPage,\n }}\n />\n </div>\n ) : (\n <Subheading> No data to show... </Subheading>\n )}\n </CardBody>\n <CardFooter></CardFooter>\n </Card>\n </>\n);\n", "metadata": { "description": "Helper widget for QueryApi.Dashboard to display Indexer Status", "image": {}, "name": "Indexer Status", "tags": { "data-platform": "", "indexers": "" } } } } } } }
Result:
{ "block_height": "123013968" }
No logs
Receipt:
Predecessor ID:
Receiver ID:
Gas Burned:
223 Ggas
Tokens Burned:
0 
Transferred 0.18621  to dev-q…tform.near
Empty result
No logs