# Artifact MediaType Filter 功能实现

## 概述

实现了 artifact registries 的 mediaType 过滤功能，支持后端返回不同类型的制品，前端在部署时只获取 chart 类型的制品。

## 功能特性

### 后端功能

1. **支持的 MediaType 过滤器**：
   - `all` - 返回所有类型的 artifacts（默认）
   - `image` - 只返回容器镜像（Docker/OCI）
   - `chart` - 只返回 Helm Charts
   - `other` - 返回未识别类型的 artifacts

2. **模糊匹配机制**：
   - 使用智能模糊匹配来识别 artifact 类型
   - 兼容不同版本的 media type 规范
   - 支持未来的新 media type 格式

3. **类型识别规则**：
   - **Helm Chart**：包含 `helm`, `cncf.helm`, `helm.chart`, `chart+json` 等关键词
   - **Docker Image**：包含 `docker`, `vnd.docker`, `docker.distribution` 等关键词
   - **OCI Image**：包含 `vnd.oci`, `oci.image`, `opencontainers`, `container.image` 等关键词

### 前端功能

1. **API 接口更新**：
   - `getTags()` 函数现在接受可选的 `mediaType` 参数
   - 默认获取所有类型（`"all"`）以支持客户端过滤切换

2. **部署场景**：
   - 前端在部署场景中只会使用 chart 类型
   - LaunchModal 组件专门用于部署 Helm Charts

3. **性能优化**：
   - 客户端缓存所有类型的 tags
   - 支持无需重新请求即可切换过滤器
   - 减少不必要的网络请求

## 技术实现

### 后端实现

#### 1. OpenAPI 规范更新

```yaml
# backend/docs/openapi.yaml
parameters:
  - name: media_type
    in: query
    description: Filter artifacts by media type (all, image, chart, other)
    schema:
      type: string
      enum: [all, image, chart, other]
      default: all
```

#### 2. REST Handler 更新

```go
// backend/internal/adapter/input/http/rest/artifact_handler.go
func (h *ArtifactHandler) ListArtifacts(w http.ResponseWriter, r *http.Request) {
    // 获取 mediaType 过滤参数
    mediaTypeFilter := r.URL.Query().Get("media_type")
    if mediaTypeFilter == "" {
        mediaTypeFilter = "all"
    }
    
    artifacts, err := h.artifactService.ListArtifacts(
        r.Context(), 
        registryID, 
        repositoryName, 
        mediaTypeFilter,
    )
    // ...
}
```

#### 3. Domain Service 更新

```go
// backend/internal/domain/service/artifact_service.go
func (s *ArtifactService) ListArtifacts(
    ctx context.Context, 
    registryID, 
    repository, 
    mediaTypeFilter string,
) ([]*entity.Artifact, error) {
    // ...
    return s.ociClient.ListArtifacts(ctx, registry, repository, mediaTypeFilter)
}
```

#### 4. OCI Client 实现

```go
// backend/internal/adapter/output/oci/real/oci_client.go
func (c *OCIClient) shouldIncludeArtifact(artifact *entity.Artifact, filter string) bool {
    if filter == "" || filter == "all" {
        return true
    }
    
    switch filter {
    case "chart":
        return artifact.Type == entity.ArtifactTypeHelm
    case "image":
        return artifact.Type == entity.ArtifactTypeDocker || 
               artifact.Type == entity.ArtifactTypeOCI
    case "other":
        return artifact.Type == entity.ArtifactTypeUnknown
    default:
        return true
    }
}
```

### 前端实现

#### 1. API 调用更新

```typescript
// frontend/src/core/api/artifact.api.ts
export async function getTags(
  registryId: string,
  repository: string,
  mediaType: string = "all"
): Promise<Tag[]> {
  // REST mode
  const url = `/v1/registries/${registryId}/repositories/${encodeURIComponent(repository)}/artifacts?media_type=${mediaType}`;
  const response = await apiRequest<Tag[]>(url);
  return response;
}
```

#### 2. 组件更新

所有调用 `getTags` 的组件都已更新为默认获取 `"all"` 类型：
- `RegistryTreeExplorer.tsx` - 主浏览器组件
- `RepositoryItem.tsx` - 仓库项组件
- `RegistryCard.tsx` - 注册表卡片组件

## API 使用示例

### 获取所有类型的 artifacts（默认）

```bash
GET /api/v1/registries/harbor-prod/repositories/charts%2Fvllm-serve/artifacts
# 或
GET /api/v1/registries/harbor-prod/repositories/charts%2Fvllm-serve/artifacts?media_type=all
```

### 只获取 Helm Charts

```bash
GET /api/v1/registries/harbor-prod/repositories/charts%2Fvllm-serve/artifacts?media_type=chart
```

### 只获取容器镜像

```bash
GET /api/v1/registries/harbor-prod/repositories/library%2Falpine/artifacts?media_type=image
```

### 只获取未识别类型

```bash
GET /api/v1/registries/harbor-prod/repositories/misc%2Fdata/artifacts?media_type=other
```

## 测试场景

### 场景 1：混合仓库过滤

**仓库内容**：
- `charts/vllm-serve:0.1.0` (Helm Chart)
- `charts/vllm-serve:0.2.0` (Helm Chart)
- `library/alpine:3.18` (Docker Image)
- `library/alpine:latest` (Docker Image)

**测试**：
```bash
# 获取所有
curl "http://localhost:8080/api/v1/registries/harbor-prod/repositories/charts%2Fvllm-serve/artifacts?media_type=all"
# 返回：2 个 charts

# 只获取 charts
curl "http://localhost:8080/api/v1/registries/harbor-prod/repositories/charts%2Fvllm-serve/artifacts?media_type=chart"
# 返回：2 个 charts

# 只获取 images
curl "http://localhost:8080/api/v1/registries/harbor-prod/repositories/library%2Falpine/artifacts?media_type=image"
# 返回：2 个 images
```

### 场景 2：前端部署流程

1. 用户浏览 artifact registries
2. 前端默认显示 chart 过滤器（但获取所有类型以支持切换）
3. 用户点击 "Launch" 按钮部署 Helm Chart
4. LaunchModal 只处理 chart 类型的 artifacts

## 兼容性

### 向后兼容

- 不带 `media_type` 参数的请求默认返回所有类型
- 前端组件可以正常工作，无需升级
- 现有的 API 客户端不受影响

### 未来扩展

该实现支持未来添加新的 artifact 类型：
1. 在后端 `entity.Artifact.SetType()` 中添加新的识别规则
2. 在 `shouldIncludeArtifact()` 中添加新的过滤条件
3. 前端自动支持新类型（通过 `type` 字段）

## 性能考虑

1. **后端过滤**：
   - 在 OCI client 层面进行过滤，减少内存使用
   - 避免传输不需要的数据

2. **前端缓存**：
   - 获取所有类型并缓存
   - 客户端快速切换过滤器
   - 减少重复的网络请求

3. **并发控制**：
   - 批量加载时使用并发限制（3个并发）
   - 避免过多同时请求

## 相关文件

### 后端文件
- `backend/docs/openapi.yaml` - API 规范定义
- `backend/internal/adapter/input/http/rest/artifact_handler.go` - HTTP handler
- `backend/internal/domain/service/artifact_service.go` - 领域服务
- `backend/internal/domain/repository/oci_client.go` - OCI 客户端接口
- `backend/internal/adapter/output/oci/real/oci_client.go` - 真实 OCI 客户端实现
- `backend/internal/adapter/output/oci/mock/oci_client_mock.go` - Mock OCI 客户端实现
- `backend/internal/domain/entity/artifact.go` - Artifact 实体（类型识别逻辑）

### 前端文件
- `frontend/src/core/api/artifact.api.ts` - API 客户端
- `frontend/src/features/artifact/registries/components/RegistryTreeExplorer.tsx` - 主浏览器
- `frontend/src/features/artifact/registries/components/RepositoryItem.tsx` - 仓库项
- `frontend/src/features/artifact/registries/components/RegistryCard.tsx` - 注册表卡片
- `frontend/src/features/artifact/registries/components/LaunchModal.tsx` - 部署模态框
- `frontend/src/features/artifact/registries/utils/artifactType.ts` - 类型工具

## 总结

✅ 后端支持返回所有 artifact 制品  
✅ 支持通过 mediaType 参数过滤（image、chart、other、all）  
✅ 采用模糊匹配机制，兼容未来版本  
✅ 前端在部署时专注于 chart 类型  
✅ 性能优化：客户端缓存 + 服务端过滤  
✅ 完全向后兼容  
✅ 易于扩展新的 artifact 类型  

