forked from florian/bouquet
feat: Added virtual all servers view
This commit is contained in:
parent
f49fc74c4d
commit
03134c37d6
@ -9,13 +9,11 @@ import {
|
||||
ShieldExclamationIcon,
|
||||
XMarkIcon,
|
||||
} from '@heroicons/react/24/outline';
|
||||
import { Server as ServerType } from '../../utils/useUserServers';
|
||||
import { ServerInfo } from '../../utils/useServerInfo';
|
||||
import { formatDate, formatFileSize } from '../../utils/utils';
|
||||
import { ServerInfo } from '../../utils/useServerInfo';
|
||||
|
||||
type ServerProps = {
|
||||
server: ServerType;
|
||||
serverInfo: ServerInfo;
|
||||
server: ServerInfo;
|
||||
selectedServer?: string | undefined;
|
||||
setSelectedServer?: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||
onTransfer?: (server: string) => void;
|
||||
@ -28,13 +26,12 @@ const Server = ({
|
||||
server,
|
||||
selectedServer,
|
||||
setSelectedServer,
|
||||
serverInfo,
|
||||
onTransfer,
|
||||
onCancel,
|
||||
onCheck,
|
||||
blobsOnlyOnThisServer,
|
||||
}: ServerProps) => {
|
||||
const readyToUse = !serverInfo.isLoading && !serverInfo.isError;
|
||||
const readyToUse = !server.isLoading && !server.isError;
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
@ -50,24 +47,24 @@ const Server = ({
|
||||
<div className="flex flex-col grow">
|
||||
<div className="server-name">
|
||||
{server.name}
|
||||
{serverInfo.isLoading && <span className="ml-2 loading loading-spinner loading-sm"></span>}
|
||||
{server.isLoading && <span className="ml-2 loading loading-spinner loading-sm"></span>}
|
||||
</div>
|
||||
{serverInfo.isError ? (
|
||||
{server.isError ? (
|
||||
<div className="badge badge-error">
|
||||
<ExclamationTriangleIcon className="w-4 mr-2" /> Error connecting to server
|
||||
</div>
|
||||
) : (
|
||||
<div className="server-stats">
|
||||
<div className="server-stat tooltip text-left" data-tip="Number of blobs">
|
||||
<DocumentDuplicateIcon /> {serverInfo.count}
|
||||
<DocumentDuplicateIcon /> {server.count}
|
||||
</div>
|
||||
<div className="server-stat tooltip text-left" data-tip="Total size of blobs">
|
||||
<CubeIcon /> {formatFileSize(serverInfo.size)}
|
||||
<CubeIcon /> {formatFileSize(server.size)}
|
||||
</div>
|
||||
<div className="server-stat tooltip text-left" data-tip="Date of last change">
|
||||
<ClockIcon /> {formatDate(serverInfo.lastChange)}
|
||||
<ClockIcon /> {formatDate(server.lastChange)}
|
||||
</div>
|
||||
{serverInfo.count > 0 && (
|
||||
{server.count > 0 && !server.virtual && (
|
||||
<div className="server-stat">
|
||||
{blobsOnlyOnThisServer > 0 ? (
|
||||
<div>
|
||||
@ -83,7 +80,7 @@ const Server = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{((selectedServer == server.name && onTransfer) || onCancel) && (
|
||||
{((selectedServer == server.name && !server.virtual && onTransfer) || onCancel) && (
|
||||
<div className="server-actions ">
|
||||
{selectedServer == server.name && (
|
||||
<>
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { Cog8ToothIcon } from '@heroicons/react/24/outline';
|
||||
import { useServerInfo } from '../../utils/useServerInfo';
|
||||
import { ServerInfo, useServerInfo } from '../../utils/useServerInfo';
|
||||
import { Server as ServerType } from '../../utils/useUserServers';
|
||||
import Server from './Server';
|
||||
import './ServerList.css';
|
||||
import ServerListPopup from '../ServerListPopup';
|
||||
import { useState } from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useNDK } from '../../utils/ndk';
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
type ServerListProps = {
|
||||
servers: ServerType[];
|
||||
servers: ServerInfo[];
|
||||
selectedServer?: string | undefined;
|
||||
setSelectedServer?: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||
onTransfer?: (server: string) => void;
|
||||
@ -18,6 +18,7 @@ type ServerListProps = {
|
||||
onCheck?: (server: string) => void;
|
||||
title?: React.ReactElement;
|
||||
manageServers?: boolean;
|
||||
withVirtualServers?: boolean;
|
||||
};
|
||||
|
||||
export const ServerList = ({
|
||||
@ -28,9 +29,10 @@ export const ServerList = ({
|
||||
onCancel,
|
||||
title,
|
||||
manageServers = false,
|
||||
withVirtualServers = false,
|
||||
}: ServerListProps) => {
|
||||
const { ndk, user } = useNDK();
|
||||
const { serverInfo, distribution } = useServerInfo();
|
||||
const { distribution } = useServerInfo();
|
||||
const blobsWithOnlyOneOccurance = Object.values(distribution)
|
||||
.filter(d => d.servers.length == 1)
|
||||
.map(d => ({ ...d.blob, server: d.servers[0] }));
|
||||
@ -58,6 +60,8 @@ export const ServerList = ({
|
||||
await ev.publish();
|
||||
};
|
||||
|
||||
const serversToList = useMemo(() => withVirtualServers ? servers : servers.filter(s => !s.virtual), [servers, withVirtualServers])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`flex flex-row py-4 ${!title ? 'justify-end' : ''}`}>
|
||||
@ -76,14 +80,13 @@ export const ServerList = ({
|
||||
isOpen={isDialogOpen}
|
||||
onClose={handleCloseDialog}
|
||||
onSave={handleSaveServers}
|
||||
initialServers={Object.values(serverInfo)}
|
||||
initialServers={servers.filter(s => !s.virtual)}
|
||||
/>
|
||||
|
||||
<div className="server-list">
|
||||
{servers.map(server => (
|
||||
{serversToList.map(server => (
|
||||
<Server
|
||||
key={server.name}
|
||||
serverInfo={serverInfo[server.name]}
|
||||
server={server}
|
||||
selectedServer={selectedServer}
|
||||
setSelectedServer={setSelectedServer}
|
||||
|
@ -4,7 +4,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { BlobDescriptor, BlossomClient } from 'blossom-client-sdk';
|
||||
import { useNDK } from '../utils/ndk';
|
||||
import BlobList from '../components/BlobList/BlobList';
|
||||
import { useServerInfo } from '../utils/useServerInfo';
|
||||
import { ServerInfo, useServerInfo } from '../utils/useServerInfo';
|
||||
import { ServerList } from '../components/ServerList/ServerList';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
@ -62,6 +62,7 @@ function Home() {
|
||||
onCheck={() => navigate('/check/' + selectedServer)}
|
||||
title={<>Servers</>}
|
||||
manageServers={true}
|
||||
withVirtualServers={true}
|
||||
></ServerList>
|
||||
|
||||
{selectedServer && serverInfo[selectedServer] && selectedServerBlobs && (
|
||||
|
@ -7,6 +7,7 @@ import { useUserServers } from './useUserServers';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
export type ServerInfo = {
|
||||
virtual: boolean;
|
||||
count: number;
|
||||
size: number;
|
||||
lastChange: number;
|
||||
@ -21,6 +22,21 @@ type BlobDictionary = {
|
||||
[key: string]: { blob: BlobDescriptor; servers: string[] };
|
||||
};
|
||||
|
||||
const mergeBlobs = (
|
||||
baseBlobs: BlobDescriptor[],
|
||||
newBlobs: BlobDescriptor[],
|
||||
existingBlobs: { [key: string]: boolean }
|
||||
): BlobDescriptor[] => {
|
||||
const result = [...baseBlobs];
|
||||
for (const blob of newBlobs) {
|
||||
if (!existingBlobs[blob.sha256]) {
|
||||
existingBlobs[blob.sha256] = true;
|
||||
result.push(blob);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export const useServerInfo = () => {
|
||||
const servers = useUserServers();
|
||||
const { user, signEventTemplate } = useNDK();
|
||||
@ -48,6 +64,7 @@ export const useServerInfo = () => {
|
||||
servers.forEach((server, sx) => {
|
||||
info[server.name] = {
|
||||
...server,
|
||||
virtual: false,
|
||||
blobs: blobs[sx].data,
|
||||
isLoading: blobs[sx].isLoading,
|
||||
isError: blobs[sx].isError,
|
||||
@ -59,6 +76,36 @@ export const useServerInfo = () => {
|
||||
return info;
|
||||
}, [servers, blobs]);
|
||||
|
||||
const allServersAggregation = useMemo(() => {
|
||||
const serversInfos = Object.values(serverInfo);
|
||||
const existingBlobs: { [key: string]: boolean } = {};
|
||||
const initial: ServerInfo = {
|
||||
virtual: true,
|
||||
count: 0,
|
||||
size: 0,
|
||||
lastChange: 0,
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
name: 'All servers',
|
||||
url: 'all',
|
||||
blobs: [],
|
||||
};
|
||||
const allInfo = serversInfos.reduce(
|
||||
(acc, server) => ({
|
||||
...acc,
|
||||
lastChange: Math.max(acc.lastChange, server.lastChange),
|
||||
isLoading: acc.isLoading || server.isLoading,
|
||||
isError: acc.isError || server.isError,
|
||||
blobs: mergeBlobs(acc.blobs || [], server.blobs || [], existingBlobs),
|
||||
}),
|
||||
initial
|
||||
);
|
||||
allInfo.size = allInfo.blobs?.reduce((acc, blob) => acc + blob.size, 0) || 0;
|
||||
allInfo.count = allInfo.blobs?.length || 0;
|
||||
|
||||
return { [allInfo.name]: allInfo, ...serverInfo };
|
||||
}, [serverInfo]);
|
||||
|
||||
const distribution = useMemo(() => {
|
||||
const dict: BlobDictionary = {};
|
||||
|
||||
@ -80,5 +127,5 @@ export const useServerInfo = () => {
|
||||
return dict;
|
||||
}, [servers, serverInfo]);
|
||||
|
||||
return { serverInfo, distribution };
|
||||
return { serverInfo: allServersAggregation, distribution };
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user