add refresh sites button

This commit is contained in:
miloschwartz 2025-06-27 16:43:09 -04:00
parent 073c318f12
commit 809a135721
No known key found for this signature in database
5 changed files with 61 additions and 11 deletions

View file

@ -776,6 +776,8 @@
"orgPoliciesAdd": "Add Organization Policy", "orgPoliciesAdd": "Add Organization Policy",
"orgRequired": "Organization is required", "orgRequired": "Organization is required",
"error": "Error", "error": "Error",
"refreshError": "Failed to refresh data",
"refresh": "Refresh",
"success": "Success", "success": "Success",
"orgPolicyAddedDescription": "Policy added successfully", "orgPolicyAddedDescription": "Policy added successfully",
"orgPolicyUpdatedDescription": "Policy updated successfully", "orgPolicyUpdatedDescription": "Policy updated successfully",

View file

@ -8,12 +8,16 @@ interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[]; columns: ColumnDef<TData, TValue>[];
data: TData[]; data: TData[];
createSite?: () => void; createSite?: () => void;
onRefresh?: () => void;
isRefreshing?: boolean;
} }
export function SitesDataTable<TData, TValue>({ export function SitesDataTable<TData, TValue>({
columns, columns,
data, data,
createSite createSite,
onRefresh,
isRefreshing
}: DataTableProps<TData, TValue>) { }: DataTableProps<TData, TValue>) {
const t = useTranslations(); const t = useTranslations();
@ -27,6 +31,8 @@ export function SitesDataTable<TData, TValue>({
searchColumn="name" searchColumn="name"
onAdd={createSite} onAdd={createSite}
addButtonText={t('siteAdd')} addButtonText={t('siteAdd')}
onRefresh={onRefresh}
isRefreshing={isRefreshing}
defaultSort={{ defaultSort={{
id: "name", id: "name",
desc: false desc: false

View file

@ -19,7 +19,7 @@ import {
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { AxiosResponse } from "axios"; import { AxiosResponse } from "axios";
import { useState } from "react"; import { useState, useEffect } from "react";
import CreateSiteForm from "./CreateSiteForm"; import CreateSiteForm from "./CreateSiteForm";
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog"; import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
import { toast } from "@app/hooks/useToast"; import { toast } from "@app/hooks/useToast";
@ -53,10 +53,31 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [selectedSite, setSelectedSite] = useState<SiteRow | null>(null); const [selectedSite, setSelectedSite] = useState<SiteRow | null>(null);
const [rows, setRows] = useState<SiteRow[]>(sites); const [rows, setRows] = useState<SiteRow[]>(sites);
const [isRefreshing, setIsRefreshing] = useState(false);
const api = createApiClient(useEnvContext()); const api = createApiClient(useEnvContext());
const t = useTranslations(); const t = useTranslations();
// Update local state when props change (e.g., after refresh)
useEffect(() => {
setRows(sites);
}, [sites]);
const refreshData = async () => {
setIsRefreshing(true);
try {
router.refresh();
} catch (error) {
toast({
title: t("error"),
description: t("refreshError"),
variant: "destructive"
});
} finally {
setIsRefreshing(false);
}
};
const deleteSite = (siteId: number) => { const deleteSite = (siteId: number) => {
api.delete(`/site/${siteId}`) api.delete(`/site/${siteId}`)
.catch((e) => { .catch((e) => {
@ -339,6 +360,8 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
createSite={() => createSite={() =>
router.push(`/${orgId}/settings/sites/create`) router.push(`/${orgId}/settings/sites/create`)
} }
onRefresh={refreshData}
isRefreshing={isRefreshing}
/> />
</> </>
); );

View file

@ -71,7 +71,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
disabled={loading || props.disabled} // Disable button when loading disabled={loading || props.disabled} // Disable button when loading
{...props} {...props}
> >
{loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} {/* {loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} */}
{props.children} {props.children}
</Comp> </Comp>
); );

View file

@ -23,13 +23,14 @@ import { Button } from "@app/components/ui/button";
import { useState } from "react"; import { useState } from "react";
import { Input } from "@app/components/ui/input"; import { Input } from "@app/components/ui/input";
import { DataTablePagination } from "@app/components/DataTablePagination"; import { DataTablePagination } from "@app/components/DataTablePagination";
import { Plus, Search } from "lucide-react"; import { Plus, Search, RefreshCw } from "lucide-react";
import { import {
Card, Card,
CardContent, CardContent,
CardHeader, CardHeader,
CardTitle CardTitle
} from "@app/components/ui/card"; } from "@app/components/ui/card";
import { useTranslations } from "next-intl";
type DataTableProps<TData, TValue> = { type DataTableProps<TData, TValue> = {
columns: ColumnDef<TData, TValue>[]; columns: ColumnDef<TData, TValue>[];
@ -37,6 +38,8 @@ type DataTableProps<TData, TValue> = {
title?: string; title?: string;
addButtonText?: string; addButtonText?: string;
onAdd?: () => void; onAdd?: () => void;
onRefresh?: () => void;
isRefreshing?: boolean;
searchPlaceholder?: string; searchPlaceholder?: string;
searchColumn?: string; searchColumn?: string;
defaultSort?: { defaultSort?: {
@ -51,6 +54,8 @@ export function DataTable<TData, TValue>({
title, title,
addButtonText, addButtonText,
onAdd, onAdd,
onRefresh,
isRefreshing,
searchPlaceholder = "Search...", searchPlaceholder = "Search...",
searchColumn = "name", searchColumn = "name",
defaultSort defaultSort
@ -60,6 +65,7 @@ export function DataTable<TData, TValue>({
); );
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]); const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const [globalFilter, setGlobalFilter] = useState<any>([]); const [globalFilter, setGlobalFilter] = useState<any>([]);
const t = useTranslations();
const table = useReactTable({ const table = useReactTable({
data, data,
@ -99,12 +105,25 @@ export function DataTable<TData, TValue>({
/> />
<Search className="h-4 w-4 absolute left-2 top-1/2 transform -translate-y-1/2 text-muted-foreground" /> <Search className="h-4 w-4 absolute left-2 top-1/2 transform -translate-y-1/2 text-muted-foreground" />
</div> </div>
{onAdd && addButtonText && ( <div className="flex items-center gap-2">
<Button onClick={onAdd}> {onRefresh && (
<Plus className="mr-2 h-4 w-4" /> <Button
{addButtonText} variant="outline"
</Button> onClick={onRefresh}
)} disabled={isRefreshing}
loading={isRefreshing}
>
<RefreshCw className={`mr-2 h-4 w-4 ${isRefreshing ? 'animate-spin' : ''}`} />
{t("refresh")}
</Button>
)}
{onAdd && addButtonText && (
<Button onClick={onAdd}>
<Plus className="mr-2 h-4 w-4" />
{addButtonText}
</Button>
)}
</div>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<Table> <Table>
@ -163,4 +182,4 @@ export function DataTable<TData, TValue>({
</Card> </Card>
</div> </div>
); );
} }