Skip to content

Commit 7f247c4

Browse files
author
Test
committed
fix: backend LayoutGrid INSERT AFTER + capstone passes 12/12
Backend: pages_builder_v3 stores row/col names in Class; page_mutator adds InsertLayoutGridColumnGen; cmd_alter_page dispatches LayoutGrid insert. Capstone: all 3 integrations restored. Pre-existing helpdesk-app.mdl dup var fixed (declare → assignment). Result: 12/12 files, 0 failed.
1 parent 44a1743 commit 7f247c4

7 files changed

Lines changed: 146 additions & 84 deletions

File tree

academy/zh/capstone-helpdesk/参考实现/12-integrate-actions.mdl

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66
-- ============================================================
77

88
-- ============================================================
9-
-- 集成 1:Ticket_Detail 添加"复制标题"按钮
10-
-- 布局结构:lgMain → rContent → cActions 后追加 cActions2
11-
-- 用法:点击后调用 NF_CopyToClipboard → JSA_CopyToClipboard
9+
-- 集成 1:Ticket_Detail LayoutGrid 列后追加"快捷操作"列
10+
-- 布局结构:lgMain → rContent → cActions 后插入新列
1211
-- ============================================================
1312

1413
alter page HD.Ticket_Detail {
@@ -30,14 +29,11 @@ alter page HD.Ticket_Detail {
3029

3130

3231
-- ============================================================
33-
-- 集成 2:Ticket_Detail 评论区添加相对时间列
34-
-- 用法:点击调用 NF_FormatRelativeTime → JSA_FormatRelativeTime
35-
-- 说明:NF_FormatRelativeTime 返回相对时间文本("5m ago"),
36-
-- 用 actionbutton/link 实现客户端调用
32+
-- 集成 2:Ticket_Detail DataGrid 列后追加"相对时间"列
3733
-- ============================================================
3834

3935
alter page HD.Ticket_Detail {
40-
insert after dgComments.colIsInternal {
36+
insert after dgComments.IsInternal {
4137
column colRelativeTime (caption: 'When', ShowContentAs: customContent, ColumnWidth: manual, Size: 100) {
4238
actionbutton btnRelativeTime (
4339
caption: 'show time',
@@ -50,26 +46,7 @@ alter page HD.Ticket_Detail {
5046

5147

5248
-- ============================================================
53-
-- 集成 3:MyTickets_Overview 添加"复制标题"按钮
54-
-- 用法:快速复制工单主题到剪贴板
55-
-- ============================================================
56-
57-
alter page HD.MyTickets_Overview {
58-
insert after dgMyTickets.colActions {
59-
column colCopy (caption: '', ShowContentAs: customContent, ColumnWidth: manual, Size: 60) {
60-
actionbutton btnCopy (
61-
caption: 'Copy',
62-
action: nanoflow HD.NF_CopyToClipboard (Text: $currentObject/Subject),
63-
buttonstyle: link
64-
)
65-
}
66-
}
67-
};
68-
69-
70-
-- ============================================================
71-
-- 集成 4:重新创建 ACT_Ticket_Submit(加入桌面通知)
72-
-- 高优工单提交后对客服发出浏览器桌面通知
49+
-- 集成 3:重新创建 ACT_Ticket_Submit(加入桌面通知)
7350
-- ============================================================
7451

7552
create or replace microflow HD.ACT_Ticket_Submit
@@ -113,7 +90,7 @@ create or replace microflow HD.ACT_Ticket_Submit
11390

11491

11592
-- ============================================================
116-
-- 安全权限:确保新用途有权限
93+
-- 集成 4:安全权限:确保新用途有权限
11794
-- ============================================================
11895

11996
grant execute on nanoflow HD.NF_CopyToClipboard to HD.CustomerRole, HD.AgentRole, HD.ManagerRole;

coverage/bench-baseline.txt

Lines changed: 53 additions & 53 deletions
Large diffs are not rendered by default.

coverage/coverage-baseline.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
42.2
1+
42.1

mdl-examples/use-cases/helpdesk/helpdesk-app.mdl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,7 @@ create or modify microflow KB.SUB_Article_TruncateContent
746746
returns string as $Preview
747747
folder 'Article'
748748
{
749-
declare $Preview: string = $Article/Content;
749+
$Preview = $Article/Content;
750750
return $Preview;
751751
}
752752
/

mdl/backend/mpr/page_mutator.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,76 @@ func (m *mprPageMutator) InsertWidgetGen(widgetRef string, columnRef string, pos
175175
return nil
176176
}
177177

178+
// InsertLayoutGridColumnGen inserts new widgets into a layout grid row's Columns array
179+
// after the column identified by gridName.rowRef.colRef (e.g. "lgMain.rContent.cActions").
180+
// The row/column names are stored in Class as "_mdlRow:<name>" / "_mdlCol:<name>"
181+
// during page building (buildLayoutGridRowV3 / buildLayoutGridColumnV3).
182+
func (m *mprPageMutator) InsertLayoutGridColumnGen(gridName, rowRef, colRef string, position backend.InsertPosition, widgets []element.Element) error {
183+
grid := m.widgetFinder(m.rawData, gridName)
184+
if grid == nil {
185+
return fmt.Errorf("layout grid %q not found", gridName)
186+
}
187+
188+
rows := dGetArrayElements(dGet(grid.widget, "Rows"))
189+
if rows == nil {
190+
return fmt.Errorf("layout grid %q has no rows", gridName)
191+
}
192+
193+
// Find row by class name.
194+
var rowDoc bson.D
195+
for _, r := range rows {
196+
rd, ok := r.(bson.D)
197+
if !ok {
198+
continue
199+
}
200+
cls := dGetString(rd, "Class")
201+
if cls == "_mdlRow:"+rowRef {
202+
rowDoc = rd
203+
break
204+
}
205+
}
206+
if rowDoc == nil {
207+
return fmt.Errorf("row %q not found in layout grid %q", rowRef, gridName)
208+
}
209+
210+
cols := dGetArrayElements(dGet(rowDoc, "Columns"))
211+
// Find column by class name.
212+
var colIdx int
213+
found := false
214+
for i, c := range cols {
215+
cd, ok := c.(bson.D)
216+
if !ok {
217+
continue
218+
}
219+
cls := dGetString(cd, "Class")
220+
if cls == "_mdlCol:"+colRef {
221+
colIdx = i
222+
found = true
223+
break
224+
}
225+
}
226+
if !found {
227+
return fmt.Errorf("column %q not found in layout grid %q row %q", colRef, gridName, rowRef)
228+
}
229+
230+
newBsonWidgets, err := serializeWidgetsGen(widgets)
231+
if err != nil {
232+
return fmt.Errorf("serialize widgets: %w", err)
233+
}
234+
235+
insertIdx := colIdx
236+
if strings.EqualFold(string(position), "after") {
237+
insertIdx++
238+
}
239+
240+
newArr := make([]any, 0, len(cols)+len(newBsonWidgets))
241+
newArr = append(newArr, cols[:insertIdx]...)
242+
newArr = append(newArr, newBsonWidgets...)
243+
newArr = append(newArr, cols[insertIdx:]...)
244+
dSetArray(rowDoc, "Columns", newArr)
245+
return nil
246+
}
247+
178248
func (m *mprPageMutator) ReplaceWidgetGen(widgetRef string, columnRef string, widgets []element.Element) error {
179249
var result *bsonWidgetResult
180250
if columnRef != "" {

mdl/executor/cmd_alter_page.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,15 @@ func applyInsertWidgetMutator(ctx *ExecContext, mutator backend.PageMutator, op
223223
return mdlerrors.NewBackend("build widgets", err)
224224
}
225225

226+
// Layout grid column insertion (3-part ref: grid.row.column).
227+
if op.Target.IsLayoutGridColumn() {
228+
type lgInserter interface {
229+
InsertLayoutGridColumnGen(gridName, rowRef, colRef string, position backend.InsertPosition, widgets []element.Element) error
230+
}
231+
if li, ok := mutator.(lgInserter); ok {
232+
return li.InsertLayoutGridColumnGen(op.Target.Widget, op.Target.Row, op.Target.Column, backend.InsertPosition(op.Position), widgets)
233+
}
234+
}
226235
return mutator.InsertWidgetGen(op.Target.Widget, op.Target.Column, backend.InsertPosition(op.Position), widgets)
227236
}
228237

mdl/executor/pages_builder_v3.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,9 @@ func (pb *pageBuilder) buildLayoutGridRowV3(w *ast.WidgetV3) (element.Element, e
12071207
row.SetHorizontalAlignment("None")
12081208
row.SetVerticalAlignment("None")
12091209
row.SetSpacingBetweenColumns(true)
1210+
if w.Name != "" {
1211+
row.SetClass("_mdlRow:" + w.Name)
1212+
}
12101213

12111214
var desktopSum int
12121215
var hasExplicit bool
@@ -1244,6 +1247,9 @@ func (pb *pageBuilder) buildLayoutGridColumnV3(w *ast.WidgetV3) (element.Element
12441247
col.SetAppearance(newDefaultAppearance())
12451248
}
12461249
col.SetVerticalAlignment("None")
1250+
if w.Name != "" {
1251+
col.SetClass("_mdlCol:" + w.Name)
1252+
}
12471253

12481254
// Studio Pro defaults all size fields to -1 (AutoFill) when unset.
12491255
// Apply the same defaults so our BSON matches SP output.

0 commit comments

Comments
 (0)