diff --git a/frontend/package.json b/frontend/package.json
index 7ce4a1c14..5a83207d9 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -12,6 +12,7 @@
"lint": "next lint"
},
"dependencies": {
+ "@apollo/client": "^3.8.7",
"@graphiql/plugin-code-exporter": "0.3.5",
"@graphiql/plugin-explorer": "0.3.5",
"@monaco-editor/react": "^4.1.3",
@@ -25,7 +26,8 @@
"eslint": "8.34.0",
"eslint-config-next": "13.1.6",
"graphiql": "3.0.6",
- "graphql": "^16.6.0",
+ "graphql": "^16.8.1",
+ "gridjs": "6.0.6",
"near-api-js": "1.1.0",
"near-social-bridge": "^1.4.1",
"next": "13.1.6",
diff --git a/frontend/src/components/Editor/Editor.js b/frontend/src/components/Editor/Editor.js
index 0da8175c4..f8a7fc2e3 100644
--- a/frontend/src/components/Editor/Editor.js
+++ b/frontend/src/components/Editor/Editor.js
@@ -381,6 +381,12 @@ const Editor = ({
height: "85vh",
}}
>
+ {!indexerDetails.code && (
+
+ Indexer Function could not be found. Are you sure this indexer exists?
+
+ )}
+ {indexerDetails.code && <>
+ >}
);
};
diff --git a/frontend/src/components/Editor/EditorButtons.jsx b/frontend/src/components/Editor/EditorButtons.jsx
index 212390f6e..83ac5dba8 100644
--- a/frontend/src/components/Editor/EditorButtons.jsx
+++ b/frontend/src/components/Editor/EditorButtons.jsx
@@ -19,7 +19,8 @@ import {
TrashFill,
XCircle,
NodePlus,
- Code
+ Code,
+ FileText,
} from "react-bootstrap-icons";
import { BlockPicker } from "./BlockPicker";
import { IndexerDetailsContext } from '../../contexts/IndexerDetailsContext';
@@ -49,7 +50,9 @@ const EditorButtons = ({
debugMode,
isCreateNewIndexer,
indexerNameField,
- setIndexerNameField
+ setIndexerNameField,
+ setShowLogsView,
+ showLogsView,
} = useContext(IndexerDetailsContext);
const removeHeight = (index) => {
@@ -69,7 +72,6 @@ const EditorButtons = ({
>
-
{accountId}
@@ -107,7 +109,7 @@ const EditorButtons = ({
)}
)}
- Reset Changes To Code}
- >
-
-
-
- Format Code}
- >
-
-
-
- Generate Types}
- >
-
-
+
+
+ )}
{(!isUserIndexer && !isCreateNewIndexer) ? (
)}
+
+
+ Reset Changes To Code}
+ >
+
+
+ Format Code}
+ >
+
+
+ Generate Types}
+ >
+
+
+
+
{debugMode && heights.length > 0 && (
diff --git a/frontend/src/components/Logs/IndexerLogs.jsx b/frontend/src/components/Logs/IndexerLogs.jsx
new file mode 100644
index 000000000..6b13b9ad8
--- /dev/null
+++ b/frontend/src/components/Logs/IndexerLogs.jsx
@@ -0,0 +1,236 @@
+import React, { useContext, useRef, useEffect, useState } from "react";
+import { Grid, html } from "gridjs";
+import "gridjs/dist/theme/mermaid.css";
+import { IndexerDetailsContext } from "../../contexts/IndexerDetailsContext";
+import LogButtons from "./LogButtons";
+import { useInitialPayload } from "near-social-bridge";
+import Status from "./Status";
+
+const LIMIT = 100;
+
+const IndexerLogsComponent = () => {
+ const { indexerDetails, debugMode, setLogsView, latestHeight } = useContext(
+ IndexerDetailsContext
+ );
+ const functionName = `${indexerDetails.accountId}/${indexerDetails.indexerName}`;
+
+ const DEBUG_LIST_STORAGE_KEY = `QueryAPI:debugList:${indexerDetails.accountId}#${indexerDetails.indexerName} `;
+
+ const { height, selectedTab, currentUserAccountId } = useInitialPayload();
+ const [heights, setHeights] = useState(
+ localStorage.getItem(DEBUG_LIST_STORAGE_KEY) || []
+ );
+ useEffect(() => {
+ localStorage.setItem(DEBUG_LIST_STORAGE_KEY, heights);
+ }, [heights]);
+
+ const indexerLogsRef = useRef(null);
+ const indexerStateRef = useRef(null);
+
+ function formatTimestamp(timestamp) {
+ const date = new Date(timestamp);
+
+ const options = {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ hour: "numeric",
+ minute: "2-digit",
+ hour12: true,
+ };
+ const formattedDate = date.toLocaleDateString(undefined, options);
+
+ const now = new Date();
+ const diffInSeconds = Math.round((now - date) / 1000);
+ let relativeTime = undefined;
+ if (diffInSeconds < 60) {
+ relativeTime = "(just now)";
+ } else if (diffInSeconds < 3600) {
+ relativeTime = `(${Math.floor(diffInSeconds / 60)} minutes ago)`;
+ } else if (diffInSeconds < 86400) {
+ relativeTime = `(${Math.floor(diffInSeconds / 3600)} hours ago)`;
+ }
+
+ return `${formattedDate} ${relativeTime ?? ""}`;
+ }
+
+ function formatTimestampToReadableLocal(timestamp) {
+ const date = new Date(timestamp);
+
+ const options = {
+ month: "short",
+ day: "numeric",
+ hour: "numeric",
+ minute: "2-digit",
+ hour12: true,
+ };
+ const formattedDate = date.toLocaleString(undefined, options);
+
+ return formattedDate;
+ }
+
+ const processLogs = (data) => {
+ const logEntries = data.indexer_log_entries.map((row) => ({
+ block_height: row.block_height,
+ timestamp: row.timestamp,
+ message: row.message,
+ }));
+
+ const groupedEntries = new Map();
+
+ logEntries.forEach(({ block_height, timestamp, message }) => {
+ if (!groupedEntries.has(block_height)) {
+ groupedEntries.set(block_height, []);
+ }
+ groupedEntries.get(block_height).push({ timestamp, message });
+ });
+
+ const mergedEntries = Array.from(groupedEntries).map(
+ ([block_height, entries]) => {
+ const messages = entries
+ .map(
+ (e) =>
+ `Timestamp: ${e.timestamp
+ }(${formatTimestampToReadableLocal(
+ e.timestamp
+ )}): \n
${e.message}
`
+ )
+ .join("
");
+
+ const minTimestamp = entries.reduce(
+ (min, e) => (e.timestamp < min ? e.timestamp : min),
+ entries[0].timestamp
+ );
+
+ const formattedMinTimstamp = formatTimestamp(minTimestamp);
+ const humanReadableStamp = formatTimestampToReadableLocal(minTimestamp);
+
+ return {
+ block_height,
+ timestamp: { humanReadableStamp, formattedMinTimstamp },
+ messages,
+ };
+ }
+ );
+
+ return mergedEntries;
+ };
+
+ useEffect(() => {
+ const grid = new Grid({
+ columns: [
+ {
+ name: "Block Height",
+ formatter: (cell) =>
+ html(
+ ``
+ ),
+ },
+ "Timestamp",
+ {
+ name: "Message",
+ formatter: (cell) => html(`${cell}
`),
+ sort: false,
+ },
+ ],
+ search: {
+ server: {
+ url: (prev, keyword) =>
+ `${process.env.NEXT_PUBLIC_HASURA_ENDPOINT}/api/rest/queryapi/logsByBlock/?_functionName=${functionName}&_blockHeight=${keyword}`,
+ then: (data) => {
+ const logs = processLogs(data).map((log) => [
+ log.block_height,
+ log.timestamp.formattedMinTimstamp,
+ log.messages,
+ ]);
+ return logs;
+ },
+ debounceTimeout: 2000,
+ },
+ },
+ sort: true,
+ resizable: true,
+ fixedHeader: true,
+ pagination: {
+ limit: 30,
+ server: {
+ url: (prev, page, limit) => {
+ return prev + "&limit=" + limit + "&offset=" + page * limit;
+ },
+ },
+ },
+ server: {
+ url: `${process.env.NEXT_PUBLIC_HASURA_ENDPOINT}/api/rest/queryapi/logs/?_functionName=${functionName}`,
+ headers: {
+ "x-hasura-role": "append",
+ },
+ then: (data) => {
+ const logs = processLogs(data).map((log) => [
+ log.block_height,
+ log.timestamp.formattedMinTimstamp,
+ log.messages,
+ ]);
+ return logs;
+ },
+ total: (data) => data.indexer_log_entries_aggregate.aggregate.count,
+ },
+ style: {
+ container: {
+ "font-family": '"Roboto Mono", monospace',
+ },
+ table: {},
+ th: {
+ "text-align": "center",
+ "max-width": "950px",
+ width: "800px",
+ },
+ td: {
+ "text-align": "left",
+ "font-size": "11px",
+ "vertical-align": "text-top",
+ "background-color": "rgb(255, 255, 255)",
+ "max-height": "400px",
+ padding: "5px",
+ },
+ },
+ language: {
+ search: {
+ placeholder: "🔍 Search by Block Height...",
+ },
+ pagination: {
+ results: () => "Indexer Logs",
+ },
+ },
+ });
+
+ grid.render(indexerLogsRef.current);
+ }, []);
+
+ return (
+ <>
+
+ >
+ );
+};
+
+export default IndexerLogsComponent;
diff --git a/frontend/src/components/Logs/LogButtons.jsx b/frontend/src/components/Logs/LogButtons.jsx
new file mode 100644
index 000000000..c831e118e
--- /dev/null
+++ b/frontend/src/components/Logs/LogButtons.jsx
@@ -0,0 +1,136 @@
+import React, { useContext } from "react";
+import {
+ Breadcrumb,
+ Button,
+ Form,
+ InputGroup,
+ Navbar,
+ Container,
+ Col,
+ Row,
+ ButtonGroup,
+ OverlayTrigger,
+ Tooltip,
+ Badge,
+} from "react-bootstrap";
+import {
+ ArrowCounterclockwise,
+ Justify,
+ TrashFill,
+ XCircle,
+ NodePlus,
+ Code,
+} from "react-bootstrap-icons";
+import { IndexerDetailsContext } from "../../contexts/IndexerDetailsContext";
+
+const LogButtons = ({
+ currentUserAccountId,
+ heights,
+ setHeights,
+ latestHeight,
+ isUserIndexer,
+}) => {
+ const {
+ indexerName,
+ accountId,
+ indexerDetails,
+ debugMode,
+ setShowLogsView,
+ showLogsView,
+ } = useContext(IndexerDetailsContext);
+
+ const removeHeight = (index) => {
+ setHeights(heights.filter((_, i) => i !== index));
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+ {accountId}
+
+ {indexerName && (
+
+ {indexerName}
+
+ )}
+
+ {
+
+ Contract Filter
+
+
+ }
+
+
+
+ <>
+ Open Editor}
+ >
+
+
+ >
+
+
+
+ {debugMode && heights.length > 0 && (
+
+
+ {heights.map((height, index) => (
+
+ {height}
+ removeHeight(index)}
+ />
+
+ ))}
+
+
+ )}
+
+
+ >
+ );
+};
+
+export default LogButtons;
diff --git a/frontend/src/components/Logs/Status.jsx b/frontend/src/components/Logs/Status.jsx
new file mode 100644
index 000000000..6f32f1b78
--- /dev/null
+++ b/frontend/src/components/Logs/Status.jsx
@@ -0,0 +1,88 @@
+import React from "react";
+import {
+ Card,
+ Badge,
+ ListGroup,
+ OverlayTrigger,
+ Tooltip,
+} from "react-bootstrap";
+import { useQuery, gql } from "@apollo/client";
+
+const Status = ({ functionName, latestHeight }) => {
+ const GET_STATUS = gql`
+ query GetState($_functionName: String!) {
+ indexer_state(where: { function_name: { _eq: $_functionName } }) {
+ status
+ function_name
+ current_block_height
+ current_historical_block_height
+ }
+ }
+ `;
+ const { loading, error, data } = useQuery(GET_STATUS, {
+ variables: {
+ _functionName: functionName,
+ },
+ });
+
+ if (loading) return Loading...
;
+ if (error) return Error : {error.message}
;
+ return (
+
+ {data &&
+ data.indexer_state.map((item, index) => (
+
+
+ Indexer Status: {item.function_name}
+
+
+ Near's Current Block Height is {latestHeight}. Your indexer has a gap of {latestHeight - item.current_block_height} Blocks}
+ >
+
+ Current Block Height:{" "}
+ {item.current_block_height}
+
+
+
+ Historical Block Height:{" "}
+ {item.current_historical_block_height}
+
+
+ {item.status === "RUNNING" ? "Indexer is operating normally" : "Indexer stopped due to errors. Check Logs for more details."}}
+ >
+ <>
+ Status:{" "}
+
+ {item.status}
+
+ >
+
+
+
+
+ ))}
+
+ );
+};
+
+export default Status;
diff --git a/frontend/src/components/Playground/graphiql.jsx b/frontend/src/components/Playground/graphiql.jsx
index c8955f6f3..bf22f29cc 100644
--- a/frontend/src/components/Playground/graphiql.jsx
+++ b/frontend/src/components/Playground/graphiql.jsx
@@ -9,7 +9,7 @@ import '@graphiql/plugin-code-exporter/dist/style.css';
import '@graphiql/plugin-explorer/dist/style.css';
const HASURA_ENDPOINT =
- process.env.NEXT_PUBLIC_HASURA_ENDPOINT ||
+ `${process.env.NEXT_PUBLIC_HASURA_ENDPOINT}/v1/graphql` ||
"https://near-queryapi.dev.api.pagoda.co/v1/graphql";
const graphQLFetcher = async (graphQLParams, accountId) => {
diff --git a/frontend/src/contexts/IndexerDetailsContext.js b/frontend/src/contexts/IndexerDetailsContext.js
index 10358857b..29ab66ecc 100644
--- a/frontend/src/contexts/IndexerDetailsContext.js
+++ b/frontend/src/contexts/IndexerDetailsContext.js
@@ -6,6 +6,7 @@ import {
wrapCode,
} from "../utils/formatters";
+import { useInitialPayload } from "near-social-bridge";
import { getLatestBlockHeight } from "../utils/getLatestBlockHeight";
// interface IndexerDetails {
// accountId: String,
@@ -39,6 +40,8 @@ export const IndexerDetailsContext = React.createContext({
indexerName: undefined,
setIndexerName: () => { },
setIndexerDetails: () => { },
+ showLogsView: false,
+ setShowLogsView: () => { },
});
export const IndexerDetailsProvider = ({ children }) => {
@@ -49,9 +52,16 @@ export const IndexerDetailsProvider = ({ children }) => {
const [showPublishModal, setShowPublishModal] = useState(false);
const [showForkIndexerModal, setShowForkIndexerModal] = useState(false);
const [debugMode, setDebugMode] = useState(false);
+ const [showLogsView, setShowLogsView] = useState(false);
const [latestHeight, setLatestHeight] = useState(0);
const [isCreateNewIndexer, setIsCreateNewIndexer] = useState(false);
+ const { activeView } = useInitialPayload();
+
+ useEffect(() => {
+ if (activeView == 'status') setShowLogsView(true)
+ }, [])
+
const requestIndexerDetails = async () => {
const data = await queryIndexerFunctionDetails(accountId, indexerName);
if (data) {
@@ -117,7 +127,9 @@ export const IndexerDetailsProvider = ({ children }) => {
setDebugMode,
latestHeight,
isCreateNewIndexer,
- setIsCreateNewIndexer
+ setIsCreateNewIndexer,
+ showLogsView,
+ setShowLogsView,
}}
>
{children}
diff --git a/frontend/src/pages/_app.tsx b/frontend/src/pages/_app.tsx
index eecf66fe2..4033f8daa 100644
--- a/frontend/src/pages/_app.tsx
+++ b/frontend/src/pages/_app.tsx
@@ -8,15 +8,26 @@ import {
} from "near-social-bridge";
import { IndexerDetailsProvider } from '../contexts/IndexerDetailsContext';
import 'regenerator-runtime/runtime';
+import { ApolloClient, InMemoryCache, ApolloProvider, gql } from '@apollo/client';
overrideLocalStorage();
export default function App({ Component, pageProps }: AppProps) {
+ const client = new ApolloClient({
+ uri: `${process.env.NEXT_PUBLIC_HASURA_ENDPOINT}/v1/graphql`,
+ cache: new InMemoryCache(),
+ options: {
+ headers: {
+ "x-hasura-role": "append"
+ }
+ }
+ });
return (
}>
+
+
);
}
-
diff --git a/frontend/src/pages/indexer-logs/index.js b/frontend/src/pages/indexer-logs/index.js
new file mode 100644
index 000000000..fd3cbe107
--- /dev/null
+++ b/frontend/src/pages/indexer-logs/index.js
@@ -0,0 +1,35 @@
+import React, { useEffect, useContext } from "react";
+
+import IndexerLogs from "../../components/Logs/IndexerLogs";
+import { withRouter } from 'next/router'
+import { Alert } from 'react-bootstrap';
+// import { EditorContext } from '../../contexts/EditorContext';
+import { IndexerDetailsContext } from '../../contexts/IndexerDetailsContext';
+
+const IndexerLogsPage = ({ router }) => {
+ const { accountId, indexerName } = router.query
+ // const { setAccountId, setIndexerName } = useContext(EditorContext);
+ const { setAccountId, setIndexerName } = useContext(IndexerDetailsContext);
+ useEffect(() => {
+ if (accountId == undefined || indexerName == undefined) {
+ return;
+ }
+ setAccountId(accountId);
+ setIndexerName(indexerName);
+ }, [accountId, indexerName, setAccountId, setIndexerName]);
+
+ if (accountId == undefined || indexerName == undefined) {
+ return (
+ <>
+
+ Both accountId and IndexerName need to be specified in the URL.
+
+ >
+ )
+ }
+ return (
+
+ );
+};
+
+export default withRouter(QueryApiEditorPage);
diff --git a/frontend/src/pages/query-api-editor/index.js b/frontend/src/pages/query-api-editor/index.js
index d9d844719..36356f337 100644
--- a/frontend/src/pages/query-api-editor/index.js
+++ b/frontend/src/pages/query-api-editor/index.js
@@ -3,13 +3,13 @@ import React, { useEffect, useContext } from "react";
import Editor from "../../components/Editor";
import { withRouter } from 'next/router'
import { Alert } from 'react-bootstrap';
-// import { EditorContext } from '../../contexts/EditorContext';
import { IndexerDetailsContext } from '../../contexts/IndexerDetailsContext';
+import IndexerLogs from "../../components/Logs/IndexerLogs";
const QueryApiEditorPage = ({ router }) => {
const { accountId, indexerName } = router.query
- // const { setAccountId, setIndexerName } = useContext(EditorContext);
- const { setAccountId, setIndexerName } = useContext(IndexerDetailsContext);
+ const { setAccountId, setIndexerName, showLogsView } = useContext(IndexerDetailsContext);
+
useEffect(() => {
if (accountId == undefined || indexerName == undefined) {
return;
@@ -28,7 +28,13 @@ const QueryApiEditorPage = ({ router }) => {
)
}
return (
-
+ <>
+ {showLogsView ? (
+
+ ) : (
+
+ )}
+ >
);
};
diff --git a/frontend/widgets/src/QueryApi.App.jsx b/frontend/widgets/src/QueryApi.App.jsx
index 033ce17bf..63313b733 100644
--- a/frontend/widgets/src/QueryApi.App.jsx
+++ b/frontend/widgets/src/QueryApi.App.jsx
@@ -1,6 +1,7 @@
const view = props.view;
const path = props.path;
const tab = props.tab;
+const activeIndexerView = props.activeIndexerView;
const selectedIndexerPath = props.selectedIndexerPath;
return (
@@ -11,6 +12,7 @@ return (
path,
tab,
selectedIndexerPath,
+ activeIndexerView
}}
/>
);
diff --git a/frontend/widgets/src/QueryApi.Dashboard.jsx b/frontend/widgets/src/QueryApi.Dashboard.jsx
index 23a937c91..2771a3f62 100644
--- a/frontend/widgets/src/QueryApi.Dashboard.jsx
+++ b/frontend/widgets/src/QueryApi.Dashboard.jsx
@@ -3,12 +3,14 @@ const [selected_accountId, selected_indexerName] = props.selectedIndexerPath
? props.selectedIndexerPath.split("/")
: [undefined, undefined];
-const activeTab = props.view ?? "indexers";
+const activeTab = props.view == "create-new-indexer" ? "create-new-indexer" : props.selectedIndexerPath ? "indexer" : "explore"
+const activeIndexerView = props.activeIndexerView ?? "editor";
const limit = 7;
let totalIndexers = 0;
State.init({
activeTab: activeTab,
+ activeIndexerView: activeIndexerView,
my_indexers: [],
all_indexers: [],
selected_indexer: undefined,
@@ -53,6 +55,11 @@ const Subheading = styled.h2`
outline: none;
`;
+const Editor = styled.div`
+`;
+const Status = styled.div`
+`;
+
const Wrapper = styled.div`
margin-top: calc(var(--body-top-padding) * -1);
`;
@@ -107,7 +114,7 @@ const Title = styled.h1`
const TabsButton = styled.button`
font-weight: 600;
- font-size: 12px;
+ font-size: 14px;
line-height: 16px;
padding: 0 12px;
position: relative;
@@ -310,9 +317,15 @@ const selectTab = (tabName) => {
});
};
+const selectIndexerPage = (viewName) => {
+ Storage.privateSet("queryapi:activeIndexerTabView", viewName);
+ State.update({
+ activeIndexerView: viewName,
+ });
+};
const indexerView = (accountId, indexerName) => {
- const editUrl = `https://near.org/#/${REPL_ACCOUNT_ID}/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}&view=editor-window`;
- const statusUrl = `https://near.org/#/${REPL_ACCOUNT_ID}/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}&view=indexer-status`;
+ const editUrl = `https://near.org/#/${REPL_ACCOUNT_ID}/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}`;
+ const statusUrl = `https://near.org/#/${REPL_ACCOUNT_ID}/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}&view=indexer&activeIndexerView=status`;
const playgroundLink = `https://cloud.hasura.io/public/graphiql?endpoint=${REPL_GRAPHQL_ENDPOINT}/v1/graphql&header=x-hasura-role%3A${accountId.replaceAll(
".",
"_"
@@ -344,10 +357,10 @@ const indexerView = (accountId, indexerName) => {
- selectTab("indexer-status")}>
+ selectIndexerPage("status")}>
View Status
- selectTab("editor-window")}>
+ selectIndexerPage("editor")}>
{accountId === context.accountId ? "Edit Indexer" : "View Indexer"}
@@ -359,14 +372,14 @@ const indexerView = (accountId, indexerName) => {
};
return (
-
+
selectTab("indexers")}
- selected={state.activeTab === "indexers"}
+ onClick={() => selectTab("explore")}
+ selected={state.activeTab === "explore"}
>
- Indexers
+ Explore Indexers
{state.activeTab == "create-new-indexer" && (
selectTab("editor-window")}
- selected={state.activeTab === "editor-window"}
+ onClick={() => selectTab("indexer")}
+ selected={state.activeTab === "indexer"}
>
- Indexer Editor
-
-
- selectTab("indexer-status")}
- selected={state.activeTab === "indexer-status"}
- >
- Indexer Status
+ Indexer ({props.selectedIndexerPath})
>
)}
-
+
selectTab("indexers")}
+ onClick={() => selectTab("explore")}
>
)}
-
- {state.activeTab === "indexer-status" && (
-
- {state.indexers.length > 0 &&
- (state.selected_indexer != "" ? (
-
{state.selected_indexer}
- ) : (
- {state.indexers[0].indexerName}
- ))}
- {indexerView(
- selected_accountId ?? state.indexers[0].accountId,
- selected_indexerName ?? state.indexers[0].indexerName
- )}
-
-
- )}
-
-
- {state.activeTab === "editor-window" && (
-
+
+
{state.indexers.length > 0 &&
(state.selected_indexer != undefined ? (
{state.selected_indexer}
@@ -511,10 +487,10 @@ return (
accountId: selected_accountId ?? state.indexers[0].accountId,
path: "query-api-editor",
tab: props.tab,
+ activeView: state.activeIndexerView
}}
/>
-
- )}
+
{state.activeTab === "create-new-indexer" && (
{state.indexers.length > 0 &&
diff --git a/frontend/widgets/src/QueryApi.Editor.jsx b/frontend/widgets/src/QueryApi.Editor.jsx
index 8deadca58..8e37a34f6 100644
--- a/frontend/widgets/src/QueryApi.Editor.jsx
+++ b/frontend/widgets/src/QueryApi.Editor.jsx
@@ -1,5 +1,6 @@
const path = props.path || "query-api-editor";
const tab = props.tab || "";
+const activeView = props.activeView || "editor";
let accountId = props.accountId || context.accountId;
let externalAppUrl = `${REPL_EXTERNAL_APP_URL}/${path}?accountId=${accountId}`;
@@ -7,13 +8,11 @@ if (props.indexerName) {
externalAppUrl += `&indexerName=${props.indexerName}`;
}
const initialViewHeight = 1000;
-if (!context.accountId) {
- return "Please sign in to use this widget.";
-}
const initialPayload = {
height: Near.block("optimistic").header.height,
selectedTab: tab,
+ activeView,
currentUserAccountId: context.accountId,
};
diff --git a/frontend/widgets/src/QueryApi.IndexerCard.jsx b/frontend/widgets/src/QueryApi.IndexerCard.jsx
index f64545ba3..191f688a1 100644
--- a/frontend/widgets/src/QueryApi.IndexerCard.jsx
+++ b/frontend/widgets/src/QueryApi.IndexerCard.jsx
@@ -1,7 +1,7 @@
const accountId = props.accountId || context.accountId;
const indexerName = props.indexerName;
-const editUrl = `https://near.org/#/${REPL_ACCOUNT_ID}/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}&view=editor-window`;
-const statusUrl = `https://near.org/#/${REPL_ACCOUNT_ID}/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}&view=indexer-status`;
+const editUrl = `https://near.org/#/${REPL_ACCOUNT_ID}/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}`;
+const statusUrl = `https://near.org/#/${REPL_ACCOUNT_ID}/widget/QueryApi.App?selectedIndexerPath=${accountId}/${indexerName}&view=indexer&activeIndexerView=status`;
const playgroundLink = `https://cloud.hasura.io/public/graphiql?endpoint=${REPL_GRAPHQL_ENDPOINT}/v1/graphql&header=x-hasura-role%3A${accountId.replaceAll(
".",
"_"
@@ -178,7 +178,7 @@ return (
href={editUrl}
onClick={() =>
State.update({
- activeTab: "editor-window",
+ activeTab: "editor",
})
}
>