Skip to content

feat: 分组群功能(用户端 API + 前端快捷填充)#2932

Open
TAYOTOoO wants to merge 1 commit intoQuantumNous:mainfrom
TAYOTOoO:feature/group-clusters
Open

feat: 分组群功能(用户端 API + 前端快捷填充)#2932
TAYOTOoO wants to merge 1 commit intoQuantumNous:mainfrom
TAYOTOoO:feature/group-clusters

Conversation

@TAYOTOoO
Copy link

@TAYOTOoO TAYOTOoO commented Feb 12, 2026

新增分组群(Group Clusters)功能,允许管理员预定义分组组合,用户创建令牌时可一键填充。

  • 新增 controller/group_cluster.go 用户端接口,返回 type='group_cluster' 的预填组
  • router/api-router.go 新增 GET /api/user/self/group_clusters 路由
  • EditTokenModal.jsx 加载分组群数据,显示快捷填充按钮
  • 悬浮显示分组群包含的分组列表

Summary by CodeRabbit

  • New Features
    • Token editor: added a "group clusters" quick-fill — browse clusters, hover to view details, and apply a cluster to populate the group field with one click.
    • Backend support: API added so the UI can load available group clusters asynchronously for the quick-fill feature.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Walkthrough

Adds a backend GET endpoint to return prefill groups of type "group_cluster" and a frontend quick-fill UI in EditTokenModal that fetches those clusters and can populate the token's group field.

Changes

Cohort / File(s) Summary
Backend controller & route
controller/group_cluster.go, router/api-router.go
Adds exported GetGroupClusters(c *gin.Context) and route GET /api/user/self/group_clusters; handler calls model.GetAllPrefillGroups("group_cluster"), logs errors via common.SysError, and returns JSON { success, data / error }.
Frontend token modal
web/src/components/table/tokens/modals/EditTokenModal.jsx
Adds groupClusters state and loadGroupClusters() fetching /api/user/self/group_clusters; invokes on init and renders Tooltip-wrapped quick-fill buttons that parse cluster items and set the form group when exactly one item is present.

Sequence Diagram(s)

sequenceDiagram
    participant User as "User (opens modal)"
    participant Client as "EditTokenModal (Client)"
    participant Router as "API Router"
    participant Controller as "GetGroupClusters"
    participant Model as "Model Layer / DB"

    rect rgba(100,149,237,0.5)
    User->>Client: open EditTokenModal
    Client->>Client: loadGroupClusters()
    end

    rect rgba(60,179,113,0.5)
    Client->>Router: GET /api/user/self/group_clusters
    Router->>Controller: forward request
    Controller->>Model: GetAllPrefillGroups(type="group_cluster")
    Model-->>Controller: groups data / error
    Controller-->>Router: JSON response { success, data / error }
    Router-->>Client: HTTP response
    end

    rect rgba(255,165,0,0.5)
    Client->>Client: setState(groupClusters) and render quick-fill buttons
    User->>Client: click cluster button -> Client sets form.group
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰
I hopped into code at dawn,
clusters clustered on the lawn.
A button click, a gentle nudge,
the group fills in—no need to judge.
I twitch my nose and skip along.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is in Chinese and directly describes the main feature added: group clusters functionality for both backend API and frontend quick-fill capability, which aligns with the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
web/src/components/table/tokens/modals/EditTokenModal.jsx (1)

395-444: Avoid double JSON.parse of cluster.items — parse once and reuse.

cluster.items is parsed in the .filter() callback and then parsed again in the .map() callback. Consider computing the parsed data once (e.g., via .flatMap or a pre-processing step) to avoid redundant parsing and the duplicated try/catch blocks.

♻️ Suggested refactor
-                  {groupClusters
-                    .filter((cluster) => {
-                      try {
-                        const items = cluster.items
-                          ? JSON.parse(cluster.items)
-                          : [];
-                        return (
-                          Array.isArray(items) && items.length === 1
-                        );
-                      } catch {
-                        return false;
-                      }
-                    })
-                    .map((cluster) => {
-                      let groupName = '';
-                      try {
-                        groupName = JSON.parse(cluster.items)[0];
-                      } catch {
-                        // ignore
-                      }
-                      return (
+                  {groupClusters
+                    .reduce((acc, cluster) => {
+                      try {
+                        const items = cluster.items
+                          ? JSON.parse(cluster.items)
+                          : [];
+                        if (Array.isArray(items) && items.length === 1) {
+                          acc.push({ cluster, groupName: items[0] });
+                        }
+                      } catch {
+                        // ignore
+                      }
+                      return acc;
+                    }, [])
+                    .map(({ cluster, groupName }) => (
                        <Tooltip
                          key={cluster.id}
                          content={groupName}
                        >
                          <Button
                            size='small'
                            theme='light'
                            onClick={() => {
                              if (groupName && formApiRef.current) {
                                formApiRef.current.setValue(
                                  'group',
                                  groupName,
                                );
                              }
                            }}
                          >
                            {cluster.name}
                          </Button>
                         </Tooltip>
-                      );
-                    })}
+                    ))}

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@controller/group_cluster.go`:
- Around line 13-18: The current error handling returns err.Error() directly in
the response (inside the c.JSON call) which may leak internal details; instead,
log the full error server-side (e.g., using the existing logger or log.Printf)
and replace the response payload with a generic message such as "internal server
error" and an appropriate HTTP status code (500) while keeping the existing JSON
shape (success:false). Locate the block where err is checked (the if err != nil
{ ... return } around the c.JSON call) and change the response to a sanitized
message and perform a separate server-side log of err.

In `@web/src/components/table/tokens/modals/EditTokenModal.jsx`:
- Around line 395-435: The Tooltip currently calls JSON.parse(cluster.items)
during render which can throw on malformed data; wrap that parse in a safe
precompute or try/catch (e.g. compute a safe display string for each cluster
before rendering and use that value for Tooltip content) to avoid crashing the
component; reuse the same parsing logic used in the Button onClick (refer to
groupClusters, cluster.items, Tooltip, Button, and formApiRef) and ensure
malformed JSON results in an empty string or a fallback message; additionally,
make multi-item clusters’ buttons behavior explicit by either disabling/hiding
the Button when parsed items.length > 1 or showing a clear tooltip/message that
multiple items exist so users aren’t confused by the no-op click.
🧹 Nitpick comments (1)
web/src/components/table/tokens/modals/EditTokenModal.jsx (1)

154-163: Silent error swallowing — consider minimal logging.

The catch block silently ignores all errors, including network failures. A console.warn would help with debugging in development without affecting users.

@TAYOTOoO TAYOTOoO force-pushed the feature/group-clusters branch 2 times, most recently from b27cf74 to 6c101e6 Compare February 12, 2026 11:42
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@web/src/components/table/tokens/modals/EditTokenModal.jsx`:
- Around line 395-442: The quick-fill buttons use groupClusters.map and always
apply only items[0] via formApiRef.current.setValue('group', items[0]), which
silently discards additional items; update the rendering logic in the
groupClusters mapping to detect multi-item clusters (parse cluster.items into
items array) and either filter them out or make them explicit: e.g., if
items.length > 1 then render the Button as disabled (Button disabled) or append
a visual marker like " (multiple)" to cluster.name and update Tooltip content to
say "contains multiple groups — select manually", while keeping the existing
single-item behavior for items.length === 1 so the click handler continues to
set 'group' to items[0]; ensure you still catch JSON parse errors as currently
done.

新增分组群(Group Clusters)功能,允许管理员预定义分组组合,用户创建令牌时可一键填充。

- 新增 controller/group_cluster.go 用户端接口,返回 type='group_cluster' 的预填组
- router/api-router.go 新增 GET /api/user/self/group_clusters 路由
- EditTokenModal.jsx 加载分组群数据,显示快捷填充按钮
- 悬浮显示分组群包含的分组列表

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@TAYOTOoO TAYOTOoO force-pushed the feature/group-clusters branch from 6c101e6 to 01fb0d7 Compare February 12, 2026 11:46
@TAYOTOoO TAYOTOoO closed this Feb 12, 2026
@TAYOTOoO TAYOTOoO reopened this Feb 12, 2026
@TAYOTOoO TAYOTOoO marked this pull request as draft February 12, 2026 12:04
@TAYOTOoO TAYOTOoO marked this pull request as ready for review February 12, 2026 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments