diff --git a/console/src/components/menu/items.tsx b/console/src/components/menu/items.tsx
index f297f9faf1..6fa733ea77 100644
--- a/console/src/components/menu/items.tsx
+++ b/console/src/components/menu/items.tsx
@@ -29,3 +29,11 @@ export const HardReloadItem = (
);
};
+
+export const DeleteItem = (): ReactElement => {
+ return (
+
} size="small">
+ Delete
+
+ );
+};
diff --git a/console/src/schematic/ontology.tsx b/console/src/schematic/ontology.tsx
index 4237fb09e4..c0bf04da08 100644
--- a/console/src/schematic/ontology.tsx
+++ b/console/src/schematic/ontology.tsx
@@ -112,7 +112,7 @@ const TreeContextMenu: Ontology.TreeContextMenu = ({
link: handleCopyUrl,
};
- const onSelect = (key: string): void => f[key]();
+ const onSelect = (key: string): void => f[key]?.();
const isSingle = resources.length === 1;
return (
@@ -124,9 +124,7 @@ const TreeContextMenu: Ontology.TreeContextMenu = ({
}>
Copy
- }>
- Delete
-
+
{isSingle && }
diff --git a/console/src/workspace/ontology.tsx b/console/src/workspace/ontology.tsx
index 0980d65d17..4d97f831a1 100644
--- a/console/src/workspace/ontology.tsx
+++ b/console/src/workspace/ontology.tsx
@@ -6,11 +6,9 @@
// As of the Change Date specified in that file, in accordance with the Business Source
// License, use of this software will be governed by the Apache License, Version 2.0,
// included in the file licenses/APL.txt.
-
import { ontology } from "@synnaxlabs/client";
import { Icon } from "@synnaxlabs/media";
-import { Menu as PMenu } from "@synnaxlabs/pluto";
-import { Tree } from "@synnaxlabs/pluto/tree";
+import { Menu as PMenu, Tree } from "@synnaxlabs/pluto";
import { deep, type UnknownRecord } from "@synnaxlabs/x";
import { type ReactElement } from "react";
@@ -18,106 +16,125 @@ import { Cluster } from "@/cluster";
import { Menu } from "@/components/menu";
import { Group } from "@/group";
import { Layout } from "@/layout";
+import { LinePlot } from "@/lineplot";
import { Link } from "@/link";
import { Ontology } from "@/ontology";
import { Schematic } from "@/schematic";
import { selectActiveKey } from "@/workspace/selectors";
import { add, rename, setActive } from "@/workspace/slice";
-const handleDelete = ({
- client,
- store,
- selection: { resources },
- state: { nodes, setNodes },
-}: Ontology.TreeContextMenuProps): void => {
- void (async () => {
- const s = store.getState();
- const activeKey = selectActiveKey(s);
- const active = resources.find((r) => r.id.key === activeKey);
- if (active != null) {
- store.dispatch(setActive(null));
- store.dispatch(Layout.clearWorkspace());
- }
- await client.workspaces.delete(...resources.map((r) => r.id.key));
- const next = Tree.removeNode({
- tree: nodes,
- keys: resources.map((r) => r.id.toString()),
- });
- setNodes([...next]);
- })();
-};
-
-const handleCreateNewSchematic = ({
- client,
- services,
- placeLayout,
- selection,
- state: { nodes, setNodes, resources, setResources },
-}: Ontology.TreeContextMenuProps): void => {
- const ws = selection.resources[0].id.key;
- void (async () => {
- const schematic = await client.workspaces.schematic.create(ws, {
- name: "New Schematic",
- snapshot: false,
- data: deep.copy(Schematic.ZERO_STATE) as unknown as UnknownRecord,
- });
- const otg = await client.ontology.retrieve(
- new ontology.ID({ key: schematic.key, type: "schematic" }),
- );
- placeLayout(
- Schematic.create({
- ...(schematic.data as unknown as Schematic.State),
- key: schematic.key,
- name: schematic.name,
- snapshot: schematic.snapshot,
- }),
- );
- setResources([...resources, otg]);
- const nextNodes = Tree.setNode({
- tree: nodes,
- destination: selection.resources[0].key,
- additions: Ontology.toTreeNodes(services, [otg]),
- });
- setNodes([...nextNodes]);
- })();
-};
-
const TreeContextMenu: Ontology.TreeContextMenu = (props): ReactElement => {
const {
- selection: { resources },
+ selection,
+ client,
+ services,
+ placeLayout,
+ store,
+ state: { nodes, setNodes, resources, setResources },
} = props;
- const clusterKey = Cluster.useSelectActiveKey();
- const handleSelect = (key: string): void => {
- switch (key) {
- case "delete":
- return handleDelete(props);
- case "rename":
- return Tree.startRenaming(resources[0].id.toString());
- case "group":
- void Group.fromSelection(props);
- return;
- case "plot":
- // TODO: actually implement this case
- return;
- case "schematic": {
- return handleCreateNewSchematic(props);
+ const handleDelete = (): void => {
+ void (async () => {
+ const s = store.getState();
+ const activeKey = selectActiveKey(s);
+ const active = selection.resources.find((r) => r.id.key === activeKey);
+ if (active != null) {
+ store.dispatch(setActive(null));
+ store.dispatch(Layout.clearWorkspace());
}
- case "link": {
- const toCopy = `synnax://cluster/${clusterKey}/workspace/${resources[0].id.key}`;
- void navigator.clipboard.writeText(toCopy);
- return;
- }
- }
+ await client.workspaces.delete(...selection.resources.map((r) => r.id.key));
+ const next = Tree.removeNode({
+ tree: nodes,
+ keys: selection.resources.map((r) => r.id.toString()),
+ });
+ setNodes([...next]);
+ })();
+ };
+
+ const handleCreateNewSchematic = (): void => {
+ const workspace = selection.resources[0].id.key;
+ void (async () => {
+ const schematic = await client.workspaces.schematic.create(workspace, {
+ name: "New Schematic",
+ snapshot: false,
+ data: deep.copy(Schematic.ZERO_STATE) as unknown as UnknownRecord,
+ });
+ const otg = await client.ontology.retrieve(
+ new ontology.ID({ key: schematic.key, type: "schematic" }),
+ );
+ placeLayout(
+ Schematic.create({
+ ...(schematic.data as unknown as Schematic.State),
+ key: schematic.key,
+ name: schematic.name,
+ snapshot: schematic.snapshot,
+ }),
+ );
+ setResources([...resources, otg]);
+ const nextNodes = Tree.setNode({
+ tree: nodes,
+ destination: selection.resources[0].key,
+ additions: Ontology.toTreeNodes(services, [otg]),
+ });
+ setNodes([...nextNodes]);
+ })();
+ };
+
+ const handleCreateNewLinePlot = (): void => {
+ const workspace = selection.resources[0].id.key;
+ void (async () => {
+ const linePlot = await client.workspaces.linePlot.create(workspace, {
+ name: "New Line Plot",
+ data: deep.copy(LinePlot.ZERO_SLICE_STATE) as unknown as UnknownRecord,
+ });
+ const otg = await client.ontology.retrieve(
+ new ontology.ID({ key: linePlot.key, type: "lineplot" }),
+ );
+ placeLayout(
+ LinePlot.create({
+ ...(linePlot.data as unknown as LinePlot.SliceState),
+ key: linePlot.key,
+ name: linePlot.name,
+ }),
+ );
+ setResources([...resources, otg]);
+ const nextNodes = Tree.setNode({
+ tree: nodes,
+ destination: selection.resources[0].key,
+ additions: Ontology.toTreeNodes(services, [otg]),
+ });
+ setNodes([...nextNodes]);
+ })();
};
- const singleResource = resources.length === 1;
+ const handleRename = (): void => {
+ return Tree.startRenaming(selection.resources[0].id.toString());
+ };
+
+ const handleGroup = (): void => {
+ void Group.fromSelection(props);
+ };
+
+ const clusterKey = Cluster.useSelectActiveKey();
+ const handleLink = (): void => {
+ const toCopy = `synnax://cluster/${clusterKey}/workspace/${selection.resources[0].id.key}`;
+ void navigator.clipboard.writeText(toCopy);
+ };
+
+ const f: Record void> = {
+ delete: handleDelete,
+ rename: handleRename,
+ group: handleGroup,
+ plot: handleCreateNewLinePlot,
+ schematic: handleCreateNewSchematic,
+ link: handleLink,
+ };
+ const onSelect = (key: string): void => f[key]?.();
+ const singleResource = selection.resources.length === 1;
return (
-
- }>
- Delete
-
+
+
{singleResource && }
{singleResource && (
@@ -138,11 +155,11 @@ const TreeContextMenu: Ontology.TreeContextMenu = (props): ReactElement => {
const handleSelect: Ontology.HandleSelect = ({ selection, client, store }) => {
void (async () => {
- const ws = await client.workspaces.retrieve(selection[0].id.key);
- store.dispatch(add({ workspaces: [ws] }));
+ const workspace = await client.workspaces.retrieve(selection[0].id.key);
+ store.dispatch(add({ workspaces: [workspace] }));
store.dispatch(
Layout.setWorkspace({
- slice: ws.layout as unknown as Layout.SliceState,
+ slice: workspace.layout as unknown as Layout.SliceState,
keepNav: false,
}),
);