Canvas: Add modal resources dialog to Overview tab
- Add Add button to Actions component visible only in Overview tab and edit mode
- Create modal dialog with Resources component for adding new resources
- Modal automatically closes when resource is added
- Resources component accepts optional onResourceAdded callback
- Maintain backward compatibility with existing Resources usage
Change-Id: Ib01fe1417ba2bbb7c91f6e1d0551fe9c52ade8c3
diff --git a/apps/canvas/front/src/Overview.tsx b/apps/canvas/front/src/Overview.tsx
index 345bb1d..8ed2c0c 100644
--- a/apps/canvas/front/src/Overview.tsx
+++ b/apps/canvas/front/src/Overview.tsx
@@ -37,7 +37,7 @@
return (
<div className="h-full w-full overflow-auto bg-white p-2">
<div className="w-full flex flex-row justify-end">
- <Actions />
+ <Actions isOverview={true} />
<Canvas className="hidden" />
</div>
<div className="flex flex-col gap-4 pt-2">
diff --git a/apps/canvas/front/src/components/actions.tsx b/apps/canvas/front/src/components/actions.tsx
index 1442b9a..5ea2920 100644
--- a/apps/canvas/front/src/components/actions.tsx
+++ b/apps/canvas/front/src/components/actions.tsx
@@ -11,8 +11,10 @@
DropdownMenuContent,
DropdownMenuTrigger,
} from "./ui/dropdown-menu";
-import { Ellipsis, LoaderCircle } from "lucide-react";
+import { Ellipsis, LoaderCircle, Plus } from "lucide-react";
import { ImportModal } from "./import-modal";
+import { Dialog, DialogContent, DialogHeader, DialogTitle } from "./ui/dialog";
+import { Resources } from "./resources";
function toNodeType(t: string): string {
if (t === "ingress") {
@@ -24,7 +26,11 @@
}
}
-export function Actions() {
+interface ActionsProps {
+ isOverview?: boolean;
+}
+
+export function Actions({ isOverview = false }: ActionsProps) {
const { toast } = useToast();
const store = useStateStore();
const projectId = useProjectId();
@@ -36,6 +42,7 @@
const [loading, setLoading] = useState(false);
const [reloading, setReloading] = useState(false);
const [showImportModal, setShowImportModal] = useState(false);
+ const [showResourcesModal, setShowResourcesModal] = useState(false);
const info = useCallback(
(title: string, description?: string, duration?: number) => {
return toast({
@@ -313,6 +320,12 @@
return (
<>
<div className="flex flex-row gap-1 items-center">
+ {isOverview && (
+ <Button onClick={() => setShowResourcesModal(true)}>
+ <Plus className="w-4 h-4 mr-1" />
+ Add
+ </Button>
+ )}
<Button onClick={deploy} {...deployProps}>
{deployProps.loading ? (
<>
@@ -355,6 +368,16 @@
</DropdownMenu>
</div>
<ImportModal open={showImportModal} onOpenChange={setShowImportModal} />
+ <Dialog open={showResourcesModal} onOpenChange={setShowResourcesModal}>
+ <DialogContent className="sm:max-w-md">
+ <DialogHeader>
+ <DialogTitle>Add Resources</DialogTitle>
+ </DialogHeader>
+ <div className="py-4">
+ <Resources onResourceAdded={() => setShowResourcesModal(false)} />
+ </div>
+ </DialogContent>
+ </Dialog>
</>
);
}
diff --git a/apps/canvas/front/src/components/resources.tsx b/apps/canvas/front/src/components/resources.tsx
index cdd58c5..cd17ac6 100644
--- a/apps/canvas/front/src/components/resources.tsx
+++ b/apps/canvas/front/src/components/resources.tsx
@@ -9,7 +9,7 @@
import { Icon } from "./icon";
import { AppNode, NodeType } from "config";
-function addResource(i: CategoryItem<NodeType>, store: AppState) {
+function addResource(i: CategoryItem<NodeType>, store: AppState, onResourceAdded?: () => void) {
const deselected = store.nodes.map((n) => ({
...n,
selected: false,
@@ -22,18 +22,25 @@
selected: true,
connectable: true,
} as any); // eslint-disable-line @typescript-eslint/no-explicit-any
+ if (onResourceAdded) {
+ onResourceAdded();
+ }
}
-export function Resources() {
+interface ResourcesProps {
+ onResourceAdded?: () => void;
+}
+
+export function Resources({ onResourceAdded }: ResourcesProps = {}) {
const store = useStateStore();
const categories = useCategories();
const projectId = useProjectId();
const mode = useMode();
const onResourceAdd = useCallback(
(item: CategoryItem<NodeType>) => {
- return () => addResource(item, store);
+ return () => addResource(item, store, onResourceAdded);
},
- [store],
+ [store, onResourceAdded],
);
const [open, setOpen] = useState<string[]>(categories.map((c) => c.title));