Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion login/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ func (c *ProfileCompo) switchLanguageCompo(ctx context.Context) h.HTMLComponent
).Items(languages).
ItemTitle("Title").
ItemValue("Value").
Attr(web.VField(queryName, lang)...).Type("autocomplete").
Attr(web.VField(queryName, lang)...).
Attr("@update:model-value",
web.Plaid().MergeQuery(true).Query(queryName, web.Var("$event")).Go())
}
39 changes: 28 additions & 11 deletions pagebuilder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,6 @@ func (b *Builder) configSharedContainer(pb *presets.Builder) {
return in(evCtx, cell, id, obj)
}
})

if b.ab != nil {
b.ab.RegisterModel(pm)
}
Expand Down Expand Up @@ -936,7 +935,7 @@ func (b *Builder) firstOrCreateDemoContainers(ctx *web.EventContext, cons ...*Co
cons = b.containerBuilders
}
for _, con := range cons {
if err := con.firstOrCreate(slices.Concat(localeCodes)); err != nil {
if err := con.firstOrCreate(ctx, slices.Concat(localeCodes)); err != nil {
continue
}
}
Expand Down Expand Up @@ -1091,14 +1090,26 @@ func (b *ContainerBuilder) Install() {
locale = ctx.ContextValue(l10n.LocaleCode)
localeCode string
con Container
msgr = i18n.MustGetModuleMessages(ctx.R, I18nPageBuilderKey, Messages_en_US).(*Messages)
)

if locale != nil {
localeCode = locale.(string)
}
b.builder.db.Where("model_id = ? and model_name = ? and locale_code = ?", modelID, b.name, localeCode).First(&con)
return h.Span("{{vars.__pageBuilderRightContentTitle?vars.__pageBuilderRightContentTitle:vars.__pageBuilderRightDefaultContentTitle}}").
comp := h.Span("{{vars.__pageBuilderRightContentTitle?vars.__pageBuilderRightContentTitle:vars.__pageBuilderRightDefaultContentTitle}}").
Attr(web.VAssign("vars", fmt.Sprintf("{__pageBuilderRightContentTitle:%q,__pageBuilderRightDefaultContentTitle:%q}", con.DisplayName, defaultTitle))...)
if con.Shared {
return VTooltip(
web.Slot(
h.Div(
comp,
VIcon("mdi-information-outline").Color(ColorWarning).Attr("v-bind", "tooltip").Class("ml-2").Size(SizeSmall),
).Class("d-flex align-center"),
).Name("activator").Scope(`{props:tooltip}`),
).Location(LocationBottom).Text(msgr.SharedContainerModificationWarning)
}
return comp
})
editing.AppendHiddenFunc(func(obj interface{}, ctx *web.EventContext) h.HTMLComponent {
if portalName := ctx.Param(presets.ParamPortalName); portalName != pageBuilderRightContentPortal {
Expand Down Expand Up @@ -1320,20 +1331,25 @@ func (b *ContainerBuilder) getContainerDataID(modelID int, primarySlug string) s
return fmt.Sprintf(inflection.Plural(strcase.ToKebab(b.name))+"_%v_%v", modelID, primarySlug)
}

func (b *ContainerBuilder) firstOrCreate(localeCodes []string) (err error) {
func (b *ContainerBuilder) firstOrCreate(ctx *web.EventContext, localeCodes []string) (err error) {
var (
db = b.builder.db
obj = b.mb.NewModel()
cons []*DemoContainer
m = &DemoContainer{}
db = b.builder.db
obj = b.mb.NewModel()
cons []*DemoContainer
m = &DemoContainer{}
saver = b.mb.Editing().Creating().Saver
)
if len(localeCodes) == 0 {
return
}
ctx.R.Form.Set(ParamContainerCreate, "1")
return db.Transaction(func(tx *gorm.DB) (vErr error) {
ctx.WithContextValue(gorm2op.CtxKeyDB{}, tx)
defer ctx.WithContextValue(gorm2op.CtxKeyDB{}, nil)
Copy link

Copilot AI Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The context value is being set and then immediately cleared in the defer statement, which means the database transaction will not be available to the saver function. The defer should be moved after the saver calls or the context clearing should be removed.

Suggested change
defer ctx.WithContextValue(gorm2op.CtxKeyDB{}, nil)

Copilot uses AI. Check for mistakes.

tx.Where("model_name = ? and locale_code in ? ", b.name, localeCodes).Find(&cons)

if len(cons) == 0 {
if vErr = tx.Create(obj).Error; vErr != nil {
if vErr = saver(obj, "", ctx); vErr != nil {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Nil Saver Causes Panic, Context Update Fails

The firstOrCreate function can panic if b.mb.Editing().Creating().Saver is nil. Additionally, ctx.WithContextValue doesn't update the ctx variable, preventing the transaction database context from being correctly propagated to the saver and cleared afterwards.

Fix in Cursor Fix in Web

Copy link

Copilot AI Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The empty string parameter passed to saver is unclear. Consider using a named constant or adding a comment to explain what this parameter represents.

Copilot uses AI. Check for mistakes.

return
}
modelID := reflectutils.MustGet(obj, "ID").(uint)
Expand Down Expand Up @@ -1364,7 +1380,7 @@ func (b *ContainerBuilder) firstOrCreate(localeCodes []string) (err error) {
continue
}
obj = b.mb.NewModel()
if vErr = tx.Create(obj).Error; vErr != nil {
if vErr = saver(obj, "", ctx); vErr != nil {
return
}
modelID := reflectutils.MustGet(obj, "ID").(uint)
Expand Down Expand Up @@ -1550,6 +1566,7 @@ func (b *Builder) deviceToggle(ctx *web.EventContext) h.HTMLComponent {
device = ctx.Param(paramDevice)
devices = b.getDevices()
pMsgr = i18n.MustGetModuleMessages(ctx.R, presets.CoreI18nModuleKey, Messages_en_US).(*presets.Messages)
isDraft = ctx.Param(paramStatus) == publish.StatusDraft
)

for _, d := range devices {
Expand All @@ -1575,7 +1592,7 @@ func (b *Builder) deviceToggle(ctx *web.EventContext) h.HTMLComponent {
Query(paramIframeEventName, changeDeviceEventName).
Query(paramContainerDataID, containerDataID).
AfterScript("vars.__pageBuilderEditingUnPassed=false;toggleLocals.oldDevice = toggleLocals.activeDevice;").
ThenScript(fmt.Sprintf(`if(%s!==""){%s}`, containerDataID,
ThenScript(fmt.Sprintf(`if(%v && %s!==""){%s}`, isDraft, containerDataID,
web.Plaid().EventFunc(EditContainerEvent).
MergeQuery(true).
Query(paramContainerDataID, containerDataID).
Expand Down
2 changes: 2 additions & 0 deletions pagebuilder/editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const (
UpdateContainerEvent = "page_builder_UpdateContainerEvent"
ReloadAddContainersListEvent = "page_builder_ReloadAddContainersEvent"

ParamContainerCreate = "paramContainerCreate"

paramPageID = "pageID"
paramPageVersion = "pageVersion"
paramLocale = "locale"
Expand Down
64 changes: 34 additions & 30 deletions pagebuilder/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,13 @@ type Messages struct {
Name string
Description string

CategoryDeleteConfirmationText string
TheResourceCanNotBeModified string
MarkAsShared string
Copy string
SharedContainerHasBeenUpdated string
TemplateFixedAreaMessage string
CategoryDeleteConfirmationText string
TheResourceCanNotBeModified string
MarkAsShared string
Copy string
SharedContainerHasBeenUpdated string
TemplateFixedAreaMessage string
SharedContainerModificationWarning string
}

var Messages_en_US = &Messages{
Expand Down Expand Up @@ -190,15 +191,16 @@ var Messages_en_US = &Messages{
AreWantDeleteContainer: func(v string) string {
return fmt.Sprintf("Are you sure you want to delete %v?", v)
},
AddPageTemplate: "Add Page Template",
Name: "Name",
Description: "Description",
CategoryDeleteConfirmationText: "this will remove all the records in all localized languages",
TheResourceCanNotBeModified: "The resource can not be modified",
MarkAsShared: "Mark As Shared",
Copy: "Copy",
SharedContainerHasBeenUpdated: "The shared container on this page has been updated. You may notice differences between the preview and the live page.",
TemplateFixedAreaMessage: "This container is fixed and cannot be updated",
AddPageTemplate: "Add Page Template",
Name: "Name",
Description: "Description",
CategoryDeleteConfirmationText: "this will remove all the records in all localized languages",
TheResourceCanNotBeModified: "The resource can not be modified",
MarkAsShared: "Mark As Shared",
Copy: "Copy",
SharedContainerHasBeenUpdated: "The shared container on this page has been updated. You may notice differences between the preview and the live page.",
TemplateFixedAreaMessage: "This container is fixed and cannot be updated",
SharedContainerModificationWarning: "This is a shared container. Any modifications you make will apply to all pages that use it",
}

var Messages_zh_CN = &Messages{
Expand Down Expand Up @@ -291,12 +293,13 @@ var Messages_zh_CN = &Messages{
Name: "名称",
Description: "说明",

CategoryDeleteConfirmationText: "这将删除所有本地化语言中的所有记录",
TheResourceCanNotBeModified: "该资源无法被修改",
MarkAsShared: "标记为已共享",
Copy: "复制",
SharedContainerHasBeenUpdated: "此页面上的共享容器已更新。您可能会注意到预览和实时页面之间的差异。",
TemplateFixedAreaMessage: "此区域由模板固定,无法编辑。",
CategoryDeleteConfirmationText: "这将删除所有本地化语言中的所有记录",
TheResourceCanNotBeModified: "该资源无法被修改",
MarkAsShared: "标记为已共享",
Copy: "复制",
SharedContainerHasBeenUpdated: "此页面上的共享容器已更新。您可能会注意到预览和实时页面之间的差异。",
TemplateFixedAreaMessage: "此区域由模板固定,无法编辑。",
SharedContainerModificationWarning: "这是一个共享容器。您所做的任何修改都将应用于使用它的所有页面",
}

var Messages_ja_JP = &Messages{
Expand Down Expand Up @@ -384,15 +387,16 @@ var Messages_ja_JP = &Messages{
AreWantDeleteContainer: func(v string) string {
return fmt.Sprintf("%v を削除してもよろしいですか?", v)
},
AddPageTemplate: "ページテンプレートを追加",
Name: "名前",
Description: "説明",
CategoryDeleteConfirmationText: "これは、すべてのローカライズされた言語のすべてのレコードを削除します",
TheResourceCanNotBeModified: "このリソースは変更できません",
MarkAsShared: "共有済みとしてマーク",
Copy: "コピー",
SharedContainerHasBeenUpdated: "このページの共有コンテナが更新されました。プレビューとライブページの間に違いがあるかもしれません。",
TemplateFixedAreaMessage: "この領域はテンプレートによって固定されており、編集できません。",
AddPageTemplate: "ページテンプレートを追加",
Name: "名前",
Description: "説明",
CategoryDeleteConfirmationText: "これは、すべてのローカライズされた言語のすべてのレコードを削除します",
TheResourceCanNotBeModified: "このリソースは変更できません",
MarkAsShared: "共有済みとしてマーク",
Copy: "コピー",
SharedContainerHasBeenUpdated: "このページの共有コンテナが更新されました。プレビューとライブページの間に違いがあるかもしれません。",
TemplateFixedAreaMessage: "この領域はテンプレートによって固定されており、編集できません。",
SharedContainerModificationWarning: "これは共有コンテナです。行った変更は、それを使用するすべてのページに適用されます",
}

type ModelsI18nModulePage struct {
Expand Down
8 changes: 4 additions & 4 deletions utils/testflow/gentool/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ require (
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/orcaman/concurrent-map/v2 v2.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/stretchr/testify v1.10.0 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/tools v0.23.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions utils/testflow/gentool/go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA=
github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
Expand All @@ -20,6 +22,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/qor5/web/v3 v3.0.12-0.20250225073451-8e876be98c21 h1:Ho7ZJ04vT96lqe6g7PJhc9eFEUsEgDGpHyPhqzwGF3E=
github.com/qor5/web/v3 v3.0.12-0.20250225073451-8e876be98c21/go.mod h1:32vdHHcZb2JimlcaclW9hLUyimdXjrllZDHTh3rl6d0=
github.com/qor5/web/v3 v3.0.12-0.20250322025751-d36834ab80b4/go.mod h1:zU8n7tDAwYgq3HWMpe0dgmywBZaZx3ENBfwmjwEwYPo=
Expand All @@ -38,6 +41,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
Expand Down
Loading