-
Notifications
You must be signed in to change notification settings - Fork 9
[add] model & card component of Open Source Project #51
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { FC } from 'react'; | ||
|
|
||
| import { Project } from '../../models/Project'; | ||
| import { GitCard } from '../Git/Card'; | ||
|
|
||
| export const ProjectCard: FC<Project> = ({ name, sourceLink, link, languages, tags, summary }) => ( | ||
| <GitCard | ||
| full_name={name as string} | ||
| html_url={sourceLink as string} | ||
| homepage={link as string} | ||
| languages={languages as string[]} | ||
| topics={tags as string[]} | ||
| description={summary as string} | ||
| /> | ||
| ); | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,66 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiDataQueryOptions, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiDataTable, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiSearch, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TableCellLink, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TableCellValue, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TableRecord, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from 'mobx-lark'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { LarkBase, larkClient } from './Base'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { LarkBitableId, ProjectTableId } from './configuration'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export type Project = LarkBase & | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Record< | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 'name' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 'type' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 'sourceLink' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 'link' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 'license' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 'languages' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 'tags' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 'summary' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 'logo' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 'status' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | 'reason', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TableCellValue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| >; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export class ProjectModel extends BiDataTable<Project>() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client = larkClient; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| queryOptions: BiDataQueryOptions = { text_field_as_array: false }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| constructor(appId = LarkBitableId, tableId = ProjectTableId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super(appId, tableId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extractFields({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fields: { sourceLink, link, languages, tags, ...fields }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...meta | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: TableRecord<Project>) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...meta, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...fields, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sourceLink: (sourceLink as TableCellLink)?.link, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| link: (link as TableCellLink)?.link, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| languages: languages?.toString().split(/\s*,\s*/) || [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tags: tags?.toString().split(/\s*,\s*/) || [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+38
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 修复字段提取逻辑中的运行时错误风险。 关键问题(第 47-48 行): 次要问题(第 45-46 行): 🔧 建议的修复方案 extractFields({
fields: { sourceLink, link, languages, tags, ...fields },
...meta
}: TableRecord<Project>) {
return {
...meta,
...fields,
- sourceLink: (sourceLink as TableCellLink)?.link,
- link: (link as TableCellLink)?.link,
- languages: languages?.toString().split(/\s*,\s*/) || [],
- tags: tags?.toString().split(/\s*,\s*/) || [],
+ sourceLink: (sourceLink as TableCellLink | undefined)?.link,
+ link: (link as TableCellLink | undefined)?.link,
+ languages: (languages?.toString() ?? '').split(/\s*,\s*/).filter(Boolean),
+ tags: (tags?.toString() ?? '').split(/\s*,\s*/).filter(Boolean),
};
}或使用更简洁的写法: - languages: languages?.toString().split(/\s*,\s*/) || [],
- tags: tags?.toString().split(/\s*,\s*/) || [],
+ languages: languages ? String(languages).split(/\s*,\s*/) : [],
+ tags: tags ? String(tags).split(/\s*,\s*/) : [],📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export class SearchProjectModel extends BiSearch<Project>(ProjectModel) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| searchKeys = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'name', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'type', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'sourceLink', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'link', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'license', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'languages', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'tags', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'summary', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'status', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'reason', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,4 +35,5 @@ export const LarkWikiDomain = hostname; | |
| export const LarkWikiId = pathname.split('/').pop()!; | ||
|
|
||
| export const LarkBitableId = process.env.NEXT_PUBLIC_LARK_BITABLE_ID!, | ||
| ActivityTableId = process.env.NEXT_PUBLIC_ACTIVITY_TABLE_ID!; | ||
| ActivityTableId = process.env.NEXT_PUBLIC_ACTIVITY_TABLE_ID!, | ||
| ProjectTableId = process.env.NEXT_PUBLIC_PROJECT_TABLE_ID!; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n models/configuration.ts | head -50Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 1725 🏁 Script executed: # Check for imports in configuration.ts to verify GitHub client handling
rg "import" models/configuration.ts -A 2Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 195 🏁 Script executed: # Search for environment variable configuration documentation
fd -t f "{\.env,.env.example,\.env.local,README}" --exec cat {} \; 2>/dev/null | head -100Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 73 🏁 Script executed: # Check if NEXT_PUBLIC_PROJECT_TABLE_ID is documented anywhere
rg "NEXT_PUBLIC_PROJECT_TABLE_ID|PROJECT_TABLE_ID" --type ts --type tsx --type mdRepository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 118 🏁 Script executed: # Check if models/Base.ts exists
ls -la models/Base.ts 2>/dev/null || echo "Base.ts not found"Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 154 🏁 Script executed: # Search for where configuration.ts is imported
rg "from.*configuration|import.*configuration" --type ts --type tsx -B 1 -A 1Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 118 🏁 Script executed: # Look for environment variable documentation in common config files
rg "NEXT_PUBLIC_PROJECT_TABLE_ID|PROJECT_TABLE_ID" -B 2 -A 2Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 359 🏁 Script executed: # Check deployment/build configuration files
fd -t f "vercel|github|docker|build|deploy" --exec cat {} \; 2>/dev/null | head -50Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 73 🏁 Script executed: # Search for .env examples or documentation
fd -type f -name "*env*" -o -name "*.example" 2>/dev/nullRepository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 73 🏁 Script executed: cat -n models/Base.tsRepository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 2812 🏁 Script executed: # Check which model files import Base.ts
rg "from.*['\"]./Base['\"]|import.*Base.*from" models/ --type tsRepository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 699 🏁 Script executed: # Check how configuration.ts is used in models directory
rg "configuration" models/ --type ts -B 1 -A 1Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 654 🏁 Script executed: # Check if there's a .env.example or similar documentation
find . -name "*.example" -o -name ".env*" -o -name "README*" | head -20Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 73 🏁 Script executed: # Check deployment/build configuration files for env variable documentation
fd -type f "vercel|next.config" | xargs cat 2>/dev/null | head -100Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 261 🏁 Script executed: # Check if Lark table IDs are used in documentation
rg "ACTIVITY_TABLE_ID|PROJECT_TABLE_ID|LARK_BITABLE" . --type md -B 1 -A 1Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 73 🏁 Script executed: # Search for any README or documentation files
find . -maxdepth 3 -type f \( -name "README*" -o -name "*.md" \) | head -20Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 73 🏁 Script executed: # Check for next.config.js or vercel.json
find . -maxdepth 2 -type f \( -name "next.config*" -o -name "vercel.json" -o -name ".env.example" \)Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 73 🏁 Script executed: # Look for any documentation mentioning environment variables
rg "NEXT_PUBLIC|环境变量|environment variable" . --type md -l 2>/dev/null || echo "No markdown files found with env var documentation"Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 141 🏁 Script executed: # Check how other projects in this repo handle environment variables
rg -l "NEXT_PUBLIC" . --type ts | head -5 | xargs -I {} grep -l "NEXT_PUBLIC" {}Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 116 🏁 Script executed: # Look at package.json or CI/CD configuration
find . -maxdepth 2 \( -name "package.json" -o -name ".github" -o -name "Dockerfile" \)Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io Length of output: 73 补充完善环境变量文档配置。 代码模式本身一致,ProjectTableId 的导出遵循了既有约定。然而,缺少关键的部署配置文档:
🤖 Prompt for AI Agents |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
类型断言存在安全隐患,且缺少 MobX observer 包装。
此组件存在两个问题:
类型安全问题(关键):所有属性都使用
as string或as string[]强制类型转换。根据models/Project.ts的定义,这些字段的类型是TableCellValue,它可能是多种类型(number、boolean、array 等)。强制转换会绕过 TypeScript 的类型检查,可能导致运行时错误。缺少 MobX observer:参考
ActivityCard和OrganizationCard,卡片组件应该用observer()包装以响应数据变化。如果 Project 数据是可观察的(observable),当前实现将无法正确更新 UI。🔧 建议的修复方案
方案 1(推荐):类型守卫 + observer 包装
方案 2:在 Project 模型层添加类型转换
如果 TableCellValue 总是返回正确类型,可在
models/Project.ts中添加类型断言辅助函数,然后在组件中使用这些安全的转换。🤖 Prompt for AI Agents