Skip to content

Commit

Permalink
feat(drive): added ability to disable drives and add names
Browse files Browse the repository at this point in the history
  • Loading branch information
christopherpickering committed Jul 24, 2023
1 parent 523abf1 commit 6650e8c
Show file tree
Hide file tree
Showing 11 changed files with 355 additions and 63 deletions.
6 changes: 6 additions & 0 deletions app/components/charts/driveBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ export const StorageChart = ({ url }: { url: string }) => {
{
fill: true,
label: 'Used',
cubicInterpolationMode: 'monotone',
tension: 0.4,
data: usageFetcher.data?.drive?.usage?.map((x: Usage) =>
bytes(Number(x.used), { unit: 'GB' }).replace('GB', ''),
),
Expand All @@ -153,6 +155,7 @@ export const StorageChart = ({ url }: { url: string }) => {
chart.chartArea,
darkGradient,
),
pointStyle: false,
},
{
label: 'Free',
Expand All @@ -163,6 +166,9 @@ export const StorageChart = ({ url }: { url: string }) => {
borderColor: '#cbd5e1',
backgroundColor: '#e2e8f0',
borderRadius: { topLeft: 2, topRight: 2 },
cubicInterpolationMode: 'monotone',
pointStyle: false,
tension: 0.4,
},
],
};
Expand Down
100 changes: 100 additions & 0 deletions app/components/driveForms/base.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Form, useFetcher } from '@remix-run/react';
import { useEffect, useState } from 'react';
import { Button } from '~/components/ui/button';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '~/components/ui/dialog';
import { Input } from '~/components/ui/input';
import { Label } from '~/components/ui/label';

import { Textarea } from '~/components/ui/textarea';

import type { Drive } from '~/models/monitor.server';
import { Switch } from '../ui/switch';

export default function Drive({ drive, children }: { drive: Drive }) {
const [open, setOpen] = useState(false);
const fetcher = useFetcher();

const [data, setData] = useState<Drive>(drive);

useEffect(() => setData(drive), [drive]);

useEffect(() => {
if (fetcher.state === 'idle' && fetcher.data?.drive != null) {
setOpen(false);
}
}, [fetcher]);

return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>{children}</DialogTrigger>
<DialogContent className="sm:min-w-[425px] sm:max-w-fit">
<DialogHeader>
<DialogTitle>{drive.name}</DialogTitle>
<DialogDescription>Editing drive.</DialogDescription>
</DialogHeader>
{fetcher.state !== 'submitting' && fetcher.data?.form?.error ? (
<small className="text-red-700">{fetcher.data.form.error}</small>
) : null}
<Form method="post" action="/monitor/new">
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label className="text-right">Enabled</Label>
<div className="self-start col-span-3">
<Switch
name="enabled"
checked={data.enabled}
onCheckedChange={(enabled) => setData({ ...data, enabled })}
/>
</div>
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input
type="text"
id="name"
value={data.title}
placeholder="Logs drive"
className="col-span-3"
onChange={(e) => setData({ ...data, title: e.target.value })}
/>
<Label htmlFor="description" className="text-right">
Description
</Label>
<Textarea
id="description"
className="col-span-3"
value={data.description || ''}
onChange={(e) =>
setData({ ...data, description: e.target.value })
}
/>
</div>
</div>
<DialogFooter className="sm:justify-between">
<div className="flex space-x-2">
<Button
type="button"
onClick={(e) => {
fetcher.submit(
{ _action: 'edit', ...data },
{ method: 'post', action: '/drive/edit' },
);
}}
>
Save
</Button>
</div>
</DialogFooter>
</Form>
</DialogContent>
</Dialog>
);
}
49 changes: 44 additions & 5 deletions app/models/monitor.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export function getMonitor({ id }: Pick<Monitor, 'id'>) {
id: true,
title: true,
hasError: true,
inactive: true,
enabled: true,
location: true,
name: true,
root: true,
Expand Down Expand Up @@ -241,10 +241,12 @@ export function getDriveNotifications({ id }: Pick<Drive, 'id'>) {
select: {
id: true,
title: true,
enabled: true,
monitorId: true,
location: true,
inactive: true,
enabled: true,
name: true,
root: true,
systemDescription: true,
description: true,
size: true,
Expand Down Expand Up @@ -323,7 +325,7 @@ export function getDriveUsage({
title: true,
monitorId: true,
location: true,
inactive: true,
enabled: true,
name: true,
description: true,
systemDescription: true,
Expand Down Expand Up @@ -439,6 +441,23 @@ export async function getMonitorLogs({
};
}

export function getMonitorDisabledDrives({
monitorId,
}: {
monitorId: Monitor['id'];
}) {
return prisma.drive.findMany({
where: { monitorId, enabled: false },
select: {
id: true,
monitorId: true,
location: true,
name: true,
root: true,
},
});
}

export function getMonitorDrives({ monitorId }: { monitorId: Monitor['id'] }) {
return prisma.drive.findMany({
where: { monitorId },
Expand All @@ -447,8 +466,9 @@ export function getMonitorDrives({ monitorId }: { monitorId: Monitor['id'] }) {
title: true,
monitorId: true,
location: true,
inactive: true,
enabled: true,
name: true,
root: true,
description: true,
systemDescription: true,
size: true,
Expand All @@ -463,7 +483,7 @@ export function getMonitorDrives({ monitorId }: { monitorId: Monitor['id'] }) {
take: 1,
},
},
orderBy: { name: 'asc' },
orderBy: [{ enabled: 'desc' }, { size: 'desc' }, { name: 'asc' }],
});
}

Expand Down Expand Up @@ -508,6 +528,25 @@ export async function createMonitor({
return monitor;
}

export function editDrive({
id,
title,
description,
enabled,
}: Pick<Drive, 'id' | 'title' | 'description' | 'enabled'>) {
return prisma.drive.update({
where: { id },
data: {
title,
description,
enabled,
},
select: {
id: true,
},
});
}

export async function editMonitor({
id,
title,
Expand Down
17 changes: 16 additions & 1 deletion app/monitors/windows.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { decrypt } from '@/lib/utils';
import { NodeSSH } from 'node-ssh';
import {
Monitor,
getMonitorDisabledDrives,
monitorError,
setDriveDays,
setDriveGrowth,
Expand Down Expand Up @@ -184,6 +185,20 @@ export default async function WindowsMonitor({
lastBoot = new Date(os.LastBootUpTime);
}

const disabledDrives = await getMonitorDisabledDrives({ id: monitor.id });

// only update drives that are enabled.
const updateableDrives = s.filter((drive) => {
const l =
disabledDrives.filter(
(d) =>
d.name == drive.Name &&
d.root == drive.Root &&
d.location == drive.CurrentLocation,
).length == 0;
return l;
});

const data = await updateMonitor({
id: monitor.id,
data: {
Expand All @@ -209,7 +224,7 @@ export default async function WindowsMonitor({
cpuLoad: pc.LoadPercentage.toString(),
cpuSpeed: pc.CurrentClockSpeed.toString(),
},
drives: s.map(
drives: updateableDrives.map(
(drive: {
CurrentLocation: any;
Name: any;
Expand Down
2 changes: 1 addition & 1 deletion app/notifications/notifier.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default async function Notifier({
// drive notifications
monitor?.drives?.map(async (drive: Drive & { usage: DriveUsage[] }) => {
// don't report inactive drives.
if (drive.inactive) return;
if (drive.enabled == false) return;

// drive has no usages, ignore.
if (drive.usage.length <= 0) return;
Expand Down
86 changes: 59 additions & 27 deletions app/routes/_auth.$monitorType_.$monitorId._index/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ import { getMonitorPublic } from '~/models/monitor.server';
import { authenticator } from '~/services/auth.server';

import { Link, useFetcher, useLoaderData } from '@remix-run/react';
import { BellRing, MoveLeft, MoveRight, Settings } from 'lucide-react';
import {
BellRing,
MoveLeft,
MoveRight,
Settings,
ToggleRight,
} from 'lucide-react';
import { Skeleton } from '~/components/ui/skeleton';
import invariant from 'tiny-invariant';

Expand All @@ -31,6 +37,7 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '/components/ui/dropdown-menu';
import { ToggleLeft } from 'lucide-react';

export const loader = async ({ params, request }: LoaderArgs) => {
await authenticator.isAuthenticated(request, {
Expand Down Expand Up @@ -94,7 +101,10 @@ export default function Index() {
</Link>
</div>
</div>
<H1>{monitor.title}</H1>
<H1 className="space-x-2">
<span>{monitor.title}</span>
{monitor.host && <span>({monitor.host})</span>}
</H1>
<div className="space-y-4 pb-4">
<div className="text-muted-foreground">{monitor.description}</div>

Expand Down Expand Up @@ -182,34 +192,56 @@ export default function Index() {
to={`/${monitor.type}/${monitor.id}/drive/${drive.id}`}
prefetch="intent"
key={drive.id}
className="flex space-x-4 border rounded-md py-2 px-4 cursor-pointer hover:shadow hover:shadow-sky-200"
className={`transition-colors flex space-x-4 border rounded-md py-2 px-4 cursor-pointer hover:shadow hover:shadow-sky-200 ${
drive.enabled ? '' : 'opacity-50 hover:opacity-100'
}`}
>
<DoughnutChart
className="w-36 h-36"
data={{
labels: [
`Used ${bytes(Number(drive.usage?.[0]?.used))}`,
`Free ${bytes(Number(drive.usage?.[0]?.free))}`,
],
datasets: [
{
label: 'Drive Usage',
data: [
Number(drive.usage?.[0]?.used),
Number(drive.usage?.[0]?.used) +
Number(drive.usage?.[0]?.free) ==
0
? 100
: Number(drive.usage?.[0]?.free),
],
},
],
}}
/>
<div>
{drive.enabled ? (
<ToggleRight size={20} className="text-slate-400" />
) : (
<ToggleLeft
size={20}
className="fill-slate-200 text-slate-400"
/>
)}
<DoughnutChart
className="w-36 h-36"
data={{
labels: [
`Used ${bytes(Number(drive.usage?.[0]?.used))}`,
`Free ${bytes(Number(drive.usage?.[0]?.free))}`,
],
datasets: [
{
label: 'Drive Usage',
data: [
Number(drive.usage?.[0]?.used),
Number(drive.usage?.[0]?.used) +
Number(drive.usage?.[0]?.free) ==
0
? 100
: Number(drive.usage?.[0]?.free),
],
},
],
}}
/>
</div>

<div className="space-y-2 flex-grow">
<H3>
{drive.name}:\{drive.location}
<H3 className="space-x-2">
{drive.title ? (
<>
<span>{drive.title}</span>
<span>({drive.root})</span>
</>
) : (
<>
{drive.root}
{drive.location}
</>
)}
</H3>

<Table>
Expand Down
Loading

0 comments on commit 6650e8c

Please sign in to comment.