From 82c88aeb6e5e49c7ba5a855f37a2eaae7fb6ee6d Mon Sep 17 00:00:00 2001 From: Mateusz Rybczonek Date: Thu, 19 Oct 2023 14:16:59 +0200 Subject: [PATCH 1/8] feat(happ-details): implement new route and components --- package.json | 2 +- src/components/PrimaryLayout.vue | 3 +- src/components/StopHostingModal.vue | 4 +- .../hAppDetails/HAppDetailsContent.vue | 173 ++++++ .../hAppDetails/HAppDetailsEarnings.vue | 59 +++ .../hAppDetails/HAppDetailsStopHosting.vue | 94 ++++ .../hAppDetails/HAppDetailsUsage.vue | 113 ++++ src/interfaces/HposInterface.ts | 53 ++ src/locales/en.ts | 15 + src/pages/HAppsPage.vue | 34 +- src/pages/HappDetails.vue | 499 +++--------------- src/store/dashboard.ts | 12 +- 12 files changed, 610 insertions(+), 451 deletions(-) create mode 100644 src/components/hAppDetails/HAppDetailsContent.vue create mode 100644 src/components/hAppDetails/HAppDetailsEarnings.vue create mode 100644 src/components/hAppDetails/HAppDetailsStopHosting.vue create mode 100644 src/components/hAppDetails/HAppDetailsUsage.vue diff --git a/package.json b/package.json index 7fa0e3c8..85e7de98 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "host-console", - "version": "1.0.0-alpha.7", + "version": "1.0.0-alpha.8", "private": true, "homepage": "https://holo-host.github.io/host-console-ui/", "scripts": { diff --git a/src/components/PrimaryLayout.vue b/src/components/PrimaryLayout.vue index 9bc9c43b..e3e5925a 100644 --- a/src/components/PrimaryLayout.vue +++ b/src/components/PrimaryLayout.vue @@ -26,12 +26,13 @@ const { showModal } = useModals() const props = withDefaults( defineProps<{ - title: string + title?: string breadcrumbs?: BreadCrumb[] isContentLoading?: boolean isContentError?: boolean }>(), { + title: '', breadcrumbs: undefined, isContentLoading: false, isContentError: false diff --git a/src/components/StopHostingModal.vue b/src/components/StopHostingModal.vue index 9ed0fbe0..7e7c0593 100644 --- a/src/components/StopHostingModal.vue +++ b/src/components/StopHostingModal.vue @@ -3,7 +3,7 @@

- Are you sure you want to stop hosting {{ happName }}? + Are you sure you want to stop hosting {{ hAppName }}?

It will be removed from your HoloPort and will not be available for you to host again for 30 days. All invoices, logs and payments associated with this hApp will remain available to you. @@ -59,7 +59,7 @@ export default { }, props: { - happName: { + hAppName: { type: String, required: true } diff --git a/src/components/hAppDetails/HAppDetailsContent.vue b/src/components/hAppDetails/HAppDetailsContent.vue new file mode 100644 index 00000000..15327cbb --- /dev/null +++ b/src/components/hAppDetails/HAppDetailsContent.vue @@ -0,0 +1,173 @@ + + + + + diff --git a/src/components/hAppDetails/HAppDetailsEarnings.vue b/src/components/hAppDetails/HAppDetailsEarnings.vue new file mode 100644 index 00000000..7ee25bf3 --- /dev/null +++ b/src/components/hAppDetails/HAppDetailsEarnings.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/src/components/hAppDetails/HAppDetailsStopHosting.vue b/src/components/hAppDetails/HAppDetailsStopHosting.vue new file mode 100644 index 00000000..df3ba05c --- /dev/null +++ b/src/components/hAppDetails/HAppDetailsStopHosting.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/src/components/hAppDetails/HAppDetailsUsage.vue b/src/components/hAppDetails/HAppDetailsUsage.vue new file mode 100644 index 00000000..79bb03e4 --- /dev/null +++ b/src/components/hAppDetails/HAppDetailsUsage.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/src/interfaces/HposInterface.ts b/src/interfaces/HposInterface.ts index 901c641b..a9ede21c 100644 --- a/src/interfaces/HposInterface.ts +++ b/src/interfaces/HposInterface.ts @@ -12,6 +12,7 @@ interface HposInterface { getUsage: () => Promise getTopHostedHapps: () => Promise getHostedHapps: () => Promise + getHAppDetails: (id: string) => Promise getHostEarnings: () => Promise getHostPreferences: () => Promise checkAuth: (email: string, password: string, authToken: string) => Promise @@ -110,6 +111,7 @@ export interface HostPreferencesResponse { type HposHolochainCallResponse = | HostEarnings | HApp[] + | HAppDetails | UsageResponse | HposStatusResponse | HoloFuelProfileResponse @@ -147,6 +149,28 @@ export interface HApp { } } +export interface HAppDetails { + id: string + name: string + description: string + categories: string[] + enabled: boolean + isPaused: boolean + sourceChains: number + daysHosted: number + earnings: { + total: number + last7Days: number + averageWeekly: number + } + last7DaysUsage: { + bandwidth: number + cpu: number + storage: number + } + hostingPlan: 'paid' | 'free' +} + export interface Earnings { last30days: number | string last7days: number | string @@ -218,6 +242,10 @@ function isHappArray(array: unknown): array is HApp[] { return Array.isArray(array) } +function isHAppDetails(data: unknown): data is HAppDetails { + return typeof data === 'object' && data !== null +} + interface HposCallArgs { pathPrefix?: string method: string @@ -415,6 +443,30 @@ export function useHposInterface(): HposInterface { } } + async function getHAppDetails( + id: string + ): Promise { + try { + const result = await hposHolochainCall({ + method: 'get', + path: '/happ', + params: { + id + } + }) + + if (isHAppDetails(result)) { + return result + } else { + console.error("getHAppDetails didn't return a HAppDetails object") + return { error: "getHAppDetails didn't return a HAppDetails object" } + } + } catch (error) { + console.error('getHAppDetails encountered an error: ', error) + return { error } + } + } + async function getHostEarnings(): Promise { try { return await hposHolochainCall({ @@ -764,6 +816,7 @@ export function useHposInterface(): HposInterface { getHostPreferences, redeemHoloFuel, getKycLevel, + getHAppDetails, HPOS_API_URL } } diff --git a/src/locales/en.ts b/src/locales/en.ts index 202b2577..3894b3b5 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -5,9 +5,12 @@ export default { ...commonTranslations.$, app_name: 'Host Console', back: 'Back', + bandwidth: 'Bandwidth', + cpu: 'CPU', dashboard: 'Dashboard', date: 'Date', days: 'days', + description: 'Description', earnings: 'Earnings', generic_error: 'Sorry, we couldn’t fetch this data.', happs: 'hApps', @@ -18,6 +21,7 @@ export default { learn_more: 'Learn more', logout: 'Logout', next: 'Next', + storage: 'Storage', terms_of_service: 'Terms of Service', try_again: 'Try again' }, @@ -37,6 +41,17 @@ export default { unpaid_invoices: 'Unpaid Invoices', weekly_earnings: 'Weekly Earnings' }, + happ_details: { + earnings: { + total: 'Total Earnings', + last_7_days: 'Earned in last 7 days', + average_weekly: 'Average weekly earnings' + }, + stop_hosting: 'Stop Hosting', + stop_hosting_warning: 'Stopping hosting of a hApp will remove it and all associated data from your HoloPort.', + total_source_chains: 'Total source chains', + total_usage: 'Total usage' + }, holofuel: { balance: 'Balance', go_to_holofuel: 'Open HoloFuel', diff --git a/src/pages/HAppsPage.vue b/src/pages/HAppsPage.vue index 435e6b48..a3d731f2 100644 --- a/src/pages/HAppsPage.vue +++ b/src/pages/HAppsPage.vue @@ -7,10 +7,11 @@ import { computed, onMounted, ref } from 'vue' import SortByDropdown from '@/components/hApps/SortByDropdown.vue' import PrimaryLayout from '@/components/PrimaryLayout.vue' import { kSortOptions } from '@/constants/ui' -import { HApp, useHposInterface } from '@/interfaces/HposInterface' +import type { HApp } from '@/interfaces/HposInterface' +import { useDashboardStore } from '@/store/dashboard' import { isError as isErrorPredicate } from '@/types/predicates' -const { getHostedHapps } = useHposInterface() +const store = useDashboardStore() const isLoading = ref(false) const isError = ref(false) @@ -28,10 +29,11 @@ function onFilterChange({ value, isActive }: FilterChangeProps): void { filterValue.value = value } -const happs = ref([]) const sortBy = ref(kSortOptions.alphabetical.value) -const filteredHapps = computed((): HApp[] => { +const hostedHApps = computed((): HApp[] | { error: unknown } => store.hostedHApps) + +const filteredHApps = computed((): HApp[] => { const sortByLogic: (a: HApp, b: HApp) => number = // Sorting by earnings is not available now as we don't have a property // like that in the HApp, we use 'sourceChains' for now @@ -39,18 +41,18 @@ const filteredHapps = computed((): HApp[] => { ? (a: HApp, b: HApp): number => (a.sourceChains < b.sourceChains ? 1 : -1) : (a: HApp, b: HApp): number => (a.name > b.name ? 1 : -1) - if (isErrorPredicate(happs.value) && happs.value.error) { + if (isErrorPredicate(hostedHApps.value) && hostedHApps.value.error) { return [] } - if (!isErrorPredicate(happs.value) && filterIsActive.value && filterValue.value) { - return happs.value + if (!isErrorPredicate(hostedHApps.value) && filterIsActive.value && filterValue.value) { + return hostedHApps.value .filter((hApp: HApp) => hApp.name.toLowerCase().includes(filterValue.value.toLowerCase())) .sort(sortByLogic) } - if (!isErrorPredicate(happs.value)) { - return [...happs.value].sort(sortByLogic) + if (!isErrorPredicate(hostedHApps.value)) { + return [...hostedHApps.value].sort(sortByLogic) } return [] @@ -66,9 +68,9 @@ async function getData(): Promise { isError.value = false isLoading.value = true - happs.value = await getHostedHapps() + await store.getHostedHApps() - if (isErrorPredicate(happs.value) && happs.value.error) { + if (isErrorPredicate(hostedHApps.value) && hostedHApps.value.error) { isError.value = true } @@ -106,18 +108,18 @@ onMounted(async () => {