Skip to content

Commit

Permalink
feat(provider): provider pricing feature (#475)
Browse files Browse the repository at this point in the history
* added server-access and server-form files

* added wallet import page - wip, fixed issue with file upload in server access forms

* added become-provider steps ui

* server access step added with state support

* added provider config and provider attribute screen

* added provider process with hoc to prevent access to pages

* added progress for becoming prvider for final stage

* Code clean up and added navigation logic to homecontainer

* package lock updated

* more cleanup and remove general warnings

* removed unused npm package

* fix minor error on api

* Added dashboard and actions page

* change status api endpoint

* added stat line and pie charts

* Added console apis to get dashboard data and show appropriate details

* fixed actions and changed home component

* token varification and refresh token fix

* changed wallet connect from wallet status to wallet provider

* fixed issue in loading provider status

* fixed home loading issue

* fixed refresh token, added disabled menu items

* fixed build process

* feat(provider): added sentry and docker

* fix(provider): fixed wallet switching and getting status

* feat(provider): reduced number of events in dashboard

* feat(provider): added docker compose changes for provider-console

* feat(provider): added deployments and deployment detail page

* fix(provider): change hours to seconds for calculation purpose)

* feat(provider): added auth for deployments and deployment details page

* feat(provider): added env and removed settingsprovider

* fix(provider): fix lint errors and removed console.logs

* fix(provider): become-provider looped, fixed it

* fix(provider): router and reset process fixed

* fix(provider): removed Get Started button for now

* fix(provider): removed unused import in nav

* fix(provider): change functions to react fc component

* fix(provider): fix lint issues

* fix(provider): change functions to react fc component

* fix(provider): added docker build and fix build related issues

* feat(provider): control machine edit, add from sidebar

* feat(provider): added attributes screen

* fix(provider): control machine auto connect on page load

* fix(provider): fix loading not showing while connecting provider control machine

* fix(provider): close drawer on successfull connection

* feat(provider): change favicon to akash favicon

* feat(provider): provider add, edit and remove and show acitons list page

* fix(provider): fix url when provider process finish

* feat(provider): provider pricing feature added

* feat(provider): added pricing update and extracted provider context

* fix(provider): auto import and lint issues fixed

* fix(provider): pricing loading screen fix

* fix(provider): merge issues with main

* fix(provider): pricing update fix

* chore: package-lock modified

* fix(provider): added types for known props
  • Loading branch information
jigar-arc10 authored Dec 10, 2024
1 parent db4fe40 commit 14d73fa
Show file tree
Hide file tree
Showing 11 changed files with 538 additions and 87 deletions.
299 changes: 235 additions & 64 deletions apps/provider-console/src/components/become-provider/ProviderPricing.tsx

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions apps/provider-console/src/components/layout/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ export const Sidebar: React.FC<Props> = ({ isMobileOpen, handleDrawerToggle, isN
{
title: "Pricing",
icon: props => <Calculator {...props} />,
url: "#",
activeRoutes: ["#"],
disabled: true
url: UrlService.pricing(),
activeRoutes: [UrlService.pricing()],
disabled: false
},
{
title: "Attributes",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"use client";
import React from "react";
import { useQuery } from "react-query";

import { ProviderDashoard, ProviderDetails } from "@src/types/provider";
import consoleClient from "@src/utils/consoleClient";
import { useWallet } from "../WalletProvider";

type ContextType = {
providerDetails: ProviderDetails | undefined;
providerDashboard: ProviderDashoard | undefined;
isLoadingProviderDetails: boolean;
isLoadingProviderDashboard: boolean;
};

const ProviderContext = React.createContext<ContextType>({} as ContextType);

export const ProviderContextProvider = ({ children }) => {
const { address } = useWallet();

const {
data: providerDetails,
isLoading: isLoadingProviderDetails
} = useQuery<ProviderDetails>(
"providerDetails",
async () => (await consoleClient.get(`/v1/providers/${address}`)).data,
{
refetchOnWindowFocus: false,
retry: 3,
enabled: !!address
}
);

const { data: providerDashboard, isLoading: isLoadingProviderDashboard } = useQuery<ProviderDashoard>(
"providerDashboard",
async () => (await consoleClient.get(`/internal/provider-dashboard/${address}`)),
{
refetchOnWindowFocus: false,
retry: 3,
enabled: !!address
}
);

return (
<ProviderContext.Provider
value={{
providerDetails,
providerDashboard,
isLoadingProviderDetails,
isLoadingProviderDashboard
}}
>
{children}
</ProviderContext.Provider>
);
};

export const useProvider = () => {
return { ...React.useContext(ProviderContext) };
};
1 change: 1 addition & 0 deletions apps/provider-console/src/context/ProviderContext/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ProviderContextProvider as ProviderContext, useProvider } from "./ProviderContext";
5 changes: 4 additions & 1 deletion apps/provider-console/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ControlMachineProvider } from "@src/context/ControlMachineProvider";
import { CustomChainProvider } from "@src/context/CustomChainProvider";
import { ColorModeProvider } from "@src/context/CustomThemeContext";
import { PricingProvider } from "@src/context/PricingProvider";
import { ProviderContextProvider } from "@src/context/ProviderContext/ProviderContext";
import { WalletProvider } from "@src/context/WalletProvider";
import { queryClient } from "@src/queries";
import { cn } from "@src/utils/styleUtils";
Expand All @@ -28,7 +29,9 @@ export default function App({ Component, pageProps }: AppProps) {
<CustomChainProvider>
<WalletProvider>
<ControlMachineProvider>
<Component {...pageProps} />
<ProviderContextProvider>
<Component {...pageProps} />
</ProviderContextProvider>
</ControlMachineProvider>
</WalletProvider>
</CustomChainProvider>
Expand Down
34 changes: 15 additions & 19 deletions apps/provider-console/src/pages/dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import { Layout } from "@src/components/layout/Layout";
import { ProviderActionList } from "@src/components/shared/ProviderActionList";
import { Title } from "@src/components/shared/Title";
import { withAuth } from "@src/components/shared/withAuth";
import { useSelectedChain } from "@src/context/CustomChainProvider";
import { useWallet } from "@src/context/WalletProvider";
import { useAKTData } from "@src/queries";
import { useProviderActions, useProviderDashboard, useProviderDetails } from "@src/queries/useProviderQuery";
import { formatUUsd } from "@src/utils/formatUsd";
import { useSelectedChain } from "@src/context/CustomChainProvider";

const OfflineWarningBanner: React.FC = () => (
<div className="mb-4 rounded-md bg-yellow-100 p-4 text-yellow-700">
Expand Down Expand Up @@ -145,25 +145,21 @@ const Dashboard: React.FC = () => {
)}
</div>
</div>
{isOnline && providerDetails && (
<>
<div className="mt-8">
<div className="text-sm font-semibold">Resources Leased Summary</div>
<div className="mt-2">
{isLoadingProviderDetails ? (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<DashboardCardSkeleton />
<DashboardCardSkeleton />
<DashboardCardSkeleton />
<DashboardCardSkeleton />
</div>
) : (
<ResourceCards providerDetails={providerDetails} />
)}
<div className="mt-8">
<div className="text-sm font-semibold">Resources Leased Summary</div>
<div className="mt-2">
{isLoadingProviderDetails ? (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<DashboardCardSkeleton />
<DashboardCardSkeleton />
<DashboardCardSkeleton />
<DashboardCardSkeleton />
</div>
</div>
</>
)}
) : (
<ResourceCards providerDetails={providerDetails} />
)}
</div>
</div>

<Separator className="mt-10" />
<div className="mt-8">
Expand Down
95 changes: 95 additions & 0 deletions apps/provider-console/src/pages/pricing/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React, { useEffect, useState } from "react";
import { Alert, AlertDescription, AlertTitle, Spinner } from "@akashnetwork/ui/components";

import { ProviderPricing } from "@src/components/become-provider/ProviderPricing";
import { Layout } from "@src/components/layout/Layout";
import { useControlMachine } from "@src/context/ControlMachineProvider";
import { useProvider } from "@src/context/ProviderContext";
import { ProviderPricingType } from "@src/types/provider";
import restClient from "@src/utils/restClient";
import { convertFromPricingAPI, sanitizeMachineAccess } from "@src/utils/sanityUtils";

const Pricing: React.FunctionComponent = () => {
const { activeControlMachine, controlMachineLoading } = useControlMachine();
const [existingPricing, setExistingPricing] = useState<ProviderPricingType | undefined>(undefined);
const [isLoading, setIsLoading] = useState(false);
const { providerDetails } = useProvider();

const fetchPricing = async () => {
try {
setIsLoading(true);
const request = {
control_machine: sanitizeMachineAccess(activeControlMachine)
};
const response: any = await restClient.post("/get-provider-pricing", request);
if (response) {
setExistingPricing(convertFromPricingAPI(response.pricing));
}
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
};

useEffect(() => {
if (activeControlMachine) {
fetchPricing();
}
}, [activeControlMachine]);

return (
<Layout>
<div className="relative">
{isLoading && (
<div className="absolute inset-0 z-50 flex items-center justify-center bg-white/80">
<div className="flex items-center gap-2">
<Spinner />
<span className="text-sm text-gray-600">Loading provider pricing...</span>
</div>
</div>
)}

<div className={isLoading ? "pointer-events-none" : ""}>
{!activeControlMachine && !controlMachineLoading && (
<Alert variant="destructive">
<AlertTitle>Control Machine Required</AlertTitle>
<AlertDescription>Please connect your control machine first to start updating pricing settings.</AlertDescription>
</Alert>
)}
{controlMachineLoading && (
<Alert>
<AlertTitle>Connecting to Control Machine</AlertTitle>
<AlertDescription className="flex items-center gap-2">
<div className="flex items-center gap-2">
<Spinner className="h-4 w-4" />
<span>Please wait while we check control machine access...</span>
</div>
</AlertDescription>
</Alert>
)}
{activeControlMachine && !existingPricing && (
<Alert variant="destructive">
<AlertTitle>Unable to fetch pricing</AlertTitle>
<AlertDescription className="flex items-center justify-between">
Please try again later.
<button onClick={fetchPricing} className="rounded bg-red-100 px-3 py-1 text-sm text-red-900 hover:bg-red-200">
Try Again
</button>
</AlertDescription>
</Alert>
)}
<ProviderPricing
existingPricing={existingPricing}
editMode={true}
stepChange={() => {}}
disabled={activeControlMachine && existingPricing ? false : true}
providerDetails={providerDetails}
/>
</div>
</div>
</Layout>
);
};

export default Pricing;
111 changes: 111 additions & 0 deletions apps/provider-console/src/types/provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
export interface ProviderDetails {
owner: string;
name: string | null;
hostUri: string;
createdHeight: number;
email: string | null;
website: string;
lastCheckDate: string;
deploymentCount: number;
leaseCount: number;
cosmosSdkVersion: string | null;
akashVersion: string | null;
ipRegion: string;
ipRegionCode: string;
ipCountry: string;
ipCountryCode: string;
ipLat: string;
ipLon: string;
activeStats: Stats;
pendingStats: Stats;
availableStats: Stats;
gpuModels: string[];
uptime1d: number;
uptime7d: number;
uptime30d: number;
isValidVersion: boolean;
isOnline: boolean;
lastOnlineDate: string;
isAudited: boolean;
attributes: Attribute[];
host: string | null;
organization: string | null;
statusPage: string | null;
locationRegion: string[];
country: string | null;
city: string | null;
timezone: string[];
locationType: string[];
hostingProvider: string | null;
hardwareCpu: string[];
hardwareCpuArch: string[];
hardwareGpuVendor: string[];
hardwareGpuModels: string[];
hardwareDisk: string[];
featPersistentStorage: boolean;
featPersistentStorageType: string[];
hardwareMemory: string[];
networkProvider: string | null;
networkSpeedDown: number;
networkSpeedUp: number;
tier: string[];
featEndpointCustomDomain: boolean;
workloadSupportChia: boolean;
workloadSupportChiaCapabilities: string[];
featEndpointIp: boolean;
uptime: Uptime[];
}

interface Stats {
cpu: number;
gpu: number;
memory: number;
storage: number;
}

interface Attribute {
key: string;
value: string;
auditedBy: string[];
}

interface Uptime {
id: string;
isOnline: boolean;
checkDate: string;
}

interface LeaseStats {
date: string;
height: number;
activeLeaseCount: number;
totalLeaseCount: number;
dailyLeaseCount: number;
totalUAktEarned: number;
dailyUAktEarned: number;
totalUUsdcEarned: number;
dailyUUsdcEarned: number;
totalUUsdEarned: number;
dailyUUsdEarned: number;
activeCPU: number;
activeGPU: number;
activeMemory: string;
activeEphemeralStorage: string;
activePersistentStorage: string;
activeStorage: string;
}

export interface ProviderDashoard {
current: LeaseStats;
previous: LeaseStats;
}

export interface ProviderPricingType {
cpu: number;
memory: number;
storage: number;
persistentStorage: number;
gpu: number;
ipScalePrice: number;
endpointBidPrice: number;
}
12 changes: 12 additions & 0 deletions apps/provider-console/src/utils/sanityUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@ export function sanitizeMachineAccess(machine: ControlMachineWithAddress | null)
passphrase: machine.access.passphrase || null
};
}

export function convertFromPricingAPI(pricing: any) {
return {
cpu: pricing.price_target_cpu,
memory: pricing.price_target_memory,
storage: pricing.price_target_hd_ephemeral,
persistentStorage: pricing.price_target_hd_pers_ssd,
gpu: Number(pricing.price_target_gpu_mappings.split('=')[1]),
ipScalePrice: pricing.price_target_ip,
endpointBidPrice: pricing.price_target_endpoint
};
}
1 change: 1 addition & 0 deletions apps/provider-console/src/utils/urlUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ export class UrlService {
static privacyPolicy = () => "/privacy-policy";
static termsOfService = () => "/terms-of-service";
static actions = () => "/actions";
static pricing = () => "/pricing";
}
1 change: 1 addition & 0 deletions packages/ui/components/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const alertVariants = cva(
variants: {
variant: {
default: "bg-background text-foreground",
success: "border-success/50 text-success dark:border-success [&>svg]:text-success",
destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
warning: "border-warning/50 text-warning dark:border-warning-500 [&>svg]:text-warning"
}
Expand Down

0 comments on commit 14d73fa

Please sign in to comment.