feat: 添加制品详情页面及相关功能;优化制品列表和数据获取逻辑

This commit is contained in:
xiongxiao
2026-03-27 00:57:47 +08:00
committed by cnb
parent 2f426df210
commit 8984913fcd
7 changed files with 666 additions and 22 deletions

299
src/modules/package-api.ts Normal file
View File

@@ -0,0 +1,299 @@
import { createQueryApi } from '@kevisual/query/api';
const api = {
"cnb": {
/**
* 获取指定制品的详细信息
*
* @param data - Request parameters
* @param data.slug - {string} 资源路径, 如 my-org/my-registry
* @param data.type - {string} 制品类型
* @param data.name - {string} 制品名称
*/
"get-package": {
"path": "cnb",
"key": "get-package",
"description": "获取制品详情, 参数 slug, type, name",
"metadata": {
"tags": [
"package"
],
"args": {
"slug": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "资源路径, 如 my-org/my-registry"
},
"type": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "制品类型"
},
"name": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "制品名称"
}
},
"skill": "get-package",
"title": "获取制品详情",
"summary": "获取指定制品的详细信息",
"url": "/api/router",
"source": "query-proxy-api"
}
},
/**
* 获取制品标签的详细信息
*
* @param data - Request parameters
* @param data.slug - {string} 资源路径, 如 my-org/my-registry
* @param data.type - {string} 制品类型
* @param data.name - {string} 制品名称
* @param data.tag - {string} 标签名称
*/
"get-package-tag": {
"path": "cnb",
"key": "get-package-tag",
"description": "获取制品标签详情, 参数 slug, type, name, tag",
"metadata": {
"tags": [
"package"
],
"args": {
"slug": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "资源路径, 如 my-org/my-registry"
},
"type": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "制品类型"
},
"name": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "制品名称"
},
"tag": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "标签名称"
}
},
"skill": "get-package-tag",
"title": "获取制品标签详情",
"summary": "获取制品标签的详细信息",
"url": "/api/router",
"source": "query-proxy-api"
}
},
/**
* 查询制品列表
*
* @param data - Request parameters
* @param data.slug - {string} 资源路径, 如 my-org/my-registry
* @param data.type - {string} 制品类型: all, docker, helm, docker-model, maven, npm, ohpm, pypi, nuget, composer, conan, cargo
* @param data.ordering - {string} 排序类型: pull_count, last_push_at, name_ascend, name_descend
* @param data.name - {string} 关键字,搜索制品名称
* @param data.page - {number} 页码
* @param data.page_size - {number} 每页数量
*/
"list-packages": {
"path": "cnb",
"key": "list-packages",
"description": "查询制品列表, 参数 slug, type",
"metadata": {
"tags": [
"package"
],
"args": {
"slug": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "资源路径, 如 my-org/my-registry"
},
"type": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "制品类型: all, docker, helm, docker-model, maven, npm, ohpm, pypi, nuget, composer, conan, cargo"
},
"ordering": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "排序类型: pull_count, last_push_at, name_ascend, name_descend",
"optional": true
},
"name": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "关键字,搜索制品名称",
"optional": true
},
"page": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "number",
"description": "页码",
"optional": true
},
"page_size": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "number",
"description": "每页数量",
"optional": true
}
},
"skill": "list-packages",
"title": "查询制品列表",
"summary": "查询制品列表",
"url": "/api/router",
"source": "query-proxy-api"
}
},
/**
* 获取制品的标签列表
*
* @param data - Request parameters
* @param data.slug - {string} 资源路径, 如 my-org/my-registry
* @param data.type - {string} 制品类型
* @param data.name - {string} 制品名称
* @param data.page - {number} 页码
* @param data.page_size - {number} 每页数量
*/
"list-package-tags": {
"path": "cnb",
"key": "list-package-tags",
"description": "获取制品标签列表, 参数 slug, type, name",
"metadata": {
"tags": [
"package"
],
"args": {
"slug": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "资源路径, 如 my-org/my-registry"
},
"type": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "制品类型"
},
"name": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "制品名称"
},
"page": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "number",
"description": "页码",
"optional": true
},
"page_size": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "number",
"description": "每页数量",
"optional": true
}
},
"skill": "list-package-tags",
"title": "获取制品标签列表",
"summary": "获取制品的标签列表",
"url": "/api/router",
"source": "query-proxy-api"
}
},
/**
* 删除指定的制品
*
* @param data - Request parameters
* @param data.slug - {string} 资源路径, 如 my-org/my-registry
* @param data.type - {string} 制品类型
* @param data.name - {string} 制品名称
*/
"delete-package": {
"path": "cnb",
"key": "delete-package",
"description": "删除制品, 参数 slug, type, name",
"metadata": {
"tags": [
"package"
],
"args": {
"slug": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "资源路径, 如 my-org/my-registry"
},
"type": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "制品类型"
},
"name": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "制品名称"
}
},
"skill": "delete-package",
"title": "删除制品",
"summary": "删除指定的制品",
"url": "/api/router",
"source": "query-proxy-api"
}
},
/**
* 删除制品的指定标签
*
* @param data - Request parameters
* @param data.slug - {string} 资源路径, 如 my-org/my-registry
* @param data.type - {string} 制品类型
* @param data.name - {string} 制品名称
* @param data.tag - {string} 标签名称
*/
"delete-package-tag": {
"path": "cnb",
"key": "delete-package-tag",
"description": "删除制品标签, 参数 slug, type, name, tag",
"metadata": {
"tags": [
"package"
],
"args": {
"slug": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "资源路径, 如 my-org/my-registry"
},
"type": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "制品类型"
},
"name": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "制品名称"
},
"tag": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"description": "标签名称"
}
},
"skill": "delete-package-tag",
"title": "删除制品标签",
"summary": "删除制品的指定标签",
"url": "/api/router",
"source": "query-proxy-api"
}
}
}
} as const;
const queryApi = createQueryApi({ api });
export { queryApi };
// 使用例子,方法为对应的方法data 为对应的 args 的参数的定义数据
// queryApi['user-app'].delete(data)

View File

@@ -0,0 +1,235 @@
import { useSearch } from "@tanstack/react-router";
import { MarkItem, usePackageStore } from "../store";
import { PackageItem } from "../store/package-type";
import { useShallow } from "zustand/shallow";
import { useEffect, useState } from "react";
import dayjs from "dayjs";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
CardAction,
} from "@/components/ui/card";
import { SidebarLayout } from "@/pages/sidebar/components";
import { ArrowLeftIcon, Copy, MoreVertical, Info, ExternalLink } from "lucide-react";
import { toast } from "sonner";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
export const App = () => {
const searchParams = useSearch({ strict: false }) as { slug?: string; id?: string };
const { slug, id } = searchParams;
const packageStore = usePackageStore(useShallow((state) => ({
packagesList: state.packagesList,
packagesListLoading: state.packagesListLoading,
getPackagesList: state.getPackagesList,
getItem: state.getItem,
})));
const [detailItem, setDetailItem] = useState<MarkItem | null>(null);
const [detailLoading, setDetailLoading] = useState(false);
useEffect(() => {
if (slug) {
packageStore.getPackagesList({ slug });
}
}, [slug]);
useEffect(() => {
if (id) {
setDetailLoading(true);
packageStore.getItem(id).then((data) => {
setDetailItem(data);
setDetailLoading(false);
});
}
}, [id]);
const onCopy = (data: PackageItem) => {
// kevisual/dev-env 取 kevisual删除最后一个斜杠和后面的内容
const _group = slug?.split?.('/')?.filter(Boolean);
_group?.shift?.();
const group = _group?.[0];
const value = `docker.cnb.cool/${slug}/${data.package}:latest`
}
const onDetail = (item: PackageItem) => {
}
const onToPage = (item: PackageItem) => {
const type = 'docker';
const url = `https://cnb.cool/${slug}/-/packages?type=${type}&ordering=last_push_at`;
}
return (
<SidebarLayout>
<div className="p-5">
<div className="flex items-center gap-3 mb-5">
<Button variant="ghost" size="sm" onClick={() => history.back()}>
<ArrowLeftIcon className="size-4 mr-1" />
</Button>
<h1 className="text-2xl font-semibold"></h1>
</div>
{id && (
<div className="mb-5">
{detailLoading ? (
<div className="text-center py-4 text-muted-foreground">...</div>
) : detailItem ? (
<Card>
<CardHeader>
<CardTitle>{detailItem.title || '未命名'}</CardTitle>
<CardDescription>{detailItem.summary || '暂无描述'}</CardDescription>
</CardHeader>
<CardContent>
{detailItem.tags && detailItem.tags.length > 0 && (
<div className="flex flex-wrap gap-1 mb-3">
{detailItem.tags.map((tag, index) => (
<Badge key={index} variant="outline">{tag}</Badge>
))}
</div>
)}
<p className="text-xs text-muted-foreground">
ID: {detailItem.id}
</p>
</CardContent>
</Card>
) : (
<div className="text-center py-4 text-muted-foreground"></div>
)}
</div>
)}
<h2 className="text-xl font-semibold mb-4"></h2>
{packageStore.packagesListLoading ? (
<div className="text-center py-10 text-muted-foreground">...</div>
) : packageStore.packagesList.length === 0 ? (
<div className="text-center py-10 text-muted-foreground"></div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{packageStore.packagesList.map((item: PackageItem) => {
const dockerValue = `docker.cnb.cool/${slug}/${item.package}:latest`;
const dockerPullValue = `docker pull ${dockerValue}`;
return (
<Card key={item.package}>
<CardHeader>
<CardTitle>{item.package || '未命名'}</CardTitle>
<CardDescription className="text-xs">: {item.package_type}</CardDescription>
<CardAction>
<div className="flex items-center gap-1">
<Tooltip>
<TooltipTrigger
render={
<Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0 cursor-pointer"
onClick={() => {
navigator.clipboard.writeText(dockerValue).then(() => {
toast.success('已复制 docker value');
});
}}
>
<Copy className="w-4 h-4" />
</Button>
}
/>
<TooltipContent></TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger
render={
<Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0 cursor-pointer"
onClick={() => {
toast.info('功能开发中');
}}
>
<Info className="w-4 h-4" />
</Button>
}
/>
<TooltipContent></TooltipContent>
</Tooltip>
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0 cursor-pointer"
>
<MoreVertical className="w-4 h-4" />
</Button>
}
/>
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuItem
onClick={() => {
navigator.clipboard.writeText(dockerPullValue).then(() => {
toast.success('已复制 docker pull 命令');
});
}}
className="cursor-pointer"
>
<Copy className="w-4 h-4 mr-2" />
docker registry
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => {
const type = 'docker';
const url = `https://cnb.cool/${slug}/-/packages?type=${type}&ordering=last_push_at`;
window.open(url, '_blank');
}}
className="cursor-pointer"
>
<ExternalLink className="w-4 h-4 mr-2" />
page
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</CardAction>
</CardHeader>
<CardContent className="space-y-2">
{item.labels && item.labels.length > 0 && (
<div className="flex flex-wrap gap-1">
{item.labels.map((label: string, index: number) => (
<Badge key={index} variant="outline">{label}</Badge>
))}
</div>
)}
{item.description && (
<p className="text-sm text-muted-foreground">{item.description}</p>
)}
<p className="text-xs text-muted-foreground">
: {item.pull_count}
</p>
<p className="text-xs text-muted-foreground">
: {item.last_pusher?.nickname || '-'}
</p>
<p className="text-xs text-muted-foreground">
: {item.last_pusher?.push_at ? dayjs(item.last_pusher.push_at).format('YYYY-MM-DD HH:mm:ss') : '-'}
</p>
</CardContent>
</Card>
);
})}
</div>
)}
</div>
</SidebarLayout>
);
};
export default App;

View File

@@ -13,10 +13,13 @@ import {
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import { CreateDialog, EditDialog } from "./components"; import { CreateDialog, EditDialog } from "./components";
import { SearchIcon, RefreshCwIcon, PlusIcon, PencilIcon, TrashIcon } from "lucide-react"; import { SearchIcon, RefreshCwIcon, PlusIcon, PencilIcon, TrashIcon, EyeIcon } from "lucide-react";
import { useNavigate } from "@tanstack/react-router";
import { SidebarLayout } from "@/pages/sidebar/components"; import { SidebarLayout } from "@/pages/sidebar/components";
import { toast } from "sonner";
export const App = () => { export const App = () => {
const navigate = useNavigate();
const packageStore = usePackageStore(useShallow((state: PackageState) => { const packageStore = usePackageStore(useShallow((state: PackageState) => {
return { return {
list: state.list, list: state.list,
@@ -31,6 +34,7 @@ export const App = () => {
setShowEditDialog: state.setShowEditDialog, setShowEditDialog: state.setShowEditDialog,
editingItem: state.editingItem, editingItem: state.editingItem,
setEditingItem: state.setEditingItem, setEditingItem: state.setEditingItem,
getItem: state.getItem,
} }
})); }));
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
@@ -49,8 +53,13 @@ export const App = () => {
packageStore.getList({ search }); packageStore.getList({ search });
}; };
const handleEdit = (item: any) => { const handleEdit = async (item: any) => {
packageStore.setEditingItem(item); const data = await packageStore.getItem(item.id);
if (!data) {
toast.error('未找到制品数据');
return;
}
packageStore.setEditingItem(data);
packageStore.setShowEditDialog(true); packageStore.setShowEditDialog(true);
}; };
@@ -107,9 +116,6 @@ export const App = () => {
{item.summary && ( {item.summary && (
<p className="text-sm text-muted-foreground">{item.summary}</p> <p className="text-sm text-muted-foreground">{item.summary}</p>
)} )}
{item.description && (
<p className="text-sm text-muted-foreground line-clamp-2">{item.description}</p>
)}
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
: {item.createdAt ? dayjs(item.createdAt).format('YYYY-MM-DD HH:mm:ss') : '-'} : {item.createdAt ? dayjs(item.createdAt).format('YYYY-MM-DD HH:mm:ss') : '-'}
</p> </p>
@@ -117,6 +123,9 @@ export const App = () => {
: {item.updatedAt ? dayjs(item.updatedAt).format('YYYY-MM-DD HH:mm:ss') : '-'} : {item.updatedAt ? dayjs(item.updatedAt).format('YYYY-MM-DD HH:mm:ss') : '-'}
</p> </p>
<div className="flex gap-2 pt-2"> <div className="flex gap-2 pt-2">
<Button variant="outline" size="sm" onClick={() => navigate({ to: '/cnb-packages/detail', search: { slug: item.title, id: item.id } })}>
<EyeIcon className="size-3.5" />
</Button>
<Button variant="outline" size="sm" onClick={() => handleEdit(item)}> <Button variant="outline" size="sm" onClick={() => handleEdit(item)}>
<PencilIcon className="size-3.5" /> <PencilIcon className="size-3.5" />
</Button> </Button>

View File

@@ -1,37 +1,43 @@
import { create } from 'zustand'; import { create } from 'zustand';
import { queryApi } from '@/modules/mark-api'; import { queryApi as markApi } from '@/modules/mark-api';
import { queryApi as cnbApi } from '@/modules/package-api';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { PackageItem } from './package-type';
type PackageItem = { export type MarkItem = {
id: string; id: string;
title: string; title: string;
tags?: string[]; tags: string[];
link?: string; link: string;
summary?: string; summary: string;
description?: string; description?: string;
data?: any;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
} }
type PackageState = { type PackageState = {
edit: boolean; edit: boolean;
setEdit: (edit: boolean) => void; setEdit: (edit: boolean) => void;
list: PackageItem[]; list: MarkItem[];
loading: boolean; loading: boolean;
setLoading: (loading: boolean) => void; setLoading: (loading: boolean) => void;
// CNB packages list
packagesList: PackageItem[];
packagesListLoading: boolean;
getPackagesList: (params: { slug: string, type?: string, ordering?: string, name?: string, page?: number, pageSize?: number }) => Promise<PackageItem[]>;
// Dialog states // Dialog states
showCreateDialog: boolean; showCreateDialog: boolean;
setShowCreateDialog: (show: boolean) => void; setShowCreateDialog: (show: boolean) => void;
showEditDialog: boolean; showEditDialog: boolean;
setShowEditDialog: (show: boolean) => void; setShowEditDialog: (show: boolean) => void;
editingItem: PackageItem | null; editingItem: MarkItem | null;
setEditingItem: (item: PackageItem | null) => void; setEditingItem: (item: MarkItem | null) => void;
// Data operations // Data operations MarkItem
getList: (params?: { search?: string, page?: number, pageSize?: number }) => Promise<void>; getList: (params?: { search?: string, page?: number, pageSize?: number }) => Promise<void>;
createItem: (data: { title: string, tags?: string[], link?: string, summary?: string, description?: string }) => Promise<void>; createItem: (data: { title: string, tags?: string[], link?: string, summary?: string, description?: string }) => Promise<void>;
updateItem: (id: string, data: { title?: string, tags?: string[], link?: string, summary?: string, description?: string }) => Promise<void>; updateItem: (id: string, data: { title?: string, tags?: string[], link?: string, summary?: string, description?: string }) => Promise<void>;
deleteItem: (id: string) => Promise<void>; deleteItem: (id: string) => Promise<void>;
getItem: (id: string) => Promise<PackageItem | null>; getItem: (id: string) => Promise<MarkItem | null>;
} }
export type { PackageState, PackageItem }; export type { PackageState, PackageItem };
@@ -42,6 +48,35 @@ export const usePackageStore = create<PackageState>((set, get) => ({
list: [], list: [],
loading: false, loading: false,
setLoading: (loading) => set({ loading }), setLoading: (loading) => set({ loading }),
packagesList: [],
packagesListLoading: false,
getPackagesList: async (params: { slug: string, type?: string, ordering?: string, name?: string, page?: number, pageSize?: number }) => {
const { slug, type = 'all', ordering, name, page = 1, pageSize = 20 } = params;
set({ packagesListLoading: true });
try {
const res = await cnbApi.cnb['list-packages']({
slug,
type,
ordering,
name,
page,
page_size: pageSize,
});
if (res.code === 200) {
set({ packagesList: res.data?.list || [] });
return res.data?.list || [];
} else {
toast.error(res.message || '获取制品列表失败');
return [];
}
} catch (e) {
console.error('获取制品列表失败', e);
toast.error('获取制品列表失败');
return [];
} finally {
set({ packagesListLoading: false });
}
},
showCreateDialog: false, showCreateDialog: false,
setShowCreateDialog: (show) => set({ showCreateDialog: show }), setShowCreateDialog: (show) => set({ showCreateDialog: show }),
showEditDialog: false, showEditDialog: false,
@@ -53,7 +88,7 @@ export const usePackageStore = create<PackageState>((set, get) => ({
const { page = 1, pageSize = 20, search } = params; const { page = 1, pageSize = 20, search } = params;
set({ loading: true }); set({ loading: true });
try { try {
const res = await queryApi.mark.list({ const res = await markApi.mark.list({
markType: 'cnb-packages', markType: 'cnb-packages',
page, page,
pageSize, pageSize,
@@ -75,7 +110,7 @@ export const usePackageStore = create<PackageState>((set, get) => ({
createItem: async (data) => { createItem: async (data) => {
try { try {
const res = await queryApi.mark.create({ const res = await markApi.mark.create({
title: data.title, title: data.title,
markType: 'cnb-packages', markType: 'cnb-packages',
tags: data.tags || [], tags: data.tags || [],
@@ -98,7 +133,7 @@ export const usePackageStore = create<PackageState>((set, get) => ({
updateItem: async (id, data) => { updateItem: async (id, data) => {
try { try {
const res = await queryApi.mark.update({ const res = await markApi.mark.update({
data: { data: {
// @ts-ignore // @ts-ignore
id, id,
@@ -124,7 +159,7 @@ export const usePackageStore = create<PackageState>((set, get) => ({
deleteItem: async (id) => { deleteItem: async (id) => {
try { try {
const res = await queryApi.mark.delete({ id }); const res = await markApi.mark.delete({ id });
if (res.code === 200) { if (res.code === 200) {
toast.success('删除成功'); toast.success('删除成功');
get().getList(); get().getList();
@@ -139,7 +174,7 @@ export const usePackageStore = create<PackageState>((set, get) => ({
getItem: async (id) => { getItem: async (id) => {
try { try {
const res = await queryApi.mark.get({ id }); const res = await markApi.mark.get({ id });
if (res.code === 200) { if (res.code === 200) {
return res.data; return res.data;
} else { } else {

View File

@@ -0,0 +1,35 @@
type PackageType = 'docker' | 'npm';
export type DockerPackage = {
package: string;
pull_count: number;
description: string;
labels: string[];
package_type: PackageType;
count: number;
last_pusher: {
name: string;
nickname: string;
push_at: string;
};
recent_pull_count: number;
last_artifact_name: string;
}
export type NpmRegistry = {
name: string;
package: string;
pull_count: number;
description: string;
labels: string[] | null;
package_type: PackageType;
count: number;
last_pusher: {
name: string;
nickname: string;
push_at: string;
};
recent_pull_count: number;
last_artifact_name: string;
}
export type PackageItem = DockerPackage | NpmRegistry;

View File

@@ -18,6 +18,7 @@ import { Route as ConfigIndexRouteImport } from './routes/config/index'
import { Route as CnbPackagesIndexRouteImport } from './routes/cnb-packages/index' import { Route as CnbPackagesIndexRouteImport } from './routes/cnb-packages/index'
import { Route as CloudEnvIndexRouteImport } from './routes/cloud-env/index' import { Route as CloudEnvIndexRouteImport } from './routes/cloud-env/index'
import { Route as ConfigGiteaRouteImport } from './routes/config/gitea' import { Route as ConfigGiteaRouteImport } from './routes/config/gitea'
import { Route as CnbPackagesDetailIndexRouteImport } from './routes/cnb-packages/detail/index'
const LoginRoute = LoginRouteImport.update({ const LoginRoute = LoginRouteImport.update({
id: '/login', id: '/login',
@@ -64,6 +65,11 @@ const ConfigGiteaRoute = ConfigGiteaRouteImport.update({
path: '/config/gitea', path: '/config/gitea',
getParentRoute: () => rootRouteImport, getParentRoute: () => rootRouteImport,
} as any) } as any)
const CnbPackagesDetailIndexRoute = CnbPackagesDetailIndexRouteImport.update({
id: '/cnb-packages/detail/',
path: '/cnb-packages/detail/',
getParentRoute: () => rootRouteImport,
} as any)
export interface FileRoutesByFullPath { export interface FileRoutesByFullPath {
'/': typeof IndexRoute '/': typeof IndexRoute
@@ -75,6 +81,7 @@ export interface FileRoutesByFullPath {
'/config/': typeof ConfigIndexRoute '/config/': typeof ConfigIndexRoute
'/repo/': typeof RepoIndexRoute '/repo/': typeof RepoIndexRoute
'/workspaces/': typeof WorkspacesIndexRoute '/workspaces/': typeof WorkspacesIndexRoute
'/cnb-packages/detail/': typeof CnbPackagesDetailIndexRoute
} }
export interface FileRoutesByTo { export interface FileRoutesByTo {
'/': typeof IndexRoute '/': typeof IndexRoute
@@ -86,6 +93,7 @@ export interface FileRoutesByTo {
'/config': typeof ConfigIndexRoute '/config': typeof ConfigIndexRoute
'/repo': typeof RepoIndexRoute '/repo': typeof RepoIndexRoute
'/workspaces': typeof WorkspacesIndexRoute '/workspaces': typeof WorkspacesIndexRoute
'/cnb-packages/detail': typeof CnbPackagesDetailIndexRoute
} }
export interface FileRoutesById { export interface FileRoutesById {
__root__: typeof rootRouteImport __root__: typeof rootRouteImport
@@ -98,6 +106,7 @@ export interface FileRoutesById {
'/config/': typeof ConfigIndexRoute '/config/': typeof ConfigIndexRoute
'/repo/': typeof RepoIndexRoute '/repo/': typeof RepoIndexRoute
'/workspaces/': typeof WorkspacesIndexRoute '/workspaces/': typeof WorkspacesIndexRoute
'/cnb-packages/detail/': typeof CnbPackagesDetailIndexRoute
} }
export interface FileRouteTypes { export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath fileRoutesByFullPath: FileRoutesByFullPath
@@ -111,6 +120,7 @@ export interface FileRouteTypes {
| '/config/' | '/config/'
| '/repo/' | '/repo/'
| '/workspaces/' | '/workspaces/'
| '/cnb-packages/detail/'
fileRoutesByTo: FileRoutesByTo fileRoutesByTo: FileRoutesByTo
to: to:
| '/' | '/'
@@ -122,6 +132,7 @@ export interface FileRouteTypes {
| '/config' | '/config'
| '/repo' | '/repo'
| '/workspaces' | '/workspaces'
| '/cnb-packages/detail'
id: id:
| '__root__' | '__root__'
| '/' | '/'
@@ -133,6 +144,7 @@ export interface FileRouteTypes {
| '/config/' | '/config/'
| '/repo/' | '/repo/'
| '/workspaces/' | '/workspaces/'
| '/cnb-packages/detail/'
fileRoutesById: FileRoutesById fileRoutesById: FileRoutesById
} }
export interface RootRouteChildren { export interface RootRouteChildren {
@@ -145,6 +157,7 @@ export interface RootRouteChildren {
ConfigIndexRoute: typeof ConfigIndexRoute ConfigIndexRoute: typeof ConfigIndexRoute
RepoIndexRoute: typeof RepoIndexRoute RepoIndexRoute: typeof RepoIndexRoute
WorkspacesIndexRoute: typeof WorkspacesIndexRoute WorkspacesIndexRoute: typeof WorkspacesIndexRoute
CnbPackagesDetailIndexRoute: typeof CnbPackagesDetailIndexRoute
} }
declare module '@tanstack/react-router' { declare module '@tanstack/react-router' {
@@ -212,6 +225,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ConfigGiteaRouteImport preLoaderRoute: typeof ConfigGiteaRouteImport
parentRoute: typeof rootRouteImport parentRoute: typeof rootRouteImport
} }
'/cnb-packages/detail/': {
id: '/cnb-packages/detail/'
path: '/cnb-packages/detail'
fullPath: '/cnb-packages/detail/'
preLoaderRoute: typeof CnbPackagesDetailIndexRouteImport
parentRoute: typeof rootRouteImport
}
} }
} }
@@ -225,6 +245,7 @@ const rootRouteChildren: RootRouteChildren = {
ConfigIndexRoute: ConfigIndexRoute, ConfigIndexRoute: ConfigIndexRoute,
RepoIndexRoute: RepoIndexRoute, RepoIndexRoute: RepoIndexRoute,
WorkspacesIndexRoute: WorkspacesIndexRoute, WorkspacesIndexRoute: WorkspacesIndexRoute,
CnbPackagesDetailIndexRoute: CnbPackagesDetailIndexRoute,
} }
export const routeTree = rootRouteImport export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren) ._addFileChildren(rootRouteChildren)

View File

@@ -0,0 +1,10 @@
import { createFileRoute } from '@tanstack/react-router'
import App from '@/pages/cnb-packages/detail/page'
export const Route = createFileRoute('/cnb-packages/detail/')({
component: RouteComponent,
})
function RouteComponent() {
return <App />
}