Skip to content

Commit

Permalink
shared worker tests, datatable refac + monitors
Browse files Browse the repository at this point in the history
  • Loading branch information
dskvr committed Nov 30, 2024
1 parent e10510b commit 502a108
Show file tree
Hide file tree
Showing 42 changed files with 925 additions and 308 deletions.
Binary file modified .yarn/install-state.gz
Binary file not shown.
1 change: 1 addition & 0 deletions apps/gui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"radix-svelte": "^0.9.0",
"surrealdb": "^1.0.6",
"svelte-time": "^0.9.0",
"svelte-timeago": "^0.1.2",
"vite-plugin-compression": "^0.5.1"
}
}
4 changes: 2 additions & 2 deletions apps/gui/src/lib/components/blocks/Header.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<h1>nostr.watch</h1>
<nav>
<a href="/">home</a>
<a href="">console</a>
<a href="">monitors</a>
<a href="/relays">relays</a>
<a href="/monitors">monitors</a>
<a href="/preferences">preferences</a>
</nav>
</header>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
<!-- src/lib/components/blocks/console/Console.svelte -->

<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { get, writable, derived } from 'svelte/store';
import { DataTable } from '@careswitch/svelte-data-table';
import * as Resizable from '$lib/components/ui/resizable';
import Filters from './Filters.svelte';
import { relayAggregates } from '$lib/stores/checks.js';
import { columnsDisable, columnsShow, filtersDisable, filtersShow, humanReadableNames, formatters, tableFormatters, filterFormatters } from './config';
// import from './config.js';
import DataTableShowResults from '$lib/components/partials/DataTableShowResults.svelte';
import DataTablePaginator from '$lib/components/partials/DataTablePaginator.svelte';
import { Debounce } from '$lib/utils/debounce';
Expand All @@ -18,6 +16,12 @@
import { Badge } from '$lib/components/ui/badge/index.js';
import * as Table from '$lib/components/ui/table/index.js';
export let data: any;
export let config: any;
export let enableFilters: boolean = true;
const { columnsDisable, columnsShow, filtersDisable, filtersShow, humanReadableNames, formatters, tableFormatters, filterFormatters } = config
const maxBadgeLength: number = 20;
// **Stores and Reactive Variables**
Expand All @@ -27,9 +31,9 @@
$: columnsInclude = [ ...columnsShow.filter(f => !columnsDisable.includes(f)) ];
const tableData = derived(
[relayAggregates],
([ $relayAggregates ]) => {
if (!$relayAggregates || $relayAggregates.length === 0) {
[data],
([ $data ]) => {
if (!$data || $data.length === 0) {
return { data: [], columns: [] };
}
Expand All @@ -43,7 +47,7 @@
name: humanReadableNames[key] ?? key.charAt(0).toUpperCase() + key.slice(1),
}));
const data = $relayAggregates.map((item) => {
const data = $data.map((item) => {
const formattedItem = { ...item };
for (const key in formatters) {
if (Object.prototype.hasOwnProperty.call(formattedItem, key)) {
Expand Down Expand Up @@ -224,15 +228,15 @@
<Resizable.Handle withHandle />
<!-- **Filters Pane** -->
<Resizable.Pane defaultSize={25}>
{#if tableInstance !== null}
<!-- **Filters Component** -->
{#if tableInstance !== null && enableFilters}
<Filters
tableData={tableData}
filters={filters}
filtersInclude={filtersInclude}
humanReadableNames={humanReadableNames}
filterFormatters={filterFormatters}
maxBadgeLength={maxBadgeLength}
{tableData}
{filters}
{filtersInclude}
{humanReadableNames}
{filterFormatters}
{maxBadgeLength}
{config}
/>
{/if}
</Resizable.Pane>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { Accordion } from 'radix-svelte';
import { writable, derived, type Writable } from 'svelte/store';
import { filterFormatters as _filterFormatters } from './config.js';
import Badge from '$lib/components/ui/badge/badge.svelte';
import {
Expand All @@ -25,6 +25,9 @@
export let filterOverrides: Record<string, { type: 'search' | 'badge', miniSearchOptions?: any }> = {};
export let maxBadgeLength: number = 10;
export let filters: Writable<Record<string, any>>; // Writable store passed from the parent component
export let config: any;
const { filterFormatters:_filterFormatters } = config;
// **Accordion States**
let rootValue;
Expand Down
155 changes: 155 additions & 0 deletions apps/gui/src/lib/components/blocks/table/monitors-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import countryCodeToFlagEmoji from 'country-code-to-flag-emoji'
import { relaySpeedGroupResolver, SpeedGroupBars, SpeedGroupColors, SpeedGroups } from '$lib/stores/checks.js';
import { makeSoftwareReadable } from '$lib/synonyms/software.js';

type Resolver = (input: any) => any

class SpeedGroupResolver {
private resolver: Resolver = () => SpeedGroups.Mid;
private unsubscribe: () => void;

constructor() {
this.unsubscribe = relaySpeedGroupResolver.subscribe((fn: Resolver) => {
this.resolver = fn;
});
}

resolve(input: number): SpeedGroups {
return this.resolver(input);
}

dispose() {
this.unsubscribe();
}
}

const speedGroupResolver = new SpeedGroupResolver();


export type NameFormatter = Record<string, string>;

export type Formatters = Record<string, Formatter>;

export type DataKeys = string[];

export type Formatter = {
(value: any): string;
}

export const normalizeKeys = (keys: DataKeys | string) => {
if(typeof keys === 'string')
return keys.toLowerCase()
if(typeof keys === 'object')
return keys.map(k => k.toLowerCase())
}

export const columnsDisable: DataKeys = ['asname']
export const filtersDisable: DataKeys = ['as', 'asname']

export const columnsShow: DataKeys = ['pubkey', 'name', 'geohash', 'lastSeen', 'checks', 'relays', 'reportingOnline']
export const filtersShow: DataKeys = ['pubkey', 'name', 'geohash', 'lastSeen', 'checks', 'relays', 'reportingOnline']

export const humanReadableNames: NameFormatter = {
// networks: 'Network',
// supportedNips: 'NIPs',
// software: 'Software',
// relay: 'Relay',
// rttNormalized: 'Speed',
// geocode: 'Country',
// paymentRequired: 'Payment',
// authRequired: 'Auth',
// isp: 'ISP'
};

export const formatters: Formatters = {}

export const tableFormatters: Formatters = {
// relay: (relay) => {
// return truncateWithEllipsis(relay, 44);
// },
// geocode: (code) => {
// if(!code) return '🌐';
// return countryCodeToFlagEmoji(code);
// },
// rttNormalized: (value) => {
// const isNumber = !isNaN(Number(value));
// if(!isNumber) return '-';
// const group: SpeedGroups = speedGroupResolver.resolve(value);
// return `<span class="text-xs" style="font-family: 'monospace';color:${SpeedGroupColors[group]};">${SpeedGroupBars[group]}</span>`;
// },
// supportedNips: (nips) => {
// let output = '';
// for(const nip of nips) {
// output += `<span class="p-1 mr-1 inline text-xs">${nip}</span>`;
// }
// return output;
// },
// paymentRequired: (r) => {
// const text = r? 'yes': 'no'
// const style = r? '': 'text-opacity-50'
// return `<span class="p-1 inline-block mr-1 uppercase text-xs bold text-${style}">${text}</span>`
// },
// authRequired: (r) => {
// const text = r? 'yes': 'no'
// const style = r? '': 'text-opacity-50'
// return `<span class="p-1 inline-block mr-1 uppercase text-xs bold text-${style}">${text}</span>`
// },
// software: (software) => {
// if(typeof software !== 'string') return '-';
// software = makeSoftwareReadable(software);
// return truncateWithEllipsis(software, 33);
// },
}

export const filterFormatters: Formatters = {
// geocode: (code) => {
// if(!code) return '🌐';
// return countryCodeToFlagEmoji(code);
// },
// supportedNips: (nip) => {
// return formatNip(nip)
// },
// paymentRequired: (r) => {
// const text = r? 'yes': 'no'
// const style = r? '': 'text-opacity-50'
// return `<span class="p-1 inline-block mr-1 uppercase text-xs bold text-${style}">${text}</span>`
// },
// authRequired: (r) => {
// const text = r? 'yes': 'no'
// const style = r? '': 'text-opacity-50'
// return `<span class="p-1 inline-block mr-1 uppercase text-xs bold text-${style}">${text}</span>`
// },
// software: (software) => {
// if(typeof software !== 'string') return '-';
// return makeSoftwareReadable(software);
// }
}


function formatNip(number: number | string): string {
if (typeof number === 'string') {
number = parseInt(number);
}
if (number > 0 || number <= 9) {
number = number.toString().padStart(2, '0')
}
return `NIP-${number}`;
}

function truncateWithEllipsis(text: string, maxLength: number): string {
if (text.length > maxLength) {
return text.slice(0, maxLength) + '...';
}
return text;
}

export default {
humanReadableNames,
formatters,
tableFormatters,
filterFormatters,
columnsDisable,
filtersDisable,
columnsShow,
filtersShow
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class SpeedGroupResolver {
}

const speedGroupResolver = new SpeedGroupResolver();


export type NameFormatter = Record<string, string>;

Expand All @@ -47,10 +46,10 @@ export const columnsDisable: DataKeys = ['as', 'asname']
export const filtersDisable: DataKeys = ['as', 'asname']

export const columnsShow: DataKeys = ['relay', 'lastSeen', 'rttNormalized', 'geocode', 'paymentRequired', 'authRequired', 'software', 'supportedNips']
export const filtersShow: DataKeys = ['network', 'paymentRequired', 'authRequired', 'isp', 'software', 'supportedNips', 'geocode']
export const filtersShow: DataKeys = ['networks', 'paymentRequired', 'authRequired', 'isp', 'software', 'supportedNips', 'geocode']

export const humanReadableNames: NameFormatter = {
network: 'Network',
networks: 'Network',
supportedNips: 'NIPs',
software: 'Software',
relay: 'Relay',
Expand Down Expand Up @@ -141,4 +140,15 @@ function truncateWithEllipsis(text: string, maxLength: number): string {
return text.slice(0, maxLength) + '...';
}
return text;
}

export default {
humanReadableNames,
formatters,
tableFormatters,
filterFormatters,
columnsDisable,
filtersDisable,
columnsShow,
filtersShow
}
68 changes: 68 additions & 0 deletions apps/gui/src/lib/components/partials/MonitorDataRow.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<script lang="ts">
import { type Monitor } from '@nostrwatch/nip66/models';
import { monitorChecksCount } from '$lib/stores/monitors.js';
import Badge from '$lib/components/ui/badge/Badge.svelte';
import { PFP } from '$lib/utils/pfp.js';
import Time from "svelte-time";
export let monitor: Monitor;
$: photo = monitor?.profile?.photo || monitor?.profile?.picture;
$: checksCount = $monitorChecksCount?.[monitor.pubkey]
$: lastActive = monitor?.lastActive
$: relays = monitor?.relays
$: checks = monitor?.checks
</script>

<section class="mb-10">
<div class="flex items-center text-gray-300">
<div class="flex-shrink-0">
{#if monitor?.profile?.photo}
<span class="rounded-full overflow-hidden">
<img src={photo} alt={photo} class="w-20 h-24" />
</span>
{:else}
<span class="rounded-full overflow-hidden">
<img src={PFP.generate(monitor.pubkey)} alt={photo} class="w-20 h-20" />
</span>
{/if}
</div>
<div class="ml-4">
<div class="flex items-center mb-1">
<span class="font-bold opacity-90 text-white">
{#if monitor?.profile?.name}
{monitor.profile.name}
{:else}
<span class="text-sm">{monitor.pubkey.slice(0, 21)}...</span>
{/if}
</span>
{#if monitor?.profile?.nip05}
<span class="ml-2 text-gray-400 text-sm font-bold">{monitor.profile.nip05}</span>
{/if}
{#if lastActive}
<span class="ml-2 text-gray-600 text-sm font-bold">last active <Time relative timestamp={lastActive * 1000} /></span>
{/if}
</div>
<div class="mb-1">
{#if checksCount}
<span class="text-sm">reporting <Badge size="default" variant="secondary">{checksCount}</Badge> relays online</span>
{/if}
</div>
<div class="mb-1">
<span class="text-sm">checks</span>
{#if checks}
{#each checks as check}
<Badge size="small" variant="secondary" class="ml-2">{check}</Badge>
{/each}
{/if}
</div>
<div class="text-sm text-gray-600">
{#if monitor?.profile?.lud16}
{monitor.profile.lud16}
{/if}
{#if relays?.length}
Publishes to {relays.length} relays {relays.join(', ')}
{/if}
</div>
</div>
</div>
</section>
Loading

0 comments on commit 502a108

Please sign in to comment.