v0.2.0
-
@lowdefy/modules-mongodb-plugins: ### Minor Changes
-
#14
1c912eeThanks @JohannMoller! - AddContactSelectorblock and wire it into thecontactsmodule as a reusable picker (contacts.contact-selectorcomponent). Search runs against an Atlas$search+$matchpipeline (search_contacts), enrichment viaget_contacts_data, and add/edit go through the existingcreate-contact/update-contactAPIs (patched to accept the picker's payload shape). Thecompaniesform now consumes the picker for linked contacts.Breaking — contacts module vars renamed:
all_contacts(module, defaultfalse, company-scoped) → per-callcompany_only_contacts(defaultfalse, unscoped). The default flipped: callers that relied on the old company-scoped default must now passcompany_only_contacts: trueexplicitly.verified(module enumoff|trusted|untrusted) →use_verified(module boolean, defaultfalse) + per-callverified(boolean). The module flag toggles the verification UI/payload writes globally; per-callverifieddecides the value each picker instance writes.- Removed: module-level
phone_label(no-op since Task 4) and the per-callpayloadvar (deprecated by per-key var pass-through).
Migration:
all_contacts: false → company_only_contacts: true (per-call) all_contacts: true → company_only_contacts: false (per-call, or omit) verified: trusted → use_verified: true (module) + verified: true (per-call) verified: untrusted → use_verified: true (module) + verified: false (per-call) verified: off → use_verified: false (module, default)
Patch Changes
-
#25
ac1d28aThanks @Yianni99! - Bump@lowdefy/block-utils,@lowdefy/blocks-antd,@lowdefy/blocks-basic,@lowdefy/helpers, and@lowdefy/nunjuckspeer-dep pins from0.0.0-experimental-20260421070726to0.0.0-experimental-20260429140004. -
#27
4d3eff1Thanks @Yianni99! - Improve theEventsTimelineblock andevents-timelinecomponent:- New block properties:
compact(boolean, defaultfalse) renders smaller avatars and tighter padding, and applies anevents-timeline-compactclass on the root for additional dense styling;contactPageUrl(string) is a URL template for linking each user avatar and timestamp to a contact page, supporting{id}substitution and falling back to appending?_id=<userId>;disableContactLink(boolean, defaultfalse) opts out of the contact-page wrapping per call. Avatars are also wrapped in a Popover showing the user's name on hover. - Component vars: the
events-timelinecomponent exposes the new properties viacontact_page_urlmodule var and per-call_varoverrides (contact_page_url,disable_contact_link,compact). All defaults are off, so existing consumers see no change. - Fix:
get-eventsrequest never fired because the component declared the request but had noonMountRequest action to trigger it. Added the trigger. - Fix: Avatar didn't render for events without a description — the React
EventTimelineItemonly included<Avatar>inside theEventDescriptionbranch. Restructured so the title-only branch also renders the avatar.
- New block properties:
-
#19
46234e1Thanks @JohannMoller! - Rewrite the two linked-record sidebar tiles — contacts on company-detail and companies on contact-detail — from a broken antd-styleList(properties.dataSource+properties.renderItem) to a plainHtmlblock. Both tiles previously rendered blank; both now list the linked records with name + email / display name and link through to the record's detail page using_module.pageId.Adds an optional
{ label, value }extension slot per tile under each module'scomponentsvar group:components.contact_card_extra_fieldson the companies module — appends rows under each contact's name/email on the company-detail tile.components.company_card_extra_fieldson the contacts module — appends rows under each company's display name on the contact-detail tile.
valuemust be a top-level key on the document as projected byget_company_contacts/get_contact_companies. Falsy primitives (0,false,"") render; onlynull/undefinedare skipped.Plugin housekeeping: declare
@lowdefy/nunjucksas a peer dependency of@lowdefy/modules-mongodb-plugins. The plugin'sparseNunjucks.jsimports it but the package wasn't declared anywhere — Turbopack failed to resolve it on fresh installs. -
#29
cd7e574Thanks @SamTolmay! - Remove the unusedDataDescriptionsblock from@lowdefy/modules-mongodb-plugins. The block was exported by the plugin but not referenced by any module or app in this repo;SmartDescriptionscovers the in-repo use cases. Consumers still importingDataDescriptionsfrom this plugin should switch toSmartDescriptionsor pin to^0.1.1. -
#28
2c4aa70Thanks @Yianni99! - Rename module pages from entity-prefixed IDs to semantic verbs to remove the redundant URL prefix (e.g./companies/companies→/companies/all). Module pages now useall,view,edit,newconsistently. Cross-module references via_module.pageId:and hardcoded scoped page IDs ({entry-id}/{page-id}) must be updated to the new IDs.Page ID changes per module:
companies:companies→all,company-detail→view,company-edit→edit,company-new→newcontacts:contacts→all,contact-detail→view,contact-edit→edit,contact-new→newuser-admin:users→all,users-view→view,users-edit→edit,users-invite→new,check-invite-email→checkuser-account:profile→view,edit-profile→edit,create-profile→new(login/logout/verify-email-requestunchanged)release-notes:release-notes→viewnotifications:inbox→all(link/invalidunchanged)
Plugin defaults updated to match:
SmartDescriptionsnow defaultscontactDetailPageIdtocontacts/viewandcompanyDetailPageIdtocompanies/view;EventsTimelineschema example updated.Also includes two fixes to the contacts new page: removed a duplicate avatar render (the avatar block was included both directly and via
form_profile), and fixed the post-create redirect that was navigating with a null_idbecause CallAPI return values are accessed at_actions: <id>.response.response.<field>, not.response.<field>. Same redirect fix applied to the companies new page. -
#31
fcd328bThanks @Yianni99! - Small UX fixes across modules and the EventsTimeline block:release-notes: Empty-state fallback now triggers whencontentis null OR an empty/whitespace-only string. The previous_if_noneonly caught null, so consumers with an emptyCHANGELOG.mdsaw a blank Card instead of the "No release notes available yet" message.companies/contacts/user-admintable components: Added a conditionaloverlayNoRowsTemplatethat renders "Loading…" while theget_all_*request is in flight and "No rows" once the request completes empty. Previously AG Grid's default "No Rows To Show" appeared during the initial load, indistinguishable from a genuinely empty result.EventsTimeline(plugin): Avatar hover swapped from<Popover>to<Tooltip>so it matches the timestamp's TimeAgo style — same name-on-hover, lighter dark-tooltip styling.
-
@lowdefy/modules-mongodb-companies: ### Minor Changes
-
#29
f9a4078Thanks @SamTolmay! - Remove thecollectionvar from thecompanies,events, andfilesmodules. Each module's MongoDB collection name is now hardcoded in its connection file (companies,log-events,filesrespectively). Consumers can no longer rename the underlying collection throughvars.collection— to point a module at a different collection, remap its connection (companies-collection,events-collection,files-collection) via the module entry'sconnectionsmapping inlowdefy.yaml.Breaking: apps that previously set
vars.collectionon any of these modules must remove it. If a non-default collection name was in use, switch to aconnectionsremap on the module entry. -
#29
2855113Thanks @SamTolmay! - Remove thedata-uploadmodule. The module has been deleted from the repo along with its pages, components, requests, connections, menus, and event-type enums. Consumers usingdata-uploadshould pin to the previous release tag or vendor the module locally. Cross-references frommodules/shared/enums/event_types.yaml,apps/demo/modules.yaml, the rootREADME.md,docs/idioms.md, and the demo.claude/guides/*.mdhave been removed. TheSYNC_S3_*secrets are no longer documented. -
#28
2c4aa70Thanks @Yianni99! - Rename module pages from entity-prefixed IDs to semantic verbs to remove the redundant URL prefix (e.g./companies/companies→/companies/all). Module pages now useall,view,edit,newconsistently. Cross-module references via_module.pageId:and hardcoded scoped page IDs ({entry-id}/{page-id}) must be updated to the new IDs.Page ID changes per module:
companies:companies→all,company-detail→view,company-edit→edit,company-new→newcontacts:contacts→all,contact-detail→view,contact-edit→edit,contact-new→newuser-admin:users→all,users-view→view,users-edit→edit,users-invite→new,check-invite-email→checkuser-account:profile→view,edit-profile→edit,create-profile→new(login/logout/verify-email-requestunchanged)release-notes:release-notes→viewnotifications:inbox→all(link/invalidunchanged)
Plugin defaults updated to match:
SmartDescriptionsnow defaultscontactDetailPageIdtocontacts/viewandcompanyDetailPageIdtocompanies/view;EventsTimelineschema example updated.Also includes two fixes to the contacts new page: removed a duplicate avatar render (the avatar block was included both directly and via
form_profile), and fixed the post-create redirect that was navigating with a null_idbecause CallAPI return values are accessed at_actions: <id>.response.response.<field>, not.response.<field>. Same redirect fix applied to the companies new page.
Patch Changes
-
#14
1c912eeThanks @JohannMoller! - AddContactSelectorblock and wire it into thecontactsmodule as a reusable picker (contacts.contact-selectorcomponent). Search runs against an Atlas$search+$matchpipeline (search_contacts), enrichment viaget_contacts_data, and add/edit go through the existingcreate-contact/update-contactAPIs (patched to accept the picker's payload shape). Thecompaniesform now consumes the picker for linked contacts.Breaking — contacts module vars renamed:
all_contacts(module, defaultfalse, company-scoped) → per-callcompany_only_contacts(defaultfalse, unscoped). The default flipped: callers that relied on the old company-scoped default must now passcompany_only_contacts: trueexplicitly.verified(module enumoff|trusted|untrusted) →use_verified(module boolean, defaultfalse) + per-callverified(boolean). The module flag toggles the verification UI/payload writes globally; per-callverifieddecides the value each picker instance writes.- Removed: module-level
phone_label(no-op since Task 4) and the per-callpayloadvar (deprecated by per-key var pass-through).
Migration:
all_contacts: false → company_only_contacts: true (per-call) all_contacts: true → company_only_contacts: false (per-call, or omit) verified: trusted → use_verified: true (module) + verified: true (per-call) verified: untrusted → use_verified: true (module) + verified: false (per-call) verified: off → use_verified: false (module, default) -
#27
24b8dd1Thanks @Yianni99! - Fix silent emptydisplaypayload on every event-emitting endpoint. The_build.array.mapcallback that builds per-app event display titles returned{key, value}objects, which_build.object.fromEntries(nativeObject.fromEntries) silently rejected as{}— so events landed in MongoDB withouttitleordescription. Switched callback bodies to a 2-element[key, value]array tuple to match the spec, and quoted"0.0"so YAML parses it as a path string instead of the float0. Affects 9 endpoints:contacts/api/{create,update}-contact,companies/api/{create,update}-company,user-admin/api/{invite,update}-user,user-admin/api/resend-invite,user-account/api/{create,update}-profile. Also fixed two latent typos (_result→_step) inuser-account/api/{create,update}-profile.yamlthat were hidden by the silent failure. -
#19
46234e1Thanks @JohannMoller! - Rewrite the two linked-record sidebar tiles — contacts on company-detail and companies on contact-detail — from a broken antd-styleList(properties.dataSource+properties.renderItem) to a plainHtmlblock. Both tiles previously rendered blank; both now list the linked records with name + email / display name and link through to the record's detail page using_module.pageId.Adds an optional
{ label, value }extension slot per tile under each module'scomponentsvar group:components.contact_card_extra_fieldson the companies module — appends rows under each contact's name/email on the company-detail tile.components.company_card_extra_fieldson the contacts module — appends rows under each company's display name on the contact-detail tile.
valuemust be a top-level key on the document as projected byget_company_contacts/get_contact_companies. Falsy primitives (0,false,"") render; onlynull/undefinedare skipped.Plugin housekeeping: declare
@lowdefy/nunjucksas a peer dependency of@lowdefy/modules-mongodb-plugins. The plugin'sparseNunjucks.jsimports it but the package wasn't declared anywhere — Turbopack failed to resolve it on fresh installs. -
#31
fcd328bThanks @Yianni99! - Small UX fixes across modules and the EventsTimeline block:release-notes: Empty-state fallback now triggers whencontentis null OR an empty/whitespace-only string. The previous_if_noneonly caught null, so consumers with an emptyCHANGELOG.mdsaw a blank Card instead of the "No release notes available yet" message.companies/contacts/user-admintable components: Added a conditionaloverlayNoRowsTemplatethat renders "Loading…" while theget_all_*request is in flight and "No rows" once the request completes empty. Previously AG Grid's default "No Rows To Show" appeared during the initial load, indistinguishable from a genuinely empty result.EventsTimeline(plugin): Avatar hover swapped from<Popover>to<Tooltip>so it matches the timestamp's TimeAgo style — same name-on-hover, lighter dark-tooltip styling.
-
@lowdefy/modules-mongodb-contacts: ### Minor Changes
-
#14
1c912eeThanks @JohannMoller! - AddContactSelectorblock and wire it into thecontactsmodule as a reusable picker (contacts.contact-selectorcomponent). Search runs against an Atlas$search+$matchpipeline (search_contacts), enrichment viaget_contacts_data, and add/edit go through the existingcreate-contact/update-contactAPIs (patched to accept the picker's payload shape). Thecompaniesform now consumes the picker for linked contacts.Breaking — contacts module vars renamed:
all_contacts(module, defaultfalse, company-scoped) → per-callcompany_only_contacts(defaultfalse, unscoped). The default flipped: callers that relied on the old company-scoped default must now passcompany_only_contacts: trueexplicitly.verified(module enumoff|trusted|untrusted) →use_verified(module boolean, defaultfalse) + per-callverified(boolean). The module flag toggles the verification UI/payload writes globally; per-callverifieddecides the value each picker instance writes.- Removed: module-level
phone_label(no-op since Task 4) and the per-callpayloadvar (deprecated by per-key var pass-through).
Migration:
all_contacts: false → company_only_contacts: true (per-call) all_contacts: true → company_only_contacts: false (per-call, or omit) verified: trusted → use_verified: true (module) + verified: true (per-call) verified: untrusted → use_verified: true (module) + verified: false (per-call) verified: off → use_verified: false (module, default) -
#28
2c4aa70Thanks @Yianni99! - Rename module pages from entity-prefixed IDs to semantic verbs to remove the redundant URL prefix (e.g./companies/companies→/companies/all). Module pages now useall,view,edit,newconsistently. Cross-module references via_module.pageId:and hardcoded scoped page IDs ({entry-id}/{page-id}) must be updated to the new IDs.Page ID changes per module:
companies:companies→all,company-detail→view,company-edit→edit,company-new→newcontacts:contacts→all,contact-detail→view,contact-edit→edit,contact-new→newuser-admin:users→all,users-view→view,users-edit→edit,users-invite→new,check-invite-email→checkuser-account:profile→view,edit-profile→edit,create-profile→new(login/logout/verify-email-requestunchanged)release-notes:release-notes→viewnotifications:inbox→all(link/invalidunchanged)
Plugin defaults updated to match:
SmartDescriptionsnow defaultscontactDetailPageIdtocontacts/viewandcompanyDetailPageIdtocompanies/view;EventsTimelineschema example updated.Also includes two fixes to the contacts new page: removed a duplicate avatar render (the avatar block was included both directly and via
form_profile), and fixed the post-create redirect that was navigating with a null_idbecause CallAPI return values are accessed at_actions: <id>.response.response.<field>, not.response.<field>. Same redirect fix applied to the companies new page.
Patch Changes
-
#27
24b8dd1Thanks @Yianni99! - Fix silent emptydisplaypayload on every event-emitting endpoint. The_build.array.mapcallback that builds per-app event display titles returned{key, value}objects, which_build.object.fromEntries(nativeObject.fromEntries) silently rejected as{}— so events landed in MongoDB withouttitleordescription. Switched callback bodies to a 2-element[key, value]array tuple to match the spec, and quoted"0.0"so YAML parses it as a path string instead of the float0. Affects 9 endpoints:contacts/api/{create,update}-contact,companies/api/{create,update}-company,user-admin/api/{invite,update}-user,user-admin/api/resend-invite,user-account/api/{create,update}-profile. Also fixed two latent typos (_result→_step) inuser-account/api/{create,update}-profile.yamlthat were hidden by the silent failure. -
#19
46234e1Thanks @JohannMoller! - Rewrite the two linked-record sidebar tiles — contacts on company-detail and companies on contact-detail — from a broken antd-styleList(properties.dataSource+properties.renderItem) to a plainHtmlblock. Both tiles previously rendered blank; both now list the linked records with name + email / display name and link through to the record's detail page using_module.pageId.Adds an optional
{ label, value }extension slot per tile under each module'scomponentsvar group:components.contact_card_extra_fieldson the companies module — appends rows under each contact's name/email on the company-detail tile.components.company_card_extra_fieldson the contacts module — appends rows under each company's display name on the contact-detail tile.
valuemust be a top-level key on the document as projected byget_company_contacts/get_contact_companies. Falsy primitives (0,false,"") render; onlynull/undefinedare skipped.Plugin housekeeping: declare
@lowdefy/nunjucksas a peer dependency of@lowdefy/modules-mongodb-plugins. The plugin'sparseNunjucks.jsimports it but the package wasn't declared anywhere — Turbopack failed to resolve it on fresh installs. -
#31
fcd328bThanks @Yianni99! - Small UX fixes across modules and the EventsTimeline block:release-notes: Empty-state fallback now triggers whencontentis null OR an empty/whitespace-only string. The previous_if_noneonly caught null, so consumers with an emptyCHANGELOG.mdsaw a blank Card instead of the "No release notes available yet" message.companies/contacts/user-admintable components: Added a conditionaloverlayNoRowsTemplatethat renders "Loading…" while theget_all_*request is in flight and "No rows" once the request completes empty. Previously AG Grid's default "No Rows To Show" appeared during the initial load, indistinguishable from a genuinely empty result.EventsTimeline(plugin): Avatar hover swapped from<Popover>to<Tooltip>so it matches the timestamp's TimeAgo style — same name-on-hover, lighter dark-tooltip styling.
-
@lowdefy/modules-mongodb-events: ### Minor Changes
-
#29
f9a4078Thanks @SamTolmay! - Remove thecollectionvar from thecompanies,events, andfilesmodules. Each module's MongoDB collection name is now hardcoded in its connection file (companies,log-events,filesrespectively). Consumers can no longer rename the underlying collection throughvars.collection— to point a module at a different collection, remap its connection (companies-collection,events-collection,files-collection) via the module entry'sconnectionsmapping inlowdefy.yaml.Breaking: apps that previously set
vars.collectionon any of these modules must remove it. If a non-default collection name was in use, switch to aconnectionsremap on the module entry.
Patch Changes
-
#27
4d3eff1Thanks @Yianni99! - Improve theEventsTimelineblock andevents-timelinecomponent:- New block properties:
compact(boolean, defaultfalse) renders smaller avatars and tighter padding, and applies anevents-timeline-compactclass on the root for additional dense styling;contactPageUrl(string) is a URL template for linking each user avatar and timestamp to a contact page, supporting{id}substitution and falling back to appending?_id=<userId>;disableContactLink(boolean, defaultfalse) opts out of the contact-page wrapping per call. Avatars are also wrapped in a Popover showing the user's name on hover. - Component vars: the
events-timelinecomponent exposes the new properties viacontact_page_urlmodule var and per-call_varoverrides (contact_page_url,disable_contact_link,compact). All defaults are off, so existing consumers see no change. - Fix:
get-eventsrequest never fired because the component declared the request but had noonMountRequest action to trigger it. Added the trigger. - Fix: Avatar didn't render for events without a description — the React
EventTimelineItemonly included<Avatar>inside theEventDescriptionbranch. Restructured so the title-only branch also renders the avatar.
- New block properties:
-
@lowdefy/modules-mongodb-files: ### Minor Changes
-
#29
f9a4078Thanks @SamTolmay! - Remove thecollectionvar from thecompanies,events, andfilesmodules. Each module's MongoDB collection name is now hardcoded in its connection file (companies,log-events,filesrespectively). Consumers can no longer rename the underlying collection throughvars.collection— to point a module at a different collection, remap its connection (companies-collection,events-collection,files-collection) via the module entry'sconnectionsmapping inlowdefy.yaml.Breaking: apps that previously set
vars.collectionon any of these modules must remove it. If a non-default collection name was in use, switch to aconnectionsremap on the module entry. -
#29
24580bcThanks @SamTolmay! - Makes3_regiona required var on thefilesmodule. Previouslyfiles.s3_regionhad a default ofca-central-1(later brieflyus-east-1). The module now requires the consumer to sets3_regionon the module entry — there is no default, and the build will fail if the var is missing.Breaking: apps using
filesmust adds3_regionto the module'svarsblock inlowdefy.yaml. Example:vars: { s3_region: us-east-1 }.
Patch Changes
-
#25
a6b13ceThanks @Yianni99! - Stamp S3 uploads withx-amz-meta-uploaded-by-{id,name,url}metadata so file uploads carry uploader id, display name, and originating page at the bucket level. Thefilesmodule gains the full set of fields and switches its presigned-post conditions to the array-of-arrays form. Uses_if_none"unknown" fallbacks so unauthenticated uploads still succeed. -
@lowdefy/modules-mongodb-notifications: ### Minor Changes
-
#28
2c4aa70Thanks @Yianni99! - Rename module pages from entity-prefixed IDs to semantic verbs to remove the redundant URL prefix (e.g./companies/companies→/companies/all). Module pages now useall,view,edit,newconsistently. Cross-module references via_module.pageId:and hardcoded scoped page IDs ({entry-id}/{page-id}) must be updated to the new IDs.Page ID changes per module:
companies:companies→all,company-detail→view,company-edit→edit,company-new→newcontacts:contacts→all,contact-detail→view,contact-edit→edit,contact-new→newuser-admin:users→all,users-view→view,users-edit→edit,users-invite→new,check-invite-email→checkuser-account:profile→view,edit-profile→edit,create-profile→new(login/logout/verify-email-requestunchanged)release-notes:release-notes→viewnotifications:inbox→all(link/invalidunchanged)
Plugin defaults updated to match:
SmartDescriptionsnow defaultscontactDetailPageIdtocontacts/viewandcompanyDetailPageIdtocompanies/view;EventsTimelineschema example updated.Also includes two fixes to the contacts new page: removed a duplicate avatar render (the avatar block was included both directly and via
form_profile), and fixed the post-create redirect that was navigating with a null_idbecause CallAPI return values are accessed at_actions: <id>.response.response.<field>, not.response.<field>. Same redirect fix applied to the companies new page. -
@lowdefy/modules-mongodb-release-notes: ### Minor Changes
-
#28
2c4aa70Thanks @Yianni99! - Rename module pages from entity-prefixed IDs to semantic verbs to remove the redundant URL prefix (e.g./companies/companies→/companies/all). Module pages now useall,view,edit,newconsistently. Cross-module references via_module.pageId:and hardcoded scoped page IDs ({entry-id}/{page-id}) must be updated to the new IDs.Page ID changes per module:
companies:companies→all,company-detail→view,company-edit→edit,company-new→newcontacts:contacts→all,contact-detail→view,contact-edit→edit,contact-new→newuser-admin:users→all,users-view→view,users-edit→edit,users-invite→new,check-invite-email→checkuser-account:profile→view,edit-profile→edit,create-profile→new(login/logout/verify-email-requestunchanged)release-notes:release-notes→viewnotifications:inbox→all(link/invalidunchanged)
Plugin defaults updated to match:
SmartDescriptionsnow defaultscontactDetailPageIdtocontacts/viewandcompanyDetailPageIdtocompanies/view;EventsTimelineschema example updated.Also includes two fixes to the contacts new page: removed a duplicate avatar render (the avatar block was included both directly and via
form_profile), and fixed the post-create redirect that was navigating with a null_idbecause CallAPI return values are accessed at_actions: <id>.response.response.<field>, not.response.<field>. Same redirect fix applied to the companies new page.
Patch Changes
-
#31
fcd328bThanks @Yianni99! - Small UX fixes across modules and the EventsTimeline block:release-notes: Empty-state fallback now triggers whencontentis null OR an empty/whitespace-only string. The previous_if_noneonly caught null, so consumers with an emptyCHANGELOG.mdsaw a blank Card instead of the "No release notes available yet" message.companies/contacts/user-admintable components: Added a conditionaloverlayNoRowsTemplatethat renders "Loading…" while theget_all_*request is in flight and "No rows" once the request completes empty. Previously AG Grid's default "No Rows To Show" appeared during the initial load, indistinguishable from a genuinely empty result.EventsTimeline(plugin): Avatar hover swapped from<Popover>to<Tooltip>so it matches the timestamp's TimeAgo style — same name-on-hover, lighter dark-tooltip styling.
-
@lowdefy/modules-mongodb-user-account: ### Minor Changes
-
#28
2c4aa70Thanks @Yianni99! - Rename module pages from entity-prefixed IDs to semantic verbs to remove the redundant URL prefix (e.g./companies/companies→/companies/all). Module pages now useall,view,edit,newconsistently. Cross-module references via_module.pageId:and hardcoded scoped page IDs ({entry-id}/{page-id}) must be updated to the new IDs.Page ID changes per module:
companies:companies→all,company-detail→view,company-edit→edit,company-new→newcontacts:contacts→all,contact-detail→view,contact-edit→edit,contact-new→newuser-admin:users→all,users-view→view,users-edit→edit,users-invite→new,check-invite-email→checkuser-account:profile→view,edit-profile→edit,create-profile→new(login/logout/verify-email-requestunchanged)release-notes:release-notes→viewnotifications:inbox→all(link/invalidunchanged)
Plugin defaults updated to match:
SmartDescriptionsnow defaultscontactDetailPageIdtocontacts/viewandcompanyDetailPageIdtocompanies/view;EventsTimelineschema example updated.Also includes two fixes to the contacts new page: removed a duplicate avatar render (the avatar block was included both directly and via
form_profile), and fixed the post-create redirect that was navigating with a null_idbecause CallAPI return values are accessed at_actions: <id>.response.response.<field>, not.response.<field>. Same redirect fix applied to the companies new page.
Patch Changes
-
#31
a167d18Thanks @Yianni99! - Fix Activity tile missing user-related events on contact-detail. user-account and user-admin events tagged the same shareduser-contactsrecord underreferences.user_ids, while the Activity tile filters oncontact_ids— so events likeupdate-profile,invite-user,update-user,resend-invite, andcreate-profilenever surfaced on the contact's timeline. Since contacts and users live in one collection with one_idspace, a user IS a contact. Renamed the reference field on those 5 events fromuser_idstocontact_idsso the existing single-field timeline match returns them. Event semantics (user vs. plain contact) stay encoded in the eventtype. Migration for existing event docs is the consuming app's responsibility —db.log-events.updateMany({ user_ids: { $exists: true } }, [{ $set: { contact_ids: '$user_ids' } }, { $unset: 'user_ids' }]). -
#27
24b8dd1Thanks @Yianni99! - Fix silent emptydisplaypayload on every event-emitting endpoint. The_build.array.mapcallback that builds per-app event display titles returned{key, value}objects, which_build.object.fromEntries(nativeObject.fromEntries) silently rejected as{}— so events landed in MongoDB withouttitleordescription. Switched callback bodies to a 2-element[key, value]array tuple to match the spec, and quoted"0.0"so YAML parses it as a path string instead of the float0. Affects 9 endpoints:contacts/api/{create,update}-contact,companies/api/{create,update}-company,user-admin/api/{invite,update}-user,user-admin/api/resend-invite,user-account/api/{create,update}-profile. Also fixed two latent typos (_result→_step) inuser-account/api/{create,update}-profile.yamlthat were hidden by the silent failure. -
@lowdefy/modules-mongodb-user-admin: ### Minor Changes
-
#28
2c4aa70Thanks @Yianni99! - Rename module pages from entity-prefixed IDs to semantic verbs to remove the redundant URL prefix (e.g./companies/companies→/companies/all). Module pages now useall,view,edit,newconsistently. Cross-module references via_module.pageId:and hardcoded scoped page IDs ({entry-id}/{page-id}) must be updated to the new IDs.Page ID changes per module:
companies:companies→all,company-detail→view,company-edit→edit,company-new→newcontacts:contacts→all,contact-detail→view,contact-edit→edit,contact-new→newuser-admin:users→all,users-view→view,users-edit→edit,users-invite→new,check-invite-email→checkuser-account:profile→view,edit-profile→edit,create-profile→new(login/logout/verify-email-requestunchanged)release-notes:release-notes→viewnotifications:inbox→all(link/invalidunchanged)
Plugin defaults updated to match:
SmartDescriptionsnow defaultscontactDetailPageIdtocontacts/viewandcompanyDetailPageIdtocompanies/view;EventsTimelineschema example updated.Also includes two fixes to the contacts new page: removed a duplicate avatar render (the avatar block was included both directly and via
form_profile), and fixed the post-create redirect that was navigating with a null_idbecause CallAPI return values are accessed at_actions: <id>.response.response.<field>, not.response.<field>. Same redirect fix applied to the companies new page.
Patch Changes
-
#31
a167d18Thanks @Yianni99! - Fix Activity tile missing user-related events on contact-detail. user-account and user-admin events tagged the same shareduser-contactsrecord underreferences.user_ids, while the Activity tile filters oncontact_ids— so events likeupdate-profile,invite-user,update-user,resend-invite, andcreate-profilenever surfaced on the contact's timeline. Since contacts and users live in one collection with one_idspace, a user IS a contact. Renamed the reference field on those 5 events fromuser_idstocontact_idsso the existing single-field timeline match returns them. Event semantics (user vs. plain contact) stay encoded in the eventtype. Migration for existing event docs is the consuming app's responsibility —db.log-events.updateMany({ user_ids: { $exists: true } }, [{ $set: { contact_ids: '$user_ids' } }, { $unset: 'user_ids' }]). -
#27
24b8dd1Thanks @Yianni99! - Fix silent emptydisplaypayload on every event-emitting endpoint. The_build.array.mapcallback that builds per-app event display titles returned{key, value}objects, which_build.object.fromEntries(nativeObject.fromEntries) silently rejected as{}— so events landed in MongoDB withouttitleordescription. Switched callback bodies to a 2-element[key, value]array tuple to match the spec, and quoted"0.0"so YAML parses it as a path string instead of the float0. Affects 9 endpoints:contacts/api/{create,update}-contact,companies/api/{create,update}-company,user-admin/api/{invite,update}-user,user-admin/api/resend-invite,user-account/api/{create,update}-profile. Also fixed two latent typos (_result→_step) inuser-account/api/{create,update}-profile.yamlthat were hidden by the silent failure. -
#31
fcd328bThanks @Yianni99! - Small UX fixes across modules and the EventsTimeline block:release-notes: Empty-state fallback now triggers whencontentis null OR an empty/whitespace-only string. The previous_if_noneonly caught null, so consumers with an emptyCHANGELOG.mdsaw a blank Card instead of the "No release notes available yet" message.companies/contacts/user-admintable components: Added a conditionaloverlayNoRowsTemplatethat renders "Loading…" while theget_all_*request is in flight and "No rows" once the request completes empty. Previously AG Grid's default "No Rows To Show" appeared during the initial load, indistinguishable from a genuinely empty result.EventsTimeline(plugin): Avatar hover swapped from<Popover>to<Tooltip>so it matches the timestamp's TimeAgo style — same name-on-hover, lighter dark-tooltip styling.