Files
Gnuboard7/tests/scenarios/layout-editor-array-editor.yaml
2026-07-01 10:30:32 +09:00

126 lines
8.3 KiB
YAML

feature: 레이아웃 편집기 배열 빌트인 — array 노드 에디터(ARRAY-PROP 속성 패널)
description: |
컴포넌트의 정적 배열 prop(node.props[arrayProp] — 예 TabNavigation tabs, Breadcrumb items,
Dropdown/ActionMenu items, DataGrid columns, PageHeader actions)을 속성 모달 본체에서 항목
단위로 구조 편집한다. capability 의 일반 슬롯 `nodeEditor:{kind:"array",params:{arrayProp,
itemLabel,fields,newItem}}`(부록4-ter)로 선언하고, 코어 빌트인 ArrayItemsEditor 를
registerCoreEditors 가 registerNodeEditor('array', ...) 로 일반 레지스트리에 등록한다(특권
분기 0 — 코어는 kind 만 알고 컴포넌트명/배열 prop 이름을 가정하지 않음. arrayProp/항목 필드
스키마는 params 가 공급 → 임의 배열 prop 컴포넌트에 동일 에디터 재사용).
children 노드 에디터(ChildrenListControl)가 실제 자식 노드 트리를 다루는 것과 달리, array
에디터는 props 안의 정적 데이터 배열(객체/원시 항목)을 추가/삭제/정렬/필드편집한다.
필드 위젯: text(평문 즉시 반영) / i18n-text(평문 blur → createCustomKey → $t:custom.* 기록,
기존 키 → updateCustomKeyValue 현재 로케일만) / select(options) / boolean / icon(아이콘명 문자열).
primary 필드(미지정 시 첫 필드)는 행 주 입력. 원시 string[] 항목은 primary 필드로 값 자체 편집.
정적-바인딩 가드: props[arrayProp] 가 `{{...}}` 데이터바인딩이거나 비-배열이면 편집
비대상 → "바인딩됨(코드 편집)" 디그레이드(덮어쓰기 위험 차단). 항목 텍스트 다국어는
children/table 항목과 공용 모델(createCustomKey) SSoT.
axes:
operation: [add, remove, move, edit_text_field, edit_i18n_field, edit_select, edit_boolean, edit_icon]
array_value: [static_array, binding_expression, non_array, empty]
field_widget: [text, i18n_text, select, boolean, icon]
template: [sirsoft-basic, sirsoft-admin_basic]
exclusions:
- { operation: add, array_value: binding_expression, reason: "바인딩식 배열 prop 은 편집 비대상(디그레이드) — CRUD 불가" }
- { operation: remove, array_value: binding_expression, reason: "동일" }
- { operation: move, array_value: binding_expression, reason: "동일" }
- { operation: edit_text_field, array_value: binding_expression, reason: "동일" }
- { operation: edit_i18n_field, array_value: binding_expression, reason: "동일" }
- { operation: edit_select, array_value: binding_expression, reason: "동일" }
- { operation: edit_boolean, array_value: binding_expression, reason: "동일" }
- { operation: edit_icon, array_value: binding_expression, reason: "동일" }
- { operation: add, array_value: non_array, reason: "비-배열 prop 은 디그레이드 — CRUD 불가" }
- { operation: remove, array_value: non_array, reason: "동일" }
- { operation: move, array_value: non_array, reason: "동일" }
- { operation: edit_text_field, array_value: non_array, reason: "동일" }
- { operation: edit_i18n_field, array_value: non_array, reason: "동일" }
- { operation: edit_select, array_value: non_array, reason: "동일" }
- { operation: edit_boolean, array_value: non_array, reason: "동일" }
- { operation: edit_icon, array_value: non_array, reason: "동일" }
- { operation: remove, array_value: empty, reason: "빈 배열은 제거 대상 없음" }
- { operation: move, array_value: empty, reason: "빈 배열은 이동 대상 없음" }
- { operation: edit_text_field, array_value: empty, reason: "빈 배열은 편집 대상 없음(추가만 가능)" }
- { operation: edit_i18n_field, array_value: empty, reason: "동일" }
- { operation: edit_select, array_value: empty, reason: "동일" }
- { operation: edit_boolean, array_value: empty, reason: "동일" }
- { operation: edit_icon, array_value: empty, reason: "동일" }
- { operation: edit_text_field, field_widget: i18n_text, reason: "필드 위젯 축은 edit 종류로 이미 분기 — 교차 중복" }
- { operation: edit_text_field, field_widget: select, reason: "동일" }
- { operation: edit_text_field, field_widget: boolean, reason: "동일" }
- { operation: edit_text_field, field_widget: icon, reason: "동일" }
- { operation: edit_i18n_field, field_widget: text, reason: "동일" }
- { operation: edit_i18n_field, field_widget: select, reason: "동일" }
- { operation: edit_i18n_field, field_widget: boolean, reason: "동일" }
- { operation: edit_i18n_field, field_widget: icon, reason: "동일" }
- { operation: edit_select, field_widget: text, reason: "동일" }
- { operation: edit_select, field_widget: i18n_text, reason: "동일" }
- { operation: edit_select, field_widget: boolean, reason: "동일" }
- { operation: edit_select, field_widget: icon, reason: "동일" }
- { operation: edit_boolean, field_widget: text, reason: "동일" }
- { operation: edit_boolean, field_widget: i18n_text, reason: "동일" }
- { operation: edit_boolean, field_widget: select, reason: "동일" }
- { operation: edit_boolean, field_widget: icon, reason: "동일" }
- { operation: edit_icon, field_widget: text, reason: "동일" }
- { operation: edit_icon, field_widget: i18n_text, reason: "동일" }
- { operation: edit_icon, field_widget: select, reason: "동일" }
- { operation: edit_icon, field_widget: boolean, reason: "동일" }
- { operation: add, field_widget: i18n_text, reason: "구조 연산(add/remove/move)은 필드 위젯 종류 무관" }
- { operation: add, field_widget: select, reason: "동일" }
- { operation: add, field_widget: boolean, reason: "동일" }
- { operation: add, field_widget: icon, reason: "동일" }
- { operation: remove, field_widget: i18n_text, reason: "동일" }
- { operation: remove, field_widget: select, reason: "동일" }
- { operation: remove, field_widget: boolean, reason: "동일" }
- { operation: remove, field_widget: icon, reason: "동일" }
- { operation: move, field_widget: i18n_text, reason: "동일" }
- { operation: move, field_widget: select, reason: "동일" }
- { operation: move, field_widget: boolean, reason: "동일" }
- { operation: move, field_widget: icon, reason: "동일" }
effects:
# capability/등록
- array_capability_declared_on_p1_components_both_templates
- array_editor_registered_via_registercoreeditors_kind_agnostic
- property_modal_dispatches_array_node_editor_in_props_tab_by_kind
# 가드
- binding_expression_array_prop_degrades_to_bound_notice
- non_array_prop_value_degrades_to_bound_notice
- missing_array_prop_capability_shows_misconfigured_notice
# 구조 연산
- add_item_appends_newitem_skeleton_patches_whole_node
- add_item_synthesizes_empty_item_from_fields_when_no_newitem
- remove_item_drops_only_that_index
- move_up_down_swaps_adjacent_with_boundary_guard
# 필드 편집
- text_field_updates_item_immediately
- icon_field_updates_item_with_icon_name_string
- select_field_updates_item_with_chosen_value
- boolean_field_toggles_item_flag
- i18n_text_plain_blur_creates_custom_key_and_writes_dollar_t_custom
- existing_custom_key_blur_updates_current_locale_value_keeps_key
- primitive_string_item_edits_value_via_primary_field
- node_prop_change_clears_draft_buffer_no_stale
# 라이브(E2E)
- live_add_tab_edit_label_reorder_save_persists_to_user_page
test_files:
- resources/js/core/template-engine/layout-editor/__tests__/components/ArrayItemsEditor.test.tsx
- resources/js/core/template-engine/layout-editor/__tests__/spec/editorRegistries.test.ts
- tests/Playwright/specs/layout-editor/array-editor.spec.ts
validation:
note: |
Vitest 단위가 axes cross product 회귀(추가/삭제/정렬, text/select/boolean/icon/i18n-text 필드
편집, 바인딩/비-배열/미선언 디그레이드, 원시 string[] 항목, 노드 파생 무상태)와 capability
부착·등록(kind-agnostic)을 잠근다. Playwright E2E 가 라이브 편집기에서 TabNavigation 선택 →
array 에디터 마운트 → 탭 추가 → 라벨 편집 → 정렬 → 저장(PUT 200) → 실사용자화면 반영을
브라우저로 검증한다. 캔버스 인플레이스 레퍼런스(TabNavigation registerCanvasOverlay)는 단계
4-b 산출물 — 본 단계는 속성 패널 경로.
e2e_spec: tests/Playwright/specs/layout-editor/array-editor.spec.ts