diff --git a/interface/src/Sidebar/Project/CustomTypes.tsx b/interface/src/Sidebar/Project/CustomTypes.tsx
index 9da559e4..44c73a62 100644
--- a/interface/src/Sidebar/Project/CustomTypes.tsx
+++ b/interface/src/Sidebar/Project/CustomTypes.tsx
@@ -1,466 +1,693 @@
import { Tabs } from "@kobalte/core";
-import { For, Show, createMemo, createSignal } from "solid-js";
+import { For, Show, ValidComponent, createMemo, createSignal } from "solid-js";
import { SidebarSection } from "../../components/Sidebar";
import { TypeEditor } from "../../components/TypeEditor";
import { IconButton } from "../../components/ui";
import { useInterfaceContext } from "../../context";
import { createTokenisedSearchFilter, tokeniseString } from "../../util";
-import { InlineTextEditor } from "../InlineTextEditor";
+import { InlineTextEditor, InlineTextEditorContext } from "../InlineTextEditor";
import { SearchInput } from "../SearchInput";
+import { ContextMenu } from "@kobalte/core/context-menu";
+import {
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuRenameItem,
+} from "../../components/Graph/ContextMenu";
export function CustomTypes() {
- const [search, setSearch] = createSignal("");
- const interfaceCtx = useInterfaceContext();
+ const [search, setSearch] = createSignal("");
+ const interfaceCtx = useInterfaceContext();
- const tokenisedEvents = createMemo(() =>
- [...interfaceCtx.core.project.customEvents].map(
- ([id, event]) => [tokeniseString(event.name), [id, event]] as const,
- ),
- );
+ const tokenisedEvents = createMemo(() =>
+ [...interfaceCtx.core.project.customEvents].map(
+ ([id, event]) => [tokeniseString(event.name), [id, event]] as const,
+ ),
+ );
- const filteredEvents = createTokenisedSearchFilter(search, tokenisedEvents);
+ const filteredEvents = createTokenisedSearchFilter(search, tokenisedEvents);
- const tokenisedStructs = createMemo(() =>
- [...interfaceCtx.core.project.customStructs].map(
- ([id, struct]) => [tokeniseString(struct.name), [id, struct]] as const,
- ),
- );
+ const tokenisedStructs = createMemo(() =>
+ [...interfaceCtx.core.project.customStructs].map(
+ ([id, struct]) => [tokeniseString(struct.name), [id, struct]] as const,
+ ),
+ );
- const filteredStructs = createTokenisedSearchFilter(search, tokenisedStructs);
+ const filteredStructs = createTokenisedSearchFilter(search, tokenisedStructs);
- const tokenisedEnums = createMemo(() =>
- [...interfaceCtx.core.project.customEnums].map(
- ([id, enm]) => [tokeniseString(enm.name), [id, enm]] as const,
- ),
- );
+ const tokenisedEnums = createMemo(() =>
+ [...interfaceCtx.core.project.customEnums].map(
+ ([id, enm]) => [tokeniseString(enm.name), [id, enm]] as const,
+ ),
+ );
- const filteredEnums = createTokenisedSearchFilter(search, tokenisedEnums);
+ const filteredEnums = createTokenisedSearchFilter(search, tokenisedEnums);
- const [selected, setSelected] = createSignal<"events" | "structs" | "enums">(
- "events",
- );
+ const [selected, setSelected] = createSignal<"events" | "structs" | "enums">(
+ "events",
+ );
- return (
-
- {
- setSelected(v as any);
- setSearch("");
- }}
- >
-
-
- Events
-
-
- Structs
-
-
- Enums
-
-
-
-
-
-
- {
- e.stopPropagation();
- setSearch(e.currentTarget.value);
- }}
- />
- {
- e.stopPropagation();
- switch (selected()) {
- case "events": {
- interfaceCtx.execute("createCustomEvent");
- return;
- }
- case "structs": {
- interfaceCtx.execute("createCustomStruct");
- return;
- }
- case "enums": {
- interfaceCtx.execute("createCustomEnum");
- return;
- }
- }
- }}
- >
-
-
-
-
-
-
- {([id, event]) => (
-
- {
- interfaceCtx.execute("setCustomEventName", {
- eventId: id,
- name: value,
- });
- }}
- >
- {
- e.stopPropagation();
+ return (
+
+ {
+ setSelected(v as any);
+ setSearch("");
+ }}
+ >
+
+
+ Events
+
+
+ Structs
+
+
+ Enums
+
+
+
+
+
+
+ {
+ e.stopPropagation();
+ setSearch(e.currentTarget.value);
+ }}
+ />
+ {
+ e.stopPropagation();
+ switch (selected()) {
+ case "events": {
+ interfaceCtx.execute("createCustomEvent");
+ return;
+ }
+ case "structs": {
+ interfaceCtx.execute("createCustomStruct");
+ return;
+ }
+ case "enums": {
+ interfaceCtx.execute("createCustomEnum");
+ return;
+ }
+ }
+ }}
+ >
+
+
+
+
+
+
+ {([id, event]) => (
+
+ {
+ interfaceCtx.execute("setCustomEventName", {
+ eventId: id,
+ name: value,
+ });
+ }}
+ >
+ {
+ e.stopPropagation();
- interfaceCtx.execute("createCustomEventField", {
- eventId: id,
- });
- }}
- >
-
-
+ interfaceCtx.execute("createCustomEventField", {
+ eventId: id,
+ });
+ }}
+ >
+
+
- {
- e.stopPropagation();
+ {
+ e.stopPropagation();
- interfaceCtx.execute("deleteCustomEvent", {
- eventId: id,
- });
- }}
- >
-
-
-
-
-
- {(field) => (
- -
- {
- interfaceCtx.execute("setCustomEventFieldName", {
- eventId: id,
- fieldId: field.id,
- name: value,
- });
- }}
- >
- {
- e.stopPropagation();
+ interfaceCtx.execute("deleteCustomEvent", {
+ eventId: id,
+ });
+ }}
+ >
+
+
+
+
+
+ {(field, i) => (
+ -
+
+
+
+ as={(asProps) => (
+
+ {...asProps}
+ as="span"
+ />
+ )}
+ class="-mx-1"
+ value={field.name ?? field.id}
+ onChange={(value) => {
+ interfaceCtx.execute(
+ "setCustomEventFieldName",
+ {
+ eventId: id,
+ fieldId: field.id,
+ name: value,
+ },
+ );
+ }}
+ >
+ {
+ e.stopPropagation();
- interfaceCtx.execute("deleteCustomEventField", {
- eventId: id,
- fieldId: field.id,
- });
- }}
- >
-
-
-
+ interfaceCtx.execute(
+ "deleteCustomEventField",
+ {
+ eventId: id,
+ fieldId: field.id,
+ },
+ );
+ }}
+ >
+
+
+
+
+
+
+
+ interfaceCtx.execute(
+ "moveCustomEventFieldToIndex",
+ {
+ eventId: event.id,
+ fieldId: field.id,
+ currentIndex: i(),
+ newIndex: i() - 1,
+ },
+ )
+ }
+ >
+
+ Move Up
+
+
+
+
+ interfaceCtx.execute(
+ "moveCustomEventFieldToIndex",
+ {
+ eventId: event.id,
+ fieldId: field.id,
+ currentIndex: i(),
+ newIndex: i() + 1,
+ },
+ )
+ }
+ >
+
+ Move Down
+
+
+
+
+
+
+ {
+ interfaceCtx.execute(
+ "setCustomEventFieldType",
+ {
+ eventId: id,
+ fieldId: field.id,
+ type: type as any,
+ },
+ );
+ }}
+ />
+
+
+ )}
+
+
+
+ )}
+
+
+
+
+ {([id, struct]) => (
+
+ {
+ interfaceCtx.execute("setCustomStructName", {
+ structId: id,
+ name: value,
+ });
+ }}
+ >
+ {
+ e.stopPropagation();
-
- {
- interfaceCtx.execute(
- "setCustomEventFieldType",
- {
- eventId: id,
- fieldId: field.id,
- type: type as any,
- },
- );
- }}
- />
-
-
- )}
-
-
-
- )}
-
-
-
-
- {([id, struct]) => (
-
- {
- interfaceCtx.execute("setCustomStructName", {
- structId: id,
- name: value,
- });
- }}
- >
- {
- e.stopPropagation();
+ interfaceCtx.execute("createCustomStructField", {
+ structId: id,
+ });
+ }}
+ >
+
+
- interfaceCtx.execute("createCustomStructField", {
- structId: id,
- });
- }}
- >
-
-
+ {
+ e.stopPropagation();
- {
- e.stopPropagation();
+ interfaceCtx.execute("deleteCustomStruct", {
+ structId: id,
+ });
+ }}
+ >
+
+
+
+
+ struct.fields[id])
+ .filter(Boolean)}
+ >
+ {(field, i) => (
+ -
+
+
+
+ as={(asProps) => (
+
+ {...asProps}
+ as="span"
+ />
+ )}
+ class="-mx-1"
+ value={field.name ?? field.id}
+ onChange={(value) => {
+ interfaceCtx.execute(
+ "setCustomStructFieldName",
+ {
+ structId: id,
+ fieldId: field.id,
+ name: value,
+ },
+ );
+ }}
+ >
+ {
+ e.stopPropagation();
- interfaceCtx.execute("deleteCustomStruct", {
- structId: id,
- });
- }}
- >
-
-
-
-
-
- {(field) => (
- -
- {
- interfaceCtx.execute("setCustomStructFieldName", {
- structId: id,
- fieldId: field.id,
- name: value,
- });
- }}
- >
- {
- e.stopPropagation();
+ interfaceCtx.execute(
+ "deleteCustomStructField",
+ { structId: id, fieldId: field.id },
+ );
+ }}
+ >
+
+
+
+
+
+
+
+ interfaceCtx.execute(
+ "moveCustomStructFieldToIndex",
+ {
+ structId: struct.id,
+ fieldId: field.id,
+ currentIndex: i(),
+ newIndex: i() - 1,
+ },
+ )
+ }
+ >
+
+ Move Up
+
+
+
+
+ interfaceCtx.execute(
+ "moveCustomStructFieldToIndex",
+ {
+ structId: struct.id,
+ fieldId: field.id,
+ currentIndex: i(),
+ newIndex: i() + 1,
+ },
+ )
+ }
+ >
+
+ Move Down
+
+
+
+
+
- interfaceCtx.execute(
- "deleteCustomStructField",
- { structId: id, fieldId: field.id },
- );
- }}
- >
-
-
-
+
+ {
+ interfaceCtx.execute(
+ "setCustomStructFieldType",
+ { structId: id, fieldId: field.id, type },
+ );
+ }}
+ />
+
+
+ )}
+
+
+
+ )}
+
+
+
+
+ {([id, enm]) => (
+
+ {
+ interfaceCtx.execute("setCustomEnumName", {
+ enumId: id,
+ name: value,
+ });
+ }}
+ >
+ {
+ e.stopPropagation();
-
- {
- interfaceCtx.execute(
- "setCustomStructFieldType",
- { structId: id, fieldId: field.id, type },
- );
- }}
- />
-
-
- )}
-
-
-
- )}
-
-
-
-
- {([id, enm]) => (
-
- {
- interfaceCtx.execute("setCustomEnumName", {
- enumId: id,
- name: value,
- });
- }}
- >
- {
- e.stopPropagation();
+ interfaceCtx.execute("createCustomEnumVariant", {
+ enumId: id,
+ });
+ }}
+ >
+
+
- interfaceCtx.execute("createCustomEnumVariant", {
- enumId: id,
- });
- }}
- >
-
-
+ {
+ e.stopPropagation();
- {
- e.stopPropagation();
+ interfaceCtx.execute("deleteCustomEnum", {
+ enumId: id,
+ });
+ }}
+ >
+
+
+
+
+
+
+ {(variant, i) => (
+ -
+
+
+
+ as={(asProps) => (
+
+ {...asProps}
+ as="span"
+ />
+ )}
+ class="-mx-1"
+ value={variant.name ?? variant.id}
+ onChange={(value) => {
+ interfaceCtx.execute(
+ "setCustomEnumVariantName",
+ {
+ enumId: id,
+ variantId: variant.id,
+ name: value,
+ },
+ );
+ }}
+ >
+ {
+ e.stopPropagation();
- interfaceCtx.execute("deleteCustomEnum", {
- enumId: id,
- });
- }}
- >
-
-
-
-
-
-
- {(variant) => (
- -
- {
- interfaceCtx.execute(
- "setCustomEnumVariantName",
- {
- enumId: id,
- variantId: variant.id,
- name: value,
- },
- );
- }}
- >
- {
- e.stopPropagation();
+ interfaceCtx.execute(
+ "createCustomEnumVariantField",
+ { enumId: id, variantId: variant.id },
+ );
+ }}
+ >
+
+
- interfaceCtx.execute(
- "createCustomEnumVariantField",
- { enumId: id, variantId: variant.id },
- );
- }}
- >
-
-
+ {
+ e.stopPropagation();
- {
- e.stopPropagation();
+ interfaceCtx.execute(
+ "deleteCustomEnumVariant",
+ { enumId: id, variantId: variant.id },
+ );
+ }}
+ >
+
+
+
+
+
+
+
+ interfaceCtx.execute(
+ "moveCustomEnumVariantToIndex",
+ {
+ enumId: enm.id,
+ variantId: variant.id,
+ currentIndex: i(),
+ newIndex: i() - 1,
+ },
+ )
+ }
+ >
+
+ Move Up
+
+
+
+
+ interfaceCtx.execute(
+ "moveCustomEnumVariantToIndex",
+ {
+ enumId: enm.id,
+ variantId: variant.id,
+ currentIndex: i(),
+ newIndex: i() + 1,
+ },
+ )
+ }
+ >
+
+ Move Down
+
+
+
+
+
- interfaceCtx.execute(
- "deleteCustomEnumVariant",
- { enumId: id, variantId: variant.id },
- );
- }}
- >
-
-
-
+ 0}>
+
+ variant.fields[id])
+ .filter(Boolean)}
+ >
+ {(field, i) => (
+ -
+
+
+
+ as={(asProps) => (
+
+ {...asProps}
+ as="span"
+ />
+ )}
+ value={field.name ?? field.id}
+ onChange={(value) => {
+ interfaceCtx.execute(
+ "setCustomEnumVariantFieldName",
+ {
+ enumId: enm.id,
+ variantId: variant.id,
+ fieldId: field.id,
+ name: value,
+ },
+ );
+ }}
+ class="-mx-1"
+ >
+ {
+ e.stopPropagation();
-
-
-
- {(field) => (
- -
- {
- interfaceCtx.execute(
- "setCustomEnumVariantFieldName",
- {
- enumId: enm.id,
- variantId: variant.id,
- fieldId: field.id,
- name: value,
- },
- );
- }}
- class="-mx-1"
- >
- {
- e.stopPropagation();
+ interfaceCtx.execute(
+ "deleteCustomEnumVariantField",
+ {
+ enumId: enm.id,
+ variantId: variant.id,
+ fieldId: field.id,
+ },
+ );
+ }}
+ >
+
+
+
+
+
+
+
+ interfaceCtx.execute(
+ "moveCustomEnumVariantFieldToIndex",
+ {
+ enumId: enm.id,
+ variantId: variant.id,
+ fieldId: field.id,
+ currentIndex: i(),
+ newIndex: i() - 1,
+ },
+ )
+ }
+ >
+
+ Move Up
+
+
+
+
+ interfaceCtx.execute(
+ "moveCustomEnumVariantFieldToIndex",
+ {
+ enumId: enm.id,
+ variantId: variant.id,
+ fieldId: field.id,
+ currentIndex: i(),
+ newIndex: i() + 1,
+ },
+ )
+ }
+ >
+
+ Move Down
+
+
+
+
+
- interfaceCtx.execute(
- "deleteCustomEnumVariantField",
- {
- enumId: enm.id,
- variantId: variant.id,
- fieldId: field.id,
- },
- );
- }}
- >
-
-
-
-
-
- {
- interfaceCtx.execute(
- "setCustomEnumVariantFieldType",
- {
- enumId: enm.id,
- variantId: variant.id,
- fieldId: field.id,
- type,
- },
- );
- }}
- />
-
-
- )}
-
-
-
-
- )}
-
-
-
-
- )}
-
-
-
-
-
- );
+
+ {
+ interfaceCtx.execute(
+ "setCustomEnumVariantFieldType",
+ {
+ enumId: enm.id,
+ variantId: variant.id,
+ fieldId: field.id,
+ type,
+ },
+ );
+ }}
+ />
+
+
+ )}
+
+
+
+
+ )}
+
+
+
+
+ )}
+
+
+
+
+
+ );
}
diff --git a/interface/src/Sidebar/Project/Graphs.tsx b/interface/src/Sidebar/Project/Graphs.tsx
index d7b4c3f1..d9bd171f 100644
--- a/interface/src/Sidebar/Project/Graphs.tsx
+++ b/interface/src/Sidebar/Project/Graphs.tsx
@@ -19,6 +19,7 @@ import {
import {
ContextMenuContent,
ContextMenuItem,
+ ContextMenuRenameItem,
} from "../../components/Graph/ContextMenu";
import { SidebarSection } from "../../components/Sidebar";
import { IconButton } from "../../components/ui";
@@ -108,101 +109,78 @@ export function Graphs(props: Props) {