Skip to content

Commit

Permalink
feat: old HW firmware/node notification (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexey-yarmosh authored and MartinKolarik committed Jan 28, 2025
1 parent 4eb276d commit cdcbd89
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 27 deletions.
11 changes: 6 additions & 5 deletions components/AddCredits.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
}"
>
<div class="flex items-center justify-between max-sm:flex-col max-sm:text-center">
<div class="ml-2">You get <span class="ml-1.5 whitespace-nowrap rounded-full border bg-surface-0 px-2.5 py-1.5 max-sm:leading-10 dark:bg-dark-700"><span class="font-bold" :class="{'text-primary': step2Completed}">+{{ creditsPerAdoptedProbePerDay }} credits</span> / probe / day</span></div>
<div class="ml-2">You get <span class="ml-1.5 whitespace-nowrap rounded-full border bg-surface-0 px-2.5 py-1.5 max-sm:leading-10 dark:bg-dark-700"><span class="font-bold" :class="{'text-primary': step2Completed}">+{{ creditsPerAdoptedProbe }} credits</span> / probe / day</span></div>
<Button
v-if="!step1Completed"
disabled
Expand Down Expand Up @@ -156,24 +156,25 @@
<script setup lang="ts">
import { readItems } from '@directus/sdk';
import { useAuth } from '~/store/auth';
import { useMetadata } from '~/store/metadata';
const { $directus } = useNuxtApp();
const config = useRuntimeConfig();
const auth = useAuth();
const metadata = useMetadata();
const user = auth.getUser as User;
defineEmits([ 'cancel', 'adopt-a-probe' ]);
const { data: adoptionsExists } = await useAsyncData('gp_adopted_probes_exist', async () => {
const { data: adoptionsExists } = await useLazyAsyncData('gp_adopted_probes_exist', async () => {
const adoptions = await $directus.request(readItems('gp_adopted_probes', {
filter: { userId: { _eq: user.id } },
limit: 1,
}));
return !!adoptions.length;
}, { default: () => false });
const creditsPerAdoptedProbePerDay = config.public.creditsPerAdoptedProbePerDay;
const creditsPerDollar = config.public.creditsPerDollar;
const creditsPerAdoptedProbe = metadata.creditsPerAdoptedProbe;
const creditsPerDollar = metadata.creditsPerDollar;
const step1Completed = computed(() => auth.isLoggedIn);
const step2Completed = computed(() => adoptionsExists.value);
Expand Down
2 changes: 1 addition & 1 deletion layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
<Popover ref="notificationsPanel">
<Accordion v-if="reverseNotifications.length" class="box-border w-96 max-w-[calc(100vw-16px)]" expand-icon="pi pi-chevron-right">
<AccordionPanel v-for="notification in reverseNotifications" :key="notification.id" :value="notification.id" @click="markNotificationAsRead(notification.id)">
<AccordionHeader :class="{ '!font-normal': notification.status !== 'inbox' }">{{ notification.subject }}</AccordionHeader>
<AccordionHeader class="text-left" :class="{ '!font-normal': notification.status !== 'inbox' }">{{ notification.subject }}</AccordionHeader>
<AccordionContent>
<!-- eslint-disable-next-line vue/no-v-html -->
<span v-if="notification.message" class="notification" v-html="notification.message"/>
Expand Down
22 changes: 10 additions & 12 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@ export default defineNuxtConfig({
directusUrl: process.env.DIRECTUS_URL || 'https://dash-directus.globalping.io',
googleMapsKey: process.env.GOOGLE_MAPS_KEY,
itemsPerTablePage: 10,
creditsPerAdoptedProbePerDay: 150,
creditsPerDollar: 2000,
},
},
$development: {
runtimeConfig: {
serverUrl: process.env.DASH_URL || 'http://localhost:13010',
public: {
gpAuthUrl: process.env.GP_API_URL || 'http://localhost:13110',
directusUrl: process.env.DIRECTUS_URL || 'http://localhost:18055',
},
},
devtools: { enabled: true },
},
app: {
head: {
titleTemplate: '%s Globalping Dashboard',
Expand Down Expand Up @@ -53,14 +61,4 @@ export default defineNuxtConfig({
typescript: {
typeCheck: 'build',
},
$development: {
runtimeConfig: {
serverUrl: process.env.DASH_URL || 'http://localhost:13010',
public: {
gpAuthUrl: process.env.GP_API_URL || 'http://localhost:13110',
directusUrl: process.env.DIRECTUS_URL || 'http://localhost:18055',
},
},
devtools: { enabled: true },
},
});
6 changes: 4 additions & 2 deletions pages/credits.vue
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
import { aggregate, customEndpoint, readItems } from '@directus/sdk';
import { usePagination } from '~/composables/pagination';
import { useAuth } from '~/store/auth';
import { useMetadata } from '~/store/metadata';
import { formatDateForTable } from '~/utils/date-formatters';
import { sendErrorToast } from '~/utils/send-toast';
Expand All @@ -108,8 +109,9 @@
const auth = useAuth();
const user = auth.getUser as User;
const { $directus } = useNuxtApp();
const creditsPerAdoptedProbePerDay = config.public.creditsPerAdoptedProbePerDay;
const metadata = useMetadata();
const creditsPerAdoptedProbe = metadata.creditsPerAdoptedProbe;
const itemsPerPage = config.public.itemsPerTablePage;
const loading = ref(false);
const creditsChangesCount = ref(0);
Expand Down Expand Up @@ -157,7 +159,7 @@
const totalAdditions = computed(() => credits.value.additions.reduce((sum, addition) => sum + addition.amount, 0));
const totalDeductions = computed(() => credits.value.deductions.reduce((sum, deduction) => sum + deduction.amount, 0));
const dailyAdditions = computed(() => credits.value.todayOnlineProbes * creditsPerAdoptedProbePerDay);
const dailyAdditions = computed(() => credits.value.todayOnlineProbes * creditsPerAdoptedProbe);
const loadLazyData = async () => {
loading.value = true;
Expand Down
9 changes: 5 additions & 4 deletions pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
<div v-for="probe in adoptedProbes.slice(0, 10)" :key="probe.id" class="probe box-content min-w-60 py-2">
<component :is="useWindowSize().width.value > 640 ? 'div' : NuxtLink" :to="`/probes/${probe.id}`" class="block">
<div class="mb-6 grid grid-cols-[auto_1fr] grid-rows-[auto_auto] gap-x-3">
<BigIcon class="col-span-1 row-span-2" :name="probe.hardwareDevice ? 'probe' : 'docker'" border :status="probe.status"/>
<BigIcon class="col-span-1 row-span-2" :name="probe.hardwareDevice ? 'probe' : 'docker'" border :status="getProbeStatus(probe)"/>
<div
class="col-start-2 col-end-3 flex items-center font-bold"
>
Expand Down Expand Up @@ -176,15 +176,16 @@
import isEmpty from 'lodash/isEmpty';
import CountryFlag from 'vue-country-flag-next';
import { useAuth } from '~/store/auth';
import { useMetadata } from '~/store/metadata';
import { getProbeStatus } from '~/utils/probe-status';
import { sendErrorToast } from '~/utils/send-toast';
useHead({
title: 'Overview -',
});
const config = useRuntimeConfig();
const { $directus } = useNuxtApp();
const creditsPerAdoptedProbePerDay = config.public.creditsPerAdoptedProbePerDay;
const creditsPerAdoptedProbe = useMetadata().creditsPerAdoptedProbe;
const route = useRoute();
const router = useRouter();
Expand Down Expand Up @@ -255,7 +256,7 @@
return creditsObj ? creditsObj.amount : 0;
});
const perDay = computed(() => adoptedProbes.value.reduce((sum, { onlineTimesToday }) => sum += onlineTimesToday ? creditsPerAdoptedProbePerDay : 0, 0));
const perDay = computed(() => adoptedProbes.value.reduce((sum, { onlineTimesToday }) => sum += onlineTimesToday ? creditsPerAdoptedProbe : 0, 0));
// ADOPT PROBE DIALOG
Expand Down
3 changes: 2 additions & 1 deletion pages/probes.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<template #body="slotProps">
<NuxtLink :to="`/probes/${slotProps.data.id}`" class="flex h-full items-center" @click="openProbeDetails(slotProps.data.id)">
<div class="grid grid-cols-[auto_1fr] grid-rows-[auto_auto] gap-x-3 px-2 py-3">
<BigIcon class="col-span-1 row-span-2" :name="slotProps.data.hardwareDevice ? 'probe' : 'docker'" border :status="slotProps.data.status"/>
<BigIcon class="col-span-1 row-span-2" :name="slotProps.data.hardwareDevice ? 'probe' : 'docker'" border :status="getProbeStatus(slotProps.data)"/>
<p class="col-start-2 col-end-3 flex items-center font-bold">{{ slotProps.data.name || slotProps.data.city }}</p>
<p class="col-start-2 col-end-3 row-start-2 row-end-3 text-[13px] text-bluegray-900 dark:text-bluegray-400">{{ slotProps.data.ip }}</p>
</div>
Expand Down Expand Up @@ -207,6 +207,7 @@
import { useGoogleMaps } from '~/composables/maps';
import { usePagination } from '~/composables/pagination';
import { useAuth } from '~/store/auth';
import { getProbeStatus } from '~/utils/probe-status';
import { sendErrorToast } from '~/utils/send-toast';
const auth = useAuth();
Expand Down
5 changes: 3 additions & 2 deletions pages/probes/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
<div class="relative border-y">
<div class="flex flex-wrap justify-between gap-4 border-b px-6 py-2">
<div>
Status:<span class="ml-2 font-bold">{{ capitalize(probe.status.replaceAll('-', ' ')) }}</span>
<StatusIcon class="ml-2 text-3xs" :status="probe.status"/>
Status:<span class="ml-2 font-bold">{{ capitalize(getProbeStatus(probe).replaceAll('-', ' ')) }}</span>
<StatusIcon class="ml-2 text-3xs" :status="getProbeStatus(probe)"/>
</div>
<div class="flex items-center">
Credits per month:
Expand Down Expand Up @@ -197,6 +197,7 @@
import CountryFlag from 'vue-country-flag-next';
import { useAuth } from '~/store/auth';
import { initGoogleMap } from '~/utils/init-google-map';
import { getProbeStatus } from '~/utils/probe-status';
import { sendErrorToast, sendToast } from '~/utils/send-toast';
const { $directus } = useNuxtApp();
Expand Down
10 changes: 10 additions & 0 deletions plugins/05.setMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { customEndpoint } from '@directus/sdk';
import { useMetadata } from '~/store/metadata.js';

export default defineNuxtPlugin(async () => {
const metadata = useMetadata();
const { $directus } = useNuxtApp();

const response = await $directus.request<Metadata>(customEndpoint({ method: 'GET', path: '/metadata' }));
metadata.setMetadata(response);
});
18 changes: 18 additions & 0 deletions store/metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defineStore } from 'pinia';

export const useMetadata = defineStore('metadata', {
state: (): Metadata => ({
targetNodeVersion: '',
targetHardwareDeviceFirmware: '',
creditsPerDollar: 0,
creditsPerAdoptedProbe: 0,
}),
actions: {
setMetadata (metadata: Metadata) {
this.targetNodeVersion = String(metadata.targetNodeVersion);
this.targetHardwareDeviceFirmware = String(metadata.targetHardwareDeviceFirmware);
this.creditsPerDollar = Number(metadata.creditsPerDollar);
this.creditsPerAdoptedProbe = Number(metadata.creditsPerAdoptedProbe);
},
},
});
8 changes: 8 additions & 0 deletions types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ declare global {
uuid: string;
version: string;
hardwareDevice: string | null;
hardwareDeviceFirmware: string | null;
nodeVersion: string;
};

Expand Down Expand Up @@ -142,4 +143,11 @@ declare global {
}
};
} | null;

type Metadata = {
targetNodeVersion: string,
targetHardwareDeviceFirmware: string,
creditsPerDollar: number,
creditsPerAdoptedProbe: number,
}
}
40 changes: 40 additions & 0 deletions utils/probe-status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useMetadata } from '~/store/metadata.js';

const compareSemver = (a: string, b: string) => {
const pa = a.split('.');
const pb = b.split('.');

for (let i = 0; i < 3; i++) {
const na = Number(pa[i]) || 0;
const nb = Number(pb[i]) || 0;

if (na > nb) { return 1; }

if (nb > na) { return -1; }
}

return 0;
};

const isOutdated = (probeValue: string | null, metadataValue: string) => {
if (!probeValue || !metadataValue) {
return false;
}

const result = compareSemver(probeValue.replaceAll('v', ''), metadataValue.replaceAll('v', ''));
return result === -1;
};

export const getProbeStatus = (probe: Probe) => {
const metadata = useMetadata();

if (
probe.status === 'ready'
&& (isOutdated(probe.hardwareDeviceFirmware, metadata.targetHardwareDeviceFirmware)
|| isOutdated(probe.nodeVersion, metadata.targetNodeVersion)
)) {
return 'ready (outdated)';
}

return probe.status;
};

0 comments on commit cdcbd89

Please sign in to comment.