Skip to content

Commit

Permalink
wip 🚧: Working on check deployments state during fetching phase
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzoronzani committed Jun 16, 2024
1 parent 2e7b3f1 commit 9caa66d
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 74 deletions.
5 changes: 0 additions & 5 deletions deps/candid/rdmx6-jaaaa-aaaaa-aaadq-cai.did
Original file line number Diff line number Diff line change
Expand Up @@ -542,11 +542,6 @@ service : (opt InternetIdentityInit) -> {
fetch_entries: () -> (vec BufferedArchiveEntry);
acknowledge_entries: (sequence_number: nat64) -> ();

// Calls used for event stats housekeeping.
// Only callable by the canister itself.
prune_events_if_necessary: () -> ();
inject_prune_event: (timestamp: Timestamp) -> ();

// V2 API
// WARNING: The following methods are experimental and may change in the future.

Expand Down
6 changes: 3 additions & 3 deletions deps/pulled.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"canisters": {
"rdmx6-jaaaa-aaaaa-aaadq-cai": {
"name": "internet_identity",
"wasm_hash": "764cff569a98a3c4d54cba6750fda63f554fc53e7d42a6365d9bdec3280d63c3",
"wasm_hash_download": "764cff569a98a3c4d54cba6750fda63f554fc53e7d42a6365d9bdec3280d63c3",
"wasm_hash": "01797eac7db02126e7cb507e2f3134e2d7b5154289808fdc2c8c03d1fc2dc60e",
"wasm_hash_download": "01797eac7db02126e7cb507e2f3134e2d7b5154289808fdc2c8c03d1fc2dc60e",
"init_guide": "Use '(null)' for sensible defaults. See the candid interface for more details.",
"init_arg": null,
"candid_args": "(opt InternetIdentityInit)",
"gzip": true
}
}
}
}
59 changes: 31 additions & 28 deletions frontend/app/dashboard/new-deployment/page.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
"use client";

import { BackButton } from "@/components/back-button";
import { useToast } from "@/components/ui/use-toast";
import { useDeploymentContext } from "@/contexts/DeploymentContext";
import {BackButton} from "@/components/back-button";
import {useToast} from "@/components/ui/use-toast";
import {useDeploymentContext} from "@/contexts/DeploymentContext";
import {
type OnWsErrorCallback,
type OnWsMessageCallback,
type OnWsOpenCallback,
useIcContext,
} from "@/contexts/IcContext";
import type { DeploymentParams, DeploymentState } from "@/declarations/backend.did";
import { extractDeploymentCreated } from "@/helpers/deployment";
import { extractOk } from "@/helpers/result";
import { sendManifestToProvider } from "@/services/deployment";
import { useRouter } from "next/navigation";
import { useCallback, useEffect, useMemo, useState } from "react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { AlertCircle } from "lucide-react";
import { displayE8sAsIcp, icpToE8s } from "@/helpers/ui";
import { Spinner } from "@/components/spinner";
import { NewDeploymentForm } from "@/components/new-deployment-form";
import { transferE8sToBackend } from "@/services/backend";
import type {DeploymentParams, DeploymentState} from "@/declarations/backend.did";
import {extractOk} from "@/helpers/result";
import {useRouter} from "next/navigation";
import {useCallback, useEffect, useMemo, useState} from "react";
import {Alert, AlertDescription, AlertTitle} from "@/components/ui/alert";
import {AlertCircle} from "lucide-react";
import {displayE8sAsIcp, icpToE8s} from "@/helpers/ui";
import {Spinner} from "@/components/spinner";
import {NewDeploymentForm} from "@/components/new-deployment-form";
import {transferE8sToBackend} from "@/services/backend";
import {extractDeploymentCreated} from "@/helpers/deployment";
import {sendManifestToProvider} from "@/services/deployment";

const FETCH_DEPLOYMENT_PRICE_INTERVAL_MS = 30_000; // 30 seconds

export default function NewDeployment() {
const router = useRouter();
const { backendActor, openWs, closeWs, setWsCallbacks, ledgerCanister, ledgerData, refreshLedgerData } = useIcContext();
const { tlsCertificateData, loadOrCreateCertificate, fetchDeployments } =
const {backendActor, openWs, closeWs, setWsCallbacks, ledgerCanister, ledgerData, refreshLedgerData} = useIcContext();
const {tlsCertificateData, loadOrCreateCertificate, fetchDeployments} =
useDeploymentContext();
const [isSubmitting, setIsSubmitting] = useState(false);
const [isDeploying, setIsDeploying] = useState(false);
Expand All @@ -38,12 +38,12 @@ export default function NewDeployment() {
const [deploymentE8sPrice, setDeploymentE8sPrice] = useState<bigint | null>(null);
const [fetchDeploymentPriceInterval, setFetchDeploymentPriceInterval] = useState<NodeJS.Timeout | null>(null);
const userHasEnoughBalance = useMemo(() =>
ledgerData.balanceE8s !== null && deploymentE8sPrice !== null && ledgerData.balanceE8s > deploymentE8sPrice,
ledgerData.balanceE8s !== null && deploymentE8sPrice !== null && ledgerData.balanceE8s > deploymentE8sPrice,
[ledgerData.balanceE8s, deploymentE8sPrice]
);
const [paymentStatus, setPaymentStatus] = useState<string | null>(null);
const [deploymentParams, setDeploymentParams] = useState<DeploymentParams | null>(null);
const { toast } = useToast();
const {toast} = useToast();

const toastError = useCallback(
(message: string) => {
Expand Down Expand Up @@ -113,7 +113,7 @@ export default function NewDeployment() {
const res = await backendActor.create_deployment(deploymentParams);
const deploymentId = extractOk(res);
console.log("deployment id", deploymentId);
setDeploymentSteps([{ Initialized: null }]);
setDeploymentSteps([{Initialized: null}]);
};

setIsDeploying(true);
Expand Down Expand Up @@ -157,12 +157,15 @@ export default function NewDeployment() {

try {
if ("LeaseCreated" in deploymentUpdate.update) {
const { manifest_sorted_json, dseq } = extractDeploymentCreated(
// closeWs();
// return;

const {manifest_sorted_json, dseq} = extractDeploymentCreated(
deploymentSteps.find((el) =>
el.hasOwnProperty("DeploymentCreated")
)!
);
const { provider_url } = deploymentUpdate.update.LeaseCreated;
const {provider_url} = deploymentUpdate.update.LeaseCreated;

const manifestUrl = new URL(
`/deployment/${dseq}/manifest`,
Expand Down Expand Up @@ -350,7 +353,7 @@ export default function NewDeployment() {
return (
<div className="flex-1 space-y-4 p-8 pt-6">
<div className="flex items-center justify-start">
<BackButton />
<BackButton/>
<h2 className="ml-4 text-3xl font-bold tracking-tight">
Create Deployment
</h2>
Expand All @@ -369,13 +372,13 @@ export default function NewDeployment() {
Price (est.):
</h5>
{deploymentE8sPrice !== null ? (
<pre>~{displayE8sAsIcp(deploymentE8sPrice, { maximumFractionDigits: 6 })}</pre>
<pre>~{displayE8sAsIcp(deploymentE8sPrice, {maximumFractionDigits: 6})}</pre>
) : (
<Spinner />
<Spinner/>
)}
{(!(isSubmitting || isDeploying) && (deploymentE8sPrice !== null) && !userHasEnoughBalance) && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertCircle className="h-4 w-4"/>
<AlertTitle>Insufficient balance</AlertTitle>
<AlertDescription>
<p>Please top up your account.</p>
Expand Down Expand Up @@ -408,13 +411,13 @@ export default function NewDeployment() {
{idx + 1}. {el}
</p>
))}
{isDeploying && <Spinner />}
{isDeploying && <Spinner/>}
</div>
</div>
)}
{Boolean(deploymentError) && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertCircle className="h-4 w-4"/>
<AlertTitle>Deployment Error</AlertTitle>
<AlertDescription>
<p>{deploymentError}</p>
Expand Down
102 changes: 64 additions & 38 deletions frontend/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
"use client";

import Tier from "@/components/Tier";
import { LoadingButton } from "@/components/loading-button";
import { Spinner } from "@/components/spinner";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
import {LoadingButton} from "@/components/loading-button";
import {Spinner} from "@/components/spinner";
import {Button} from "@/components/ui/button";
import {Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card";
import {Collapsible, CollapsibleContent, CollapsibleTrigger,} from "@/components/ui/collapsible";
import {
Dialog,
DialogContent,
Expand All @@ -26,10 +15,10 @@ import {
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { useToast } from "@/components/ui/use-toast";
import { useDeploymentContext } from "@/contexts/DeploymentContext";
import { useIcContext } from "@/contexts/IcContext";
import { type Deployment } from "@/declarations/backend.did";
import {useToast} from "@/components/ui/use-toast";
import {useDeploymentContext} from "@/contexts/DeploymentContext";
import {useIcContext} from "@/contexts/IcContext";
import {type Deployment} from "@/declarations/backend.did";
import {
extractDeploymentCreated,
extractLeaseCreated,
Expand All @@ -41,25 +30,25 @@ import {
isDeploymentClosed,
isDeploymentFailed,
} from "@/helpers/deployment";
import { displayIcp } from "@/helpers/ui";
import { queryLeaseStatus } from "@/services/deployment";
import { DeploymentTier } from "@/types/deployment";
import { ChevronsUpDown } from "lucide-react";
import { useRouter } from "next/navigation";
import { useCallback, useEffect, useState } from "react";
import {displayIcp} from "@/helpers/ui";
import {queryLeaseStatus, sendManifestToProvider} from "@/services/deployment";
import {DeploymentTier} from "@/types/deployment";
import {ChevronsUpDown} from "lucide-react";
import {useRouter} from "next/navigation";
import {useCallback, useEffect, useState} from "react";

export default function Dashboard() {
const router = useRouter();
const { isLoggedIn, backendActor } = useIcContext();
const { deployments, fetchDeployments, loadOrCreateCertificate } =
const {isLoggedIn, backendActor} = useIcContext();
const {deployments, fetchDeployments, loadOrCreateCertificate} =
useDeploymentContext();
const [isClosingDeployment, setIsClosingDeployment] = useState(false);
const [dialogDeploymentId, setDialogDeploymentId] = useState<string>();
const [isStatusDialogOpen, setIsStatusDialogOpen] = useState(false);
const [isFetchingStatus, setIsFetchingStatus] = useState(false);
const [leaseStatusData, setLeaseStatusData] =
useState<Record<string, unknown>>();
const { toast } = useToast();
const {toast} = useToast();

const handleNewDeployment = useCallback(async () => {
router.push("/dashboard/new-deployment");
Expand Down Expand Up @@ -92,10 +81,10 @@ export default function Dashboard() {
try {
const certData = await loadOrCreateCertificate(backendActor!);
const updates = deployment.state_history.map(([_, d]) => d);
const { dseq } = extractDeploymentCreated(
const {dseq} = extractDeploymentCreated(
updates.find((el) => el.hasOwnProperty("DeploymentCreated"))!
);
const { provider_url } = extractLeaseCreated(
const {provider_url} = extractLeaseCreated(
updates.find((el) => el.hasOwnProperty("LeaseCreated"))!
);

Expand Down Expand Up @@ -129,6 +118,41 @@ export default function Dashboard() {
}
}, [isLoggedIn, fetchDeployments, backendActor]);

useEffect(() => {
checkDeploymentState();
}, [deployments]);

const checkDeploymentState = useCallback(async () => {
for (const deployment of deployments) {
const lastState = deployment.deployment.state_history[deployment.deployment.state_history.length - 1][1];
if ("LeaseCreated" in lastState) {
try {
const cert = await loadOrCreateCertificate(backendActor!);

const deploymentCreatedState = deployment.deployment.state_history.find(([_, state]) => "DeploymentCreated" in state)!;
const {manifest_sorted_json, dseq} = extractDeploymentCreated(
deploymentCreatedState[1]
);

const {provider_url} = lastState.LeaseCreated;

const manifestUrl = new URL(
`/deployment/${dseq}/manifest`,
provider_url
);

await sendManifestToProvider(
manifestUrl.toString(),
manifest_sorted_json,
cert!
);
} catch (e) {
console.error(e);
}
}
}
}, [deployments]);

return (
<div className="flex-1 space-y-4 p-8 pt-6">
<div className="flex items-center justify-between space-y-2">
Expand All @@ -144,7 +168,9 @@ export default function Dashboard() {
<Card key={el.id}>
<CardHeader>
<CardTitle className="text-sm font-medium">{el.deployment.params.name}</CardTitle>
<CardDescription><pre className="font-xs">{el.id}</pre></CardDescription>
<CardDescription>
<pre className="font-xs">{el.id}</pre>
</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-1">
<div>
Expand All @@ -163,17 +189,17 @@ export default function Dashboard() {
Tier:
{/* TODO: display the actual deployment tier */}
<div className="border rounded-md px-3 py-2">
<Tier tier={DeploymentTier.SMALL} />
<Tier tier={DeploymentTier.SMALL}/>
</div>
</div>
<div className="flex flex-row gap-1">
Price:
<pre>{displayIcp(el.deployment.icp_price, { maximumFractionDigits: 6 })}</pre>
<pre>{displayIcp(el.deployment.icp_price, {maximumFractionDigits: 6})}</pre>
</div>
<Collapsible>
<CollapsibleTrigger className="flex items-center gap-4 w-full mt-4">
Status history
<ChevronsUpDown className="h-4 w-4" />
<ChevronsUpDown className="h-4 w-4"/>
</CollapsibleTrigger>
<CollapsibleContent className="flex flex-col gap-1">
{el.deployment.state_history.map((item, i) => (
Expand Down Expand Up @@ -209,7 +235,7 @@ export default function Dashboard() {
<DialogTitle>Deployment status</DialogTitle>
<DialogDescription>
{isFetchingStatus ? (
<Spinner />
<Spinner/>
) : (
Boolean(leaseStatusData) && (
<span className="font-mono">
Expand Down Expand Up @@ -237,9 +263,9 @@ export default function Dashboard() {
<DialogTitle>Are you sure?</DialogTitle>
<DialogDescription>
Deployment id to close:
<br />
<br/>
<span className="font-mono text-nowrap">{el.id}</span>
<br />
<br/>
<b>This action cannot be undone.</b>
</DialogDescription>
</DialogHeader>
Expand Down

0 comments on commit 9caa66d

Please sign in to comment.