object-layout
Skill13 starsChanged 33 days agoMITView on GitHub
Quản lý layout Cogover Object qua Layouts V2 API `/bapi/v1/layouts_v2`: tạo, xem, cập nhật, xoá layout; tạo layout `isForm: 1` khi $object-form gọi; thiết kế row/column/section/tab/group/component; lấy/cập nhật `pageSettings.script`; đặt Object Button vào `pageSettings.buttons.listButton`, Path Component và Federation component (custom component) vào layout xem/sửa.
- Reads credentials
In this repository23 other files it gives its agents.
- agent-builderSkill
- app-menu-managerSkill
- build-cogover-appSkill
- cogover-api-authSkill
- cogover-custom-moduleSkill
- cogover-iconSkill
- cogover-overviewSkill
- create-cogover-objectsSkill
- dashboard-builderSkill
- document-templateSkill
- layout-scriptingSkill
- object-buttonSkill
- object-filterSkill
- object-formSkill
- object-history-trackingSkill
- object-infoSkill
- object-path-componentSkill
- object-recordSkill
- object-transition-ruleSkill
- process-creatorSkill
- record-emailSkill
- report-builderSkill
- user-permissionSkill
The file
Files
Object Layout
- Phiên bản:
1.2.0 - Ngày phát hành:
2026-10-06
Skill này được $object-form gọi như sub-skill khi Object chưa có layout isForm hợp lệ, được $layout-scripting dùng để lấy/ghi pageSettings.script, và phối hợp với $object-button, $document-template, $object-path-component khi cần đặt Object Button hoặc Path Component lên layout xem/sửa. $cogover-custom-module gọi skill này để nhúng custom component của Custom Frontend Module (item Federation component) vào layout.
Chuẩn bị
- Credential, header và quy ước response/lỗi chung: theo $cogover-api-auth. Skill này chỉ dùng nhóm
/bapi/v1(API Key Bearer), cụ thể/bapi/v1/layouts_v2. Khi API v2 lỗi xác thực, không nhận payload hoặc xác minh sai: báo nguyên nhân cùng thông báo lỗi từ response rồi dừng; không đổi endpoint, phiên bản API hay cơ chế xác thực. objectTypeSlugvà danh sách field của Object (id,name,slug,fieldType,description,metaData,manualModifyAllow, related lists): lấy qua $object-info (POST /bapi/v1/objects/list,includeFields: true). Không đoán field ID hoặc slug từ tên.- Tài liệu trong skill, đọc đúng bước cần dùng:
| Khi làm gì | Đọc |
Dựng hoặc sửa content (schema row/column/section/tab/group/component) | references/layout-json-structure.md và mẫu thật assets/sample_layout_1.json |
Cấu hình component theo fieldType (lookup, file, related_list, display_box, report, dashboard, button_group, path_component, federation_component...) | references/component-field-types.md |
Dựng pageSettings | references/page-settings.md |
| Cần ví dụ cây bố cục Lead/Đơn hàng khi thiết kế | references/layout-design-examples.md, assets/sample_layout_create_order.json |
Dựng payload PUT (mẫu curl, jq cho script) | references/layout-update-payload.md |
| Thêm, sắp xếp hoặc gỡ Object Button trên layout xem/sửa | references/record-button-placement.md |
Nguyên tắc xác nhận
- Mặc định không hỏi xác nhận bổ sung cho tạo, cập nhật, đặt/gỡ Object Button hoặc xoá layout khi người dùng đã nêu rõ thao tác và đích. Sau khi resolve đúng tài nguyên, payload hợp lệ và đủ quyền: thực hiện ngay rồi xác minh kết quả.
- Chỉ hiển thị bản xem trước/tóm tắt và chờ xác nhận khi người dùng chủ động yêu cầu xem trước, phê duyệt hoặc xác nhận trước khi ghi.
- Đích hoặc phạm vi mơ hồ và các lựa chọn dẫn đến kết quả khác nhau đáng kể: hỏi làm rõ phạm vi; đây không phải bước xác nhận mặc định.
- Xoá: vẫn resolve chính xác ID, hiển thị ID/tên/slug/đối tượng, nêu rõ không thể hoàn tác và kiểm tra tác động trước khi gọi API; không thêm lượt xác nhận nếu yêu cầu xoá đã rõ và người dùng không yêu cầu quy trình phê duyệt.
- Khi
$object-formgọi vì thiếu layoutisForm: không hỏi lại thông tin đã có, không yêu cầu xác nhận; dùng đúng Object đã resolve, đặt tên tiếng Anh theo form/Object, tự thiết kế bố cục mặc định hợp lý từ các field có thể nhập nếu người dùng chưa mô tả chi tiết.
Layouts V2 API
| Thao tác | Request |
| Tạo | POST /bapi/v1/layouts_v2 |
| Danh sách layout của Object | POST /bapi/v1/layouts_v2/list body {"objectTypeSlug": "{OBJECT_SLUG}", "limit": 2000, "page": 1} |
| Chi tiết | POST /bapi/v1/layouts_v2/view body {"id": "{LAYOUT_ID}"} |
| Cập nhật | PUT /bapi/v1/layouts_v2/{LAYOUT_ID} |
| Xoá | POST /bapi/v1/layouts_v2/delete body {"data": ["{LAYOUT_ID}"]} |
Link layout: https://{WORKSPACE_DOMAIN}/settings/object/{OBJECT_SLUG}/layout/{LAYOUT_ID}.
Quy tắc cho mọi PUT:
- View lại layout ngay trước khi sửa và dựng payload từ
datamới nhất để không ghi đè thay đổi của người khác. - Payload chỉ gồm allowlist:
name,objectTypeSlug,status,type,updateRecordMode,accessControls,hasComponentPath,content,title,pageSettings,functionLayout,isWeb,isMobile. Không gửi rawdatacủa response view (chứa trường server-managedid,slug,created,updated,createdBy,updatedBy,workspaceId,objectTypeId,contentCompiledmà API update không nhận). Không gửi payload rút gọn chỉ cópageSettings.scripthoặc chỉname,content,pageSettings. - Giữ nguyên mọi giá trị không được yêu cầu thay đổi, kể cả
hasComponentPath(có thể lànull); không tự dựng lạicontentkhi chỉ sửa script, button hoặc thêm một component. titlephải là object hợp lệ: view trảtitle: nullthì bỏ keytitlekhỏi payload hoặc dựng object theo layout-json-structure.md. Gửititle: nullhoặc thiếupageSettingstrả42201vớimetanhư{"title": "array"}; đọcmetađể biết khoá sai.- Layout tiêu chuẩn sinh khi tạo Object (thường tên "Giao diện tiêu chuẩn") có thể có
contentrỗng vàtitle: null; đã quan sátPUTcontentvào layout này trảr: 0nhưng view lại vẫn rỗng. Không dùng nó làm đích: tạo layout custom theo Tạo layout. - Layout custom tồn tại song song với layout tiêu chuẩn: xác định layout giao diện thực sự dùng cho màn Tạo và Xem/Sửa bằng cách mở form, theo Kiểm tra trên giao diện.
- Sau
PUT, view lại và so với payload. SoaccessControlstheofunctions,option,items,type: server cấp lạiid,created,updatedcủa từng entry ở mỗi lầnPUTdù quyền không đổi (đã quan sát). Không khớp: báo dữ liệu chưa được lưu đúng và dừng.
Phân loại layout
| Loại | functionLayout | accessControls[].functions | Ghi chú |
| Tạo | 1 | ["ADD"] | |
| Xem/Sửa | 2 | ["VIEW_EDIT"] | Loại duy nhất nhận Path Component |
| Tạo/Xem/Sửa | 3 | ["ADD", "VIEW_EDIT"] | Field manualModifyAllow: false và auto_number tự ẩn khi tạo |
isWeb/isMobilechọn layout dùng cho Web, Mobile hoặc cả hai.isForm: 1chỉ khi người dùng yêu cầu layout cho Object Form hoặc$object-formgọi fallback; layout khác dùngisForm: 0hoặc giữ mặc định backend. Không suy diễn layout Add thông thường là form-compatible; không chuyển layout hiện có từisForm: 0sang1.- Layout cho Object Form: Web active với
functionLayout: 1, quyềnADD,isForm: 1,status: 1,isWeb: truevàcontenthợp lệ; không dùngfunctionLayout: 3cho fallback này. Sau create, view/list lại và chỉ trả ID cho$object-formkhiobjectTypeSlugcùng các giá trị trên khớp chính xác.
Tạo layout
Object vừa tạo: xem Checklist hoàn thiện Object mới.
Bước 1: Thu thập yêu cầu
- Đối tượng (
objectTypeSlug). - Mô tả bố cục: bao nhiêu row, column, section, tab, group và field nào ở đâu.
- Tên layout: chuẩn hoá hoặc dịch sang tiếng Anh; nếu không chỉ định, đặt theo chức năng (
Create,View/Edit,Create Order).
Lấy fields của Object qua $object-info; xác định id, name, slug, fieldType, description, metaData của từng field sẽ đặt lên layout.
Bước 2: Thiết kế bố cục
Đóng vai chuyên gia UI/UX cho nhân viên doanh nghiệp dùng CRM/HRM/ERP: đọc name/slug/description của field và Object, sắp xếp field theo thứ tự nhập/đọc trong nghiệp vụ; ưu tiên thuận tiện, logic, không hoa mỹ. Có thể list/view layout của Object tương tự để tham khảo cách bố trí (Lead: functionLayout: 1 cho tạo, 2 cho xem/sửa; ID lấy từ API list). Ví dụ cây bố cục: references/layout-design-examples.md.
Layout tham khảo chỉ dùng để học cấu trúc. Trước khi tái sử dụng content, xác minh nó là array không rỗng và đủ chuỗi layoutRow → layoutColumn → section → tab → group → component; nếu content là null, không phải array, [] hoặc có cấp con rỗng, không dùng làm payload mà dựng mới từ fields của Object và asset mẫu.
Layout Tạo (functionLayout: 1 hoặc 3)
- Khung trang: giữ
settingPage.paddingTop/Bottom/Left/Right: 0,settingPage.typeColor: "primary",settingPage.combinationRatio: 100;settingContentPage.maxWidth: 100,unitMaxWidth: "%",isShowBorder: false. Giới hạn độ rộng form bằng Layout Row ngoài cùng, không đổisettingContentPagesang1000px. - Row ngoài cùng, tính trước khi dựng JSON: form thường (không có bảng/component rộng) →
maxWidth: 1000,unitMaxWidth: "px",horizontalAlignment: "center"(đủ cho group 2-3 cột; chọn độ rộng khác chỉ khi số cột, loại field hoặc UI thực tế chứng minh cần). Córelated_listtypeView: "list"hoặc bảng/component rộng tương tự →maxWidth: 100,unitMaxWidth: "%",horizontalAlignment: "center". Không dùng100%cho form thường chỉ vì nhiều field. - Cấu trúc: 1 Layout Row, 1 Layout Column trừ khi có lý do rõ hoặc người dùng yêu cầu. Trong Column chia 1 hoặc nhiều Section có border (
isBorder: true) và tiêu đề (isShowName: true); ví dụ Lead: "Lead Information", "Additional Information". - Field quan trọng (tên, tiêu đề, trạng thái) và field
requiredlên đầu section đầu tiên. - Group: field nội dung dài (tiêu đề, mô tả) →
numberOfColumns: 1; field ngắn (SĐT, email, trạng thái, select) →2hoặc3; cặp liên quan ngắn đặt cùng hàng trong group nhiều cột (Họ + Tên, Quốc gia + Thành phố, Ngày bắt đầu + Ngày kết thúc). Field xếp từ trái qua phải, hết hàng thì xuống dòng. long_textđặt cuối section/group. Boolean gom vào group nhiều cột vớilabelPlacement: "right".- Không đưa vào layout tạo: field
manualModifyAllow: false,auto_number,created,updated,created_by,updated_by(tự ẩn nếufunctionLayout: 3, nhưng vẫn tránh). - Object cha cần nhập danh sách con ngay khi tạo (Đơn hàng → Sản phẩm trong đơn hàng, Báo giá → Sản phẩm báo giá): đặt
related_listtypeView: "list"cótableSettings.editableColumnstrong GroupnumberOfColumns: 1ở cuối section, sau các field cơ bản của cha; Row ngoài cùng dùng100%. Quy tắc chọneditableColumns/showingColumns: references/component-field-types.md#related_list; mẫuassets/sample_layout_create_order.json.
Layout Xem/Sửa (functionLayout: 2 hoặc 3)
- 1-2 Layout Row. Row chính nhiều cột: 2 cột sidebar + main
colSpan1:2hoặc1:3; 3 cột1:2:1(trái: liên hệ/tóm tắt; giữa: nội dung chính + tab; phải: bổ sung/metadata). - Sidebar: avatar (
display_box), liên hệ cơ bản, tóm tắt; hoặc owner và metadata. Group trong sidebar dùngnumberOfColumns: 1. - Cột chính: tiêu đề/tên (Group 1 cột) → field chính (Group 2 cột) → Tab-section (
typeSection: "menu") gom related list, activities, lịch sử; mỗi tab một nhóm related list liên quan (ví dụ "Activities", "Converted to", "Marketing Campaign"). - Field hệ thống (
created,updated,created_by,updated_by,last_activity_time): section riêng hoặc sidebar/cột phụ, dưới cùng. - Path Component: chỉ layout
functionLayout: 2quyềnVIEW_EDIT. Không chỉ định vị trí → Row đầu tiên, Row 1 Column (numberOfColumns: 1,colSpan: 1), GroupnumberOfColumns: 1, Section không border và không hiện tên. Đây là gợi ý UI, không phải ràng buộc schema; có thể đặt Row/Column khác nếu người dùng yêu cầu hoặc bố cục đủ rộng. Quy trình: mục "Đưa Path Component vào layout Xem/sửa". - Related list editable trên xem/sửa: như layout tạo, nhưng
showingColumnscó thể thêm cột tính toán (subtotal);_action_columnkhông cần trongshowingColumnskhi đã ởpinnedColumns.right;orderBy: "created"thay vì"updated"để giữ thứ tự dòng; đặt trong section riêng trên cột chính, lookup liên quan phía trên (Bảng giá trên bảng Sản phẩm). - Record-level Object Button nằm ở
pageSettings.buttons.listButton, không phải trongcontent. Quy trình: mục "Đặt Object Button lên layout xem/sửa". - Federation component (custom component của Custom Frontend Module): Group 1 cột không border, không hiện tên, đặt ngay trên Related List hoặc field mà component thao tác. Quy trình: mục "Đưa Federation component vào layout".
Mọi loại layout
- Nhóm field theo ngữ nghĩa vào cùng section/group: cá nhân (họ, tên, danh xưng, chức danh); liên lạc (email, điện thoại, địa chỉ); công ty (tên, ngành, doanh thu, số nhân viên, website).
- Thứ tự: định danh (tên, tiêu đề, mã) → trạng thái/phân loại → nghiệp vụ chính (owner, giá trị, số lượng) → liên hệ → mô tả/ghi chú → hệ thống.
- Không group/section trống. Section hiện tiêu đề khi có từ 2 section; 1 section duy nhất có thể ẩn tiêu đề.
- Lookup quan trọng (owner, assigned_to): layout tạo ở section chính, layout xem ở sidebar. Ảnh đại diện ở đầu sidebar; file đính kèm cuối section hoặc section riêng.
Bước 3: Dựng JSON
Dựng payload trong bộ nhớ để gửi API; không tạo file JSON. Schema từng cấp: references/layout-json-structure.md và assets/sample_layout_1.json; thuộc tính theo fieldType: references/component-field-types.md; pageSettings: references/page-settings.md.
content[] → layoutRow → layoutColumn → section (normal | menu) → tab → group → components[]Quy tắc bắt buộc; sai sẽ gây lỗi UI "Cannot read properties of undefined (reading 'map')":
- Container dùng
type("layoutRow","layoutColumn","section","group"), không dùngfieldType. - Phần tử con nằm trong
children(row → column → section → tab → group); không dùnglayoutColumns,sections,tabs,groups. - Group chứa field trong
components, không phảichildren. - Field nằm trực tiếp trong
components; không bọc dạng{"component": {...}, "fieldType": "component"}. idcủa Object Field là Object Field ID (OF...), không phải UUID. Component đặc biệt không phải Object Field (path_component,display_box,related_list,report,federation_component...) dùng UUID v4 riêng và không cầnfieldMetaData.idcủa layoutRow, layoutColumn, section, tab, group là UUID v4.- Field và component bắt buộc nằm trong Group; không đặt trực tiếp vào section hoặc tab.
Object Field component bắt buộc có id thật và fieldMetaData (chuỗi JSON stringify từ metaData của field). Thiếu thì layout vẫn tạo được nhưng không sửa/di chuyển/xoá được field trong layout editor, chỉ thêm mới từ palette.
showFieldName của lookup mặc định "$record.name"; lookup tới Personnel (personnel) dùng "{$record.first_name} {$record.last_name}", thứ tự họ tên đối chiếu dòng personnel của $object-info và cách giao diện Workspace đang hiển thị; Object có cách hiển thị tên riêng thì chỉnh tương ứng.
Tên và slug:
namelayout bắt buộc tiếng Anh, ngắn, theo chức năng (Create,View/Edit,Create Order); đầu vào ngôn ngữ khác thì dịch trước khi gọi API, không có ngoại lệ. Không gửiTạo,Xem,Chỉnh sửa.- UUID v4 cho
idcủa mọi container và component đặc biệt không phải Object Field. - Slug sinh mới:
{type_prefix}_{meaningful_name}, tiếng Anh, chữ thường,snake_case, bất kể ngôn ngữ của tên layout/tên hiển thị. Prefix đúng loại:layout_row_,layout_column_,section_,tab_,group_,related_list_,display_box_,report_,dashboard_,button_group_,path_component_,workflow_button_,federation_component_. Đặt theo chức năng/nội dung hoặc suy từ vai trò, vị trí, field bên trong (layout_column_contact_sidebar,section_system_information,group_address_fields); tránhsection_1,group_new; không thêm timestamp. - Slug phải unique trên toàn hệ thống, không chỉ trong một layout: kiểm tra với slug đã có và mọi slug trong payload đang dựng. Chỉ thêm hậu tố khi trùng thật, dùng số nhỏ nhất chưa dùng (
group_address_fields,group_address_fields_2,_3...). API báo slug đã tồn tại → tăng hậu tố và gọi lại. uiSlug: Object Field{field_slug}_{số thứ tự}(name_1,status_1); component sinh mới{component_slug}_{số thứ tự}(display_box_contact_summary_1).- Không dịch hoặc đổi slug tham chiếu có sẵn: Object Field slug,
originSlug,dashboardSlug,pathComponentSlug.
Quy tắc tạo layout:
contentlà array không rỗng;null, kiểu khác array hoặc[]là payload không hợp lệ.- Mỗi layoutRow ≥ 1 layoutColumn; layoutColumn ≥ 1 section; section ≥ 1 tab (section
normalvẫn có 1 tab ẩn); tab ≥ 1 group; group ≥ 1 component. idObject Field khớpidfield trong Object definition.- Mỗi field chỉ xuất hiện một lần trong toàn layout, trừ khi ở tab khác nhau của section
menu. - Tổng
colSpancác cột =numberOfColumnscủa layoutRow. - Layout cho Object Form: theo mục "Phân loại layout".
Bước 4: Kiểm tra trước khi gọi API
- Chặn payload rỗng: chỉ gọi
POSTkhicontentlà array có phần tử; kiểm tra đệ quy từng cấp theo Quy tắc tạo layout. - Layout Tạo: Row ngoài cùng có đúng bộ
maxWidth/unitMaxWidth/horizontalAlignment: "center"(1000px hoặc 100% theo Bước 2); không nhầm vớipageSettings.settingContentPage. namelà tiếng Anh với mọi request tạo hoặc đổiname.- Khi
$object-formgọi: payload cófunctionLayout: 1,ADD,isForm: 1,status: 1,isWeb: true. - Layout tham khảo có
content: null,[]hoặc cấp con rỗng: không gửi và không thử lại cùng payload; dựngcontentmới rồi chạy lại toàn bộ kiểm tra. - Đủ điều kiện thì gọi API ngay; chỉ chờ khi người dùng chủ động yêu cầu xem trước.
Bước 5: Gọi API tạo và xác minh
curl --silent --location 'https://{WORKSPACE_DOMAIN}/bapi/v1/layouts_v2' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {API_KEY}' \
--data '{
"objectTypeSlug": "{OBJECT_SLUG}",
"name": "Create",
"functionLayout": 3,
"isForm": 0,
"status": 1,
"isWeb": true,
"accessControls": [ ... ],
"content": [ ... ],
"pageSettings": { ... }
}'Hiển thị ID, tên, slug và link layout. Khi tạo cho $object-form: functionLayout: 1, isForm: 1, quyền ADD, status: 1, isWeb: true; view/list lại và chỉ trả ID khi khớp. Sau đó kiểm tra theo Kiểm tra trên giao diện.
Kiểm tra trên giao diện
Quy tắc chung: xác nhận giao diện của $cogover-api-auth. Riêng layout, script và vị trí nút:
- View lại chỉ xác nhận cấu hình đã lưu, không xác nhận layout nào đang được dùng, field có hiện, script có chạy hay nút có xuất hiện.
- Trước khi báo hoàn tất: mở form Tạo và màn Xem của một record test trong trình duyệt người dùng đã đăng nhập sẵn. Chưa mở được thì báo "đã lưu, chưa kiểm tra giao diện" và liệt kê màn hình người dùng cần mở.
- Layout xem có thể tự lưu khi rời ô (inline edit): chỉ thao tác thử trên record test.
Xem danh sách và chi tiết layout
- Danh sách: gọi
listtheoobjectTypeSlug, hiển thị bảng ID, tên, slug,functionLayout,isWeb,isMobile,status. - Chi tiết: gọi
viewtheo ID.
Lấy script đang có sẵn trên layout
- View layout, đọc
data.pageSettings.script(jq -r '.data.pageSettings.script // ""'). - Giá trị
null, rỗng hoặc không tồn tại → trả lời rõ layout chưa có script. - Chỉ hiển thị script; không tự chỉnh sửa layout.
Cập nhật script cho một layout
Chỉ thay đổi pageSettings.script; giữ content, title, quyền truy cập và cấu hình khác nếu không được yêu cầu.
- View layout, dựng payload theo allowlist (mục "Layouts V2 API"), chỉ thay
pageSettings.scriptbằng script mới; xoá script →""hoặcnulltheo payload hiện tại của hệ thống. - Ưu tiên dựng bằng
jq --rawfileđể giữ nguyên xuống dòng và dấu nháy; mẫu ở references/layout-update-payload.md. PUT, rồi view lại và so sánhdata.pageSettings.script. Lỗi hoặc không khớp → báo và dừng. Khớp → kiểm tra trên giao diện xem script có chạy.
Cập nhật layout
- View layout, hiển thị cấu trúc hiện tại, thu thập thay đổi, dựng
content/pageSettingsmới theo quy tắc ở "Tạo layout". - Payload theo allowlist; giữ nguyên phần không được yêu cầu thay đổi.
- Mặc định cập nhật ngay;
PUTrồi view lại để xác minh, sau đó kiểm tra trên giao diện.
Xoá layout
- Resolve chính xác layout; hiển thị ID, tên, slug, đối tượng; nêu rõ hành động không thể hoàn tác.
- Gọi
deletengay sau các kiểm tra bắt buộc; chỉ chờ xác nhận khi người dùng chủ động yêu cầu, hoặc hỏi làm rõ khi nhiều layout có thể khớp. - List/view lại để xác minh layout không còn tồn tại.
Đặt Object Button lên layout xem/sửa
Đọc references/record-button-placement.md trước. Dùng khi record-level Object Button đã tồn tại nhưng chưa xuất hiện trên màn hình bản ghi.
- Xác minh button qua Object Buttons API
view:id,slug,objectTypeSlug, trạng thái, icon. Không đoán ID/slug từ tên. - Button chỉ hiển thị trên màn danh sách (list action
16/19hoặc luồng list/bulk tương ứng) → cấu hình ở màn danh sách/filter, không đặt vào record layout. - Resolve layout đích bằng ID hoặc list layout của Object: cùng
objectTypeSlug,functionLayout: 2hoặc3cóVIEW_EDIT. Nhiều layout theo quyền hoặc web/mobile → không tự cập nhật tất cả; yêu cầu người dùng chọn khi chưa đủ ngữ cảnh. - View layout ngay trước khi sửa; đọc
pageSettings.buttons, chưa có thì khởi tạo theo schema trong reference. - Chống trùng theo
buttonId: đã có thì không thêm bản sao, chỉ đổi cấu hình hiển thị khi được yêu cầu. Giữ nguyên thứ tự và toàn bộ entry hiện có; chèn vào vị trí người dùng yêu cầu, không chỉ định thì append cuối. Dùng ID, slug, icon thật của button; mặc định quan sát đượctype: "gray",size: "medium",customName: null. - Payload theo allowlist, chỉ thay
pageSettings.buttons;PUTrồi view lại. Lưu thành công khipageSettings.buttons.listButtoncó đúng một entry vớibuttonIdmục tiêu và các button cũ vẫn nguyên; nút chỉ coi là xuất hiện sau khi kiểm tra trên giao diện.
Gỡ button khỏi layout chỉ làm button không hiển thị trên layout đó, không xoá Object Button. Xoá Object Button không tự gỡ tham chiếu trên layout → kiểm tra các layout liên quan trước khi xoá.
Đưa Path Component vào layout Xem/sửa
Dùng khi Path Component đã tồn tại trên Object và cần hiển thị trên màn hình bản ghi. Schema component và Row mặc định: references/component-field-types.md#path_component.
Ràng buộc:
- Layout đích phải
functionLayout: 2và cóVIEW_EDIT; không đưa vào layout1hoặc3. - Path phải active và cùng
objectTypeSlug; resolve bằng$object-path-component(thao tác read) theo ID/URL/slug, không đoán slug. - Layout lưu slug thật của Path trong
pathComponentSlug, không lưu Path IDPC...; từ URL/ID phải resolve detail rồi lấypath.slug. idcomponent là UUID v4 mới, không phải Path ID hay Object Field ID; không cầnfieldMetaData.- Duyệt đệ quy toàn bộ
content: đã có đúng một component cùngpathComponentSlug→ idempotent, không thêm bản sao; nhiều bản sao hoặc có Path khác tại vị trí đích → báo rõ, không tự xoá hay thay thế. - Giữ
hasComponentPathđúng như response, kể cảnull; không tự set1. - Tạo mới: slug
path_component_<name>tiếng Anhsnake_case, unique toàn hệ thống, sinhuiSlugtương ứng;useLayouts: [2],status: 1,isPinned: falsetrừ khi người dùng yêu cầu khác. Di chuyển component có sẵn: giữ nguyênid,slug,uiSlug.
Quy trình:
- Resolve Path detail và layout detail mới nhất; xác minh Path active, cùng Object; layout
functionLayout: 2, cóVIEW_EDIT,contenthợp lệ. - Duyệt mọi
group.componentsđể kiểm tra trùngpathComponentSlugvà thu thập mọiid,slug,uiSlugđang tồn tại. - Dựng component. Không chỉ định vị trí → dựng Row mặc định và prepend vào
content; có vị trí → merge component vào Group đích, không dựng lại phần còn lại. - Kiểm tra hierarchy không rỗng, UUID và slug unique, mỗi
pathComponentSlugmục tiêu chỉ xuất hiện một lần. - Payload theo allowlist,
PUT, view lại. Thành công khi: layout vẫnfunctionLayout: 2; có đúng một component activefieldType: "path_component"vớipathComponentSlugmục tiêu, nằm đúng vị trí; Row/component cũ và top-level setting không đổi ngoài diff dự kiến.
Đưa Federation component vào layout
Dùng khi Custom Frontend Module dạng custom component (phát triển theo $cogover-custom-module) đã publish và activate, cần hiển thị trên màn hình bản ghi. Schema: references/component-field-types.md#federation_component. Schema quan sát từ view một layout Xem/sửa do layout editor tạo và đã kiểm chứng PUT payload allowlist chứa component này trả r: 0, view lại giữ nguyên content (ngày 2026-09-15); sau PUT vẫn bắt buộc view lại và mở form thật để xác nhận component tải được.
Ràng buộc:
federationUrl={slugSlot}/Components/<TênComponent>:slugSlot(_cm_N) lấy từ project frontend đangACTIVEqua API Custom Frontend Module trong$cogover-custom-module, không đoán;<TênComponent>khớp chữ hoa/thường với khóa expose./Components/<TênComponent>trongvite.config.tscủa module. Không có/đầu, không kèm origin. URLlocalhostdonpm run previewin ra chỉ dùng khi người dùng đang debug local và phải thay trước khi bàn giao.- Đã quan sát trên layout Xem/sửa (
functionLayout: 2,VIEW_EDIT); layout1/3chưa xác minh, chỉ thêm khi người dùng yêu cầu và báo rõ chưa kiểm chứng. idlà UUID v4 mới; không cầnfieldMetaData,useLayouts. Slug mới:federation_component_<name>tiếng Anhsnake_case, unique toàn hệ thống, sinhuiSlugtương ứng. Component có sẵn: giữ nguyênid,slug,uiSlug, kể cả slug dạng timestamp do layout editor sinh.- Duyệt đệ quy
content: đã có component cùngfederationUrl→ idempotent, chỉ đổi vị trí hoặclabelkhi được yêu cầu; không tự xoá hay thay thế component khác. - Component thao tác form qua
formBuilder.execScriptbằng slug item trên layout (related_listslug, fieldslug), không phải slug Object hay Related List: cung cấp các slug này cho người phát triển module. Component cần Related List → đặt trong cùng cột, ngay trên Group chứarelated_listđó.
Quy trình:
- View layout mới nhất; xác minh
contenthợp lệ; thu thậpid,slug,uiSlughiện có và slug các item mà component cần. - Xác định
federationUrltừslugSlotvà expose key đã xác minh. - Dựng component. Không chỉ định vị trí → Group 1 cột không border, không hiện tên, ngay trên Related List liên quan hoặc đầu cột chính khi không có Related List; có vị trí → merge vào Group đích, không dựng lại phần còn lại.
- Kiểm tra hierarchy không rỗng, UUID và slug unique, mỗi
federationUrlmục tiêu chỉ xuất hiện một lần. - Payload theo allowlist,
PUT, view lại. Thành công khi có đúng một componentfieldType: "federation_component"vớifederationUrlmục tiêu ở đúng vị trí và phần còn lại không đổi ngoài diff dự kiến. Mở form bản ghi trong browser đã đăng nhập: component không tải → kiểm tra module đã activate,slugSlotvà expose key theo$cogover-custom-modulebước 9; không sửa layout thêm để che lỗi module.
Xử lý lỗi đặc thù
| Tình huống | Xử lý |
Layout tham khảo có content: null, [] hoặc cấp con rỗng | Không dùng làm payload, không gọi API với nó; dựng content mới từ fields và asset mẫu rồi kiểm tra lại hierarchy |
| API trả slug đã tồn tại | Tăng hậu tố số của slug và gọi lại |
| Field người dùng nêu không có trong Object | Báo field không tồn tại trong Object và hỏi lại |
42201 khi PUT | Đọc meta; thường do title: null, thiếu pageSettings/type/updateRecordMode. Bỏ title null hoặc dựng object, giữ đủ allowlist |
PUT content trả r: 0 nhưng view vẫn rỗng | Layout tiêu chuẩn tự sinh; tạo layout custom, không thử lại |
| Update trả thành công nhưng view không khớp | Báo dữ liệu chưa được lưu đúng và dừng; không fallback endpoint khác |
401/403, 422 hoặc r khác 0, 5xx | Theo $cogover-api-auth; hiển thị r, msg; không đổi endpoint hay cơ chế xác thực |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

