From 324424741fe3530e5897436ee61191651126204e Mon Sep 17 00:00:00 2001 From: shark Date: Sat, 9 May 2026 18:35:07 +0800 Subject: [PATCH 1/4] docs(admin): design remote entity select --- docs/designs/remote-entity-select.md | 597 +++++++++++++++++++++++++++ 1 file changed, 597 insertions(+) create mode 100644 docs/designs/remote-entity-select.md diff --git a/docs/designs/remote-entity-select.md b/docs/designs/remote-entity-select.md new file mode 100644 index 0000000..2f374da --- /dev/null +++ b/docs/designs/remote-entity-select.md @@ -0,0 +1,597 @@ + + +# Remote Entity Select Design + +**Scope:** Synapse Admin select controls and Keystone list APIs + +## 1. Purpose + +This document defines a staged development plan for replacing large static select +option lists in Synapse Admin with remote searchable selects. + +The immediate problem is that many Admin pages load only the first paginated +resource page, usually `limit=50`, and then build select options from that +partial client-side list. Once resource tables contain more rows than the first +page, users cannot find valid organizations, orders, scenes, SOPs, devices, +collectors, or workstations in select controls. + +The proposed solution is to use a reusable remote select pattern similar to the +robot device ID and collector operator ID selectors in the data production +statistics page: + +- Search options by keyword on the server. +- Page option results with `limit` and `offset`. +- Load more options without requiring full-table preloading. +- Preserve selected option labels even when the selected item is not in the + current result page. +- Keep existing API pagination limits and avoid increasing all list calls to + very large limits. + +## 2. Background + +### 2.1 Current frontend behavior + +Synapse Admin currently uses two main select patterns: + +- `BaseSelect` with fully materialized `options`. +- Page-local custom searchable selects in + `src/views/admin/statistics/DataProductionStatistics.vue` for robot device ID + and collector operator ID. + +Many pages call `fetchList()` without explicit large pagination. The generic +`useEntityCrud()` composable defaults to `limit=50`, and API modules also +default to `limit=50`. This means option lists frequently represent only the +first page of a resource. + +The batch management page is the most visible example. It builds filters and +form options from: + +- `organizations` +- `orders` +- `stations` +- `robots` +- `data_collectors` +- `sops` +- `scenes` +- `subscenes` + +These resources can all exceed one page in realistic deployments. + +### 2.2 Current backend behavior + +Keystone list APIs already expose standardized pagination: + +```json +{ + "items": [], + "total": 0, + "limit": 50, + "offset": 0, + "hasNext": false, + "hasPrev": false +} +``` + +`ParsePagination()` caps `limit` at `100`. This is acceptable and should stay in +place. The missing piece is consistent keyword search across list endpoints. + +Search support is currently uneven: + +| Resource | Endpoint | Current useful filters | Current keyword search | +|---|---|---|---| +| Organization | `GET /organizations` | `factory_id` | No | +| Scene | `GET /scenes` | `factory_id` | No | +| Subscene | `GET /subscenes` | `scene_id` | No | +| Skill | `GET /skills` | none | No | +| SOP | `GET /sops` | none | No | +| Robot type | `GET /robot_types` | none | No | +| Robot | `GET /robots` | `factory_id`, `status`, `robot_type_id`, `connected` | Yes: `keyword`, `q`, `search`, `device_id` | +| Data collector | `GET /data_collectors` | `organization_id`, `status` | Yes: `keyword`, `q`, `search`, `operator_id` | +| Inspector | `GET /inspectors` | `organization_id`, `certification_level`, `status` | No | +| Station | `GET /stations` | `factory_id`, `organization_id`, `robot_type_id`, `status` | No | +| Order | `GET /orders` | `organization_id`, `scene_id`, `status`, `priority`, `ids` | No | +| Batch | `GET /batches` | several list filters | Not the main select source | + +## 3. Goals + +- Provide one reusable remote select implementation for Admin pages. +- Support single-select and multi-select use cases. +- Support server-side keyword search and paginated option loading. +- Preserve selected labels across pagination, refresh, and route state restore. +- Keep static enum selects as simple `BaseSelect` controls. +- Make option fetching explicit and resource-specific rather than relying on + page-wide preloading. +- Improve large-data correctness without weakening backend pagination limits. + +## 4. Non-goals + +- Do not replace every select in one large refactor. +- Do not build a generic backend `/options` endpoint in the first phase. +- Do not remove `BaseSelect`; it remains appropriate for enum and small static + option sets. +- Do not change table pagination behavior. +- Do not change creation/update payload contracts for existing resources. + +## 5. UX Contract + +### 5.1 Single select + +Single-select controls should support: + +- Placeholder text. +- Clear selection when the field is optional. +- Keyword search with debounce. +- Loading state while searching. +- Empty state when no option matches. +- "Load more" when `hasNext` is true. +- Selected label display even if the selected option is not in the current + option page. + +### 5.2 Multi select + +Multi-select controls should support: + +- Search and page loading. +- Checkbox-style options. +- Selected chips. +- Remove a selected item from its chip. +- Clear all selected items. +- Collapsed chip preview when many values are selected. + +### 5.3 Keyboard and focus behavior + +Remote selects replace native `