Skip to content

feat: expand item types and improve API response handling #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
May 18, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
eb738b2
feat: expand item types and improve API response handling
cubxxw May 15, 2025
945e9d3
refactor: clean up exports and improve type definitions in client files
cubxxw May 15, 2025
24ec5dd
refactor: improve API response handling and type assertions in ItemsT…
cubxxw May 15, 2025
8597763
fix: enhance error handling and localization in dashboard and login c…
cubxxw May 15, 2025
db7a5f4
chore: update pnpm version and enhance error handling in components
cubxxw May 15, 2025
5b6d0ae
fix: update item description handling in DashboardPage component
cubxxw May 16, 2025
d1b77aa
chore: update environment configurations and enhance Google OAuth han…
cubxxw May 16, 2025
b19bebc
fix: enhance authentication flow and improve error handling in middle…
cubxxw May 16, 2025
30581cf
chore: add extension testing capabilities and update Makefile
cubxxw May 16, 2025
fcca09d
chore: update client generation workflow and enhance admin dependencies
cubxxw May 16, 2025
8632aa7
chore: remove deprecated files and update project structure
cubxxw May 16, 2025
c235c6d
chore: remove SECURITY.md and update popup components for better acce…
cubxxw May 16, 2025
292e23a
chore: update Jest configuration and enhance testing utilities
cubxxw May 16, 2025
8ed343e
chore: update Makefile and improve code formatting across components
cubxxw May 16, 2025
3e934dd
feat: enhance sidebar functionality and improve API interactions
cubxxw May 17, 2025
0aa50fa
feat: add diagnose functionality and enhance sidebar resources
cubxxw May 17, 2025
37d3779
feat: add resource links for independent developers in README_zh-CN
cubxxw May 17, 2025
e057865
fix: update favicon file types and replace icon assets
cubxxw May 17, 2025
15803ba
chore: update Makefile and enhance extension functionality
cubxxw May 17, 2025
904b9db
refactor: enhance extension build process and update documentation
cubxxw May 18, 2025
8184607
chore: update test setup and enhance database management
cubxxw May 18, 2025
326d986
feat: add social media integration and improve options page layout
cubxxw May 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/generate-client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
version: 9.9.0

- name: Setup Node.js
uses: actions/setup-node@v4
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v2
uses: pnpm/action-setup@v3
with:
version: 8
version: 9.9.0
- uses: actions/setup-node@v4
with:
node-version: lts/*
Expand Down
2 changes: 0 additions & 2 deletions admin/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@ export { CancelablePromise, CancelError } from "./core/CancelablePromise"
export { OpenAPI, type OpenAPIConfig } from "./core/OpenAPI"
export * from "./sdk.gen"
export * from "./types.gen"
export { isApiResponse, extractApiResponseError } from "./utils"
export { type ItemPublic } from "./types"
34 changes: 30 additions & 4 deletions admin/src/client/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,33 @@
* 项目的公共接口定义
*/
export interface ItemPublic {
id: string;
title: string;
description?: string | null;
}
id: string
title: string
description?: string | null
}

/**
* 项目集合的公共接口定义
*/
export interface ItemsPublic {
data: Array<ItemPublic>
count: number
}

/**
* 从API响应中提取Item数据的类型
*/
export type ItemResponse = {
data: ItemPublic
meta?: Record<string, unknown> | null
error?: string | null
}

/**
* 从API响应中提取Items集合数据的类型
*/
export type ItemsResponse = {
data: ItemsPublic
meta?: Record<string, unknown> | null
error?: string | null
}
32 changes: 16 additions & 16 deletions admin/src/client/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
* 检查一个值是否为API响应格式
*/
export const isApiResponse = (value: unknown): boolean => {
if (!value || typeof value !== 'object') {
if (!value || typeof value !== "object") {
return false
}

const obj = value as Record<string, unknown>
// 检查是否包含API响应格式的关键字段
return ('data' in obj || 'meta' in obj || 'error' in obj)
return "data" in obj || "meta" in obj || "error" in obj
}

/**
Expand All @@ -22,41 +22,41 @@ export const extractApiResponseError = (response: unknown): string | null => {
if (!isApiResponse(response)) {
return null
}

const apiResponse = response as Record<string, unknown>

// 直接返回error字段
if (typeof apiResponse.error === 'string') {
if (typeof apiResponse.error === "string") {
return apiResponse.error
}

// 尝试从meta中提取详细错误信息
if (apiResponse.meta && typeof apiResponse.meta === 'object') {
if (apiResponse.meta && typeof apiResponse.meta === "object") {
const meta = apiResponse.meta as Record<string, unknown>

// 检查meta中是否有details字段
if (meta.details) {
if (Array.isArray(meta.details) && meta.details.length > 0) {
const firstDetail = meta.details[0]
if (typeof firstDetail === 'object' && firstDetail !== null) {
if (typeof firstDetail === "object" && firstDetail !== null) {
// 尝试获取msg或message字段
const detailObj = firstDetail as Record<string, unknown>
if (typeof detailObj.msg === 'string') {
if (typeof detailObj.msg === "string") {
return detailObj.msg
}
if (typeof detailObj.message === 'string') {
if (typeof detailObj.message === "string") {
return detailObj.message
}
}
// 如果是字符串,直接返回
if (typeof firstDetail === 'string') {
if (typeof firstDetail === "string") {
return firstDetail
}
} else if (typeof meta.details === 'string') {
} else if (typeof meta.details === "string") {
return meta.details
}
}
}

return null
}
}
16 changes: 7 additions & 9 deletions admin/src/routes/_layout/items.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,15 @@ function ItemsTable() {
})

// 安全地处理API响应
const apiData = apiResponse?.data || ({} as any)

const responseData = apiResponse?.data || {} as any
// 使用类型断言处理响应数据
const items: ItemPublic[] = Array.isArray(apiData.data)
? apiData.data
: Array.isArray(apiData)
? apiData
: []

const items: ItemPublic[] = Array.isArray(responseData.data)
? responseData.data
: []

// 使用类型断言处理计数
const count = typeof apiData.count === "number" ? apiData.count : items.length
const count = typeof responseData.count === "number" ? responseData.count : items.length

if (isLoading) {
return <PendingItems />
Expand Down
41 changes: 24 additions & 17 deletions backend/app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

from pydantic import (
AnyUrl,
BaseModel,
BeforeValidator,
EmailStr,
HttpUrl,
Expand Down Expand Up @@ -123,29 +122,37 @@ def SQLALCHEMY_DATABASE_URI(self) -> PostgresDsn:

password = urllib.parse.quote_plus(self.SUPABASE_DB_PASSWORD or "")

return PostgresDsn(str(URL.build(
scheme="postgresql+psycopg",
user=self.SUPABASE_DB_USER or "",
password=password,
host=self.SUPABASE_DB_HOST,
port=port,
path=f"/{self.SUPABASE_DB_NAME or ''}",
)))
return PostgresDsn(
str(
URL.build(
scheme="postgresql+psycopg",
user=self.SUPABASE_DB_USER or "",
password=password,
host=self.SUPABASE_DB_HOST,
port=port,
path=f"/{self.SUPABASE_DB_NAME or ''}",
)
)
)
else:
# Use standard PostgreSQL connection
# URL encode the password to handle special characters
import urllib.parse

password = urllib.parse.quote_plus(self.POSTGRES_PASSWORD)

return PostgresDsn(str(URL.build(
scheme="postgresql+psycopg",
user=self.POSTGRES_USER,
password=password,
host=self.POSTGRES_SERVER,
port=self.POSTGRES_PORT,
path=f"/{self.POSTGRES_DB}",
)))
return PostgresDsn(
str(
URL.build(
scheme="postgresql+psycopg",
user=self.POSTGRES_USER,
password=password,
host=self.POSTGRES_SERVER,
port=self.POSTGRES_PORT,
path=f"/{self.POSTGRES_DB}",
)
)
)

SMTP_TLS: bool = True
SMTP_SSL: bool = False
Expand Down
1 change: 1 addition & 0 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dev-dependencies = [
"ruff<1.0.0,>=0.2.2",
"pre-commit<4.0.0,>=3.6.2",
"types-passlib<2.0.0.0,>=1.7.7.20240106",
"types-requests<3.0.0.0,>=2.32.0",
"coverage<8.0.0,>=7.4.3",
]

Expand Down
14 changes: 14 additions & 0 deletions backend/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 20 additions & 3 deletions frontend/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ interface Item {
owner_id?: string;
}

// 定义可能的API响应类型
interface ApiErrorResponse {
message?: string;
error?: string;
meta?: {
message?: string;
[key: string]: unknown;
};
[key: string]: unknown;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Deduplicate ApiErrorResponse – extract into a shared types module

ApiErrorResponse is now declared here and in
frontend/components/actions/items-action.ts.
Keeping separate but identical interfaces invites drift and increases
maintenance effort. Consider moving this definition to
@/lib/types, re-exporting it, and importing it in both places.

🤖 Prompt for AI Agents
In frontend/app/dashboard/page.tsx around lines 29 to 38, the ApiErrorResponse
interface is duplicated in another file. To avoid duplication and maintenance
issues, move the ApiErrorResponse interface definition into a shared module at
@/lib/types. Then, re-export it from there and update both this file and
frontend/components/actions/items-action.ts to import ApiErrorResponse from the
shared module instead of declaring it locally.


export default async function DashboardPage() {
const itemsResponse = await fetchItems();

Expand All @@ -37,10 +48,16 @@ export default async function DashboardPage() {
itemsList = itemsResponse;
console.log("Dashboard received items:", itemsList.length);
} else if (itemsResponse && typeof itemsResponse === "object") {
if ("message" in itemsResponse) {
errorMessage = itemsResponse.message as string;
console.error("Dashboard received error:", errorMessage);
// 处理可能的错误响应格式
const errorResponse = itemsResponse as ApiErrorResponse;
if ("message" in errorResponse) {
errorMessage = String(errorResponse.message);
} else if ("error" in errorResponse) {
errorMessage = String(errorResponse.error);
} else if (errorResponse.meta && "message" in errorResponse.meta) {
errorMessage = String(errorResponse.meta.message);
}
console.error("Dashboard received error:", errorMessage);
}

return (
Expand Down
Loading
Loading