feat: show ip info
This commit is contained in:
parent
3c7736dae7
commit
1f5506a920
10
src/api.ts
10
src/api.ts
@ -54,6 +54,11 @@ export interface VmStatus {
|
||||
disk_read: number;
|
||||
}
|
||||
|
||||
export interface VmIpAssignment {
|
||||
id: number;
|
||||
ip: string;
|
||||
}
|
||||
|
||||
export interface VmInstance {
|
||||
id: number;
|
||||
host_id: number;
|
||||
@ -61,8 +66,8 @@ export interface VmInstance {
|
||||
image_id: number;
|
||||
template_id: number;
|
||||
ssh_key_id: number;
|
||||
created: Date;
|
||||
expires: Date;
|
||||
created: string;
|
||||
expires: string;
|
||||
cpu: number;
|
||||
memory: number;
|
||||
disk_size: number;
|
||||
@ -72,6 +77,7 @@ export interface VmInstance {
|
||||
template?: VmTemplate;
|
||||
image?: VmOsImage;
|
||||
ssh_key?: UserSshKey;
|
||||
ip_assignments: Array<VmIpAssignment>;
|
||||
}
|
||||
|
||||
export interface VmOsImage {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { MouseEventHandler } from "react";
|
||||
|
||||
import Icons from "../icons.svg";
|
||||
import Icons from "../icons.svg?url";
|
||||
|
||||
type Props = {
|
||||
name: string;
|
||||
|
@ -11,16 +11,25 @@ export default function VmActions({ vm }: { vm: VmInstance }) {
|
||||
name={state === "running" ? "stop" : "start"}
|
||||
className="bg-neutral-700 p-2 rounded-lg hover:bg-neutral-600"
|
||||
size={40}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
<Icon
|
||||
name="delete"
|
||||
className="bg-neutral-700 p-2 rounded-lg hover:bg-neutral-600"
|
||||
size={40}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
<Icon
|
||||
name="refresh-1"
|
||||
className="bg-neutral-700 p-2 rounded-lg hover:bg-neutral-600"
|
||||
size={40}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,15 +1,19 @@
|
||||
import { Link } from "react-router-dom";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { VmInstance } from "../api";
|
||||
import OsImageName from "./os-image-name";
|
||||
import VpsResources from "./vps-resources";
|
||||
import VmActions from "./vps-actions";
|
||||
|
||||
export default function VpsInstanceRow({ vm }: { vm: VmInstance }) {
|
||||
export default function VpsInstanceRow({ vm, actions }: { vm: VmInstance, actions?: boolean }) {
|
||||
const expires = new Date(vm.expires);
|
||||
const isExpired = expires <= new Date();
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className="flex justify-between items-center rounded-xl bg-neutral-900 px-3 py-2 cursor-pointer hover:bg-neutral-800">
|
||||
<div className="flex justify-between items-center rounded-xl bg-neutral-900 px-3 py-2 cursor-pointer hover:bg-neutral-800"
|
||||
onClick={() => navigate("/vm", {
|
||||
state: vm
|
||||
})}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div>
|
||||
<span className="text-sm text-neutral-400">#{vm.id}</span>
|
||||
@ -22,7 +26,7 @@ export default function VpsInstanceRow({ vm }: { vm: VmInstance }) {
|
||||
</div>
|
||||
<VpsResources vm={vm} />
|
||||
</div>
|
||||
<div className="flex gap-2 items-center">
|
||||
{(actions ?? true) && <div className="flex gap-2 items-center">
|
||||
{isExpired && (
|
||||
<>
|
||||
<Link to="/vm/renew" className="text-red-500 text-sm" state={vm}>
|
||||
@ -31,7 +35,7 @@ export default function VpsInstanceRow({ vm }: { vm: VmInstance }) {
|
||||
</>
|
||||
)}
|
||||
{!isExpired && <VmActions vm={vm} />}
|
||||
</div>
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ export const GB = KB * 1000;
|
||||
export const TB = GB * 1000;
|
||||
export const PB = TB * 1000;
|
||||
|
||||
//export const ApiUrl = "http://localhost:8000";
|
||||
export const ApiUrl = "https://api.lnvps.net";
|
||||
export const ApiUrl = "http://localhost:8000";
|
||||
//export const ApiUrl = "https://api.lnvps.net";
|
||||
|
||||
export const NostrProfile = new NostrLink(
|
||||
NostrPrefix.Profile,
|
||||
|
@ -23,7 +23,7 @@ export default function AccountPage() {
|
||||
<h3>My Resources</h3>
|
||||
<div className="flex flex-col gap-2">
|
||||
{vms.map((a) => (
|
||||
<VpsInstanceRow key={a.id} vm={a} />
|
||||
<VpsInstanceRow key={a.id} vm={a} actions={false} />
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
|
@ -6,6 +6,8 @@ import { ApiUrl } from "../const";
|
||||
import { EventPublisher } from "@snort/system";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import VpsPayment from "../components/vps-payment";
|
||||
import CostLabel from "../components/cost";
|
||||
import { AsyncButton } from "../components/button";
|
||||
|
||||
export default function VmPage() {
|
||||
const { state } = useLocation() as { state?: VmInstance };
|
||||
@ -39,7 +41,24 @@ export default function VmPage() {
|
||||
}
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<VpsInstanceRow vm={state} />
|
||||
<VpsInstanceRow vm={state} actions={false} />
|
||||
{action === undefined && <>
|
||||
<div className="text-xl">Renewal</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<div>{new Date(state.expires).toDateString()}</div>
|
||||
{state.template?.cost_plan && <div><CostLabel cost={state.template?.cost_plan} /></div>}
|
||||
</div>
|
||||
<AsyncButton onClick={() => navigate("/vm/renew", { state })}>
|
||||
Extend Now
|
||||
</AsyncButton>
|
||||
<div className="text-xl">Network</div>
|
||||
<div className="flex gap-4">
|
||||
{(state.ip_assignments?.length ?? 0) === 0 && <div className="text-sm text-red-500">No IP's assigned</div>}
|
||||
{state.ip_assignments?.map(a => <div key={a.id} className="text-sm bg-neutral-900 px-3 py-1 rounded-lg">
|
||||
{a.ip.split("/")[0]}
|
||||
</div>)}
|
||||
</div>
|
||||
</>}
|
||||
{action === "renew" && (
|
||||
<>
|
||||
<h3>Renew VPS</h3>
|
||||
@ -56,6 +75,7 @@ export default function VmPage() {
|
||||
navigate("/vm", {
|
||||
state: newState,
|
||||
});
|
||||
setPayment(undefined);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
Loading…
x
Reference in New Issue
Block a user