mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
feat: add icons to buttons and alerts for improved UI clarity
This commit is contained in:
@@ -2,6 +2,7 @@ import { arktypeResolver } from "@hookform/resolvers/arktype";
|
|||||||
import { type } from "arktype";
|
import { type } from "arktype";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
import { Check, Pencil, Save, X } from "lucide-react";
|
||||||
import { cn, slugify } from "~/client/lib/utils";
|
import { cn, slugify } from "~/client/lib/utils";
|
||||||
import { deepClean } from "~/utils/object";
|
import { deepClean } from "~/utils/object";
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
@@ -267,6 +268,7 @@ export const CreateRepositoryForm = ({
|
|||||||
{form.watch("path") || "/var/lib/zerobyte/repositories"}
|
{form.watch("path") || "/var/lib/zerobyte/repositories"}
|
||||||
</div>
|
</div>
|
||||||
<Button type="button" variant="outline" onClick={() => setShowPathWarning(true)} size="sm">
|
<Button type="button" variant="outline" onClick={() => setShowPathWarning(true)} size="sm">
|
||||||
|
<Pencil className="h-4 w-4 mr-2" />
|
||||||
Change
|
Change
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -292,13 +294,17 @@ export const CreateRepositoryForm = ({
|
|||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Cancel
|
||||||
|
</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowPathBrowser(true);
|
setShowPathBrowser(true);
|
||||||
setShowPathWarning(false);
|
setShowPathWarning(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Check className="h-4 w-4 mr-2" />
|
||||||
I Understand, Continue
|
I Understand, Continue
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
@@ -320,8 +326,14 @@ export const CreateRepositoryForm = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>
|
||||||
<AlertDialogAction onClick={() => setShowPathBrowser(false)}>Done</AlertDialogAction>
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Cancel
|
||||||
|
</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={() => setShowPathBrowser(false)}>
|
||||||
|
<Check className="h-4 w-4 mr-2" />
|
||||||
|
Done
|
||||||
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
@@ -775,6 +787,7 @@ export const CreateRepositoryForm = ({
|
|||||||
|
|
||||||
{mode === "update" && (
|
{mode === "update" && (
|
||||||
<Button type="submit" className="w-full" loading={loading}>
|
<Button type="submit" className="w-full" loading={loading}>
|
||||||
|
<Save className="h-4 w-4 mr-2" />
|
||||||
Save Changes
|
Save Changes
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { arktypeResolver } from "@hookform/resolvers/arktype";
|
import { arktypeResolver } from "@hookform/resolvers/arktype";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { type } from "arktype";
|
import { type } from "arktype";
|
||||||
import { CheckCircle, Loader2, XCircle } from "lucide-react";
|
import { CheckCircle, Loader2, Pencil, Plug, Save, XCircle } from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { cn, slugify } from "~/client/lib/utils";
|
import { cn, slugify } from "~/client/lib/utils";
|
||||||
@@ -152,6 +152,7 @@ export const CreateVolumeForm = ({ onSubmit, mode = "create", initialValues, for
|
|||||||
<div className="text-sm font-mono break-all">{field.value}</div>
|
<div className="text-sm font-mono break-all">{field.value}</div>
|
||||||
</div>
|
</div>
|
||||||
<Button type="button" variant="outline" size="sm" onClick={() => field.onChange("")}>
|
<Button type="button" variant="outline" size="sm" onClick={() => field.onChange("")}>
|
||||||
|
<Pencil className="h-4 w-4 mr-2" />
|
||||||
Change
|
Change
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -561,6 +562,7 @@ export const CreateVolumeForm = ({ onSubmit, mode = "create", initialValues, for
|
|||||||
{!testBackendConnection.isPending && testMessage && !testMessage.success && (
|
{!testBackendConnection.isPending && testMessage && !testMessage.success && (
|
||||||
<XCircle className="mr-2 h-4 w-4 text-red-500" />
|
<XCircle className="mr-2 h-4 w-4 text-red-500" />
|
||||||
)}
|
)}
|
||||||
|
{!testBackendConnection.isPending && !testMessage && <Plug className="mr-2 h-4 w-4" />}
|
||||||
{testBackendConnection.isPending
|
{testBackendConnection.isPending
|
||||||
? "Testing..."
|
? "Testing..."
|
||||||
: testMessage
|
: testMessage
|
||||||
@@ -584,6 +586,7 @@ export const CreateVolumeForm = ({ onSubmit, mode = "create", initialValues, for
|
|||||||
)}
|
)}
|
||||||
{mode === "update" && (
|
{mode === "update" && (
|
||||||
<Button type="submit" className="w-full" loading={loading}>
|
<Button type="submit" className="w-full" loading={loading}>
|
||||||
|
<Save className="h-4 w-4 mr-2" />
|
||||||
Save Changes
|
Save Changes
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useCallback, useState } from "react";
|
|||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { ChevronDown, FileIcon, FolderOpen, RotateCcw } from "lucide-react";
|
import { ChevronDown, FileIcon, FolderOpen, RotateCcw, X } from "lucide-react";
|
||||||
import { Button } from "~/client/components/ui/button";
|
import { Button } from "~/client/components/ui/button";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
|
||||||
import { Checkbox } from "~/client/components/ui/checkbox";
|
import { Checkbox } from "~/client/components/ui/checkbox";
|
||||||
@@ -161,9 +161,11 @@ export function RestoreForm({ snapshot, repositoryName, snapshotId, returnPath }
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Button variant="outline" onClick={() => navigate(returnPath)}>
|
<Button variant="outline" onClick={() => navigate(returnPath)}>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="primary" onClick={handleRestore} disabled={isRestoring || !canRestore}>
|
<Button variant="primary" onClick={handleRestore} disabled={isRestoring || !canRestore}>
|
||||||
|
<RotateCcw className="h-4 w-4 mr-2" />
|
||||||
{isRestoring
|
{isRestoring
|
||||||
? "Restoring..."
|
? "Restoring..."
|
||||||
: selectedPaths.size > 0
|
: selectedPaths.size > 0
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
import { Calendar, Clock, Database, FolderTree, HardDrive, Trash2 } from "lucide-react";
|
import { Calendar, Clock, Database, FolderTree, HardDrive, Trash2, X } from "lucide-react";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { ByteSize } from "~/client/components/bytes-size";
|
import { ByteSize } from "~/client/components/bytes-size";
|
||||||
@@ -163,12 +163,16 @@ export const SnapshotsTable = ({ snapshots, repositoryName }: Props) => {
|
|||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Cancel
|
||||||
|
</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={handleConfirmDelete}
|
onClick={handleConfirmDelete}
|
||||||
disabled={deleteSnapshot.isPending}
|
disabled={deleteSnapshot.isPending}
|
||||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
>
|
>
|
||||||
|
<Trash2 className="h-4 w-4 mr-2" />
|
||||||
Delete snapshot
|
Delete snapshot
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import { Bell, Plus, Trash2 } from "lucide-react";
|
import { Bell, Plus, Save, Trash2, X } from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { Button } from "~/client/components/ui/button";
|
import { Button } from "~/client/components/ui/button";
|
||||||
@@ -174,6 +174,7 @@ export const ScheduleNotificationsConfig = ({ scheduleId, destinations }: Props)
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<Button variant="ghost" size="sm" onClick={() => setIsAddingNew(false)}>
|
<Button variant="ghost" size="sm" onClick={() => setIsAddingNew(false)}>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -254,9 +255,11 @@ export const ScheduleNotificationsConfig = ({ scheduleId, destinations }: Props)
|
|||||||
{hasChanges && (
|
{hasChanges && (
|
||||||
<div className="flex gap-2 justify-end mt-4 pt-4">
|
<div className="flex gap-2 justify-end mt-4 pt-4">
|
||||||
<Button variant="outline" size="sm" onClick={handleReset}>
|
<Button variant="outline" size="sm" onClick={handleReset}>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="default" size="sm" onClick={handleSave} loading={updateNotifications.isPending}>
|
<Button variant="default" size="sm" onClick={handleSave} loading={updateNotifications.isPending}>
|
||||||
|
<Save className="h-4 w-4 mr-2" />
|
||||||
Save changes
|
Save changes
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Eraser, Pencil, Play, Square, Trash2 } from "lucide-react";
|
import { Check, Eraser, Pencil, Play, Square, Trash2, X } from "lucide-react";
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { OnOff } from "~/client/components/onoff";
|
import { OnOff } from "~/client/components/onoff";
|
||||||
import { Button } from "~/client/components/ui/button";
|
import { Button } from "~/client/components/ui/button";
|
||||||
@@ -199,11 +199,15 @@ export const ScheduleSummary = (props: Props) => {
|
|||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<div className="flex gap-3 justify-end">
|
<div className="flex gap-3 justify-end">
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Cancel
|
||||||
|
</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={handleConfirmDelete}
|
onClick={handleConfirmDelete}
|
||||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
>
|
>
|
||||||
|
<Trash2 className="h-4 w-4 mr-2" />
|
||||||
Delete schedule
|
Delete schedule
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</div>
|
</div>
|
||||||
@@ -220,8 +224,14 @@ export const ScheduleSummary = (props: Props) => {
|
|||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<div className="flex gap-3 justify-end">
|
<div className="flex gap-3 justify-end">
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>
|
||||||
<AlertDialogAction onClick={handleConfirmForget}>Run cleanup</AlertDialogAction>
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Cancel
|
||||||
|
</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={handleConfirmForget}>
|
||||||
|
<Check className="h-4 w-4 mr-2" />
|
||||||
|
Run cleanup
|
||||||
|
</AlertDialogAction>
|
||||||
</div>
|
</div>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { FileIcon } from "lucide-react";
|
import { FileIcon, RotateCcw, Trash2 } from "lucide-react";
|
||||||
import { Link } from "react-router";
|
import { Link } from "react-router";
|
||||||
import { FileTree } from "~/client/components/file-tree";
|
import { FileTree } from "~/client/components/file-tree";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
|
||||||
@@ -98,6 +98,7 @@ export const SnapshotFileBrowser = (props: Props) => {
|
|||||||
}
|
}
|
||||||
className={buttonVariants({ variant: "primary", size: "sm" })}
|
className={buttonVariants({ variant: "primary", size: "sm" })}
|
||||||
>
|
>
|
||||||
|
<RotateCcw className="h-4 w-4 mr-2" />
|
||||||
Restore
|
Restore
|
||||||
</Link>
|
</Link>
|
||||||
{onDeleteSnapshot && (
|
{onDeleteSnapshot && (
|
||||||
@@ -108,6 +109,7 @@ export const SnapshotFileBrowser = (props: Props) => {
|
|||||||
disabled={isDeletingSnapshot}
|
disabled={isDeletingSnapshot}
|
||||||
loading={isDeletingSnapshot}
|
loading={isDeletingSnapshot}
|
||||||
>
|
>
|
||||||
|
<Trash2 className="h-4 w-4 mr-2" />
|
||||||
{isDeletingSnapshot ? "Deleting..." : "Delete Snapshot"}
|
{isDeletingSnapshot ? "Deleting..." : "Delete Snapshot"}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useId, useState } from "react";
|
|||||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||||
import { redirect, useNavigate } from "react-router";
|
import { redirect, useNavigate } from "react-router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import { Save, Trash2, X } from "lucide-react";
|
||||||
import { Button } from "~/client/components/ui/button";
|
import { Button } from "~/client/components/ui/button";
|
||||||
import {
|
import {
|
||||||
AlertDialog,
|
AlertDialog,
|
||||||
@@ -201,9 +202,11 @@ export default function ScheduleDetailsPage({ params, loaderData }: Route.Compon
|
|||||||
<CreateScheduleForm volume={schedule.volume} initialValues={schedule} onSubmit={handleSubmit} formId={formId} />
|
<CreateScheduleForm volume={schedule.volume} initialValues={schedule} onSubmit={handleSubmit} formId={formId} />
|
||||||
<div className="flex justify-end mt-4 gap-2">
|
<div className="flex justify-end mt-4 gap-2">
|
||||||
<Button type="submit" className="ml-auto" variant="primary" form={formId} loading={updateSchedule.isPending}>
|
<Button type="submit" className="ml-auto" variant="primary" form={formId} loading={updateSchedule.isPending}>
|
||||||
|
<Save className="h-4 w-4 mr-2" />
|
||||||
Update schedule
|
Update schedule
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="outline" onClick={() => setIsEditMode(false)}>
|
<Button variant="outline" onClick={() => setIsEditMode(false)}>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -254,12 +257,16 @@ export default function ScheduleDetailsPage({ params, loaderData }: Route.Compon
|
|||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Cancel
|
||||||
|
</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={handleConfirmDelete}
|
onClick={handleConfirmDelete}
|
||||||
disabled={deleteSnapshot.isPending}
|
disabled={deleteSnapshot.isPending}
|
||||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
>
|
>
|
||||||
|
<Trash2 className="h-4 w-4 mr-2" />
|
||||||
Delete snapshot
|
Delete snapshot
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useId, useState } from "react";
|
import { useId, useState } from "react";
|
||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import { Database, HardDrive } from "lucide-react";
|
import { Database, HardDrive, Plus } from "lucide-react";
|
||||||
import { Link, useNavigate } from "react-router";
|
import { Link, useNavigate } from "react-router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import {
|
import {
|
||||||
@@ -160,6 +160,7 @@ export default function CreateBackup({ loaderData }: Route.ComponentProps) {
|
|||||||
<CreateScheduleForm volume={selectedVolume} onSubmit={handleSubmit} formId={formId} />
|
<CreateScheduleForm volume={selectedVolume} onSubmit={handleSubmit} formId={formId} />
|
||||||
<div className="flex justify-end mt-4 gap-2">
|
<div className="flex justify-end mt-4 gap-2">
|
||||||
<Button type="submit" variant="primary" form={formId} loading={createSchedule.isPending}>
|
<Button type="submit" variant="primary" form={formId} loading={createSchedule.isPending}>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
Create
|
Create
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { Bell } from "lucide-react";
|
import { Bell, Plus, X } from "lucide-react";
|
||||||
import { useId } from "react";
|
import { useId } from "react";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
@@ -65,9 +65,11 @@ export default function CreateNotification() {
|
|||||||
<CreateNotificationForm mode="create" formId={formId} onSubmit={handleSubmit} />
|
<CreateNotificationForm mode="create" formId={formId} onSubmit={handleSubmit} />
|
||||||
<div className="flex justify-end gap-2 pt-4 border-t">
|
<div className="flex justify-end gap-2 pt-4 border-t">
|
||||||
<Button type="button" variant="secondary" onClick={() => navigate("/notifications")}>
|
<Button type="button" variant="secondary" onClick={() => navigate("/notifications")}>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" form={formId} loading={createNotification.isPending}>
|
<Button type="submit" form={formId} loading={createNotification.isPending}>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
Create Destination
|
Create Destination
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { getNotificationDestination } from "~/client/api-client/sdk.gen";
|
|||||||
import type { Route } from "./+types/notification-details";
|
import type { Route } from "./+types/notification-details";
|
||||||
import { cn } from "~/client/lib/utils";
|
import { cn } from "~/client/lib/utils";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "~/client/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "~/client/components/ui/card";
|
||||||
import { Bell, TestTube2 } from "lucide-react";
|
import { Bell, Save, TestTube2, Trash2, X } from "lucide-react";
|
||||||
import { Alert, AlertDescription } from "~/client/components/ui/alert";
|
import { Alert, AlertDescription } from "~/client/components/ui/alert";
|
||||||
import { CreateNotificationForm, type NotificationFormValues } from "../components/create-notification-form";
|
import { CreateNotificationForm, type NotificationFormValues } from "../components/create-notification-form";
|
||||||
|
|
||||||
@@ -147,6 +147,7 @@ export default function NotificationDetailsPage({ loaderData }: Route.ComponentP
|
|||||||
variant="destructive"
|
variant="destructive"
|
||||||
loading={deleteDestination.isPending}
|
loading={deleteDestination.isPending}
|
||||||
>
|
>
|
||||||
|
<Trash2 className="h-4 w-4 mr-2" />
|
||||||
Delete
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,6 +175,7 @@ export default function NotificationDetailsPage({ loaderData }: Route.ComponentP
|
|||||||
<CreateNotificationForm mode="update" formId={formId} onSubmit={handleSubmit} initialValues={data.config} />
|
<CreateNotificationForm mode="update" formId={formId} onSubmit={handleSubmit} initialValues={data.config} />
|
||||||
<div className="flex justify-end gap-2 pt-4 border-t">
|
<div className="flex justify-end gap-2 pt-4 border-t">
|
||||||
<Button type="submit" form={formId} loading={updateDestination.isPending}>
|
<Button type="submit" form={formId} loading={updateDestination.isPending}>
|
||||||
|
<Save className="h-4 w-4 mr-2" />
|
||||||
Save Changes
|
Save Changes
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -190,8 +192,14 @@ export default function NotificationDetailsPage({ loaderData }: Route.ComponentP
|
|||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>
|
||||||
<AlertDialogAction onClick={handleConfirmDelete}>Delete</AlertDialogAction>
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Cancel
|
||||||
|
</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={handleConfirmDelete}>
|
||||||
|
<Trash2 className="h-4 w-4 mr-2" />
|
||||||
|
Delete
|
||||||
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { Database } from "lucide-react";
|
import { Database, Plus, X } from "lucide-react";
|
||||||
import { useId } from "react";
|
import { useId } from "react";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
@@ -76,9 +76,11 @@ export default function CreateRepository() {
|
|||||||
/>
|
/>
|
||||||
<div className="flex justify-end gap-2 pt-4 border-t">
|
<div className="flex justify-end gap-2 pt-4 border-t">
|
||||||
<Button type="button" variant="secondary" onClick={() => navigate("/repositories")}>
|
<Button type="button" variant="secondary" onClick={() => navigate("/repositories")}>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" form={formId} loading={createRepository.isPending}>
|
<Button type="submit" form={formId} loading={createRepository.isPending}>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
Create Repository
|
Create Repository
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import { cn } from "~/client/lib/utils";
|
|||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs";
|
||||||
import { RepositoryInfoTabContent } from "../tabs/info";
|
import { RepositoryInfoTabContent } from "../tabs/info";
|
||||||
import { RepositorySnapshotsTabContent } from "../tabs/snapshots";
|
import { RepositorySnapshotsTabContent } from "../tabs/snapshots";
|
||||||
import { Loader2 } from "lucide-react";
|
import { Loader2, Stethoscope, Trash2, X } from "lucide-react";
|
||||||
|
|
||||||
export const handle = {
|
export const handle = {
|
||||||
breadcrumb: (match: Route.MetaArgs) => [
|
breadcrumb: (match: Route.MetaArgs) => [
|
||||||
@@ -152,10 +152,14 @@ export default function RepositoryDetailsPage({ loaderData }: Route.ComponentPro
|
|||||||
Running Doctor...
|
Running Doctor...
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
"Run Doctor"
|
<>
|
||||||
|
<Stethoscope className="h-4 w-4 mr-2" />
|
||||||
|
Run Doctor
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="destructive" onClick={() => setShowDeleteConfirm(true)} disabled={deleteRepo.isPending}>
|
<Button variant="destructive" onClick={() => setShowDeleteConfirm(true)} disabled={deleteRepo.isPending}>
|
||||||
|
<Trash2 className="h-4 w-4 mr-2" />
|
||||||
Delete
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -184,11 +188,15 @@ export default function RepositoryDetailsPage({ loaderData }: Route.ComponentPro
|
|||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<div className="flex gap-3 justify-end">
|
<div className="flex gap-3 justify-end">
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Cancel
|
||||||
|
</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={handleConfirmDelete}
|
onClick={handleConfirmDelete}
|
||||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
>
|
>
|
||||||
|
<Trash2 className="h-4 w-4 mr-2" />
|
||||||
Delete repository
|
Delete repository
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</div>
|
</div>
|
||||||
@@ -230,7 +238,10 @@ export default function RepositoryDetailsPage({ loaderData }: Route.ComponentPro
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<Button onClick={() => setShowDoctorResults(false)}>Close</Button>
|
<Button onClick={() => setShowDoctorResults(false)}>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useMutation } from "@tanstack/react-query";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
|
import { Check, Save, X } from "lucide-react";
|
||||||
import { Card } from "~/client/components/ui/card";
|
import { Card } from "~/client/components/ui/card";
|
||||||
import { Button } from "~/client/components/ui/button";
|
import { Button } from "~/client/components/ui/button";
|
||||||
import { Input } from "~/client/components/ui/input";
|
import { Input } from "~/client/components/ui/input";
|
||||||
@@ -146,6 +147,7 @@ export const RepositoryInfoTabContent = ({ repository }: Props) => {
|
|||||||
|
|
||||||
<div className="flex justify-end pt-4 border-t">
|
<div className="flex justify-end pt-4 border-t">
|
||||||
<Button type="submit" disabled={!hasChanges || updateMutation.isPending} loading={updateMutation.isPending}>
|
<Button type="submit" disabled={!hasChanges || updateMutation.isPending} loading={updateMutation.isPending}>
|
||||||
|
<Save className="h-4 w-4 mr-2" />
|
||||||
Save Changes
|
Save Changes
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -159,8 +161,14 @@ export const RepositoryInfoTabContent = ({ repository }: Props) => {
|
|||||||
<AlertDialogDescription>Are you sure you want to update the repository settings?</AlertDialogDescription>
|
<AlertDialogDescription>Are you sure you want to update the repository settings?</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>
|
||||||
<AlertDialogAction onClick={confirmUpdate}>Update</AlertDialogAction>
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Cancel
|
||||||
|
</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={confirmUpdate}>
|
||||||
|
<Check className="h-4 w-4 mr-2" />
|
||||||
|
Update
|
||||||
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { Database } from "lucide-react";
|
import { Database, X } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { listSnapshotsOptions } from "~/client/api-client/@tanstack/react-query.gen";
|
import { listSnapshotsOptions } from "~/client/api-client/@tanstack/react-query.gen";
|
||||||
import { SnapshotsTable } from "~/client/components/snapshots-table";
|
import { SnapshotsTable } from "~/client/components/snapshots-table";
|
||||||
@@ -124,6 +124,7 @@ export const RepositorySnapshotsTabContent = ({ repository }: Props) => {
|
|||||||
<div className="flex flex-col items-center gap-3">
|
<div className="flex flex-col items-center gap-3">
|
||||||
<p className="text-muted-foreground">No snapshots match your search.</p>
|
<p className="text-muted-foreground">No snapshots match your search.</p>
|
||||||
<Button onClick={() => setSearchQuery("")} variant="outline" size="sm">
|
<Button onClick={() => setSearchQuery("")} variant="outline" size="sm">
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
Clear search
|
Clear search
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { Download, KeyRound, User } from "lucide-react";
|
import { Download, KeyRound, User, X } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
@@ -195,6 +195,7 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button type="submit" loading={changePassword.isPending} className="mt-4">
|
<Button type="submit" loading={changePassword.isPending} className="mt-4">
|
||||||
|
<KeyRound className="h-4 w-4 mr-2" />
|
||||||
Change Password
|
Change Password
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
@@ -252,9 +253,11 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
|
|||||||
setDownloadPassword("");
|
setDownloadPassword("");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" loading={downloadResticPassword.isPending}>
|
<Button type="submit" loading={downloadResticPassword.isPending}>
|
||||||
|
<Download className="h-4 w-4 mr-2" />
|
||||||
Download
|
Download
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { formatDistanceToNow } from "date-fns";
|
import { formatDistanceToNow } from "date-fns";
|
||||||
import { HeartIcon } from "lucide-react";
|
import { Activity, HeartIcon } from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { healthCheckVolumeMutation, updateVolumeMutation } from "~/client/api-client/@tanstack/react-query.gen";
|
import { healthCheckVolumeMutation, updateVolumeMutation } from "~/client/api-client/@tanstack/react-query.gen";
|
||||||
import { OnOff } from "~/client/components/onoff";
|
import { OnOff } from "~/client/components/onoff";
|
||||||
@@ -80,6 +80,7 @@ export const HealthchecksCard = ({ volume }: Props) => {
|
|||||||
loading={healthcheck.isPending}
|
loading={healthcheck.isPending}
|
||||||
onClick={() => healthcheck.mutate({ path: { name: volume.name } })}
|
onClick={() => healthcheck.mutate({ path: { name: volume.name } })}
|
||||||
>
|
>
|
||||||
|
<Activity className="h-4 w-4 mr-2" />
|
||||||
Run Health Check
|
Run Health Check
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { HardDrive } from "lucide-react";
|
import { HardDrive, Plus, X } from "lucide-react";
|
||||||
import { useId } from "react";
|
import { useId } from "react";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
@@ -70,9 +70,11 @@ export default function CreateVolume() {
|
|||||||
<CreateVolumeForm mode="create" formId={formId} onSubmit={handleSubmit} loading={createVolume.isPending} />
|
<CreateVolumeForm mode="create" formId={formId} onSubmit={handleSubmit} loading={createVolume.isPending} />
|
||||||
<div className="flex justify-end gap-2 pt-4 border-t">
|
<div className="flex justify-end gap-2 pt-4 border-t">
|
||||||
<Button type="button" variant="secondary" onClick={() => navigate("/volumes")}>
|
<Button type="button" variant="secondary" onClick={() => navigate("/volumes")}>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" form={formId} loading={createVolume.isPending}>
|
<Button type="submit" form={formId} loading={createVolume.isPending}>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
Create Volume
|
Create Volume
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useMutation, useQuery } from "@tanstack/react-query";
|
|||||||
import { useNavigate, useParams, useSearchParams } from "react-router";
|
import { useNavigate, useParams, useSearchParams } from "react-router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { CircleStop, Play, Trash2, X } from "lucide-react";
|
||||||
import { StatusDot } from "~/client/components/status-dot";
|
import { StatusDot } from "~/client/components/status-dot";
|
||||||
import { Button } from "~/client/components/ui/button";
|
import { Button } from "~/client/components/ui/button";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs";
|
||||||
@@ -148,6 +149,7 @@ export default function VolumeDetails({ loaderData }: Route.ComponentProps) {
|
|||||||
loading={mountVol.isPending}
|
loading={mountVol.isPending}
|
||||||
className={cn({ hidden: volume.status === "mounted" })}
|
className={cn({ hidden: volume.status === "mounted" })}
|
||||||
>
|
>
|
||||||
|
<Play className="h-4 w-4 mr-2" />
|
||||||
Mount
|
Mount
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -156,9 +158,11 @@ export default function VolumeDetails({ loaderData }: Route.ComponentProps) {
|
|||||||
loading={unmountVol.isPending}
|
loading={unmountVol.isPending}
|
||||||
className={cn({ hidden: volume.status !== "mounted" })}
|
className={cn({ hidden: volume.status !== "mounted" })}
|
||||||
>
|
>
|
||||||
|
<CircleStop className="h-4 w-4 mr-2" />
|
||||||
Unmount
|
Unmount
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="destructive" onClick={() => setShowDeleteConfirm(true)} disabled={deleteVol.isPending}>
|
<Button variant="destructive" onClick={() => setShowDeleteConfirm(true)} disabled={deleteVol.isPending}>
|
||||||
|
<Trash2 className="h-4 w-4 mr-2" />
|
||||||
Delete
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -200,11 +204,15 @@ export default function VolumeDetails({ loaderData }: Route.ComponentProps) {
|
|||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<div className="flex gap-3 justify-end">
|
<div className="flex gap-3 justify-end">
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>
|
||||||
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Cancel
|
||||||
|
</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={handleConfirmDelete}
|
onClick={handleConfirmDelete}
|
||||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
>
|
>
|
||||||
|
<Trash2 className="h-4 w-4 mr-2" />
|
||||||
Delete volume
|
Delete volume
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useMutation } from "@tanstack/react-query";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import { Check, X } from "lucide-react";
|
||||||
import { CreateVolumeForm, type FormValues } from "~/client/components/create-volume-form";
|
import { CreateVolumeForm, type FormValues } from "~/client/components/create-volume-form";
|
||||||
import {
|
import {
|
||||||
AlertDialog,
|
AlertDialog,
|
||||||
@@ -93,8 +94,14 @@ export const VolumeInfoTabContent = ({ volume, statfs }: Props) => {
|
|||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>
|
||||||
<AlertDialogAction onClick={confirmUpdate}>Update</AlertDialogAction>
|
<X className="h-4 w-4 mr-2" />
|
||||||
|
Cancel
|
||||||
|
</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={confirmUpdate}>
|
||||||
|
<Check className="h-4 w-4 mr-2" />
|
||||||
|
Update
|
||||||
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
|
|||||||
Reference in New Issue
Block a user