From fe2f3dbf1f1928def49592dc6e9b290373906a6c Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Thu, 25 Jan 2024 14:44:00 -0500 Subject: [PATCH] Include template params in template (flow def expressions) inspection --- flows/actions/send_msg.go | 16 ++++++++++++++-- flows/actions/testdata/send_msg.json | 17 ++++++++++++++++- flows/inspect/templates.go | 26 +++++++++++++++++--------- flows/interfaces.go | 4 ++++ utils/misc.go | 2 +- 5 files changed, 52 insertions(+), 13 deletions(-) diff --git a/flows/actions/send_msg.go b/flows/actions/send_msg.go index ce46f487e..75c302c71 100644 --- a/flows/actions/send_msg.go +++ b/flows/actions/send_msg.go @@ -9,6 +9,7 @@ import ( "github.com/nyaruka/goflow/assets" "github.com/nyaruka/goflow/flows" "github.com/nyaruka/goflow/flows/events" + "github.com/nyaruka/goflow/utils" ) func init() { @@ -57,8 +58,19 @@ type TemplateParams struct { Values map[string][]string } -// LocalizationUUID gets the UUID which identifies this object for localization -func (p *TemplateParams) LocalizationUUID() uuids.UUID { return uuids.UUID(p.UUID) } +func (p *TemplateParams) EnumerateTemplates(localization flows.Localization, include func(i18n.Language, string)) { + for _, comp := range utils.SortedKeys(p.Values) { + for _, v := range p.Values[comp] { + include(i18n.NilLanguage, v) + } + for _, lang := range localization.Languages() { + lvals := localization.GetItemTranslation(lang, p.UUID, comp) + for _, v := range lvals { + include(lang, v) + } + } + } +} func (p *TemplateParams) MarshalJSON() ([]byte, error) { if p == nil { diff --git a/flows/actions/testdata/send_msg.json b/flows/actions/testdata/send_msg.json index 965f9c9f5..a0f807e08 100644 --- a/flows/actions/testdata/send_msg.json +++ b/flows/actions/testdata/send_msg.json @@ -477,6 +477,8 @@ "templates": [ "Hi Ryan Lewis, who's a good boy?", "@contact.name", + "boy", + "@contact.name", "boy" ], "localizables": [ @@ -580,6 +582,10 @@ "@contact.name", "boy", "@contact.name", + "niño", + "@contact.name", + "boy", + "@contact.name", "niño" ], "localizables": [ @@ -935,7 +941,16 @@ "Yes", "No", "Si", - "No" + "No", + "@contact.name", + "boy", + "@contact.name", + "niño", + "Yeah", + "Sip", + "Nope", + "http://templates.com/red.jpg", + "http://templates.com/rojo.jpg" ], "localizables": [ "Hey Ryan Lewis, your gender is saved as boy.", diff --git a/flows/inspect/templates.go b/flows/inspect/templates.go index d6df275f0..d51f60421 100644 --- a/flows/inspect/templates.go +++ b/flows/inspect/templates.go @@ -17,18 +17,26 @@ func Templates(s any, localization flows.Localization, include func(i18n.Languag } func templateValues(v reflect.Value, localization flows.Localization, include func(i18n.Language, string)) { - walk(v, nil, func(sv reflect.Value, fv reflect.Value, ef *EngineField) { - if ef.Evaluated { - extractTemplates(fv, i18n.NilLanguage, include) + walk(v, + func(v reflect.Value) { + te, ok := v.Interface().(flows.TemplateEnumerator) + if ok { + te.EnumerateTemplates(localization, include) + } + }, + func(sv reflect.Value, fv reflect.Value, ef *EngineField) { + if ef.Evaluated { + extractTemplates(fv, i18n.NilLanguage, include) - // if this field is also localized, each translation is a template and needs to be included - if ef.Localized && localization != nil { - localizable := sv.Interface().(flows.Localizable) + // if this field is also localized, each translation is a template and needs to be included + if ef.Localized && localization != nil { + localizable := sv.Interface().(flows.Localizable) - Translations(localization, localizable.LocalizationUUID(), ef.JSONName, include) + Translations(localization, localizable.LocalizationUUID(), ef.JSONName, include) + } } - } - }) + }, + ) } func Translations(localization flows.Localization, itemUUID uuids.UUID, property string, include func(i18n.Language, string)) { diff --git a/flows/interfaces.go b/flows/interfaces.go index 9a32aeae0..b50881295 100644 --- a/flows/interfaces.go +++ b/flows/interfaces.go @@ -122,6 +122,10 @@ type Localizable interface { LocalizationUUID() uuids.UUID } +type TemplateEnumerator interface { + EnumerateTemplates(Localization, func(i18n.Language, string)) +} + // Flow describes the ordered logic of actions and routers type Flow interface { Contextable diff --git a/utils/misc.go b/utils/misc.go index 736b28cfb..28afeb98a 100644 --- a/utils/misc.go +++ b/utils/misc.go @@ -35,7 +35,7 @@ func Set[K constraints.Ordered](s []K) map[K]bool { } // SortedKeys returns the keys of a set in lexical order -func SortedKeys[K constraints.Ordered](m map[K]bool) []K { +func SortedKeys[K constraints.Ordered, V any](m map[K]V) []K { keys := maps.Keys(m) slices.Sort(keys) return keys