refactor(important): change binđing geometry to bound_with(up side down tree)
This commit is contained in:
@@ -47,7 +47,7 @@ export type FeatureProperties = {
|
||||
geometry_preset?: GeometryPreset | null;
|
||||
time_start?: number | null;
|
||||
time_end?: number | null;
|
||||
binding?: string[];
|
||||
bound_with?: string | null;
|
||||
|
||||
// UI/editor-only denormalized fields.
|
||||
entity_id?: string | null;
|
||||
@@ -103,7 +103,7 @@ export type GeometrySnapshot = {
|
||||
type?: string | null;
|
||||
draw_geometry?: Geometry;
|
||||
geometry?: Geometry;
|
||||
binding?: string[];
|
||||
bound_with?: string | null;
|
||||
time_start?: number | null;
|
||||
time_end?: number | null;
|
||||
bbox?: {
|
||||
|
||||
@@ -76,7 +76,7 @@ Checklist an toàn:
|
||||
- `type`
|
||||
- `geometry_preset`
|
||||
- `entity_ids`
|
||||
- `binding`
|
||||
- `bound_with`
|
||||
6. Kiểm tra interaction cleanup khi chuyển mode.
|
||||
|
||||
Nếu mode chưa được cleanup đúng, map rất dễ giữ preview cũ hoặc event listener cũ.
|
||||
@@ -101,7 +101,7 @@ File quan trọng nhất là `editorSnapshot.ts`.
|
||||
|
||||
- `normalizeEditorSnapshot(raw)`
|
||||
- đọc payload từ backend
|
||||
- rehydrate fields UI như `entity_ids`, `entity_name`, `binding`, `time_start`, `time_end`
|
||||
- rehydrate fields UI như `entity_ids`, `entity_name`, `bound_with`, `time_start`, `time_end`
|
||||
- `buildEditorSnapshot(options)`
|
||||
- strip các field generate-only khỏi `editor_feature_collection`
|
||||
- build `geometry_entity[]` và `entity_wiki[]`
|
||||
@@ -175,7 +175,7 @@ Có thể do:
|
||||
|
||||
- timeline filter
|
||||
- geometry visibility theo type
|
||||
- binding filter
|
||||
- bound_with filter
|
||||
|
||||
Không phải lúc nào cũng là bug render layer.
|
||||
|
||||
|
||||
@@ -94,9 +94,9 @@ Các link entity-wiki hiện tại của snapshot. Snapshot builder sẽ tự si
|
||||
|
||||
Join table persist quan hệ geometry-entity trong snapshot commit. `feature.properties.entity_ids` chỉ là field denormalized cho UI.
|
||||
|
||||
### `binding`
|
||||
### `bound_with`
|
||||
|
||||
Field geometry-geometry binding trên feature. Binding này không tính là entity binding; geometry không có `entity_ids/entity_id` hợp lệ vẫn là orphan.
|
||||
Field geometry-geometry trên feature con, lưu id geometry cha mà nó nằm trong. `bound_with` không tính là entity binding; geometry không có `entity_ids/entity_id` hợp lệ vẫn là orphan.
|
||||
|
||||
### `geometryVisibility`
|
||||
|
||||
@@ -104,7 +104,7 @@ Map local visibility override. Key có thể là geometry id hoặc semantic geo
|
||||
|
||||
### `applyGeometryBindingFilter`
|
||||
|
||||
Filter map theo selection/binding. Chỉ ảnh hưởng render trên map, không đổi draft và không đi snapshot.
|
||||
Filter map theo selection/bound_with. Chỉ ảnh hưởng render trên map, không đổi draft và không đi snapshot.
|
||||
|
||||
## Guard rails
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ Geometry mới mặc định có:
|
||||
- `type: "country"`
|
||||
- `geometry_preset: "polygon"`
|
||||
- `entity_ids: []`
|
||||
- `binding: []`
|
||||
- `bound_with: null`
|
||||
|
||||
### Point (`add-point`)
|
||||
|
||||
@@ -143,7 +143,7 @@ Khi đang ở `select`, editor có thể sửa polygon/circle qua `editingEngine
|
||||
- `time_start`
|
||||
- `time_end`
|
||||
|
||||
`binding` đang được hiển thị trong state form nhưng không có input edit trực tiếp trong panel; việc bind/unbind geometry hiện đi qua `GeometryBindingPanel`.
|
||||
`bound_with` không nằm trong form metadata; việc bind/unbind geometry hiện đi qua `GeometryBindingPanel`.
|
||||
|
||||
Các ràng buộc đang có:
|
||||
|
||||
@@ -203,12 +203,12 @@ Panel `ProjectEntityRefsPanel` là nơi bind/unbind entity theo geometry đang c
|
||||
|
||||
### Geometry ↔ Geometry
|
||||
|
||||
`GeometryBindingPanel` thao tác trên `feature.properties.binding`.
|
||||
`GeometryBindingPanel` thao tác trên `feature.properties.bound_with` của geometry con.
|
||||
|
||||
- Chọn một geometry làm gốc.
|
||||
- Bind/unbind với geometry khác trong project.
|
||||
- Bind/unbind với geometry khác trong project bằng cách set/clear `bound_with` của geometry con.
|
||||
- Có nút focus để zoom vào geometry trong list binding.
|
||||
- Có toggle `Filter`: map chỉ hiển thị geometry liên quan tới selection nếu filter binding đang bật.
|
||||
- Có toggle `Filter`: map chỉ hiển thị geometry liên quan tới selection nếu filter bound_with đang bật.
|
||||
- Row geometry hiển thị chip trạng thái trong panel:
|
||||
- `no entity` nếu geometry chưa bind entity.
|
||||
- `no time` nếu thiếu cả `time_start` và `time_end`.
|
||||
|
||||
@@ -52,7 +52,7 @@ Checklist này dùng sau mỗi lần sửa editor. Không thay thế typecheck/l
|
||||
- Chọn một geometry, bind geometry khác trong `GeometryBindingPanel`.
|
||||
- Panel hiện chip `bound` cho geometry liên quan.
|
||||
- Toggle Filter: map chỉ hiện selection, selected children và parent/root phù hợp.
|
||||
- Undo bind/unbind geometry phải khôi phục `properties.binding`.
|
||||
- Undo bind/unbind geometry phải khôi phục `properties.bound_with`.
|
||||
- Bind geometry-geometry không làm mất chip `no entity` nếu geometry vẫn chưa bind entity.
|
||||
|
||||
## 6. Wiki và entity-wiki
|
||||
@@ -69,7 +69,7 @@ Checklist này dùng sau mỗi lần sửa editor. Không thay thế typecheck/l
|
||||
## 7. Replay
|
||||
|
||||
- Chọn geometry có entity, bấm replay.
|
||||
- Replay mở với MAIN geo và các target ids liên quan binding.
|
||||
- Replay mở với MAIN geo và các target ids có `bound_with` trỏ tới MAIN.
|
||||
- Tạo stage, tạo step, đổi duration.
|
||||
- Thêm narrative action `set_title` và `set_descriptions`.
|
||||
- Thêm map action `set_time_filter`, `show_labels`, `hide_labels`.
|
||||
|
||||
@@ -79,16 +79,16 @@ Một thao tác không cần undo nếu nó chỉ đổi trạng thái xem/đi
|
||||
| Ẩn/hiện geometry local | Eye button, map hide callback | `geometryVisibility` | Không | Không | Local UI only, không đi snapshot |
|
||||
| Geometry status panel | `GeometryBindingPanel` | Derived từ draft/timeline/visibility | Không | Không | Hiện `no entity`, `no time`, `partial time`, `timeline`, `out timeline`, `hidden`, `bound`, `new`; ID chỉ nằm trong tooltip |
|
||||
|
||||
## 3. Geometry binding
|
||||
## 3. Geometry bound_with
|
||||
|
||||
| Thao tác | Entry point | State đổi | Undo | Snapshot/commit | Ghi chú |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Bind entity vào selected geometry | `ProjectEntityRefsPanel` checkbox | `entity_id`, `entity_ids`, `entity_name`, `entity_names` trên selected features | `properties` hoặc `group` | `geometry_entity[]` | Multi-select chỉ hợp lệ khi cùng shape type |
|
||||
| Unbind entity | `ProjectEntityRefsPanel` checkbox | Các field entity trên feature | `properties` hoặc `group` | `geometry_entity[]` delete delta nếu baseline có link | Commit/submit chặn geometry không còn entity |
|
||||
| Bind geometry-geometry | `GeometryBindingPanel` lock button | `feature.properties.binding` | `properties` hoặc `group` | `geometries[].binding` | Binding geometry không thay thế entity binding |
|
||||
| Unbind geometry-geometry | `GeometryBindingPanel` unlock button | `feature.properties.binding` | `properties` hoặc `group` | `geometries[].binding` | Không ảnh hưởng `geometry_entity[]` |
|
||||
| Bind nhiều geometry vào target | Map bind callback | `binding` của target geometry | `properties` | `geometries[].binding` | Tự bỏ target id khỏi source ids |
|
||||
| Toggle binding filter | `GeometryBindingPanel` filter checkbox | `geometryBindingFilterEnabled` | Không | Không | Chỉ lọc hiển thị map theo selection/binding |
|
||||
| Bind geometry-geometry | `GeometryBindingPanel` lock button | `child.properties.bound_with = selectedGeometryId` | `properties` | `geometries[].bound_with` | Geometry con lưu id cha; không thay thế entity binding |
|
||||
| Unbind geometry-geometry | `GeometryBindingPanel` unlock button | `child.properties.bound_with = null` | `properties` | `geometries[].bound_with` | Không ảnh hưởng `geometry_entity[]` |
|
||||
| Bind nhiều geometry vào target | Map bind callback | `bound_with` của từng source geometry | `properties` hoặc `group` | `geometries[].bound_with` | Tự bỏ target id khỏi source ids và chặn cycle |
|
||||
| Toggle binding filter | `GeometryBindingPanel` filter checkbox | `geometryBindingFilterEnabled` | Không | Không | Chỉ lọc hiển thị map theo selection/bound_with |
|
||||
|
||||
## 4. Entity snapshot
|
||||
|
||||
@@ -189,7 +189,7 @@ Khi một thao tác cần đi vào commit, kiểm output snapshot:
|
||||
- Wiki rows nằm trong `wikis[]`.
|
||||
- Entity-wiki rows nằm trong `entity_wiki[]`.
|
||||
- Replay script nằm trong `replays[]`, không lưu `replayDraft`.
|
||||
- Generate-only fields trên feature như `entity_id`, `entity_ids`, `entity_name`, `entity_names`, `entity_label_candidates`, `time_start`, `time_end`, `binding`, `type` được snapshot builder xử lý/loại bỏ đúng chỗ trước API payload.
|
||||
- Generate-only fields trên feature như `entity_id`, `entity_ids`, `entity_name`, `entity_names`, `entity_label_candidates`, `time_start`, `time_end`, `bound_with`, `type` được snapshot builder xử lý/loại bỏ đúng chỗ trước API payload.
|
||||
|
||||
## 12. Các thao tác cần audit lại nếu editor đổi lớn
|
||||
|
||||
|
||||
@@ -63,10 +63,12 @@ Mỗi feature trong `mainDraft.features` sinh một row:
|
||||
| `operation` | `"create"`, `"update"` hoặc `"reference"` theo baseline/diff |
|
||||
| `type` | FE type key trước `toApiEditorSnapshot()`, backend code string sau normalize API |
|
||||
| `draw_geometry` | `feature.geometry` |
|
||||
| `binding` | `normalizeFeatureBindingIds(feature)` |
|
||||
| `bound_with` | `normalizeFeatureBoundWith(feature)` |
|
||||
| `time_start` / `time_end` | `feature.properties.time_start/time_end ?? null` |
|
||||
| `bbox` | BBox tính từ geometry, hoặc `null` |
|
||||
|
||||
Snapshot legacy có `binding: string[]` trên geometry cha được FE migrate khi load bằng cách invert sang `bound_with` trên từng geometry con.
|
||||
|
||||
Geometry đã bị xóa sinh row:
|
||||
|
||||
```ts
|
||||
@@ -93,7 +95,7 @@ Geometry đã bị xóa sinh row:
|
||||
- `type`
|
||||
- `time_start`
|
||||
- `time_end`
|
||||
- `binding`
|
||||
- `bound_with`
|
||||
- `entity_id`
|
||||
- `entity_ids`
|
||||
- `entity_name`
|
||||
@@ -103,7 +105,7 @@ Geometry đã bị xóa sinh row:
|
||||
|
||||
Các field này được lưu ở collection chuẩn hơn:
|
||||
|
||||
- `type/time/binding` nằm ở `geometries[]`.
|
||||
- `type/time/bound_with` nằm ở `geometries[]`.
|
||||
- entity relation nằm ở `geometry_entity[]`.
|
||||
- entity label/name được hydrate lại từ `entities[]` và join table khi load.
|
||||
|
||||
@@ -125,7 +127,7 @@ Build rule:
|
||||
|
||||
Rows được dedupe/sort theo `geometry_id`, rồi `entity_id`.
|
||||
|
||||
Commit/submit hiện chặn nếu có geometry không có entity ids hợp lệ. Geometry-geometry `binding` không được tính là đã bind entity.
|
||||
Commit/submit hiện chặn nếu có geometry không có entity ids hợp lệ. Geometry-geometry `bound_with` không được tính là đã bind entity.
|
||||
|
||||
## 6. Entity contract
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ Replay seed mới có dạng:
|
||||
|
||||
- MAIN geo
|
||||
- toàn bộ bulk selection hiện tại
|
||||
- toàn bộ `binding` của MAIN geo trong `mainDraft`
|
||||
- toàn bộ geometry con có `bound_with` trỏ tới MAIN geo trong `mainDraft`
|
||||
|
||||
Rule hiện tại:
|
||||
|
||||
@@ -110,7 +110,7 @@ Hydrate hiện tại:
|
||||
|
||||
- lấy feature từ `mainDraft` theo đúng thứ tự `target_geometry_ids`
|
||||
- clone ra `FeatureCollection` mới
|
||||
- flatten `binding` thành `[]` để các geo trong replay bình đẳng với nhau
|
||||
- flatten `bound_with` thành `null` để các geo trong replay bình đẳng với nhau
|
||||
|
||||
## 6. Trong replay mode map đang đọc gì
|
||||
|
||||
|
||||
@@ -116,9 +116,8 @@ Editor hiện có `undo`, nhưng chưa có redo.
|
||||
- `type_key`
|
||||
- `time_start`
|
||||
- `time_end`
|
||||
- `binding`
|
||||
|
||||
`geometryMetaForm.binding` hiện chủ yếu là giá trị hiển thị/đồng bộ UI, còn chỉnh sửa binding thật đi qua `GeometryBindingPanel`.
|
||||
Geometry-geometry bound state không nằm trong `geometryMetaForm`; `GeometryBindingPanel` chỉnh trực tiếp `feature.properties.bound_with` của geometry con.
|
||||
|
||||
### 4.3. Replay state
|
||||
|
||||
@@ -324,5 +323,5 @@ Hiệu ứng:
|
||||
- có `undo`, chưa có `redo`
|
||||
- timeline state có `timelineYear`, nhưng page hiện dùng `timelineDraftYear` cho filtering
|
||||
- dirty count của commit không tương ứng một-một với số mutation backend
|
||||
- map selection, binding filter và timeline filter đều là state client-side
|
||||
- map selection, bound_with filter và timeline filter đều là state client-side
|
||||
- trạng thái orphan/time/timeline trong `GeometryBindingPanel` là derived từ draft + visibility, không phải field persist riêng
|
||||
|
||||
@@ -86,7 +86,7 @@ FE không còn export/persist cả `FeatureCollection` riêng của replay nữa
|
||||
|
||||
- geo MAIN
|
||||
- các geo được đưa vào replay từ bulk select
|
||||
- binding của MAIN geo
|
||||
- các geometry con có `bound_with` trỏ tới MAIN geo
|
||||
|
||||
Khi mở replay, FE sẽ hydrate lại `replayDraft` từ:
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ Source này dùng cho:
|
||||
`useMapSync()` chịu trách nhiệm:
|
||||
|
||||
1. nhận `renderDraft` đã được page áp timeline/replay/preview filter trước
|
||||
2. filter draft theo binding nếu `applyGeometryBindingFilter = true`
|
||||
2. filter draft theo `bound_with` nếu `applyGeometryBindingFilter = true`
|
||||
3. filter theo geometry visibility
|
||||
4. split feature thành nhóm polygon/line/point
|
||||
5. decorate line/polygon/point cho label rendering
|
||||
@@ -100,7 +100,7 @@ Source này dùng cho:
|
||||
- data mà map render không phải raw `mainDraft` nguyên xi
|
||||
- `renderDraft` là nguồn quyết định geometry nào xuất hiện trên map
|
||||
- `labelContextDraft` chỉ dùng để lookup label/entity name, có thể chứa geometry đã bị timeline filter ẩn, và không được dùng để quyết định render
|
||||
- source MapLibre cuối cùng là `renderDraft` sau khi đã qua binding filter, geometry visibility và label decoration
|
||||
- source MapLibre cuối cùng là `renderDraft` sau khi đã qua bound_with filter, geometry visibility và label decoration
|
||||
|
||||
## 5. Map interaction layer
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ Có ba lớp filter hiển thị trong runtime:
|
||||
|
||||
1. background layer visibility
|
||||
2. geometry visibility theo type key từ panel phải
|
||||
3. binding filter / replay filter / timeline filter ở phía data trước khi set source
|
||||
3. bound_with filter / replay filter / timeline filter ở phía data trước khi set source
|
||||
|
||||
Vì vậy khi một geometry "không hiện", có thể nguyên nhân nằm ở data filtering chứ không phải style layer.
|
||||
|
||||
@@ -170,6 +170,6 @@ Implementation hiện tại không làm vậy.
|
||||
Thay vào đó:
|
||||
|
||||
- timeline filter đang chạy phía data trong `page.tsx`
|
||||
- binding filter và geometry visibility cũng chủ yếu chạy trước khi set source
|
||||
- bound_with filter và geometry visibility cũng chủ yếu chạy trước khi set source
|
||||
|
||||
Tức là phần lớn filtering là `prepare data -> set source`, không phải `add layer filter expression per year`.
|
||||
|
||||
@@ -151,7 +151,7 @@ và sinh ra:
|
||||
Các điểm quan trọng:
|
||||
|
||||
- geometry many-to-many với entity được persist ở `geometry_entity[]`
|
||||
- denormalized fields trên feature như `entity_ids`, `entity_name`, `binding`, `time_start` sẽ bị strip khỏi `editor_feature_collection` trước khi gửi API
|
||||
- denormalized fields trên feature như `entity_ids`, `entity_name`, `bound_with`, `time_start` sẽ bị strip khỏi `editor_feature_collection` trước khi gửi API
|
||||
- wiki/entity/link được chuẩn hóa lại thành `reference`, `binding`, `delete`, `create`, `update` tùy baseline
|
||||
- replay script được persist ở `replays[]`; `replayDraft` không được gửi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user