forked from github-starred/komodo
sortable resource table
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { NewLayout } from "@components/layouts";
|
||||
import { useRead, useTagsFilter, useWrite } from "@lib/hooks";
|
||||
import { useRead, useWrite } from "@lib/hooks";
|
||||
import { Types } from "@monitor/client";
|
||||
import {
|
||||
Select,
|
||||
@@ -13,12 +13,11 @@ import { RequiredResourceComponents } from "@types";
|
||||
import { Input } from "@ui/input";
|
||||
import { AlarmClock } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { DataTable, SortableHeader } from "@ui/data-table";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Card, CardDescription, CardHeader, CardTitle } from "@ui/card";
|
||||
import { AlerterConfig } from "./config";
|
||||
import { TagsWithBadge } from "@components/tags";
|
||||
import { DeleteResource, ResourceLink } from "../common";
|
||||
import { DeleteResource } from "../common";
|
||||
import { AlerterTable } from "./table";
|
||||
|
||||
const useAlerter = (id?: string) =>
|
||||
useRead("ListAlerters", {}).data?.find((d) => d.id === id);
|
||||
@@ -85,50 +84,7 @@ export const AlerterComponents: RequiredResourceComponents = {
|
||||
);
|
||||
},
|
||||
|
||||
Table: ({ search }) => {
|
||||
const tags = useTagsFilter();
|
||||
const alerters = useRead("ListAlerters", {}).data;
|
||||
const searchSplit = search?.split(" ") || [];
|
||||
return (
|
||||
<DataTable
|
||||
tableKey="alerters"
|
||||
data={
|
||||
alerters?.filter(
|
||||
(resource) =>
|
||||
tags.every((tag) => resource.tags.includes(tag)) &&
|
||||
(searchSplit.length > 0
|
||||
? searchSplit.every((search) => resource.name.includes(search))
|
||||
: true)
|
||||
) ?? []
|
||||
}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Name" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<ResourceLink type="Alerter" id={row.original.id} />
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Type",
|
||||
accessorKey: "info.alerter_type",
|
||||
},
|
||||
{
|
||||
header: "Tags",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className="flex gap-1">
|
||||
<TagsWithBadge tag_ids={row.original.tags} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
},
|
||||
Table: AlerterTable,
|
||||
|
||||
Name: ({ id }: { id: string }) => <>{useAlerter(id)?.name}</>,
|
||||
name: (id) => useAlerter(id)?.name,
|
||||
|
||||
51
frontend/src/components/resources/alerter/table.tsx
Normal file
51
frontend/src/components/resources/alerter/table.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { useRead, useTagsFilter } from "@lib/hooks";
|
||||
import { DataTable, SortableHeader } from "@ui/data-table";
|
||||
import { ResourceLink } from "../common";
|
||||
import { TagsWithBadge } from "@components/tags";
|
||||
|
||||
export const AlerterTable = ({ search }: { search?: string }) => {
|
||||
const tags = useTagsFilter();
|
||||
const alerters = useRead("ListAlerters", {}).data;
|
||||
const searchSplit = search?.split(" ") || [];
|
||||
return (
|
||||
<DataTable
|
||||
tableKey="alerters"
|
||||
data={
|
||||
alerters?.filter(
|
||||
(resource) =>
|
||||
tags.every((tag) => resource.tags.includes(tag)) &&
|
||||
(searchSplit.length > 0
|
||||
? searchSplit.every((search) => resource.name.includes(search))
|
||||
: true)
|
||||
) ?? []
|
||||
}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Name" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<ResourceLink type="Alerter" id={row.original.id} />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "info.alerter_type",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Type" />
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Tags",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className="flex gap-1">
|
||||
<TagsWithBadge tag_ids={row.original.tags} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -26,20 +26,23 @@ export const BuildTable = ({ search }: { search?: string }) => {
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Name" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<ResourceLink type="Build" id={row.original.id} />
|
||||
),
|
||||
cell: ({ row }) => <ResourceLink type="Build" id={row.original.id} />,
|
||||
},
|
||||
{
|
||||
header: "Version",
|
||||
accessorFn: ({ info }) => fmt_version(info.version),
|
||||
},
|
||||
{
|
||||
header: "Repo",
|
||||
accessorKey: "info.repo",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Repo" />
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Last Built",
|
||||
accessorKey: "info.last_built_at",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Last Built" />
|
||||
),
|
||||
accessorFn: ({ info: { last_built_at } }) => {
|
||||
if (last_built_at > 0) {
|
||||
return fmt_date_with_minutes(new Date(last_built_at));
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { NewLayout } from "@components/layouts";
|
||||
import { useRead, useTagsFilter, useWrite } from "@lib/hooks";
|
||||
import { useRead, useWrite } from "@lib/hooks";
|
||||
import { Types } from "@monitor/client";
|
||||
import { RequiredResourceComponents } from "@types";
|
||||
import { Card, CardDescription, CardHeader, CardTitle } from "@ui/card";
|
||||
import { DataTable, SortableHeader } from "@ui/data-table";
|
||||
import { Input } from "@ui/input";
|
||||
import {
|
||||
Select,
|
||||
@@ -17,7 +16,8 @@ import { Cloud, Bot, Factory } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { BuilderConfig } from "./config";
|
||||
import { DeleteResource, ResourceLink } from "../common";
|
||||
import { DeleteResource } from "../common";
|
||||
import { BuidlerTable } from "./table";
|
||||
|
||||
const useBuilder = (id?: string) =>
|
||||
useRead("ListBuilders", {}).data?.find((d) => d.id === id);
|
||||
@@ -84,45 +84,7 @@ export const BuilderComponents: RequiredResourceComponents = {
|
||||
);
|
||||
},
|
||||
|
||||
Table: ({ search }) => {
|
||||
const tags = useTagsFilter();
|
||||
const builders = useRead("ListBuilders", {}).data;
|
||||
const searchSplit = search?.split(" ") || [];
|
||||
return (
|
||||
<DataTable
|
||||
tableKey="builders"
|
||||
data={
|
||||
builders?.filter(
|
||||
(resource) =>
|
||||
tags.every((tag) => resource.tags.includes(tag)) &&
|
||||
(searchSplit.length > 0
|
||||
? searchSplit.every((search) => resource.name.includes(search))
|
||||
: true)
|
||||
) ?? []
|
||||
}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Name" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<ResourceLink type="Builder" id={row.original.id} />
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Provider",
|
||||
accessorKey: "info.provider",
|
||||
},
|
||||
{
|
||||
header: "Instance Type",
|
||||
accessorKey: "info.instance_type",
|
||||
},
|
||||
{ header: "Tags", accessorFn: ({ tags }) => tags.join(", ") },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
},
|
||||
Table: BuidlerTable,
|
||||
|
||||
Name: ({ id }: { id: string }) => <>{useBuilder(id)?.name}</>,
|
||||
name: (id) => useBuilder(id)?.name,
|
||||
|
||||
57
frontend/src/components/resources/builder/table.tsx
Normal file
57
frontend/src/components/resources/builder/table.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { useRead, useTagsFilter } from "@lib/hooks";
|
||||
import { DataTable, SortableHeader } from "@ui/data-table";
|
||||
import { ResourceLink } from "../common";
|
||||
import { TagsWithBadge } from "@components/tags";
|
||||
|
||||
export const BuidlerTable = ({ search }: { search?: string }) => {
|
||||
const tags = useTagsFilter();
|
||||
const builders = useRead("ListBuilders", {}).data;
|
||||
const searchSplit = search?.split(" ") || [];
|
||||
return (
|
||||
<DataTable
|
||||
tableKey="builders"
|
||||
data={
|
||||
builders?.filter(
|
||||
(resource) =>
|
||||
tags.every((tag) => resource.tags.includes(tag)) &&
|
||||
(searchSplit.length > 0
|
||||
? searchSplit.every((search) => resource.name.includes(search))
|
||||
: true)
|
||||
) ?? []
|
||||
}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Name" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<ResourceLink type="Builder" id={row.original.id} />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "info.provider",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Provider" />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "info.instance_type",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Instance Type" />
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Tags",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className="flex gap-1">
|
||||
<TagsWithBadge tag_ids={row.original.tags} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -30,8 +30,10 @@ export const ProcedureTable = ({ search }: { search?: string }) => {
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Type",
|
||||
accessorKey: "info.procedure_type",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Type" />
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Tags",
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { TagsWithBadge } from "@components/tags";
|
||||
import { useRead, useTagsFilter } from "@lib/hooks";
|
||||
import { useRead } from "@lib/hooks";
|
||||
import { RequiredResourceComponents } from "@types";
|
||||
import { Card, CardDescription, CardHeader, CardTitle } from "@ui/card";
|
||||
import { DataTable, SortableHeader } from "@ui/data-table";
|
||||
import { FolderGit, GitBranch } from "lucide-react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { RepoConfig } from "./config";
|
||||
import { CloneRepo, PullRepo } from "./actions";
|
||||
import { DeleteResource, NewResource, ResourceLink } from "../common";
|
||||
import { DeleteResource, NewResource } from "../common";
|
||||
import { RepoTable } from "./table";
|
||||
|
||||
const useRepo = (id?: string) =>
|
||||
useRead("ListRepos", {}).data?.find((d) => d.id === id);
|
||||
@@ -34,54 +33,7 @@ export const RepoComponents: RequiredResourceComponents = {
|
||||
|
||||
New: () => <NewResource type="Repo" />,
|
||||
|
||||
Table: ({ search }) => {
|
||||
const tags = useTagsFilter();
|
||||
const repos = useRead("ListRepos", {}).data;
|
||||
const searchSplit = search?.split(" ") || [];
|
||||
return (
|
||||
<DataTable
|
||||
tableKey="repos"
|
||||
data={
|
||||
repos?.filter(
|
||||
(resource) =>
|
||||
tags.every((tag) => resource.tags.includes(tag)) &&
|
||||
(searchSplit.length > 0
|
||||
? searchSplit.every((search) => resource.name.includes(search))
|
||||
: true)
|
||||
) ?? []
|
||||
}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Name" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<ResourceLink type="Repo" id={row.original.id} />
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Repo",
|
||||
accessorKey: "info.repo",
|
||||
},
|
||||
{
|
||||
header: "Branch",
|
||||
accessorKey: "info.branch",
|
||||
},
|
||||
{
|
||||
header: "Tags",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className="flex gap-1">
|
||||
<TagsWithBadge tag_ids={row.original.tags} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
},
|
||||
Table: RepoTable,
|
||||
|
||||
Name: ({ id }: { id: string }) => <>{useRepo(id)?.name}</>,
|
||||
name: (id) => useRepo(id)?.name,
|
||||
|
||||
55
frontend/src/components/resources/repo/table.tsx
Normal file
55
frontend/src/components/resources/repo/table.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { useRead, useTagsFilter } from "@lib/hooks";
|
||||
import { DataTable, SortableHeader } from "@ui/data-table";
|
||||
import { ResourceLink } from "../common";
|
||||
import { TagsWithBadge } from "@components/tags";
|
||||
|
||||
export const RepoTable = ({ search }: { search?: string }) => {
|
||||
const tags = useTagsFilter();
|
||||
const repos = useRead("ListRepos", {}).data;
|
||||
const searchSplit = search?.split(" ") || [];
|
||||
return (
|
||||
<DataTable
|
||||
tableKey="repos"
|
||||
data={
|
||||
repos?.filter(
|
||||
(resource) =>
|
||||
tags.every((tag) => resource.tags.includes(tag)) &&
|
||||
(searchSplit.length > 0
|
||||
? searchSplit.every((search) => resource.name.includes(search))
|
||||
: true)
|
||||
) ?? []
|
||||
}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Name" />
|
||||
),
|
||||
cell: ({ row }) => <ResourceLink type="Repo" id={row.original.id} />,
|
||||
},
|
||||
{
|
||||
accessorKey: "info.repo",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Repo" />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "info.branch",
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Branch" />
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Tags",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className="flex gap-1">
|
||||
<TagsWithBadge tag_ids={row.original.tags} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -31,7 +31,22 @@ export const ServerTable = ({ search }: { search?: string }) => {
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Deployments",
|
||||
accessorKey: "id",
|
||||
sortingFn: (a, b) => {
|
||||
const sa = useDeploymentCount(a.original.id);
|
||||
const sb = useDeploymentCount(b.original.id);
|
||||
|
||||
if (!sa && !sb) return 0;
|
||||
if (!sa) return -1;
|
||||
if (!sb) return 1;
|
||||
|
||||
if (sa > sb) return 1;
|
||||
else if (sa < sb) return -1;
|
||||
else return 0;
|
||||
},
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Deployments" />
|
||||
),
|
||||
cell: ({ row }) => <DeploymentCountOnServer id={row.original.id} />,
|
||||
},
|
||||
{
|
||||
@@ -69,9 +84,12 @@ export const ServerTable = ({ search }: { search?: string }) => {
|
||||
};
|
||||
|
||||
const DeploymentCountOnServer = ({ id }: { id: string }) => {
|
||||
const { data } = useRead("ListDeployments", {
|
||||
query: { specific: { server_ids: [id] } },
|
||||
});
|
||||
|
||||
return <>{data?.length ?? 0}</>;
|
||||
const count = useDeploymentCount(id);
|
||||
return <>{count ?? 0}</>;
|
||||
};
|
||||
|
||||
const useDeploymentCount = (id: string) => {
|
||||
return useRead("ListDeployments", {}).data?.filter(
|
||||
(d) => d.info.server_id === id
|
||||
).length;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user