- {Object.keys(component.metadata.keySchema).map((name) => (
-
- {String(key[name])}
- |
- ))}
- {Object.keys(component.metadata.valueSchema).map((name) => {
+ {entity} |
+ {Object.keys(component.schema).map((name) => {
const fieldValue = value[name];
return (
- {Array.isArray(fieldValue) ? fieldValue.map(String).join(", ") : String(fieldValue)}
+ {component.schema[name] === Type.T
+ ? serialize(fieldValue)
+ : Array.isArray(fieldValue)
+ ? fieldValue.map(String).join(", ")
+ : String(fieldValue)}
|
);
})}
diff --git a/packages/dev-tools/src/recs/ComponentsPage.tsx b/packages/dev-tools/src/recs/ComponentsPage.tsx
index d4f53bb62e..2cd10b8e02 100644
--- a/packages/dev-tools/src/recs/ComponentsPage.tsx
+++ b/packages/dev-tools/src/recs/ComponentsPage.tsx
@@ -3,25 +3,26 @@ import { NavButton } from "../NavButton";
import { useEffect, useRef } from "react";
import { twMerge } from "tailwind-merge";
import { useDevToolsContext } from "../DevToolsContext";
-import { isStoreComponent } from "@latticexyz/store-sync/recs";
+import { getComponentName } from "./getComponentName";
export function ComponentsPage() {
const { recsWorld: world } = useDevToolsContext();
if (!world) throw new Error("Missing recsWorld");
- const components = world.components.filter(isStoreComponent);
+ const components = [...world.components].sort((a, b) => getComponentName(a).localeCompare(getComponentName(b)));
+
// TODO: lift up selected component so we can remember previous selection between tab nav
const { id: idParam } = useParams();
- const selectedComponent = components.find((component) => component.id === idParam);
+ const selectedComponent = components.find((component) => component.id === idParam) ?? components[0];
const detailsRef = useRef(null);
const navigate = useNavigate();
useEffect(() => {
- if (components.length && !selectedComponent) {
- navigate(components[0].id);
+ if (idParam !== selectedComponent.id) {
+ navigate(selectedComponent.id);
}
- }, [components, selectedComponent]);
+ }, [idParam, selectedComponent.id]);
useEffect(() => {
const listener = (event: MouseEvent) => {
@@ -45,7 +46,7 @@ export function ComponentsPage() {
{selectedComponent ? (
- {selectedComponent.metadata.componentName}
+ {getComponentName(selectedComponent)}
) : (
Pick a component…
)}
@@ -68,7 +69,7 @@ export function ComponentsPage() {
}
}}
>
- {component.metadata.componentName}
+ {getComponentName(component)}
))}
diff --git a/packages/dev-tools/src/recs/StoreComponentDataTable.tsx b/packages/dev-tools/src/recs/StoreComponentDataTable.tsx
new file mode 100644
index 0000000000..6e012dc312
--- /dev/null
+++ b/packages/dev-tools/src/recs/StoreComponentDataTable.tsx
@@ -0,0 +1,56 @@
+import { useEntityQuery } from "@latticexyz/react";
+import { Component, Has, Schema, getComponentValueStrict } from "@latticexyz/recs";
+import { StoreComponentMetadata, decodeEntity } from "@latticexyz/store-sync/recs";
+
+// TODO: use react-table or similar for better perf with lots of logs
+
+type Props = {
+ component: Component;
+};
+
+export function StoreComponentDataTable({ component }: Props) {
+ // TODO: this breaks when navigating because its state still has entity IDs from prev page
+ const entities = useEntityQuery([Has(component)]);
+
+ return (
+
+
+
+ {Object.keys(component.metadata.keySchema).map((name) => (
+
+ {name}
+ |
+ ))}
+ {Object.keys(component.metadata.valueSchema).map((name) => (
+
+ {name}
+ |
+ ))}
+
+
+
+ {entities.map((entity) => {
+ const key = decodeEntity(component.metadata.keySchema, entity);
+ const value = getComponentValueStrict(component, entity);
+ return (
+
+ {Object.keys(component.metadata.keySchema).map((name) => (
+
+ {String(key[name])}
+ |
+ ))}
+ {Object.keys(component.metadata.valueSchema).map((name) => {
+ const fieldValue = value[name];
+ return (
+
+ {Array.isArray(fieldValue) ? fieldValue.map(String).join(", ") : String(fieldValue)}
+ |
+ );
+ })}
+
+ );
+ })}
+
+
+ );
+}
diff --git a/packages/dev-tools/src/recs/getComponentName.ts b/packages/dev-tools/src/recs/getComponentName.ts
new file mode 100644
index 0000000000..3b37186ed8
--- /dev/null
+++ b/packages/dev-tools/src/recs/getComponentName.ts
@@ -0,0 +1,5 @@
+import { Component } from "@latticexyz/recs";
+
+export function getComponentName(component: Component): string {
+ return String(component.metadata?.componentName ?? component.id);
+}
diff --git a/packages/dev-tools/src/summary/ComponentsSummary.tsx b/packages/dev-tools/src/summary/ComponentsSummary.tsx
index 102f441f66..2c3d60964d 100644
--- a/packages/dev-tools/src/summary/ComponentsSummary.tsx
+++ b/packages/dev-tools/src/summary/ComponentsSummary.tsx
@@ -1,25 +1,25 @@
import { World } from "@latticexyz/recs";
import { NavButton } from "../NavButton";
-import { isStoreComponent } from "@latticexyz/store-sync/recs";
+import { getComponentName } from "../recs/getComponentName";
type Props = {
world: World;
};
export function ComponentsSummary({ world }: Props) {
- const componentsWithName = world.components.filter(isStoreComponent);
+ const components = [...world.components].sort((a, b) => getComponentName(a).localeCompare(getComponentName(b)));
return (
<>
- {componentsWithName.length ? (
+ {components.length ? (
<>
- {componentsWithName.map((component) => (
+ {components.map((component) => (
- {String(component.metadata.componentName)}
+ {getComponentName(component)}
))}
diff --git a/packages/store-sync/src/recs/defineInternalComponents.ts b/packages/store-sync/src/recs/defineInternalComponents.ts
index e73627471a..5f4a461549 100644
--- a/packages/store-sync/src/recs/defineInternalComponents.ts
+++ b/packages/store-sync/src/recs/defineInternalComponents.ts
@@ -1,21 +1,13 @@
-import { World, defineComponent, Type, Component, Schema } from "@latticexyz/recs";
+import { World, defineComponent, Type, Component, Schema, Metadata } from "@latticexyz/recs";
import { Table } from "../common";
-import { StoreComponentMetadata } from "./common";
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function defineInternalComponents(world: World) {
return {
- TableMetadata: defineComponent<{ table: Type.T }, StoreComponentMetadata, Table>(
+ TableMetadata: defineComponent<{ table: Type.T }, Metadata, Table>(
world,
{ table: Type.T },
- {
- metadata: {
- componentName: "TableMetadata",
- tableName: "recs:TableMetadata",
- keySchema: {},
- valueSchema: {},
- },
- }
+ { metadata: { componentName: "TableMetadata" } }
),
SyncProgress: defineComponent(
world,
@@ -26,14 +18,7 @@ export function defineInternalComponents(world: World) {
latestBlockNumber: Type.BigInt,
lastBlockNumberProcessed: Type.BigInt,
},
- {
- metadata: {
- componentName: "SyncProgress",
- tableName: "recs:SyncProgress",
- keySchema: {},
- valueSchema: {},
- },
- }
+ { metadata: { componentName: "SyncProgress" } }
),
- } as const satisfies Record>;
+ } as const satisfies Record>;
}