Canvas: Get ready for trial
Change-Id: I16088fa041dd0fb35ac801ddbbedf3c1c6e8563d
diff --git a/apps/canvas/back/src/index.ts b/apps/canvas/back/src/index.ts
index cd8249d..6dede14 100644
--- a/apps/canvas/back/src/index.ts
+++ b/apps/canvas/back/src/index.ts
@@ -478,19 +478,15 @@
resp.write(
JSON.stringify({
// TODO(gio): get from env or command line flags
- managerAddr: "http://10.42.0.211:8081",
+ managerAddr: "http://10.42.0.95:8081",
deployKey: project.deployKey,
integrations: {
github: !!project.githubToken,
},
networks: [
{
- name: "Public",
- domain: "v1.dodo.cloud",
- },
- {
- name: "Private",
- domain: "p.v1.dodo.cloud",
+ name: "Trial",
+ domain: "trial.dodoapp.xyz",
},
],
services,
diff --git a/apps/canvas/front/src/Integrations.tsx b/apps/canvas/front/src/Integrations.tsx
index 55acf1a..185a884 100644
--- a/apps/canvas/front/src/Integrations.tsx
+++ b/apps/canvas/front/src/Integrations.tsx
@@ -85,10 +85,26 @@
{(!githubService || isEditing) && (
<div className="flex flex-row items-center gap-1 text-sm">
- <div>Follow the link to generate new PAT:</div>
- <a href="https://github.com/settings/personal-access-tokens" target="_blank">
- https://github.com/settings/personal-access-tokens
- </a>
+ <div>
+ Follow the link to generate new PAT:{" "}
+ <a href="https://github.com/settings/personal-access-tokens" target="_blank">
+ https://github.com/settings/personal-access-tokens
+ </a>
+ <br />
+ Grant following <b>Repository</b> permissions:
+ <ul>
+ <li>
+ <b>Contents</b> - Read-only access so dodo can clone the repository
+ </li>
+ <li>
+ <b>Metadata</b> - Read-only access so dodo can search for repositories
+ </li>
+ <li>
+ <b>Administration</b> - Read and write access so dodo automatically add deploy keys
+ to repositories
+ </li>
+ </ul>
+ </div>
</div>
)}
{(!githubService || isEditing) && (
diff --git a/apps/canvas/front/src/Messages.tsx b/apps/canvas/front/src/Messages.tsx
index 8cd6652..0701afb 100644
--- a/apps/canvas/front/src/Messages.tsx
+++ b/apps/canvas/front/src/Messages.tsx
@@ -1,5 +1,5 @@
import { Button } from "./components/ui/button";
-import { AppNode, AppState, Message, nodeLabel, useMessages } from "./lib/state";
+import { AppNode, AppState, Message, nodeLabel, useMessages, useProjectId } from "./lib/state";
import { useCallback, useEffect, useState } from "react";
import { useNodes } from "@xyflow/react";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "./components/ui/accordion";
@@ -8,6 +8,7 @@
export function Messages() {
const nodes = useNodes<AppNode>();
+ const projectId = useProjectId();
const [nodeMap, setNodeMap] = useState<Map<string, AppNode>>(new Map());
useEffect(() => {
setNodeMap(new Map(nodes.map((n) => [n.id, n])));
@@ -24,14 +25,25 @@
const [grouped, setGrouped] = useState<Map<string, Message[]>>(new Map());
useEffect(() => {
const g = new Map<string, Message[]>();
- messages.forEach((m) => {
- const id = m.nodeId || "global";
- const existing: Message[] = g.get(id) || [];
- existing.push(m);
- g.set(id, existing);
- });
+ if (projectId == null) {
+ g.set("global", [
+ {
+ id: "global",
+ nodeId: undefined,
+ message: "Create a new project or select existing one to get started",
+ type: "FATAL",
+ },
+ ]);
+ } else {
+ messages.forEach((m) => {
+ const id = m.nodeId || "global";
+ const existing: Message[] = g.get(id) || [];
+ existing.push(m);
+ g.set(id, existing);
+ });
+ }
setGrouped(g);
- }, [messages, setGrouped]);
+ }, [projectId, messages, setGrouped]);
const [open, setOpen] = useState<string[]>([...grouped.keys()]);
useEffect(() => {
// TODO(gio): do not reopen closed ones
diff --git a/apps/canvas/front/src/components/actions.tsx b/apps/canvas/front/src/components/actions.tsx
index c7481c1..b8771b3 100644
--- a/apps/canvas/front/src/components/actions.tsx
+++ b/apps/canvas/front/src/components/actions.tsx
@@ -164,6 +164,9 @@
if (projectId == null) {
return;
}
+ if (!confirm("Are you sure you want to delete this project? This action cannot be undone.")) {
+ return;
+ }
const resp = await fetch(`/api/project/${projectId}`, {
method: "DELETE",
});
diff --git a/apps/canvas/front/src/components/resources.tsx b/apps/canvas/front/src/components/resources.tsx
index ddb68ac..1fd631a 100644
--- a/apps/canvas/front/src/components/resources.tsx
+++ b/apps/canvas/front/src/components/resources.tsx
@@ -3,7 +3,7 @@
import { useCallback, useState } from "react";
import { Accordion, AccordionTrigger } from "./ui/accordion";
import { AccordionContent, AccordionItem } from "@radix-ui/react-accordion";
-import { AppState, NodeType, useCategories, useStateStore } from "@/lib/state";
+import { AppState, NodeType, useCategories, useMode, useProjectId, useStateStore } from "@/lib/state";
import { CategoryItem } from "@/lib/categories";
import { Icon } from "./icon";
@@ -25,7 +25,8 @@
export function Resources() {
const store = useStateStore();
const categories = useCategories();
-
+ const projectId = useProjectId();
+ const mode = useMode();
const onResourceAdd = useCallback(
(item: CategoryItem<NodeType>) => {
return () => addResource(item, store);
@@ -48,6 +49,7 @@
key={item.title}
onClick={onResourceAdd(item)}
style={{ justifyContent: "flex-start" }}
+ disabled={projectId == null || mode !== "edit"}
>
<Icon type={item.type} />
{item.title}
diff --git a/apps/canvas/front/src/lib/config.ts b/apps/canvas/front/src/lib/config.ts
index 63f6642..572fc78 100644
--- a/apps/canvas/front/src/lib/config.ts
+++ b/apps/canvas/front/src/lib/config.ts
@@ -449,7 +449,7 @@
id: `${n.id}-${p.id}-no-ingress`,
type: "WARNING",
nodeId: n.id,
- message: `Connect to ingress: ${p.name} - ${p.value}`,
+ message: `Connect to gateway: ${p.name} - ${p.value}`,
onHighlight: (store) => {
store.updateNode(n.id, { selected: true });
store.setHighlightCategory("gateways", true);
diff --git a/apps/canvas/front/src/lib/state.ts b/apps/canvas/front/src/lib/state.ts
index 9d74d5b..aae7600 100644
--- a/apps/canvas/front/src/lib/state.ts
+++ b/apps/canvas/front/src/lib/state.ts
@@ -85,7 +85,7 @@
"hugo:latest",
"php:8.2-apache",
"nextjs:deno-2.0.0",
- "node-23.1.0",
+ "nodejs:23.1.0",
] as const;
export type ServiceType = (typeof ServiceTypes)[number];