diff --git a/console/packages/starwhale-ui/src/IconFont/index.tsx b/console/packages/starwhale-ui/src/IconFont/index.tsx index e6e4560014..3a398385f9 100644 --- a/console/packages/starwhale-ui/src/IconFont/index.tsx +++ b/console/packages/starwhale-ui/src/IconFont/index.tsx @@ -120,6 +120,7 @@ export type IconTypesT = | 'a-Versionhistory' | 'fold21' | 'unfold21' + | 'a-onlineevaluation' interface IIconFontProps { style?: React.CSSProperties diff --git a/console/packages/starwhale-ui/src/Input/QueryInput.tsx b/console/packages/starwhale-ui/src/Input/QueryInput.tsx index 84058ab920..10d04e8a03 100644 --- a/console/packages/starwhale-ui/src/Input/QueryInput.tsx +++ b/console/packages/starwhale-ui/src/Input/QueryInput.tsx @@ -33,6 +33,7 @@ export function QueryInput(props: any) { onChange={(event) => setValue((event.target as HTMLInputElement).value)} value={value} clearable + placeholder={props.placeholder} /> ) } diff --git a/console/src/domain/report/hooks/useReport.ts b/console/src/domain/report/hooks/useReport.ts new file mode 100644 index 0000000000..8ec94cd186 --- /dev/null +++ b/console/src/domain/report/hooks/useReport.ts @@ -0,0 +1,7 @@ +import { useQuery } from 'react-query' +import { listReports } from '@/domain/report/services/report' +import { IListQuerySchema } from '@base/schemas/list' + +export function useFetchReports(projectId: string, query: IListQuerySchema) { + return useQuery(['useFetchReports', projectId, query], () => listReports(projectId, query)) +} diff --git a/console/src/domain/report/schemas/report.ts b/console/src/domain/report/schemas/report.ts new file mode 100644 index 0000000000..e80f8d18e8 --- /dev/null +++ b/console/src/domain/report/schemas/report.ts @@ -0,0 +1,16 @@ +import { IUserSchema } from '@user/schemas/user' + +export interface IReportSchema { + id: number + uuid: string + title: string + description?: string + createdTime: number + modifiedTime: number + owner: IUserSchema + shared: boolean +} + +export interface IReportDetailSchema extends IReportSchema { + content: string +} diff --git a/console/src/domain/report/services/report.ts b/console/src/domain/report/services/report.ts new file mode 100644 index 0000000000..a11dc16823 --- /dev/null +++ b/console/src/domain/report/services/report.ts @@ -0,0 +1,33 @@ +import axios from 'axios' +import { IListSchema } from '@starwhale/core' +import { IReportDetailSchema, IReportSchema } from '@/domain/report/schemas/report' +import { IListQuerySchema } from '@base/schemas/list' + +export async function listReports(project: string, query: IListQuerySchema): Promise> { + const { data } = await axios.get>(`/api/v1/project/${project}/report`, { + params: query, + }) + return data +} + +export async function fetchReport(project: string, reportId: string): Promise { + const { data } = await axios.get(`/api/v1/project/${project}/report/${reportId}`) + return data +} + +export async function createReport(project: string, report: IReportDetailSchema): Promise { + const { data } = await axios.post(`/api/v1/project/${project}/report`, report) + return data +} + +export async function removeReport(projectId: string, reportId: number): Promise { + const { data } = await axios.delete(`/api/v1/project/${projectId}/report/${reportId}`) + return data +} + +export async function updateReportShared(projectId: string, reportId: number, shared: boolean): Promise { + const { data } = await axios.put(`/api/v1/project/${projectId}/report/${reportId}/shared`, null, { + params: { shared }, + }) + return data +} diff --git a/console/src/i18n/locales.ts b/console/src/i18n/locales.ts index 4372a788e8..d1bb01ba9c 100644 --- a/console/src/i18n/locales.ts +++ b/console/src/i18n/locales.ts @@ -474,6 +474,21 @@ const evaluation = { }, } +const report = { + 'Reports': { + en: 'Reports', + zh: '报告', + }, + 'report.title': { + en: 'Title', + zh: '标题', + }, + 'report.search.by.title': { + en: 'Search by title', + zh: '按标题搜索', + }, +} + const table = { 'table.column.manage': { en: 'Manage Columns', @@ -1652,6 +1667,7 @@ const locales0 = { ...trash, ...project, ...job, + ...report, ...table, ...evaluation, ...widget, diff --git a/console/src/pages/Project/ProjectSidebar.tsx b/console/src/pages/Project/ProjectSidebar.tsx index 00303ffe2e..7a9f2f556a 100644 --- a/console/src/pages/Project/ProjectSidebar.tsx +++ b/console/src/pages/Project/ProjectSidebar.tsx @@ -61,6 +61,12 @@ export default function ProjectSidebar({ style }: IComposedSidebarProps) { activePathPattern: /\/(runtimes|new_runtime)\/?/, icon: , }, + { + title: t('Reports'), + path: `/projects/${projectId}/reports`, + activePathPattern: /\/(reports)\/?/, + icon: , + }, isPrivileged ? { title: t('trash.title'), diff --git a/console/src/pages/Report/ReportEdit.tsx b/console/src/pages/Report/ReportEdit.tsx new file mode 100644 index 0000000000..03eb55a4ca --- /dev/null +++ b/console/src/pages/Report/ReportEdit.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import { useParams } from 'react-router-dom' + +export default function ReportEdit() { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { projectId, reportId } = useParams<{ + projectId: string + reportId: string + }>() + + return <> +} diff --git a/console/src/pages/Report/ReportListCard.tsx b/console/src/pages/Report/ReportListCard.tsx new file mode 100644 index 0000000000..43cda103e3 --- /dev/null +++ b/console/src/pages/Report/ReportListCard.tsx @@ -0,0 +1,104 @@ +import React from 'react' +import { useFetchReports } from '@/domain/report/hooks/useReport' +import { useParams } from 'react-router-dom' +import Card from '@/components/Card' +import Table from '@/components/Table' +import useTranslation from '@/hooks/useTranslation' +import { IReportSchema } from '@/domain/report/schemas/report' +import { TextLink } from '@/components/Link' +import { Button, QueryInput, Toggle, useConfirmCtx } from '@starwhale/ui' +import { toaster } from 'baseui/toast' +import { removeReport, updateReportShared } from '@/domain/report/services/report' +import Text from '@starwhale/ui/Text' +import Copy from 'react-copy-to-clipboard' +import { usePage } from '@/hooks/usePage' +import { formatTimestampDateTime } from '@/utils/datetime' + +export default function ReportListCard() { + const [t] = useTranslation() + const [page] = usePage() + const { projectId } = useParams<{ projectId: string }>() + const [filter, setFilter] = React.useState('') + const reports = useFetchReports(projectId, { ...page, search: filter }) + const confirmCtx = useConfirmCtx() + + const handleDelete = async (id: number, title: string) => { + const ok = await confirmCtx.show({ title: t('Confirm'), content: t('delete sth confirm', [title]) }) + if (!ok) { + return + } + await removeReport(projectId, id) + await reports.refetch() + } + + const renderRow = (report: IReportSchema) => { + return [ + + {report.title} + , + { + try { + await updateReportShared(projectId, report.id, share) + await reports.refetch() + toaster.positive(t('dataset.overview.shared.success')) + } catch (e) { + toaster.negative(t('dataset.overview.shared.fail')) + } + }} + />, + {report.description}, + report.owner.name, + report.createdTime ? formatTimestampDateTime(report.createdTime) : '', + report.modifiedTime ? formatTimestampDateTime(report.modifiedTime) : '', +
+ {/* TODO: get link from the server */} + { + toaster.positive(t('Copied'), { autoHideDuration: 1000 }) + }} + > +
, + ] + } + + return ( + +
+ { + setFilter(val) + }} + /> +
+ { + await reports.refetch() + }, + }} + /> + + ) +} diff --git a/console/src/pages/Report/ReportOverviewLayout.tsx b/console/src/pages/Report/ReportOverviewLayout.tsx new file mode 100644 index 0000000000..5b25d647d8 --- /dev/null +++ b/console/src/pages/Report/ReportOverviewLayout.tsx @@ -0,0 +1,6 @@ +import React from 'react' +import BaseSubLayout from '@/pages/BaseSubLayout' + +export default function ReportOverviewLayout({ children }: { children: React.ReactNode }) { + return {children} +} diff --git a/console/src/routes.tsx b/console/src/routes.tsx index 59163b5e50..97b493d72f 100644 --- a/console/src/routes.tsx +++ b/console/src/routes.tsx @@ -55,6 +55,9 @@ import { getAuthedRoutes, getUnauthedRoutes } from './routesUtils' import EvaluationListResult from './pages/Evaluation/EvaluationListResult' import DatasetBuildListCard from './pages/Dataset/DatasetBuildListCard' import ModelReadmeOverview from './pages/Model/ModelReadmeOverview' +import ReportOverviewLayout from '@/pages/Report/ReportOverviewLayout' +import ReportListCard from '@/pages/Report/ReportListCard' +import ReportEdit from '@/pages/Report/ReportEdit' const useStyles = createUseStyles({ root: ({ theme }: IThemedStyleProps) => ({ @@ -286,6 +289,19 @@ const Routes = () => { + + + + + + + + + {/* trash */}