Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"is-ipfs": "^8.0.1",
"is-utf8": "^0.2.1",
"lodash.capitalize": "^4.2.1",
"lodash.clonedeep": "^4.5.0",
"lodash.debounce": "^4.0.8",
"lodash.isnil": "^4.0.0",
"lodash.last": "^3.0.0",
Expand Down
5 changes: 5 additions & 0 deletions site/src/components/runtime/tabTables/palletsDataDisplay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import DataDisplay from "../../dataDisplay";

export default function RuntimePalletsDataDisplay({ pallet }) {
return <DataDisplay tableData={pallet} JSONData={pallet} />;
}
14 changes: 14 additions & 0 deletions site/src/components/runtime/tabTables/palletsTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { runtimePalletsHead } from "../../../utils/constants";
import { toRuntimePalletsTabTableItem } from "../../../utils/viewFuncs/toTableItem";
import { StyledPanelTableWrapper } from "../../styled/panel";
import Table from "../../table";

export default function RuntimePalletsTable({ pallets = [] }) {
const data = pallets?.map(toRuntimePalletsTabTableItem);

return (
<StyledPanelTableWrapper>
<Table heads={runtimePalletsHead} data={data} />
</StyledPanelTableWrapper>
);
}
16 changes: 16 additions & 0 deletions site/src/pages/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useParams } from "react-router-dom";
import BreadCrumb from "../components/breadCrumb";
import DetailTabs from "../components/detail/tabs";
import DetailLayout from "../components/layout/detailLayout";
import List from "../components/list";
import RuntimePalletsTable from "../components/runtime/tabTables/palletsTable";
import { Panel } from "../components/styled/panel";
import {
clearRuntimeDetail,
runtimeDetailSelector,
runtimeFetchDetail,
} from "../store/reducers/runtimeSlice";
import { parseLookupTypesToDict, parseTypedPallets } from "../utils/runtime";
import { bigNumberToLocaleString } from "../utils/viewFuncs";
import {
clearHttpError,
Expand All @@ -23,9 +26,12 @@ export default function Runtime() {

const dispatch = useDispatch();
const runtime = useSelector(runtimeDetailSelector);
const dict = parseLookupTypesToDict(runtime?.metadata?.lookup?.types);

const listData = runtime ? toRuntimeDetailItem(runtime) : {};

const typedPallets = parseTypedPallets(runtime?.metadata?.pallets, dict);

useEffect(() => {
if (version && startHeight) {
clearHttpError(dispatch);
Expand All @@ -50,11 +56,21 @@ export default function Runtime() {
/>
);

const tabs = [
{
name: "Pallets",
count: runtime?.metadata?.pallets?.length,
children: <RuntimePalletsTable pallets={typedPallets} />,
},
];

return (
<DetailLayout breadCrumb={breadCrumb}>
<Panel>
<List data={listData} />
</Panel>

<DetailTabs tabs={tabs} />
</DetailLayout>
);
}
18 changes: 18 additions & 0 deletions site/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,24 @@ export const runtimesHead = [
{ name: "CONSTANTS", width: 160, align: "right" },
];

/**
* page runtime detail tabs
*/
export const runtimePalletsHead = [
{ name: "MODULES", width: 432 },
{ name: "CALLS", width: 160, align: "right" },
{ name: "EVENTS", width: 160, align: "right" },
{ name: "STORAGES", width: 160, align: "right" },
{ name: "CONSTANTS", width: 160, align: "right" },
{ name: "ERROR TYPES", width: 160, align: "right" },
{
name: "Data",
type: "data",
align: "right",
display: "table",
},
];

export const transfersHead = [
{ name: "Event ID", width: 160 },
{ name: "Extrinsic ID", width: 160, align: "center" },
Expand Down
208 changes: 208 additions & 0 deletions site/src/utils/runtime/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import cloneDeep from "lodash.clonedeep";
import noop from "lodash.noop";
import { Fragment } from "react";

/**
* @description transform lookup types to dict
*/
export function parseLookupTypesToDict(lookupTypes = []) {
/** @type {{[k: string]: string}} */
const dict = {};
const laterTypeItems = [];
const laterParamsItems = [];

// collect dict
// specs
// - def: object, has only single key
each(lookupTypes, (item) => {
const { id, type } = item ?? {};
const { def, path, params } = type ?? {};

if (def?.primitive) {
dict[id] = def?.primitive;
}
// struct
else if (def?.composite) {
dict[id] = parseUseCratePaths(path);
}
// struct
else if (def?.variant) {
dict[id] = parseUseCratePaths(path);
}
// NOTE: not sure, def.array.type = 2
else if (def?.array) {
dict[id] = `[u8; ${def.array.len}]`;
}
// TODO: not sure, not like real Tuple
else if (def?.tuple) {
dict[id] = `Tuple(${def.tuple.join(", ")})`;
}
// ref like
else if (def?.compact) {
dict[id] = dict[def?.compact.type];
}
// ref like
else if (def?.sequence) {
dict[id] = dict[def?.sequence.type];
}
// historicMetaCompat
// value: string
else if (def?.historicMetaCompat) {
dict[id] = def.historicMetaCompat;
}
// hack, unknown def, for safe
else {
const key = Object.keys(def ?? {})[0] ?? "";
const val = def[key];
if (typeof val === "number") {
dict[id] = dict[val] ?? val;
} else {
dict[id] = val;
}
}

if (params?.length) {
laterParamsItems.push(item);
}

// didn't match the type yet, match it again later
// e.g. 9 map to 10, 12 map to 178
if (!dict[id]) {
laterTypeItems.push(item);
}
});

// collect missed dict
// compact, sequence
each(laterTypeItems, (item) => {
const { id } = item ?? {};
const { type } =
item?.type?.def?.compact ?? item?.type?.def?.sequence ?? {};

dict[id] = dict[type];
});
laterTypeItems.length = 0; // clean

// parse generic params
each(laterParamsItems, (item) => {
const { id, type } = item;
const { params } = type;

dict[id] = dict[id] + parseGenericParams(dict, params);
});
laterParamsItems.length = 0; // clean

return dict;
}

/**
* @param {ReturnType<transformLookupTypesDict>} dict
*/
export function parseTypedPallets(pallets = [], dict = {}) {
return each(pallets, (pallet) => {
pallet = cloneDeep(pallet);

if (pallet.constants) {
pallet.constants = each(pallet.constants, (constant) => {
const { type, docs } = constant;

if (type) {
constant.type = dict[type];
}

if (docs) {
constant.docs = parseDocs(docs);
}

return constant;
});
}

if (pallet.storage?.items) {
pallet.storage.items = each(pallet.storage?.items, (storage) => {
const {
type: { plain, map },
docs,
} = storage;

if (map) {
const { key, value } = map;
storage.type.map.key = dict[key];
storage.type.map.value = dict[value];
}

if (plain) {
storage.type.plain = dict[plain];
}

if (docs) {
storage.docs = parseDocs(docs);
}

return storage;
});
}

return pallet;
});
}

/**
* @returns {any[]}
*/
function each(array = [], cb = noop) {
const res = [];

if (array?.length) {
for (let idx = 0; idx < array.length; idx++) {
const element = array[idx];
res.push(cb(element, idx, array));
}
}

return res;
}

/**
* @description for struct, fn etc.
*/
function parseGenericParams(dict = {}, params = []) {
let genericStr = params
.map((param) => {
let name = param.name;

const type = dict[param.type];
if (type) {
name += `: ${type}`;
}

return name;
})
.filter(Boolean)
.join(", ");

return `<${genericStr}>`;
}

/**
* @param {string[]} docs
* @description parse docs array to string text
*/
function parseDocs(docs = []) {
return (
<div>
{docs.map((text, idx) => (
<Fragment key={idx}>
{text ? <div role="document">{text}</div> : <p />}
</Fragment>
))}
</div>
);
}

/**
* @description `::`
*/
function parseUseCratePaths(paths = []) {
return paths.join("::");
}
16 changes: 16 additions & 0 deletions site/src/utils/viewFuncs/toTableItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import NftStatus from "../../components/nft/status";
import NftName from "../../components/nft/name";
import Thumbnail from "../../components/nft/thumbnail";
import getTransferDecimals from "./transferDecimals";
import RuntimePalletsDataDisplay from "../../components/runtime/tabTables/palletsDataDisplay";

export const toEventTabTableItem = (events) => {
return (
Expand Down Expand Up @@ -239,3 +240,18 @@ export const toNftInstanceTransferTabTableItem = (
</Tooltip>,
];
};

/**
* page runtime detail tab pallets
*/
export const toRuntimePalletsTabTableItem = (pallet) => {
return [
pallet.name,
"TODO",
"TODO",
pallet.storage?.items?.length || 0,
pallet.constants?.length || 0,
"TODO",
<RuntimePalletsDataDisplay pallet={pallet} />,
];
};
5 changes: 5 additions & 0 deletions site/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6628,6 +6628,11 @@ lodash.capitalize@^4.2.1:
resolved "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9"
integrity sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==

lodash.clonedeep@^4.5.0:
version "4.5.0"
resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==

lodash.curry@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170"
Expand Down