diff --git a/src/services/runtimeMetadataService.ts b/src/services/runtimeMetadataService.ts
index 219e63ae..a617598b 100644
--- a/src/services/runtimeMetadataService.ts
+++ b/src/services/runtimeMetadataService.ts
@@ -1,4 +1,4 @@
-import { Table } from "dexie";
+import { Collection, Table } from "dexie";
import { Network } from "../model/network";
import { RuntimeMetadataCall } from "../model/runtime-metadata/runtimeMetadataCall";
@@ -16,57 +16,69 @@ import { RuntimeSpecWorker } from "../workers/runtimeSpecWorker";
export async function getRuntimeMetadataPallets(network: string, specVersion: string, filter?: (it: RuntimeMetadataPallet) => boolean) {
await loadRuntimeMetadata(network, specVersion);
- return queryStore(runtimeMetadataRepository.pallets, {network, specVersion}, filter).toArray();
+ return applyFilter(runtimeMetadataRepository.pallets.where({network, specVersion}), filter).toArray();
+}
+
+export async function getRuntimeMetadataPalletsByName(namePrefix: string, filter?: (it: RuntimeMetadataPallet) => boolean) {
+ return applyFilter(runtimeMetadataRepository.pallets.where("name").startsWithIgnoreCase(namePrefix), filter).toArray();
}
export async function getRuntimeMetadataCalls(network: string, specVersion: string, pallet: string, filter?: (it: RuntimeMetadataCall) => boolean) {
await loadRuntimeMetadata(network, specVersion);
- return queryStore(runtimeMetadataRepository.calls, {network, specVersion, pallet}, filter).toArray();
+ return applyFilter(runtimeMetadataRepository.calls.where({network, specVersion, pallet}), filter).toArray();
+}
+
+export async function getRuntimeMetadataCallsByName(namePrefix: string, filter?: (it: RuntimeMetadataCall) => boolean) {
+ return applyFilter(runtimeMetadataRepository.calls.where("name").startsWithIgnoreCase(namePrefix), filter).toArray();
}
export async function getRuntimeMetadataEvents(network: string, specVersion: string, pallet: string, filter?: (it: RuntimeMetadataEvent) => boolean) {
await loadRuntimeMetadata(network, specVersion);
- return queryStore(runtimeMetadataRepository.events, {network, specVersion, pallet}, filter).toArray();
+ return applyFilter(runtimeMetadataRepository.events.where({network, specVersion, pallet}), filter).toArray();
+}
+
+export async function getRuntimeMetadataEventsByName(namePrefix: string, filter?: (it: RuntimeMetadataEvent) => boolean) {
+ return applyFilter(runtimeMetadataRepository.events.where("name").startsWithIgnoreCase(namePrefix), filter).toArray();
}
export async function getRuntimeMetadataConstants(network: string, specVersion: string, pallet: string, filter?: (it: RuntimeMetadataConstant) => boolean) {
await loadRuntimeMetadata(network, specVersion);
- return queryStore(runtimeMetadataRepository.constants, {network, specVersion, pallet}, filter).toArray();
+ return applyFilter(runtimeMetadataRepository.constants.where({network, specVersion, pallet}), filter).toArray();
}
export async function getRuntimeMetadataStorages(network: string, specVersion: string, pallet: string, filter?: (it: RuntimeMetadataStorage) => boolean) {
await loadRuntimeMetadata(network, specVersion);
- return queryStore(runtimeMetadataRepository.storages, {network, specVersion, pallet}, filter).toArray();
+ return applyFilter(runtimeMetadataRepository.storages.where({network, specVersion, pallet}), filter).toArray();
}
export async function getRuntimeMetadataErrors(network: string, specVersion: string, pallet: string, filter?: (it: RuntimeMetadataError) => boolean) {
await loadRuntimeMetadata(network, specVersion);
- return queryStore(runtimeMetadataRepository.errors, {network, specVersion, pallet}, filter).toArray();
+ return applyFilter(runtimeMetadataRepository.errors.where({network, specVersion, pallet}), filter).toArray();
}
export async function getRuntimeMetadataCall(network: string, specVersion: string, pallet: string, name: string) {
await loadRuntimeMetadata(network, specVersion);
- return queryStore(runtimeMetadataRepository.calls, {network, specVersion, pallet, name}).first();
+ return runtimeMetadataRepository.calls.where({network, specVersion, pallet, name}).first();
}
export async function getRuntimeMetadataEvent(network: string, specVersion: string, pallet: string, name: string) {
await loadRuntimeMetadata(network, specVersion);
- return queryStore(runtimeMetadataRepository.events, {network, specVersion, pallet, name}).first();
+ return runtimeMetadataRepository.events.where({network, specVersion, pallet, name}).first();
}
export async function getRuntimeMetadataConstant(network: string, specVersion: string, pallet: string, name: string) {
await loadRuntimeMetadata(network, specVersion);
- return queryStore(runtimeMetadataRepository.constants, {network, specVersion, pallet, name}).first();
+ return runtimeMetadataRepository.constants.where({network, specVersion, pallet, name}).first();
}
export async function getRuntimeMetadataStorage(network: string, specVersion: string, pallet: string, name: string) {
await loadRuntimeMetadata(network, specVersion);
- return queryStore(runtimeMetadataRepository.storages, {network, specVersion, pallet, name}).first();
+ return runtimeMetadataRepository.storages.where({network, specVersion, pallet, name}).first();
}
export async function getRuntimeMetadataError(network: string, specVersion: string, pallet: string, name: string) {
await loadRuntimeMetadata(network, specVersion);
- return queryStore(runtimeMetadataRepository.errors, {network, specVersion, pallet, name}).first();
+ return runtimeMetadataRepository.errors.where({network, specVersion, pallet, name}).first();
}
export async function normalizePalletName(network: Network, name: string, specVersion: string) {
@@ -147,7 +159,7 @@ export async function normalizeErrorName(network: Network, name: string, specVer
/*** PRIVATE ***/
-async function loadRuntimeMetadata(network: string, specVersion: string) {
+export async function loadRuntimeMetadata(network: string, specVersion: string) {
await self.navigator.locks.request(`runtime-metadata/${network}/${specVersion}`, async () => {
const spec = await runtimeMetadataRepository.specs.get([network, specVersion]);
@@ -165,9 +177,7 @@ async function loadRuntimeMetadata(network: string, specVersion: string) {
});
}
-function queryStore(table: Table, where: Record, filter?: (it: T) => boolean) {
- let collection = table.where(where);
-
+function applyFilter(collection: Collection, filter?: (it: T) => boolean) {
if (filter) {
collection = collection.filter(filter);
}
diff --git a/src/services/searchService.ts b/src/services/searchService.ts
index 186371ea..87a467ee 100644
--- a/src/services/searchService.ts
+++ b/src/services/searchService.ts
@@ -24,13 +24,14 @@ import { NetworkError, NonFatalError } from "../utils/error";
import { extractConnectionItems, paginationToConnectionCursor } from "../utils/itemsConnection";
import { emptyItemsResponse } from "../utils/itemsResponse";
import { PickByType } from "../utils/types";
+import { uniqBy } from "../utils/uniq";
import { BlocksFilter, blocksFilterToArchiveFilter, blocksFilterToExplorerSquidFilter, unifyArchiveBlock, unifyExplorerSquidBlock } from "./blocksService";
import { addEventsArgs, eventsFilterToExplorerSquidFilter, unifyExplorerSquidEvent } from "./eventsService";
import { ExtrinsicsFilter, extrinsicFilterToArchiveFilter, extrinsicFilterToExplorerSquidFilter, unifyArchiveExtrinsic, unifyExplorerSquidExtrinsic } from "./extrinsicsService";
import { fetchArchive, fetchExplorerSquid } from "./fetchService";
import { getNetwork, hasSupport } from "./networksService";
-import { normalizeCallName, normalizeEventName } from "./runtimeMetadataService";
+import { getRuntimeMetadataCallsByName, getRuntimeMetadataEventsByName, getRuntimeMetadataPalletsByName, normalizeCallName, normalizeEventName } from "./runtimeMetadataService";
import { getLatestRuntimeSpecVersion } from "./runtimeSpecService";
export type SearchPaginationOptions = Record>, PaginationOptions>;
@@ -136,6 +137,58 @@ export async function search(query: string, networks: Network[], pagination: Sea
};
}
+export async function autocompleteSearchQuery(query: string, networks: Network[]) {
+ if (!query) {
+ return [];
+ }
+
+ const networkNames = networks.map(it => it.name);
+
+ let pallet: string|undefined;
+
+ if (query.includes(".")) {
+ [pallet = "", query = ""] = query.split(".");
+ }
+
+ console.log("autocomplete", pallet, query, networkNames);
+
+ const pallets = await getRuntimeMetadataPalletsByName(query, it => (networkNames.length === 0 || networkNames.includes(it.network)) && !pallet);
+ const calls = await getRuntimeMetadataCallsByName(query, it => (networkNames.length === 0 || networkNames.includes(it.network)) && (!pallet || it.pallet === pallet));
+ const events = await getRuntimeMetadataEventsByName(query, it => (networkNames.length === 0 || networkNames.includes(it.network)) && (!pallet || it.pallet === pallet));
+
+ const palletOptions = uniqBy(pallets, it => it.name).map(it => ({
+ label: it.name,
+ highlight: [0, query.length],
+ type: "pallet"
+ }));
+
+ const callOptions = uniqBy(calls, it => `${it.pallet}.${it.name}`).map(it => ({
+ label: `${it.pallet}.${it.name}`,
+ highlight: [
+ it.pallet.length + 1,
+ it.pallet.length + 1 + query.length
+ ],
+ type: "call"
+ }));
+
+ const eventOptions = uniqBy(events, it => `${it.pallet}.${it.name}`).map(it => ({
+ label: `${it.pallet}.${it.name}`,
+ highlight: [
+ it.pallet.length + 1,
+ it.pallet.length + 1 + query.length
+ ],
+ type: "event"
+ }));
+
+ return [
+ ...palletOptions,
+ ...[
+ ...callOptions,
+ ...eventOptions
+ ].sort((a, b) => a.label.toLowerCase().localeCompare(b.label.toLowerCase()))
+ ];
+}
+
export function getQueryType(network: Network, query: string) {
if (isHex(query)) {
return "hash";
@@ -574,7 +627,10 @@ function networkResultsToSearchResultItems 0) {
+ // if positive total count found and also some data are fetched
+ // (extrinsics and events by name do not fetch data when searching multiple networks)
+
const item = items.data[0] as unknown as T;
data.push({
@@ -582,11 +638,11 @@ function networkResultsToSearchResultItems 1) {
+ } else if (items.totalCount >= 1) {
data.push({
id: `${result.network.name}-grouped`,
network: result.network,
- groupedCount: items.totalCount > 1 ? items.totalCount : undefined
+ groupedCount: items.totalCount
});
}
diff --git a/src/workers/runtimeSpecWorker.runtime.ts b/src/workers/runtimeSpecWorker.runtime.ts
index cfe0094d..fe142584 100644
--- a/src/workers/runtimeSpecWorker.runtime.ts
+++ b/src/workers/runtimeSpecWorker.runtime.ts
@@ -10,6 +10,7 @@ import { fetchArchive } from "../services/fetchService";
import { WebWorkerRuntime } from "../utils/webWorker";
import { RuntimeSpecWorkerMethods } from "./runtimeSpecWorker";
+import { RuntimeMetadataAutocomplete } from "../model/runtime-metadata/runtimeMetadataAutocomplete";
/**
* The reason to obtaining runtime metadata in a web worker is
@@ -34,7 +35,6 @@ class RuntimeSpecWorkerRuntime extends WebWorkerRuntime implements RuntimeSpecWo
);
console.log("hex downloaded", network, specVersion);
- console.log(JSON.stringify(response));
response.metadata[0] && await this.decodeAndSaveRuntimeMetadata(network, specVersion, response.metadata[0].hex);
}
@@ -60,7 +60,7 @@ class RuntimeSpecWorkerRuntime extends WebWorkerRuntime implements RuntimeSpecWo
repository.events,
repository.constants,
repository.storages,
- repository.errors
+ repository.errors,
], async () => {
await repository.specs.put({
network,
diff --git a/test/e2e/home.spec.ts b/test/e2e/home.spec.ts
index 3d6c2e24..5130f5b1 100644
--- a/test/e2e/home.spec.ts
+++ b/test/e2e/home.spec.ts
@@ -5,6 +5,12 @@ test.describe("home page", () => {
test("shows home page", async ({ page, takeScreenshot }) => {
await navigate(page, "/", {waitUntil: "load"});
+ const $searchInput = page.getByTestId("search-input");
+ const $networks = page.getByTestId("networks");
+
+ await expect($searchInput).toBeVisible();
+ await expect($networks).toBeVisible();
+
await takeScreenshot("home");
});
});
diff --git a/test/utils/navigate.ts b/test/utils/navigate.ts
index f3719cc6..950503c2 100644
--- a/test/utils/navigate.ts
+++ b/test/utils/navigate.ts
@@ -13,6 +13,10 @@ const customEvents = ["data-loaded", "chart-finished"];
export async function navigate(page: Page, url: string, options: GotoOptions = {}) {
let customEvent: string|undefined = undefined;
+ await page.goto(url, {waitUntil: "commit"});
+ await page.evaluate(() => localStorage.setItem("skip-runtime-metadata-preload", "true"));
+ await page.evaluate(() => localStorage.setItem("runtime-metadata-preloaded", "true"));
+
if (options.waitUntil && customEvents.includes(options.waitUntil)) {
customEvent = options.waitUntil;
options.waitUntil = "domcontentloaded";