Skip to content

Commit

Permalink
Dev-1223 (#19)
Browse files Browse the repository at this point in the history
* feat: add device dialog & NATS use

* feat: add i18n Chinese support

* perf: add default import support of shadcn

* ci: update from nodejs 18 to 20

* ci: fix NATS_SERVER connect error
  • Loading branch information
mocusez authored Dec 25, 2023
1 parent 8ddd33e commit d95b00e
Show file tree
Hide file tree
Showing 19 changed files with 430 additions and 11 deletions.
5 changes: 4 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ EMAIL_SERVER_HOST="host"
EMAIL_SERVER_PORT=123
EMAIL_SERVER_USER="user"
EMAIL_SERVER_PASSWORD="password"
EMAIL_FROM="[email protected]"
EMAIL_FROM="[email protected]"

# Nats
NATS_SERVER = "demo.nats.io:4222"
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v2

- name: Setup Node.js 18.x
- name: Setup Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 18.x
node-version: 20.x
cache: "pnpm"

- name: Install dependencies
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v2

- name: Setup Node.js 18.x
- name: Setup Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 18.x
node-version: 20.x
cache: "pnpm"

- name: Install dependencies
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/prettier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v2

- name: Setup Node.js 18.x
- name: Setup Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 18.x
node-version: 20.x
cache: "pnpm"

- name: Install dependencies
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/type-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v2

- name: Setup Node.js 18.x
- name: Setup Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 18.x
node-version: 20.x
cache: "pnpm"

- name: Install dependencies
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
"use client";

import { useState } from "react";
import { CaretSortIcon, CheckIcon } from "@radix-ui/react-icons";
import { Button } from "~/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
} from "~/components/ui/command";
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 {
Popover,
PopoverContent,
PopoverTrigger,
} from "~/components/ui/popover";
import { useToast } from "~/components/ui/use-toast";
import { cn } from "~/lib/utils";
import { api } from "~/trpc/react";
import { I18nDict } from "~/types";

interface Props {
dictionary: I18nDict;
id: string;
}

export function AddDeviceDialog({ dictionary, id }: Props) {
const { toast } = useToast();
const [dialogOpen, setDialogOpen] = useState(false);
const [open, setOpen] = useState(false);
const [locationName, setLocationName] = useState("");
const [locationId, setLocationId] = useState("");
const [deviceId, setDeviceId] = useState("");

const locations = api.location.getAll.useQuery();
const addDevice = api.device.add.useMutation({
onSuccess: () => {
setDeviceId("");
toast({
description: dictionary.successToast,
});
setDialogOpen(false);
},
onError: (error) => {
toast({
variant: "destructive",
description: dictionary.errorToast,
});
},
});

const submit = async () => {
addDevice.mutate({ device: deviceId, locationId: locationId });
};

function Content() {
if (locations.status === "loading") {
return <span>{dictionary["location-fetch-loading"]}</span>;
}
if (locations.status === "error") {
return <span>{dictionary["location-fetch-error"]}</span>;
}

return (
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="locationName" className="text-right">
{dictionary["location-name"]}
</Label>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="w-[300px] justify-between"
>
{locationName
? locations.data.find((location) => location.id === locationId)
?.name
: dictionary["location-select"]}
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[300px] p-0">
<Command>
<CommandInput
placeholder={dictionary["location-input-placeholder"]}
className="h-9"
/>
<CommandEmpty>
{dictionary["location-empty-placeholder"]}
</CommandEmpty>
<CommandGroup>
{locations.data.map((location) => (
<CommandItem
key={location.id}
value={location.id}
onSelect={(currentValue) => {
setLocationId(
currentValue === locationId ? "" : currentValue,
);
setLocationName(
locations.data.find(
(location) => location.id === currentValue,
)!.name,
);
setOpen(false);
}}
>
{location.name}
<CheckIcon
className={cn(
"ml-auto h-4 w-4",
locationName === location.name
? "opacity-100"
: "opacity-0",
)}
/>
</CommandItem>
))}
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
</div>
);
}

return (
<div className="mb-4">
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
<DialogTrigger asChild>
<span
className="text-lg font-semibold text-primary hover:cursor-pointer"
onClick={() => locations.refetch()}
>
{dictionary.title}
</span>
</DialogTrigger>
<DialogContent className="sm:max-w-[625px]">
<DialogHeader>
<DialogTitle>{dictionary.title}</DialogTitle>
</DialogHeader>
<div className="grid gap-4 py-4">
<Content />
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
{dictionary.name}
</Label>
<Input
id="name"
className="w-[400px]"
value={deviceId}
onChange={(e) => setDeviceId(e.target.value)}
autoComplete="off"
/>
</div>
</div>
<DialogFooter>
<Button
type="submit"
onClick={submit}
disabled={addDevice.isLoading}
>
{addDevice.isLoading ? dictionary.wait : dictionary.add}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<p className="mb-2 text-sm">{dictionary.description}</p>
</div>
);
}
5 changes: 5 additions & 0 deletions src/app/[locale]/(mainboard)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Icons } from "~/components/icons";
import type { Locale } from "~/i18n-config";
import { getDictionary } from "~/lib/dictionary";
import { getServerAuthSession } from "~/server/auth";
import { AddDeviceDialog } from "./_components/add-device-dialog";
import { CreateLocationDialog } from "./_components/create-location-dialog";
import { CreateOrganizationDialog } from "./_components/create-organization-dialog";
import { DocumentsStartupSection } from "./_components/documents-startup-section";
Expand All @@ -27,6 +28,10 @@ export default async function DashBoard({ params: { locale } }: Props) {
dictionary={d.dashboard["create-location"]}
id={session!.user.id}
/>
<AddDeviceDialog
dictionary={d.dashboard["add-device"]}
id={session!.user.id}
/>
</div>
<div className="w-1/4 flex-col px-2 lg:w-3/4">
<div>
Expand Down
11 changes: 11 additions & 0 deletions src/config/ironhive-command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const ironhiveRequest = {
ping: JSON.stringify({ func: "ping" }),
publicIp: JSON.stringify({ func: "publicip" }),
cpuUssage: JSON.stringify({ func: "cpuussage" }),
softwareList: JSON.stringify({ func: "softwarelist" }),
procs: JSON.stringify({ func: "procs" }),
};

export const ironhiveResponse = {
ping: "pong",
};
15 changes: 15 additions & 0 deletions src/dictionaries/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@
"wait": "Creating...",
"successToast": "Location created successfully",
"errorToast": "Oops, Error creating location"
},
"add-device": {
"title": "Add device",
"description": "Add a new device",
"name": "Device ID",
"successToast": "Machine added successfully",
"errorToast": "Oops, Error on adding device",
"location-name": "Location Name",
"location-select": "Select location...",
"location-input-placeholder": "Search location...",
"location-empty-placeholder": "No location found.",
"location-fetch-loading": "Loading...",
"location-fetch-error": "Oops, there are something wrong with server.",
"add": "Add",
"wait": "Adding..."
}
}
}
15 changes: 15 additions & 0 deletions src/dictionaries/es-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@
"wait": "Creating...",
"successToast": "Location created successfully",
"errorToast": "Oops, Error creating location"
},
"add-device": {
"title": "Add device",
"description": "Add a new device",
"name": "Device ID",
"successToast": "Machine added successfully",
"errorToast": "Oops, Error on adding device",
"location-name": "Location Name",
"location-select": "Select location...",
"location-input-placeholder": "Search location...",
"location-empty-placeholder": "No location found.",
"location-fetch-loading": "Loading...",
"location-fetch-error": "Oops, there are something wrong with server.",
"add": "Add",
"wait": "Adding..."
}
}
}
Loading

0 comments on commit d95b00e

Please sign in to comment.