@wildo-ai/saas-frontend-lib 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/dist/esm/companion-exports.d.ts +1 -1
  2. package/dist/esm/companion-exports.d.ts.map +1 -1
  3. package/dist/esm/companion-exports.js +1 -1
  4. package/dist/esm/companion-exports.js.map +1 -1
  5. package/dist/esm/components/ai-elements/decision/approval.d.ts +13 -1
  6. package/dist/esm/components/ai-elements/decision/approval.d.ts.map +1 -1
  7. package/dist/esm/components/ai-elements/decision/approval.js.map +1 -1
  8. package/dist/esm/components/flows-actors/approval.d.ts.map +1 -1
  9. package/dist/esm/components/flows-actors/approval.js +12 -7
  10. package/dist/esm/components/flows-actors/approval.js.map +1 -1
  11. package/dist/esm/components/flows-actors/approval.labels.d.ts.map +1 -1
  12. package/dist/esm/components/flows-actors/approval.labels.js +3 -0
  13. package/dist/esm/components/flows-actors/approval.labels.js.map +1 -1
  14. package/dist/esm/components/flows-actors/execution-plan.js +1 -1
  15. package/dist/esm/components/flows-actors/execution-plan.js.map +1 -1
  16. package/dist/esm/components/flows-actors/task-memory.js +1 -1
  17. package/dist/esm/components/flows-actors/task-memory.js.map +1 -1
  18. package/dist/esm/components/form/automated/generated-relationship-field.hooks.d.ts +1 -1
  19. package/dist/esm/components/form/controls/number/slider.d.ts +1 -1
  20. package/dist/esm/components/form/fields/form-field-file-provider-constraints.frontend.utils.d.ts +1 -1
  21. package/dist/esm/components/form/fields/form-field-file-provider-constraints.frontend.utils.d.ts.map +1 -1
  22. package/dist/esm/components/form/fields/form-field-file-provider-constraints.frontend.utils.js.map +1 -1
  23. package/dist/esm/components/form/fields/form-field-file.d.ts.map +1 -1
  24. package/dist/esm/components/form/fields/form-field-file.js +66 -17
  25. package/dist/esm/components/form/fields/form-field-file.js.map +1 -1
  26. package/dist/esm/components/form/fields/form-field-file.labels.js +2 -2
  27. package/dist/esm/components/form/fields/form-field-file.labels.js.map +1 -1
  28. package/dist/esm/components/form/form-field-types.d.ts +20 -0
  29. package/dist/esm/components/form/form-field-types.d.ts.map +1 -1
  30. package/dist/esm/components/form/form-field-types.js.map +1 -1
  31. package/dist/esm/components/navigation/NavigationItemBadge.d.ts +7 -1
  32. package/dist/esm/components/navigation/NavigationItemBadge.d.ts.map +1 -1
  33. package/dist/esm/components/navigation/NavigationItemBadge.js +29 -1
  34. package/dist/esm/components/navigation/NavigationItemBadge.js.map +1 -1
  35. package/dist/esm/components/navigation/menu-bar.d.ts +1 -1
  36. package/dist/esm/components/overlays/containers/OverlayContainer.d.ts.map +1 -1
  37. package/dist/esm/components/overlays/containers/OverlayContainer.js +36 -9
  38. package/dist/esm/components/overlays/containers/OverlayContainer.js.map +1 -1
  39. package/dist/esm/components/overlays/floating/context-menu.d.ts +1 -1
  40. package/dist/esm/components/overlays/floating/dropdown-menu.d.ts +1 -1
  41. package/dist/esm/components/resources/ResourceLayout_FilterChips.js +1 -1
  42. package/dist/esm/components/resources/ResourceLayout_FilterChips.js.map +1 -1
  43. package/dist/esm/components/resources/ResourceListItemRenderer.js +1 -1
  44. package/dist/esm/components/resources/ResourceListItemRenderer.js.map +1 -1
  45. package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.d.ts +12 -0
  46. package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.d.ts.map +1 -1
  47. package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.js +13 -1
  48. package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.js.map +1 -1
  49. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.d.ts +106 -49
  50. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.d.ts.map +1 -1
  51. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.js +311 -109
  52. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.js.map +1 -1
  53. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.labels.d.ts.map +1 -1
  54. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.labels.js +32 -2
  55. package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.labels.js.map +1 -1
  56. package/dist/esm/components/settings/SettingsHub.d.ts.map +1 -1
  57. package/dist/esm/components/settings/SettingsHub.js +30 -6
  58. package/dist/esm/components/settings/SettingsHub.js.map +1 -1
  59. package/dist/esm/components/views/onboarding-view/OnboardingView.d.ts.map +1 -1
  60. package/dist/esm/components/views/onboarding-view/OnboardingView.js +9 -2
  61. package/dist/esm/components/views/onboarding-view/OnboardingView.js.map +1 -1
  62. package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.d.ts +16 -0
  63. package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.d.ts.map +1 -1
  64. package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.js +17 -0
  65. package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.js.map +1 -1
  66. package/dist/esm/core/automated-layout/default-layout-generator.frontend.utils.d.ts.map +1 -1
  67. package/dist/esm/core/automated-layout/default-layout-generator.frontend.utils.js +3 -2
  68. package/dist/esm/core/automated-layout/default-layout-generator.frontend.utils.js.map +1 -1
  69. package/dist/esm/core/billing/billing-launcher.js +1 -1
  70. package/dist/esm/core/billing/billing-launcher.js.map +1 -1
  71. package/dist/esm/core/components-registry/provider-component-registry.frontend.service.d.ts +64 -4
  72. package/dist/esm/core/components-registry/provider-component-registry.frontend.service.d.ts.map +1 -1
  73. package/dist/esm/core/components-registry/provider-component-registry.frontend.service.js +76 -4
  74. package/dist/esm/core/components-registry/provider-component-registry.frontend.service.js.map +1 -1
  75. package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.d.ts +8 -0
  76. package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.d.ts.map +1 -1
  77. package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.js +1 -0
  78. package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.js.map +1 -1
  79. package/dist/esm/core/config/chart-view.frontend.schemas.d.ts +8 -8
  80. package/dist/esm/core/config/composite-view.schemas.d.ts +4 -4
  81. package/dist/esm/core/config/engine-settings-destinations.d.ts +0 -69
  82. package/dist/esm/core/config/engine-settings-destinations.d.ts.map +1 -1
  83. package/dist/esm/core/config/engine-settings-destinations.js +35 -74
  84. package/dist/esm/core/config/engine-settings-destinations.js.map +1 -1
  85. package/dist/esm/core/config/settings-hub.frontend.schemas.d.ts +10 -1
  86. package/dist/esm/core/config/settings-hub.frontend.schemas.d.ts.map +1 -1
  87. package/dist/esm/core/config/settings-hub.frontend.schemas.js +9 -0
  88. package/dist/esm/core/config/settings-hub.frontend.schemas.js.map +1 -1
  89. package/dist/esm/core/config/useSettingsHubConfig.d.ts.map +1 -1
  90. package/dist/esm/core/config/useSettingsHubConfig.js +8 -1
  91. package/dist/esm/core/config/useSettingsHubConfig.js.map +1 -1
  92. package/dist/esm/core/events/events.frontend.schemas.d.ts +4 -4
  93. package/dist/esm/core/external-providers/ProviderFilePickerHost.d.ts +12 -1
  94. package/dist/esm/core/external-providers/ProviderFilePickerHost.d.ts.map +1 -1
  95. package/dist/esm/core/external-providers/ProviderFilePickerHost.js +15 -2
  96. package/dist/esm/core/external-providers/ProviderFilePickerHost.js.map +1 -1
  97. package/dist/esm/core/external-providers/provider-file-selection.frontend.utils.d.ts +1 -2
  98. package/dist/esm/core/external-providers/provider-file-selection.frontend.utils.d.ts.map +1 -1
  99. package/dist/esm/core/external-providers/provider-file-selection.frontend.utils.js.map +1 -1
  100. package/dist/esm/core/flows-actors/FlowsActorsContext.d.ts +6 -1
  101. package/dist/esm/core/flows-actors/FlowsActorsContext.d.ts.map +1 -1
  102. package/dist/esm/core/flows-actors/FlowsActorsContext.js +10 -2
  103. package/dist/esm/core/flows-actors/FlowsActorsContext.js.map +1 -1
  104. package/dist/esm/core/i18n/I18nContext.d.ts +23 -0
  105. package/dist/esm/core/i18n/I18nContext.d.ts.map +1 -1
  106. package/dist/esm/core/i18n/I18nContext.js +6 -1
  107. package/dist/esm/core/i18n/I18nContext.js.map +1 -1
  108. package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.d.ts +75 -2
  109. package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.d.ts.map +1 -1
  110. package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.js +52 -0
  111. package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.js.map +1 -1
  112. package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.d.ts +3 -2
  113. package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.d.ts.map +1 -1
  114. package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.js +57 -4
  115. package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.js.map +1 -1
  116. package/dist/esm/core/resources/ResourceReadCacheBridge.d.ts.map +1 -1
  117. package/dist/esm/core/resources/ResourceReadCacheBridge.js +130 -37
  118. package/dist/esm/core/resources/ResourceReadCacheBridge.js.map +1 -1
  119. package/dist/esm/core/resources/resources.frontend.schemas.d.ts +2 -2
  120. package/dist/esm/core/runtime/start-application.frontend.service.d.ts.map +1 -1
  121. package/dist/esm/core/runtime/start-application.frontend.service.js +17 -9
  122. package/dist/esm/core/runtime/start-application.frontend.service.js.map +1 -1
  123. package/dist/esm/core/security/UserOrgsContext.d.ts.map +1 -1
  124. package/dist/esm/core/security/UserOrgsContext.js +61 -5
  125. package/dist/esm/core/security/UserOrgsContext.js.map +1 -1
  126. package/dist/tsconfig.build.tsbuildinfo +1 -1
  127. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"AppPage_ConnectedAccountsSettings.js","sourceRoot":"","sources":["../../../../src/components/settings/AppPage_ConnectedAccountsSettings.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAc,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EACL,0CAA0C,EAC1C,sCAAsC,GACvC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,8CAA8C,CAAC;AACxG,OAAO,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAC;AAC/F,OAAO,EAAE,SAAS,EAAE,MAAM,oDAAoD,CAAC;AAC/E,OAAO,EAAE,IAAI,EAAE,MAAM,gDAAgD,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,0DAA0D,CAAC;AACnG,OAAO,EAAE,OAAO,EAAE,MAAM,uCAAuC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,+CAA+C,CAAC;AAC5E,OAAO,EACL,wBAAwB,GAEzB,MAAM,mFAAmF,CAAC;AAE3F,MAAM,SAAS,GAAG,qBAAqB,CAAC,uCAAuC,CAAC;AAEhF;;;;;;;GAOG;AACH,MAAM,iBAAiB,GAAG,GAAqD,EAAE;IAC/E,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,EAAE,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3D,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,SAAS;QAC/C,eAAe,EAAE,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,SAAS;KAC5D,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG,CAClD,SAA6C,EAClB,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC5D,QAAQ,CAAC,WAAW;OACjB,QAAQ,CAAC,qBAAqB,CAAC,IAAI,CACpC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,KAAK,sCAAsC,CAAC,IAAI,CAC5E,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,iCAAiC,GAAa,GAAG,EAAE;IAC9D,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;IAClE,MAAM,EAAE,IAAI,EAAE,GAAG,WAAW,EAAE,CAAC;IAE/B,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjF;;;;;;OAMG;IACH,MAAM,UAAU,GAAG,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC;IAErC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAA4B,EAAE,CAAC,CAAC;IAC1E,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAC5D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,yGAAyG;IACzG,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAyC,EAAE,CAAC,CAAC;IAEnF,kGAAkG;IAClG,gGAAgG;IAChG,MAAM,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAE9C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,wBAAwB,EAAE,CAAC,wBAAwB,EAAE,CAAC;gBACxE,IAAI,CAAC,SAAS;oBAAE,YAAY,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;YACpD,CAAC;YAAC,OAAO,CAAU,EAAE,CAAC;gBACpB,IAAI,mBAAmB,CAAC,CAAC,CAAC;oBAAE,MAAM,CAAC,CAAC;gBACpC,IAAI,CAAC,SAAS;oBAAE,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;YAC9C,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,SAAS;oBAAE,UAAU,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,GAAG,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAER,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,oCAAoC,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEtG,MAAM,aAAa,GAAG,WAAW,CAC/B,KAAK,EAAE,QAAiC,EAAE,EAAE;QAC1C,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACjC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,IAAI,CAAC;YACH,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,wBAAwB,EAAE,CAAC,uBAAuB,CAC/E,QAAQ,CAAC,WAAW,EACpB;gBACE,kFAAkF;gBAClF,wEAAwE;gBACxE,MAAM,EAAE;oBACN,UAAU,EAAE,sCAAsC,CAAC,IAAI;oBACvD,OAAO,EAAE,UAAW;oBACpB,UAAU,EAAE,0CAA0C,CAAC,OAAO;iBAC/D;gBACD,oBAAoB,EAAE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;aACpD,CACF,CAAC;YACF,2FAA2F;YAC3F,4FAA4F;YAC5F,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,YAAY,CAAC;QACtC,CAAC;QAAC,OAAO,CAAU,EAAE,CAAC;YACpB,IAAI,mBAAmB,CAAC,CAAC,CAAC;gBAAE,MAAM,CAAC,CAAC;YACpC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;YAC5B,UAAU,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,EACD,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC,CACzB,CAAC;IAEF,oEAAoE;IACpE,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,OAAO,CACL,eAAK,SAAS,EAAC,2BAA2B,aACxC,eAAK,SAAS,EAAC,2BAA2B,aAGxC,aAAI,SAAS,EAAC,wCAAwC,YAAE,CAAC,CAAC,WAAW,CAAC,GAAM,EAC5E,KAAC,IAAI,IAAC,SAAS,EAAC,+BAA+B,YAAE,CAAC,CAAC,iBAAiB,CAAC,GAAQ,IACzE,EAIL,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,CAClC,KAAC,KAAK,cAAC,KAAC,gBAAgB,cAAE,CAAC,CAAC,iBAAiB,CAAC,GAAoB,GAAQ,CAC3E,EACA,OAAO,CAAC,eAAe,KAAK,UAAU,IAAI,CACzC,KAAC,KAAK,cAAC,KAAC,gBAAgB,cAAE,CAAC,CAAC,gBAAgB,CAAC,GAAoB,GAAQ,CAC1E,EACA,OAAO,CAAC,eAAe,KAAK,SAAS,IAAI,OAAO,CAAC,eAAe,KAAK,UAAU,IAAI,CAClF,KAAC,KAAK,IAAC,OAAO,EAAC,aAAa,YAAC,KAAC,gBAAgB,cAAE,CAAC,CAAC,cAAc,CAAC,GAAoB,GAAQ,CAC9F,EAEA,KAAK,IAAI,CACR,KAAC,KAAK,IAAC,OAAO,EAAC,aAAa,YAAC,KAAC,gBAAgB,cAAE,KAAK,GAAoB,GAAQ,CAClF,EAkBD,KAAC,IAAI,IAAC,SAAS,EAAC,+BAA+B,YAAE,CAAC,CAAC,kBAAkB,CAAC,GAAQ,EAE7E,OAAO,CAAC,CAAC,CAAC,CACT,KAAC,IAAI,IAAC,SAAS,EAAC,+BAA+B,YAAE,CAAC,CAAC,SAAS,CAAC,GAAQ,CACtE,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACnC,KAAC,IAAI,IAAC,SAAS,EAAC,+BAA+B,YAAE,CAAC,CAAC,OAAO,CAAC,GAAQ,CACpE,CAAC,CAAC,CAAC,CACF,cAAK,SAAS,EAAC,yBAAyB,YACrC,iBAAiB,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CACnC,MAAC,IAAI,eACH,KAAC,UAAU,cAIT,KAAC,SAAS,cAAE,QAAQ,CAAC,WAAW,GAAa,GAClC,EACb,MAAC,WAAW,IAAC,SAAS,EAAC,yBAAyB,aAC7C,QAAQ,CAAC,MAAM,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAC9D,MAAC,IAAI,IAAC,SAAS,EAAC,+BAA+B,aAC5C,CAAC,CAAC,cAAc,CAAC,OAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAC1C,CACR,EAMA,QAAQ,CAAC,oBAAoB,KAAK,SAAS,IAAI,QAAQ,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,IAAI,CAC1F,eAAK,SAAS,EAAC,2BAA2B,aACxC,KAAC,IAAI,IAAC,SAAS,EAAC,qBAAqB,YAAE,CAAC,CAAC,mBAAmB,CAAC,GAAQ,EACrE,KAAC,IAAI,IAAC,SAAS,EAAC,+BAA+B,YAAE,CAAC,CAAC,uBAAuB,CAAC,GAAQ,EAClF,QAAQ,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC;wCAChD,2EAA2E;wCAC3E,8EAA8E;wCAC9E,4EAA4E;wCAC5E,qEAAqE;wCACrE,KAAC,SAAS,kBAII,SAAS,EACrB,WAAW,EAAE,SAAS,EACtB,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,EACvD,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;gDAC7C,GAAG,QAAQ;gDACX,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE;oDACtB,GAAG,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC;oDACjC,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;iDAChC;6CACF,CAAC,CAAC,IAZE,SAAS,CAad,CACH,CAAC,IACE,CACP,EAED,cAAK,SAAS,EAAC,kBAAkB,YAC/B,KAAC,MAAM,IACL,IAAI,EAAE,UAAU,CAAC,EAAE,EACnB,OAAO,EAAE,sBAAsB,CAAC,OAAO;wCACvC,+EAA+E;wCAC/E,mBAAmB;wCACnB,QAAQ,EACN,OAAO,KAAK,QAAQ,CAAC,WAAW;4CAChC,8EAA8E;4CAC9E,kEAAkE;+CAC/D,UAAU,KAAK,IAAI;+CACnB,CAAC,QAAQ,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC,IAAI,CAC3C,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAChF,EAEH,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,YAErC,OAAO,KAAK,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,GACvE,GACL,IACM,KAlEL,QAAQ,CAAC,WAAW,CAmExB,CACR,CAAC,GACE,CACP,IACG,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["/**\n * AppPage_ConnectedAccountsSettings — the Settings Hub \"Connected accounts\" connect panel.\n *\n * A bespoke `ENGINE_PANEL`, and the reason is the shape of the act rather than the shape of the data.\n * The stored credentials ARE a resource, and the generic surface beside this one lists, inspects and\n * deletes them perfectly. What it cannot do is CONNECT: that is not a row somebody creates, it is a\n * flow that leaves the application, obtains consent at a vendor, and returns with a grant nobody\n * typed. A resource screen has no mechanism for an action of that shape, so until this existed the\n * whole outbound-authorization lane — controller, exchange, refresher, encrypted store, migrations —\n * had no surface that could begin it.\n *\n * ## Two reads, deliberately not one\n *\n * `listConnectableProviders()` answers what MAY be connected; the sibling resource list answers what\n * IS. Merging them would make \"you have connected nothing\" and \"there is nothing to connect\"\n * indistinguishable — and the first of those is the state every person starts in, which is precisely\n * when they need the second question answered.\n *\n * ## USER scope only, and that is not a simplification\n *\n * This panel lives under the person's own settings, so it offers only connections the provider admits\n * as USER-owned. A tenant's shared integration is the administrator's screen next door\n * (`provider-credentials`), and the two must never be merged: one is an individual's own account that\n * nobody else may see or spend, the other is a shared credential an administrator configures for\n * everyone. There is no cross-scope defaulting anywhere in this lane — a person with no credential of\n * their own is refused rather than quietly spending the organization's.\n *\n * ## Why it navigates instead of following a redirect\n *\n * The start leg answers with a URL. A 302 would be followed by this fetch, produce an opaque\n * cross-origin response, and render the vendor's consent screen into a response body nobody sees. So\n * the panel assigns `window.location.href` and the browser leaves — which is also why the OUTCOME\n * arrives back as a query parameter rather than as a promise resolving: the return trip is a fresh\n * page load from the vendor, not a continuation of this component.\n *\n * i18n follows the framework convention: `useI18n({ component })` requests this component's label\n * namespace, the panel gates rendering on `isReady` so it never flashes raw key paths, and a thin\n * `t(key)` reads each label. Copy is owned by the labelling pipeline (sibling `.labels.ts`) — no\n * hardcoded strings, and no humanized provider ref either: a provider identifier is an open\n * vocabulary with no authored label, so it is rendered verbatim rather than invented from its own\n * characters.\n *\n * assurance-control: WILDO.IDENTITY.DELEGATED_AUTHORIZATION — the surface on which a person\n * authorizes this application to act toward a named third party on their behalf.\n */\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport { ButtonSize, FrontendComponentType } from '@wildo-ai/presets-components-models';\nimport { isWildoBackendError } from '@wildo-ai/saas-models';\nimport {\n ExternalProvider_Connection_DelegationMode,\n ExternalProvider_Connection_OwnerScope,\n} from '@wildo-ai/external-connectors-models';\nimport { Card, CardContent, CardHeader, CardTitle } from '~wildo-frontend-lib/components/sections/card';\nimport { Button, ButtonVariants_Variant } from '~wildo-frontend-lib/components/actions/button';\nimport { InputRoot } from '~wildo-frontend-lib/components/form/controls/input';\nimport { Text } from '~wildo-frontend-lib/components/typography/text';\nimport { Alert, AlertDescription } from '~wildo-frontend-lib/components/overlays/containers/alert';\nimport { useI18n } from '~wildo-frontend-lib/core/i18n/useI18n';\nimport { useUserOrgs } from '~wildo-frontend-lib/core/security/useUserOrgs';\nimport {\n getManualCallsHttpClient,\n type ConnectableProviderView,\n} from '~wildo-frontend-lib/core/requests/wildo-http-client-manual-calls.frontend.service';\n\nconst COMPONENT = FrontendComponentType.APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS;\n\n/**\n * The outcome the callback wrote into the URL on its way back.\n *\n * Read once, from `window.location`, because this component did not survive the round trip — the\n * browser left for the vendor and came back on a fresh page load. Read as a plain string rather than\n * branched into a closed vocabulary: the callback's `connected` value is a provider ref, which is an\n * open set.\n */\nconst readReturnOutcome = (): { connected?: string; connectionError?: string } => {\n if (typeof window === 'undefined') return {};\n const params = new URLSearchParams(window.location.search);\n return {\n connected: params.get('connected') ?? undefined,\n connectionError: params.get('connectionError') ?? undefined,\n };\n};\n\n/**\n * The providers THIS person may connect for themselves.\n *\n * Named and exported rather than inlined because it is the panel's one substantive claim, and both\n * halves of it are a way for a button to be DEAD on press:\n *\n * - a provider admitting only ORGANIZATION-owned connections belongs on the administrator's screen\n * next door; offering it here renders a Connect button that answers 403;\n * - a provider whose credential is pasted has no authorization flow to start, so its button would\n * have nowhere to navigate.\n *\n * The two filters look interchangeable and are not: dropping the first shows an action the person is\n * not entitled to, dropping the second shows an action that does not exist.\n */\nexport const selectPersonallyConnectableProviders = (\n providers: readonly ConnectableProviderView[],\n): ConnectableProviderView[] => providers.filter((provider) =>\n provider.connectable\n && provider.admissibleConnections.some(\n (shape) => shape.ownerScope === ExternalProvider_Connection_OwnerScope.USER,\n ));\n\nexport const AppPage_ConnectedAccountsSettings: React.FC = () => {\n const { tComponent, isReady } = useI18n({ component: COMPONENT });\n const { user } = useUserOrgs();\n\n const t = useCallback((key: string) => tComponent(COMPONENT, key), [tComponent]);\n\n /**\n * Whose account is being connected — always the caller's own.\n *\n * Sent explicitly because the target schema is the SAME one the call leg uses, and there an owner\n * genuinely varies. The backend does not trust this value: it re-checks `ownerId === callerId` and\n * refuses anything else, so supplying it is a statement of intent rather than a decision.\n */\n const selfUserId = user?._id ?? null;\n\n const [providers, setProviders] = useState<ConnectableProviderView[]>([]);\n const [loading, setLoading] = useState(true);\n const [busyRef, setBusyRef] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n /** Answers to a provider's `{placeholders}`, per provider ref. Nothing is remembered across a reload. */\n const [answers, setAnswers] = useState<Record<string, Record<string, string>>>({});\n\n // Read once on mount. The outcome describes a journey that has already finished; re-reading it on\n // every render would make the banner reappear after the person dismissed the tab and came back.\n const [outcome] = useState(readReturnOutcome);\n\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const res = await getManualCallsHttpClient().listConnectableProviders();\n if (!cancelled) setProviders(res.providers ?? []);\n } catch (e: unknown) {\n if (isWildoBackendError(e)) throw e;\n if (!cancelled) setError(t('errorGeneric'));\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => { cancelled = true; };\n }, [t]);\n\n const personalProviders = useMemo(() => selectPersonallyConnectableProviders(providers), [providers]);\n\n const handleConnect = useCallback(\n async (provider: ConnectableProviderView) => {\n setBusyRef(provider.providerRef);\n setError(null);\n try {\n const { authorizeUrl } = await getManualCallsHttpClient().startProviderConnection(\n provider.providerRef,\n {\n // The person connects their OWN account and nobody else's — the backend re-checks\n // exactly this, so a tampered owner id is refused rather than honoured.\n target: {\n ownerScope: ExternalProvider_Connection_OwnerScope.USER,\n ownerId: selfUserId!,\n delegation: ExternalProvider_Connection_DelegationMode.SERVICE,\n },\n connectionParameters: answers[provider.providerRef],\n },\n );\n // The browser leaves. No state is set afterwards on purpose: this component is about to be\n // unmounted by a navigation, and a `setState` here would be a React warning on the way out.\n window.location.href = authorizeUrl;\n } catch (e: unknown) {\n if (isWildoBackendError(e)) throw e;\n setError(t('errorGeneric'));\n setBusyRef(null);\n }\n },\n [answers, selfUserId, t],\n );\n\n // Gate on label readiness so the panel never flashes raw key paths.\n if (!isReady) return null;\n\n return (\n <div className=\"flex flex-col gap-section\">\n <div className=\"flex flex-col gap-item-xs\">\n {/* `h3`, not `h2`: the Settings Hub header owns the `h2` for this dialog, so a panel\n heading is one level below it. */}\n <h3 className=\"text-base font-semibold tracking-tight\">{t('pageTitle')}</h3>\n <Text className=\"text-sm text-muted-foreground\">{t('pageDescription')}</Text>\n </div>\n\n {/* The return leg's own report. `declined` is NOT destructive — somebody who pressed \"Deny\"\n made a decision, and dressing it in red tells them they did something wrong. */}\n {outcome.connected !== undefined && (\n <Alert><AlertDescription>{t('connectedNotice')}</AlertDescription></Alert>\n )}\n {outcome.connectionError === 'declined' && (\n <Alert><AlertDescription>{t('declinedNotice')}</AlertDescription></Alert>\n )}\n {outcome.connectionError !== undefined && outcome.connectionError !== 'declined' && (\n <Alert variant=\"destructive\"><AlertDescription>{t('failedNotice')}</AlertDescription></Alert>\n )}\n\n {error && (\n <Alert variant=\"destructive\"><AlertDescription>{error}</AlertDescription></Alert>\n )}\n\n {/*\n * A standing note, not a banner: it is true all the time rather than the report of something\n * that just happened, so it does not use `Alert` and does not come and go.\n *\n * It exists because removing a connection deletes THIS application's copy of the\n * authorization and tells the provider nothing — the token the provider issued stays valid\n * there until it expires on its own, and a refresh token frequently never does. Somebody who\n * presses Disconnect reasonably concludes they have withdrawn access, and that conclusion is\n * not quite true. Saying so is the honest answer available today; revoking at the provider is\n * tracked separately, and no wording here should imply it already happens.\n *\n * It sits on THIS tab rather than beside the Disconnect button because the credential list is\n * an auto-generated resource surface with no slot for copy, and giving every settings\n * destination one for the sake of a single note would be a framework change out of all\n * proportion to it.\n */}\n <Text className=\"text-xs text-muted-foreground\">{t('disconnectNotice')}</Text>\n\n {loading ? (\n <Text className=\"text-sm text-muted-foreground\">{t('loading')}</Text>\n ) : personalProviders.length === 0 ? (\n <Text className=\"text-sm text-muted-foreground\">{t('empty')}</Text>\n ) : (\n <div className=\"flex flex-col gap-group\">\n {personalProviders.map((provider) => (\n <Card key={provider.providerRef}>\n <CardHeader>\n {/* The provider ref verbatim. There is no authored label for an open vocabulary of\n vendors, and deriving words from the identifier would invent display text no\n translator can reach. */}\n <CardTitle>{provider.providerRef}</CardTitle>\n </CardHeader>\n <CardContent className=\"flex flex-col gap-group\">\n {provider.scopes !== undefined && provider.scopes.length > 0 && (\n <Text className=\"text-xs text-muted-foreground\">\n {t('scopesPrefix')} {provider.scopes.join(', ')}\n </Text>\n )}\n\n {/* Which cloud, which directory, which region. Facts about the ACCOUNT being\n connected, known only to the person connecting it — and without them the\n vendor's own URL still contains a brace, so the flow would fail in the browser\n rather than at the point where the missing input could be asked for. */}\n {provider.connectionParameters !== undefined && provider.connectionParameters.length > 0 && (\n <div className=\"flex flex-col gap-item-xs\">\n <Text className=\"text-sm font-medium\">{t('parametersHeading')}</Text>\n <Text className=\"text-xs text-muted-foreground\">{t('parametersDescription')}</Text>\n {provider.connectionParameters.map((parameter) => (\n // `InputRoot`, not `Input`: the compound `Input` is the SCHEMA-DRIVEN form\n // control and requires a `name` and a Zod `schema`. These fields belong to no\n // resource — they are answers to a vendor's URL, held for the length of one\n // click — so inventing a schema for them would be inventing a model.\n <InputRoot\n key={parameter}\n // The parameter name IS the vendor's own token (`cloud`, `tenantId`), not\n // display copy — it is what the person must look up in their own account.\n aria-label={parameter}\n placeholder={parameter}\n value={answers[provider.providerRef]?.[parameter] ?? ''}\n onChange={(event) => setAnswers((previous) => ({\n ...previous,\n [provider.providerRef]: {\n ...previous[provider.providerRef],\n [parameter]: event.target.value,\n },\n }))}\n />\n ))}\n </div>\n )}\n\n <div className=\"flex justify-end\">\n <Button\n size={ButtonSize.SM}\n variant={ButtonVariants_Variant.DEFAULT}\n // Every placeholder must be answered: a half-answered set builds a URL that is\n // still not a URL.\n disabled={\n busyRef === provider.providerRef\n // No identity yet — the auth context has not settled. Pressing now would send\n // an empty owner and be refused for a reason nobody could act on.\n || selfUserId === null\n || (provider.connectionParameters ?? []).some(\n (parameter) => (answers[provider.providerRef]?.[parameter] ?? '').trim() === '',\n )\n }\n onClick={() => handleConnect(provider)}\n >\n {busyRef === provider.providerRef ? t('connectingButton') : t('connectButton')}\n </Button>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </div>\n );\n};\n"]}
1
+ {"version":3,"file":"AppPage_ConnectedAccountsSettings.js","sourceRoot":"","sources":["../../../../src/components/settings/AppPage_ConnectedAccountsSettings.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * AppPage_ConnectedAccountsSettings — connecting a third-party account, at either owner scope.\n *\n * A bespoke `ENGINE_PANEL`, and the reason is the shape of the act rather than the shape of the data.\n * The stored credentials ARE a resource and the generic surface beside this one lists, inspects and\n * deletes them perfectly. What it cannot do is CONNECT: that is not a row somebody creates, it is a\n * flow that leaves the application, obtains consent at a vendor, and returns with a grant nobody\n * typed. A resource screen has no mechanism for an action of that shape.\n *\n * ## Nothing is typed by hand\n *\n * The provider comes from a SELECT over what the application declares; the credential fields come\n * from that provider's own secrets contract. Both were free text until this panel existed, which is\n * how somebody ends up typing `secretSlug` into a box and storing a grant in a slot nothing reads.\n *\n * ## The flow follows the AUTH METHOD\n *\n * A connect surface cannot be one form. A vendor with an authorization flow gets the consent round\n * trip; a vendor whose credential is typed gets a form over the fields IT declares. One button for\n * both would be wrong for whichever it was not built around.\n *\n * ## A provider this deployment cannot connect is SHOWN, never hidden\n *\n * When the application has not registered with a vendor, the panel names the environment variables an\n * operator must set. Removing the provider would answer \"we do not support Asana\", which is false and\n * unfixable; naming `ASANA_CLIENT_ID` is true and is the thing that gets it set.\n *\n * ## One component, both scopes\n *\n * `ownerScope` decides whose account is being connected — a person's own, or the tenant's. The panel\n * is otherwise identical because the ACT is identical, and duplicating it would guarantee the two\n * drift. What must never be shared is the DATA: a person's connection and a tenant's shared\n * integration have different owners, different authorization and different readers, and the scope is\n * what keeps them apart at every call this panel makes.\n *\n * assurance-control: WILDO.IDENTITY.DELEGATED_AUTHORIZATION — the surface on which a principal\n * authorizes this application to act toward a named third party on their behalf.\n */\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { z } from 'zod';\nimport { ButtonSize, FrontendComponentType } from '@wildo-ai/presets-components-models';\nimport { isWildoBackendError, ProviderAuthMethod, ProviderConnectabilityBlocker } from '@wildo-ai/saas-models';\nimport {\n ExternalProvider_Connection_DelegationMode,\n ExternalProvider_Connection_OwnerScope,\n} from '@wildo-ai/external-connectors-models';\nimport { Card, CardContent, CardHeader, CardTitle } from '~wildo-frontend-lib/components/sections/card';\nimport { Button, ButtonVariants_Variant } from '~wildo-frontend-lib/components/actions/button';\nimport { InputRoot } from '~wildo-frontend-lib/components/form/controls/input';\nimport { Select } from '~wildo-frontend-lib/components/form/controls/enum/select';\nimport { Text } from '~wildo-frontend-lib/components/typography/text';\nimport { Alert, AlertDescription } from '~wildo-frontend-lib/components/overlays/containers/alert';\nimport { useI18n } from '~wildo-frontend-lib/core/i18n/useI18n';\nimport { useUserOrgs } from '~wildo-frontend-lib/core/security/useUserOrgs';\nimport {\n getManualCallsHttpClient,\n type ConnectableProviderView,\n} from '~wildo-frontend-lib/core/requests/wildo-http-client-manual-calls.frontend.service';\n\nconst COMPONENT = FrontendComponentType.APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS;\n\n/** The select's schema. A provider ref is an open identifier, so the control validates shape only. */\nconst PROVIDER_REF_SCHEMA = z.string().min(1);\n/** The chooser's own shape. Its OPTIONS are the provider's declared delegations, never this. */\nconst DELEGATION_SCHEMA = z.string().min(1);\n\n/**\n * The providers connectable AT THIS SCOPE.\n *\n * Exported and named because it is the panel's one substantive claim: a provider admitting only\n * ORGANIZATION connections must never be offered on a person's screen, and vice versa — offering it\n * renders an action that answers 403 at the start leg.\n *\n * It deliberately does NOT filter on `connectable`. A provider this deployment cannot connect is\n * still offered, because the panel's answer for it is the missing configuration rather than silence.\n */\nexport const selectProvidersForScope = (\n providers: readonly ConnectableProviderView[],\n ownerScope: ExternalProvider_Connection_OwnerScope,\n): ConnectableProviderView[] => providers.filter((provider) => provider.admissibleConnections.some(\n (shape) => shape.ownerScope === ownerScope,\n));\n\n/**\n * ON WHOSE BEHALF this provider admits a connection at this scope — DERIVED, never assumed.\n *\n * The panel used to send `delegation: SERVICE` for every connect, at both scopes. That is one of the\n * five declared shapes, so it worked by coincidence for the providers that happen to declare it and\n * answered `409 CONNECTION_NOT_ADMISSIBLE` for the rest — the start leg checks the exact\n * (ownerScope, delegation) PAIR against what the provider admits, and a scope does not imply a\n * delegation.\n *\n * Measured across the generated catalogue on 2026-09-10, which is why this is a derivation rather\n * than a better constant: at ORGANIZATION scope, 75 vendors declare `USER` and 39 declare `SERVICE`.\n * A hard-coded `SERVICE` was therefore wrong for the larger half — `asana` among them, which is how\n * this surfaced: the provider was listed, the button rendered, and the vendor was never reached.\n *\n * The pair is the provider's own statement, so the panel reads it rather than the person supplying\n * it. Where a provider declares BOTH delegations for one scope — 27 vendors do, `box`, `dropbox`,\n * `gmail` and `google-calendar` among them — the declaration genuinely does not decide, and only\n * then is there a question to put to anybody. See `.claude/rules/derive-before-you-ask.md`.\n */\nexport const admissibleDelegationsForScope = (\n provider: ConnectableProviderView,\n ownerScope: ExternalProvider_Connection_OwnerScope,\n): ExternalProvider_Connection_DelegationMode[] => {\n // The view types both members as `string` — it is a wire record — so this is where they become\n // the vocabulary. NARROWED rather than cast: a delegation this build does not know is dropped\n // instead of being sent to the start leg, which would answer 409 for a value the panel invented.\n const known = new Set<string>(Object.values(ExternalProvider_Connection_DelegationMode));\n const delegations: ExternalProvider_Connection_DelegationMode[] = [];\n for (const shape of provider.admissibleConnections) {\n if (shape.ownerScope !== ownerScope || !known.has(shape.delegation)) continue;\n const delegation = shape.delegation as ExternalProvider_Connection_DelegationMode;\n if (!delegations.includes(delegation)) delegations.push(delegation);\n }\n return delegations;\n};\n\n/**\n * The target the start leg is given — assembled here so the shape is TESTABLE, not inlined.\n *\n * `ExternalProvider_ConnectionTargetSchema` refines two fields the panel cannot leave to be\n * inferred, and it refuses in BOTH directions:\n *\n * - a `USER`-delegated call MUST name `actingForUserId` — \"a delegated call acts FOR someone, and\n * the user it acts for is what makes it permissible\";\n * - a `SERVICE` call MUST NOT, because naming a person there \"reads as delegation the runtime will\n * not perform, which is worse than an error: the call succeeds as the wrong identity\".\n *\n * The panel sent neither until 2026-09-10, so every `USER`-delegated connect answered\n * `400 VALIDATION_FAILED` — and that refusal names no field, so the screen could only report a\n * generic failure. It was invisible because the shape that WORKS is `SERVICE`-delegated: `USER` at\n * ORGANIZATION scope is what 75 of the harvested vendors declare, `asana` among them, and it is\n * exactly the half nobody had driven.\n *\n * `actingForUserId` is the SIGNED-IN person and is independent of `ownerId`: a tenant-owned\n * connection acting for one of its members carries the organization in `ownerId` and the person\n * here. At USER scope the two coincide, which is why one field cannot serve both.\n *\n * `ownerId` is omitted for APPLICATION, which the schema likewise refuses — \"an application-owned\n * connection has exactly one instance, so an ownerId here names something that does not exist\".\n * The Settings Hub renders only USER and ORGANIZATION today, so that arm is unreachable from this\n * panel; it is handled because the function is the shape's one statement, and a caller that grows\n * the third scope should not have to rediscover the rule.\n */\nexport const buildConnectionTarget = (input: {\n ownerScope: ExternalProvider_Connection_OwnerScope;\n ownerId: string | null;\n delegation: ExternalProvider_Connection_DelegationMode;\n signedInUserId: string | null;\n}): {\n ownerScope: ExternalProvider_Connection_OwnerScope;\n delegation: ExternalProvider_Connection_DelegationMode;\n ownerId?: string;\n actingForUserId?: string;\n} => ({\n ownerScope: input.ownerScope,\n delegation: input.delegation,\n ...(input.ownerScope === ExternalProvider_Connection_OwnerScope.APPLICATION || input.ownerId === null\n ? {}\n : { ownerId: input.ownerId }),\n ...(input.delegation === ExternalProvider_Connection_DelegationMode.USER && input.signedInUserId !== null\n ? { actingForUserId: input.signedInUserId }\n : {}),\n});\n\n/**\n * What the callback left in the URL on its way back. Read once — see the panel's mount.\n *\n * Two shapes arrive here, and they are different acts. `connectionError` is a FINISHED outcome the\n * callback already decided — a refusal at the vendor, or an attempt it could not recognise. `state`\n * and `code` are an approval that is NOT yet redeemed: the callback cannot redeem it, because a\n * vendor redirect carries no bearer token, so it hands the approval to this screen to finish.\n */\nconst readReturnOutcome = (): {\n connected?: string;\n connectionError?: string;\n state?: string;\n code?: string;\n} => {\n if (typeof window === 'undefined') return {};\n const params = new URLSearchParams(window.location.search);\n return {\n connected: params.get('connected') ?? undefined,\n connectionError: params.get('connectionError') ?? undefined,\n state: params.get('state') ?? undefined,\n code: params.get('code') ?? undefined,\n };\n};\n\n/**\n * Take the approval out of the address bar once it has been redeemed.\n *\n * `replaceState` rather than a navigation: the entry is REPLACED, so the code does not sit in\n * history for a back button to return to, and no re-render is triggered. It is single-use at the\n * backend regardless — this is about not leaving it lying in the URL, in a referrer, or in whatever\n * the browser syncs.\n */\nconst clearApprovalFromAddressBar = (): void => {\n if (typeof window === 'undefined') return;\n const url = new URL(window.location.href);\n url.searchParams.delete('state');\n url.searchParams.delete('code');\n window.history.replaceState(window.history.state, '', url.toString());\n};\n\nexport interface ConnectedAccountsSettingsProps {\n /**\n * WHOSE account is being connected.\n *\n * A prop rather than two components: the act is identical and duplicating it would guarantee the\n * two screens drift. The DATA never mixes — every call this panel makes carries the scope.\n */\n ownerScope: ExternalProvider_Connection_OwnerScope;\n}\n\nexport const AppPage_ConnectedAccountsSettings: React.FC<Partial<ConnectedAccountsSettingsProps>> = ({\n // Defaults to the person's own, which is the destination this panel was built for; the\n // organization surface passes the scope explicitly.\n ownerScope = ExternalProvider_Connection_OwnerScope.USER,\n}) => {\n const { tComponent, isReady } = useI18n({ component: COMPONENT });\n const { user, currentOrganizationId } = useUserOrgs() as {\n user?: { _id?: string };\n currentOrganizationId?: string | null;\n };\n\n const t = useCallback((key: string) => tComponent(COMPONENT, key), [tComponent]);\n\n /**\n * WHOSE account, resolved for the scope in play.\n *\n * The backend re-checks it — a USER target must be the caller, an ORGANIZATION target goes through\n * the membership port — so supplying it is a statement of intent rather than a decision.\n */\n const ownerId = ownerScope === ExternalProvider_Connection_OwnerScope.USER\n ? user?._id ?? null\n : currentOrganizationId ?? null;\n\n const [providers, setProviders] = useState<ConnectableProviderView[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [selectedRef, setSelectedRef] = useState<string>('');\n const [busy, setBusy] = useState(false);\n /** Set ONLY when the provider declares both delegations for this scope — otherwise derived. */\n const [delegationChoice, setDelegationChoice] = useState<string>('');\n /** Answers keyed by the slug the PROVIDER declared — never by a name somebody typed. */\n const [answers, setAnswers] = useState<Record<string, string>>({});\n\n const [outcome, setOutcome] = useState(readReturnOutcome);\n\n /**\n * Redeem an approval the vendor just granted — the half the callback could not do.\n *\n * ## The in-flight request is CACHED, and both mounts subscribe to it\n *\n * React 18 mounts an effect, tears it down and mounts it again in StrictMode, and the attempt is\n * consumed atomically by the backend — so a second redemption answers\n * `CONNECTION_ATTEMPT_INVALID` and the `catch` would replace a connection that genuinely succeeded\n * with a failure notice. That is not hypothetical: on the first real consent, 2026-09-10, the\n * backend logged `[oauth2-connect] account connected` with `grantedScopes: [\"default\",\"identity\"]`\n * and stored the credential, and the browser then posted a second time and showed a 400.\n *\n * A once-guard alone does not fix it, and the way it fails is worse than the defect — the same\n * trap `TotpEnrollmentMethod.strict-mode-setup.test.tsx` records. A guard PLUS a cancel-on-cleanup\n * flag means mount 1 starts the request, its cleanup cancels the only subscriber, and the guard\n * then stops mount 2 from applying anything: the account connects and the panel says nothing at\n * all. Caching the PROMISE instead lets the remount re-subscribe, so there is one request and the\n * live mount is the one that renders its result.\n *\n * The address bar is cleared beside the request rather than after it, for its own reason: not\n * leaving an authorization code sitting in history behind a back button.\n */\n const redemption = useRef<Promise<{ connected: string }> | null>(null);\n useEffect(() => {\n const { state, code } = outcome;\n if (state === undefined || code === undefined) return;\n if (redemption.current === null) {\n clearApprovalFromAddressBar();\n redemption.current = getManualCallsHttpClient().completeProviderConnection({ state, code });\n }\n let cancelled = false;\n redemption.current\n .then(({ connected }) => { if (!cancelled) setOutcome({ connected }); })\n .catch((e: unknown) => {\n if (isWildoBackendError(e)) throw e;\n // The callback's own vocabulary, so the notices below stay one set rather than two.\n if (!cancelled) setOutcome({ connectionError: 'failed' });\n });\n return () => { cancelled = true; };\n // `outcome` is seeded once from the URL and the cached promise is what makes this issue one\n // request, so this deliberately does not re-run on the outcome it sets itself.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const res = await getManualCallsHttpClient().listConnectableProviders();\n if (!cancelled) setProviders(res.providers ?? []);\n } catch (e: unknown) {\n if (isWildoBackendError(e)) throw e;\n if (!cancelled) setError(t('errorGeneric'));\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => { cancelled = true; };\n }, [t]);\n\n const available = useMemo(() => selectProvidersForScope(providers, ownerScope), [providers, ownerScope]);\n\n /**\n * EVERY declared provider still missing part of its configuration — not just the selected one.\n *\n * A gap found by selecting a provider is a gap found one click at a time, and an operator asking\n * \"what is not configured\" would have to walk all eighteen. This answers it once.\n *\n * Deliberately NOT filtered by `ownerScope`. A missing environment variable is a fact about the\n * APPLICATION: `ASANA_CLIENT_ID` is absent for everybody, and hiding it on the person's screen\n * because Asana also admits a tenant connection would make the same gap visible or invisible\n * depending on which settings page somebody happened to open.\n */\n const configurationGaps = useMemo(\n () => providers\n .filter((provider) => (provider.missingRegistration ?? []).length > 0)\n .map((provider) => ({\n providerRef: provider.providerRef,\n envVarNames: (provider.missingRegistration ?? []).map((slot) => slot.envVarName),\n })),\n [providers],\n );\n const selected = useMemo(\n () => available.find((provider) => provider.providerRef === selectedRef),\n [available, selectedRef],\n );\n\n // Answers belong to the provider they were typed for. Clearing on change is what stops a value\n // meant for one vendor being submitted to another when somebody changes their mind mid-form.\n const chooseProvider = useCallback((ref: string) => {\n setSelectedRef(ref);\n setAnswers({});\n setDelegationChoice('');\n setError(null);\n }, []);\n\n /**\n * What this provider admits at the scope in play, and the one the connect will carry.\n *\n * `delegationChoice` is only ever set by the chooser below, which renders solely when the provider\n * declares more than one. For the ordinary provider `delegations` has a single member and that\n * member IS the answer — nothing is asked and nothing is assumed.\n */\n const delegations = useMemo(\n () => (selected === undefined ? [] : admissibleDelegationsForScope(selected, ownerScope)),\n [ownerScope, selected],\n );\n const delegation = delegations.length === 1\n ? delegations[0]\n : delegations.find((candidate) => candidate === delegationChoice);\n\n const [savedNotice, setSavedNotice] = useState<string | null>(null);\n\n /**\n * The two acts behind one button, branching on the provider's own auth method.\n *\n * An authorization flow ENDS THE PAGE — the browser leaves for the vendor and returns to a fresh\n * load. A typed credential ends in a stored row and the person stays here. Sharing a handler is\n * right because the person's intent is the same (\"connect this\"); sharing the OUTCOME would not be,\n * which is why only one of the branches navigates.\n */\n const handleConnect = useCallback(async () => {\n // `delegation` undefined means the provider declares several and none is chosen yet. The button\n // is disabled in that state; the guard is here because a disabled control is a courtesy and this\n // is the statement that a target is never assembled with a delegation nobody chose.\n if (selected === undefined || ownerId === null || delegation === undefined) return;\n setBusy(true);\n setError(null);\n setSavedNotice(null);\n const target = buildConnectionTarget({ ownerScope, ownerId, delegation, signedInUserId: user?._id ?? null });\n try {\n if (selected.authMethods?.includes(ProviderAuthMethod.OAUTH2_AUTHORIZATION_CODE) ?? false) {\n const { authorizeUrl } = await getManualCallsHttpClient().startProviderConnection(\n selected.providerRef,\n { target, connectionParameters: answers },\n );\n // The browser leaves. No state is set afterwards: this component is about to be unmounted by\n // a navigation, and a `setState` here would be a React warning on the way out.\n window.location.href = authorizeUrl;\n return;\n }\n\n // Only the values the provider DECLARED, so a stale answer left over from a field that is no\n // longer offered cannot be posted. The route re-checks this; sending less is still the honest\n // thing for the screen to do.\n const declared = new Set((selected.credentialFields ?? []).map((field) => field.slug));\n const values = Object.fromEntries(\n Object.entries(answers).filter(([slug, value]) => declared.has(slug) && value.trim() !== ''),\n );\n await getManualCallsHttpClient().storeProviderCredential(selected.providerRef, { target, values });\n\n // The typed values are cleared once stored. They are secrets, and a form that keeps them\n // on screen after they have been sealed is holding them for no reason.\n setAnswers({});\n setSavedNotice(t('credentialStoredNotice'));\n setBusy(false);\n } catch (e: unknown) {\n if (isWildoBackendError(e)) throw e;\n setError(t('errorGeneric'));\n setBusy(false);\n }\n }, [answers, delegation, ownerId, ownerScope, selected, t, user?._id]);\n\n if (!isReady) return null;\n\n const providerOptions = available.map((provider) => ({\n value: provider.providerRef,\n // The ref VERBATIM. There is no authored label for an open vocabulary of vendors, and deriving\n // words from an identifier would invent display text no translator can reach.\n label: provider.providerRef,\n }));\n\n const oauth2 = selected?.authMethods?.includes(ProviderAuthMethod.OAUTH2_AUTHORIZATION_CODE) ?? false;\n const missing = selected?.missingRegistration ?? [];\n const parameters = selected?.connectionParameters ?? [];\n const credentialFields = selected?.credentialFields ?? [];\n /** What the authorization will REQUEST — rendered before the button, never only after consent. */\n const scopes = selected?.scopes ?? [];\n const unanswered = (oauth2 ? parameters : credentialFields.filter((f) => f.required).map((f) => f.slug))\n .some((key) => (answers[key] ?? '').trim() === '');\n\n return (\n <div className=\"flex flex-col gap-section\">\n <div className=\"flex flex-col gap-item-xs\">\n {/* `h3`, not `h2`: the Settings Hub header owns the `h2` for this dialog. */}\n <h3 className=\"text-base font-semibold tracking-tight\">{t('pageTitle')}</h3>\n <Text className=\"text-sm text-muted-foreground\">{t('pageDescription')}</Text>\n </div>\n\n {/* The return leg's own report. `declined` is NOT destructive — somebody who pressed \"Deny\"\n made a decision, and dressing it in red tells them they did something wrong. */}\n {outcome.connected !== undefined && (\n <Alert><AlertDescription>{t('connectedNotice')}</AlertDescription></Alert>\n )}\n {outcome.connectionError === 'declined' && (\n <Alert><AlertDescription>{t('declinedNotice')}</AlertDescription></Alert>\n )}\n {outcome.connectionError !== undefined && outcome.connectionError !== 'declined' && (\n <Alert variant=\"destructive\"><AlertDescription>{t('failedNotice')}</AlertDescription></Alert>\n )}\n {savedNotice && <Alert><AlertDescription>{savedNotice}</AlertDescription></Alert>}\n {error && <Alert variant=\"destructive\"><AlertDescription>{error}</AlertDescription></Alert>}\n\n {/*\n * The whole configuration's gaps, stated once and before anything else.\n *\n * Written rather than hidden, which is the decision this panel exists to make visible: a\n * provider whose registration is absent still appears in the chooser, and this says what an\n * operator must set for ANY of them to work. An environment variable's NAME is not a secret —\n * it is the only thing that makes the gap actionable.\n */}\n {configurationGaps.length > 0 && (\n <Alert variant=\"destructive\">\n <AlertDescription>\n <div className=\"flex flex-col gap-item-xs\">\n <Text className=\"text-sm font-medium\">{t('configurationGapsHeading')}</Text>\n <Text className=\"text-xs\">{t('configurationGapsDescription')}</Text>\n <ul className=\"list-disc pl-4\">\n {configurationGaps.map((gap) => (\n <li key={gap.providerRef} className=\"text-xs\">\n {gap.providerRef}\n {': '}\n {gap.envVarNames.join(', ')}\n </li>\n ))}\n </ul>\n </div>\n </AlertDescription>\n </Alert>\n )}\n\n <Card>\n <CardHeader><CardTitle>{t('chooseProviderHeading')}</CardTitle></CardHeader>\n <CardContent className=\"flex flex-col gap-group\">\n {loading ? (\n <Text className=\"text-sm text-muted-foreground\">{t('loading')}</Text>\n ) : providerOptions.length === 0 ? (\n <Text className=\"text-sm text-muted-foreground\">{t('empty')}</Text>\n ) : (\n <>\n {/* A SELECT over what the application declares. The whole point: a provider ref is\n never typed, so it can never be a ref that does not exist. */}\n <Select\n name=\"providerRef\"\n schema={PROVIDER_REF_SCHEMA}\n options={providerOptions}\n value={selectedRef}\n placeholder={t('choosePlaceholder')}\n onChange={chooseProvider}\n />\n\n {selected !== undefined && (\n <div className=\"flex flex-col gap-group\">\n {/* An operator's gap, named rather than hidden. `missingRegistration` carries the\n environment variables — which are not secrets, and are the only thing that makes\n this actionable. */}\n {missing.length > 0 && (\n <Alert variant=\"destructive\">\n <AlertDescription>\n {t('notRegisteredNotice')}\n {' '}\n {missing.map((slot) => slot.envVarName).join(', ')}\n </AlertDescription>\n </Alert>\n )}\n\n {!oauth2 && missing.length === 0 && (\n <Text className=\"text-xs text-muted-foreground\">{t('pastedCredentialNotice')}</Text>\n )}\n\n {/* ON WHOSE BEHALF — asked ONLY where the provider's own declaration leaves it open.\n One admitted delegation is an answer, not a question, so the ordinary provider\n renders nothing here and the connect carries what the vendor declared. The 27\n that admit both at one scope are a real choice between two different accounts —\n the tenant's own token, or a token minted for the person acting — and neither\n the panel nor a default may make it on their behalf. */}\n {delegations.length > 1 && (\n <div className=\"flex flex-col gap-item-xs\">\n <Text className=\"text-sm font-medium\">{t('delegationHeading')}</Text>\n <Text className=\"text-xs text-muted-foreground\">{t('delegationDescription')}</Text>\n <Select\n name=\"delegation\"\n schema={DELEGATION_SCHEMA}\n options={delegations.map((mode) => ({\n value: mode,\n label: t(mode === ExternalProvider_Connection_DelegationMode.SERVICE\n ? 'delegationServiceOption'\n : 'delegationUserOption'),\n }))}\n value={delegationChoice}\n placeholder={t('delegationPlaceholder')}\n onChange={setDelegationChoice}\n />\n </div>\n )}\n\n {/* WHAT THIS WILL ASK THE VENDOR FOR, before the button that asks for it.\n *\n * The scopes are the substance of the consent: `slack` requests THIRTY of them,\n * `gitlab` asks for `api`, and a panel that sends somebody to a vendor without\n * naming them is asking for a signature on an unread page. The catalogue has\n * carried `scopes` since the route was written and nothing rendered it — the\n * label existed too, authored and never wired.\n *\n * VERBATIM, and deliberately: a scope is the vendor's own token, it is the\n * string the vendor's own consent screen is about to show, and there is no\n * authored label for an open vocabulary spanning every provider. Prettifying\n * `channels:write.invites` into words would invent display text no translator\n * can reach and would no longer match what the vendor says next. */}\n {oauth2 && scopes.length > 0 && (\n <Text className=\"text-xs text-muted-foreground\">\n {t('scopesPrefix')}\n {' '}\n {scopes.join(', ')}\n </Text>\n )}\n\n {/* THE DECLARED FIELDS — for an authorization flow, the placeholders its own URLs\n carry; for a typed credential, the slots the provider's secrets contract names.\n Either way the form knows what to ask for, and nobody types a slug. */}\n {(oauth2 ? parameters.length > 0 : credentialFields.length > 0) && (\n <div className=\"flex flex-col gap-item-xs\">\n <Text className=\"text-sm font-medium\">{t('parametersHeading')}</Text>\n <Text className=\"text-xs text-muted-foreground\">{t('parametersDescription')}</Text>\n </div>\n )}\n\n {(oauth2\n ? parameters.map((name) => ({ key: name, label: name, description: undefined as string | undefined }))\n : credentialFields.map((field) => ({ key: field.slug, label: field.slug, description: field.description }))\n ).map((field) => (\n <div key={field.key} className=\"flex flex-col gap-item-xs\">\n <Text className=\"text-sm font-medium\">{field.label}</Text>\n {field.description !== undefined && (\n <Text className=\"text-xs text-muted-foreground\">{field.description}</Text>\n )}\n <InputRoot\n aria-label={field.label}\n // A credential is typed into a password field; a connection parameter — which\n // cloud, which directory — is not a secret and is shown.\n type={oauth2 ? 'text' : 'password'}\n value={answers[field.key] ?? ''}\n onChange={(event) => setAnswers((previous) => ({ ...previous, [field.key]: event.target.value }))}\n />\n </div>\n ))}\n\n <div className=\"flex justify-end\">\n <Button\n size={ButtonSize.SM}\n variant={ButtonVariants_Variant.DEFAULT}\n disabled={\n busy\n || ownerId === null\n || selected.notConnectableBecause === ProviderConnectabilityBlocker.APPLICATION_NOT_REGISTERED\n || unanswered\n || delegation === undefined\n }\n onClick={handleConnect}\n >\n {busy ? t('connectingButton') : t('connectButton')}\n </Button>\n </div>\n </div>\n )}\n </>\n )}\n\n {/*\n * A standing note, not a banner: it is true all the time rather than the report of\n * something that just happened.\n *\n * Removing a connection deletes THIS application's copy of the authorization and tells the\n * provider nothing — the token stays valid there until it expires on its own, and a refresh\n * token frequently never does. Somebody who presses Disconnect reasonably concludes they\n * have withdrawn access, and that conclusion is not quite true.\n */}\n <Text className=\"text-xs text-muted-foreground\">{t('disconnectNotice')}</Text>\n </CardContent>\n </Card>\n </div>\n );\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"AppPage_ConnectedAccountsSettings.labels.d.ts","sourceRoot":"","sources":["../../../../src/components/settings/AppPage_ConnectedAccountsSettings.labels.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EAEzB,MAAM,qCAAqC,CAAC;AAO7C,eAAO,MAAM,yCAAyC,EAAE,mBAAmB,EAiB1E,CAAC"}
1
+ {"version":3,"file":"AppPage_ConnectedAccountsSettings.labels.d.ts","sourceRoot":"","sources":["../../../../src/components/settings/AppPage_ConnectedAccountsSettings.labels.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EAEzB,MAAM,qCAAqC,CAAC;AA2B7C,eAAO,MAAM,yCAAyC,EAAE,mBAAmB,EA2B1E,CAAC"}
@@ -4,22 +4,52 @@ import { FrontendComponentType, LabelKind, registerComponentLabels, } from '@wil
4
4
  // `components.APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS.*` bundle; NOT imported at runtime, so it
5
5
  // never ships in the browser bundle. Keep in lock-step with the keys the component reads via
6
6
  // `tComponent(APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS, ...)`.
7
+ //
8
+ // LOCK-STEP DRIFTS SILENTLY IN BOTH DIRECTIONS, and on 2026-09-10 it had drifted both ways at once.
9
+ // Nothing mechanical compares this array to the component's `t('...')` call sites, and neither
10
+ // failure raises anything: a key the component reads and this array omits renders as its RAW KEY
11
+ // PATH in the browser — visible only to somebody looking at the panel — while a key declared here
12
+ // and never read costs a generated entry plus a translation round trip in every locale, and tells
13
+ // the next reader the panel renders a message it does not. Five of each had accumulated before the
14
+ // panel was first rendered. When you add or remove a `t('...')` call, edit this array in the same
15
+ // change, and regenerate with
16
+ // `wildo generate labels --units component:APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS --force`
17
+ // followed by the matching `wildo generate translate`.
18
+ //
19
+ // `errorNotAdmissible` and `errorForbidden` were declared here and REMOVED on 2026-09-10 rather
20
+ // than wired. The start route really does answer 409 CONNECTION_NOT_ADMISSIBLE and 403 FORBIDDEN
21
+ // with those two distinct meanings — but this panel's catch does `if (isWildoBackendError(e)) throw
22
+ // e`, so a structured backend refusal propagates to the global error handler and no branch in this
23
+ // component can ever render either message. Reintroducing them is a real option and it is a
24
+ // DECISION, not a cleanup: it means this panel stops re-throwing those two statuses and reports
25
+ // them itself, which departs from the repository-wide convention that a `WildoBackendError`
26
+ // belongs to the global handler. Declare them again in the same change that makes them reachable.
7
27
  export const AppLayoutsConnectedAccountsSettingsLabels = [
8
28
  { ref: 'pageTitle', kind: LabelKind.HEADING, purpose: 'Heading for the panel where a person connects their own third-party accounts' },
9
29
  { ref: 'pageDescription', kind: LabelKind.DESCRIPTION, purpose: 'Sub-heading explaining that connecting an account lets this application act as that account on the person’s behalf, and that they can disconnect at any time' },
10
30
  { ref: 'loading', kind: LabelKind.MESSAGE, purpose: 'Shown while the list of connectable providers is being loaded' },
11
31
  { ref: 'empty', kind: LabelKind.MESSAGE, purpose: 'Shown when this application declares no provider a person may connect individually' },
32
+ { ref: 'chooseProviderHeading', kind: LabelKind.HEADING, purpose: 'Heading above the control where somebody picks which third-party provider to connect' },
33
+ { ref: 'choosePlaceholder', kind: LabelKind.LABEL, purpose: 'Placeholder shown in the provider chooser before anything is selected, inviting the person to pick a provider' },
12
34
  { ref: 'connectButton', kind: LabelKind.BUTTON, purpose: 'Button that starts connecting the named third-party account, sending the person to that vendor to grant consent' },
13
35
  { ref: 'connectingButton', kind: LabelKind.BUTTON, purpose: 'Button caption while the authorization URL is being obtained, before the browser leaves for the vendor' },
36
+ { ref: 'delegationHeading', kind: LabelKind.HEADING, purpose: 'Heading above the control asking on whose behalf the connection will act — shown only for a provider that admits both a service identity and a user-delegated one at this scope' },
37
+ { ref: 'delegationDescription', kind: LabelKind.DESCRIPTION, purpose: 'Explains that this provider can be connected either as the tenant itself or as the person acting, that these are two different accounts at the vendor, and that nobody may choose on the person’s behalf' },
38
+ { ref: 'delegationPlaceholder', kind: LabelKind.LABEL, purpose: 'Placeholder in the on-whose-behalf chooser before either delegation is picked' },
39
+ { ref: 'delegationServiceOption', kind: LabelKind.LABEL, purpose: 'Option naming the connection that acts as the organization or application itself, using a shared identity rather than any individual’s account' },
40
+ { ref: 'delegationUserOption', kind: LabelKind.LABEL, purpose: 'Option naming the connection that acts as the individual person authorizing it, so anything it does at the vendor is attributed to them' },
14
41
  { ref: 'parametersHeading', kind: LabelKind.HEADING, purpose: 'Heading above the inputs a person must answer before connecting, such as which cloud or which directory their account lives in' },
15
42
  { ref: 'parametersDescription', kind: LabelKind.DESCRIPTION, purpose: 'Explains that these answers are facts about the account being connected and that the vendor’s own addresses cannot be built without them' },
16
43
  { ref: 'scopesPrefix', kind: LabelKind.LABEL, purpose: 'Prefix before the list of permissions the connection will ask the vendor for (e.g. "Requests:")' },
44
+ { ref: 'credentialStoredNotice', kind: LabelKind.MESSAGE, purpose: 'Confirmation shown after a typed credential has been saved for a provider that has no authorization flow' },
17
45
  { ref: 'connectedNotice', kind: LabelKind.MESSAGE, purpose: 'Confirmation shown after returning from a vendor where the account was connected successfully' },
18
46
  { ref: 'declinedNotice', kind: LabelKind.MESSAGE, purpose: 'Shown after returning from a vendor where the person chose not to grant access — a decision, not an error' },
19
47
  { ref: 'failedNotice', kind: LabelKind.MESSAGE, purpose: 'Shown after returning from a vendor when the connection attempt could not be completed and should be started again' },
20
48
  { ref: 'errorGeneric', kind: LabelKind.MESSAGE, purpose: 'Generic error shown when listing connectable providers or starting a connection fails' },
21
- { ref: 'errorNotAdmissible', kind: LabelKind.MESSAGE, purpose: 'Shown when this provider does not admit a personally-owned connection, so nobody may connect it individually' },
22
- { ref: 'errorForbidden', kind: LabelKind.MESSAGE, purpose: 'Shown when the person is not allowed to connect an account on behalf of the named owner' },
49
+ { ref: 'configurationGapsHeading', kind: LabelKind.HEADING, purpose: 'Heading of the block listing every provider whose application-level configuration is incomplete, shown before the chooser' },
50
+ { ref: 'configurationGapsDescription', kind: LabelKind.DESCRIPTION, purpose: 'Explains that the providers listed below cannot be connected by anybody until an operator sets the named environment variables for this deployment, and that this is a configuration gap rather than a lack of support' },
51
+ { ref: 'notRegisteredNotice', kind: LabelKind.MESSAGE, purpose: 'Explains that this application has not yet registered with the provider, so connecting is not possible until an operator creates an application at that vendor and configures its credentials — shown in place of the Connect button' },
52
+ { ref: 'pastedCredentialNotice', kind: LabelKind.MESSAGE, purpose: 'Explains that this provider has no authorization flow because its credential is typed rather than granted, and points the person at the credentials tab' },
23
53
  { ref: 'disconnectNotice', kind: LabelKind.MESSAGE, purpose: 'Standing note explaining that removing a connection deletes this application\u2019s copy of the authorization but does not withdraw it at the provider, and that the person should also remove the application in the provider\u2019s own connected-applications settings if they want access ended there' },
24
54
  ];
25
55
  registerComponentLabels(FrontendComponentType.APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS, AppLayoutsConnectedAccountsSettingsLabels);
@@ -1 +1 @@
1
- {"version":3,"file":"AppPage_ConnectedAccountsSettings.labels.js","sourceRoot":"","sources":["../../../../src/components/settings/AppPage_ConnectedAccountsSettings.labels.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,SAAS,EAET,uBAAuB,GACxB,MAAM,qCAAqC,CAAC;AAE7C,iGAAiG;AACjG,0DAA0D;AAC1D,gGAAgG;AAChG,6FAA6F;AAC7F,8DAA8D;AAC9D,MAAM,CAAC,MAAM,yCAAyC,GAA0B;IAC9E,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,8EAA8E,EAAE;IACtI,EAAE,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,SAAS,CAAC,WAAW,EAAE,OAAO,EAAE,8JAA8J,EAAE;IAChO,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,+DAA+D,EAAE;IACrH,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,oFAAoF,EAAE;IACxI,EAAE,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,iHAAiH,EAAE;IAC5K,EAAE,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,wGAAwG,EAAE;IACtK,EAAE,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,gIAAgI,EAAE;IAChM,EAAE,GAAG,EAAE,uBAAuB,EAAE,IAAI,EAAE,SAAS,CAAC,WAAW,EAAE,OAAO,EAAE,0IAA0I,EAAE;IAClN,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,iGAAiG,EAAE;IAC1J,EAAE,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,+FAA+F,EAAE;IAC7J,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,2GAA2G,EAAE;IACxK,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,oHAAoH,EAAE;IAC/K,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,uFAAuF,EAAE;IAClJ,EAAE,GAAG,EAAE,oBAAoB,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,8GAA8G,EAAE;IAC/K,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,yFAAyF,EAAE;IACtJ,EAAE,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,2SAA2S,EAAE;CAC3W,CAAC;AAEF,uBAAuB,CAAC,qBAAqB,CAAC,uCAAuC,EAAE,yCAAyC,CAAC,CAAC","sourcesContent":["import {\n FrontendComponentType,\n LabelKind,\n type LabellingUnitaryDef,\n registerComponentLabels,\n} from '@wildo-ai/presets-components-models';\n\n// Companion-only label metadata for the Connected-accounts panel: keys + kind + per-key purpose.\n// Statically scanned by the dev companion to generate the\n// `components.APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS.*` bundle; NOT imported at runtime, so it\n// never ships in the browser bundle. Keep in lock-step with the keys the component reads via\n// `tComponent(APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS, ...)`.\nexport const AppLayoutsConnectedAccountsSettingsLabels: LabellingUnitaryDef[] = [\n { ref: 'pageTitle', kind: LabelKind.HEADING, purpose: 'Heading for the panel where a person connects their own third-party accounts' },\n { ref: 'pageDescription', kind: LabelKind.DESCRIPTION, purpose: 'Sub-heading explaining that connecting an account lets this application act as that account on the person’s behalf, and that they can disconnect at any time' },\n { ref: 'loading', kind: LabelKind.MESSAGE, purpose: 'Shown while the list of connectable providers is being loaded' },\n { ref: 'empty', kind: LabelKind.MESSAGE, purpose: 'Shown when this application declares no provider a person may connect individually' },\n { ref: 'connectButton', kind: LabelKind.BUTTON, purpose: 'Button that starts connecting the named third-party account, sending the person to that vendor to grant consent' },\n { ref: 'connectingButton', kind: LabelKind.BUTTON, purpose: 'Button caption while the authorization URL is being obtained, before the browser leaves for the vendor' },\n { ref: 'parametersHeading', kind: LabelKind.HEADING, purpose: 'Heading above the inputs a person must answer before connecting, such as which cloud or which directory their account lives in' },\n { ref: 'parametersDescription', kind: LabelKind.DESCRIPTION, purpose: 'Explains that these answers are facts about the account being connected and that the vendor’s own addresses cannot be built without them' },\n { ref: 'scopesPrefix', kind: LabelKind.LABEL, purpose: 'Prefix before the list of permissions the connection will ask the vendor for (e.g. \"Requests:\")' },\n { ref: 'connectedNotice', kind: LabelKind.MESSAGE, purpose: 'Confirmation shown after returning from a vendor where the account was connected successfully' },\n { ref: 'declinedNotice', kind: LabelKind.MESSAGE, purpose: 'Shown after returning from a vendor where the person chose not to grant access — a decision, not an error' },\n { ref: 'failedNotice', kind: LabelKind.MESSAGE, purpose: 'Shown after returning from a vendor when the connection attempt could not be completed and should be started again' },\n { ref: 'errorGeneric', kind: LabelKind.MESSAGE, purpose: 'Generic error shown when listing connectable providers or starting a connection fails' },\n { ref: 'errorNotAdmissible', kind: LabelKind.MESSAGE, purpose: 'Shown when this provider does not admit a personally-owned connection, so nobody may connect it individually' },\n { ref: 'errorForbidden', kind: LabelKind.MESSAGE, purpose: 'Shown when the person is not allowed to connect an account on behalf of the named owner' },\n { ref: 'disconnectNotice', kind: LabelKind.MESSAGE, purpose: 'Standing note explaining that removing a connection deletes this application\\u2019s copy of the authorization but does not withdraw it at the provider, and that the person should also remove the application in the provider\\u2019s own connected-applications settings if they want access ended there' },\n];\n\nregisterComponentLabels(FrontendComponentType.APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS, AppLayoutsConnectedAccountsSettingsLabels);\n"]}
1
+ {"version":3,"file":"AppPage_ConnectedAccountsSettings.labels.js","sourceRoot":"","sources":["../../../../src/components/settings/AppPage_ConnectedAccountsSettings.labels.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n FrontendComponentType,\n LabelKind,\n type LabellingUnitaryDef,\n registerComponentLabels,\n} from '@wildo-ai/presets-components-models';\n\n// Companion-only label metadata for the Connected-accounts panel: keys + kind + per-key purpose.\n// Statically scanned by the dev companion to generate the\n// `components.APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS.*` bundle; NOT imported at runtime, so it\n// never ships in the browser bundle. Keep in lock-step with the keys the component reads via\n// `tComponent(APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS, ...)`.\n//\n// LOCK-STEP DRIFTS SILENTLY IN BOTH DIRECTIONS, and on 2026-09-10 it had drifted both ways at once.\n// Nothing mechanical compares this array to the component's `t('...')` call sites, and neither\n// failure raises anything: a key the component reads and this array omits renders as its RAW KEY\n// PATH in the browser — visible only to somebody looking at the panel — while a key declared here\n// and never read costs a generated entry plus a translation round trip in every locale, and tells\n// the next reader the panel renders a message it does not. Five of each had accumulated before the\n// panel was first rendered. When you add or remove a `t('...')` call, edit this array in the same\n// change, and regenerate with\n// `wildo generate labels --units component:APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS --force`\n// followed by the matching `wildo generate translate`.\n//\n// `errorNotAdmissible` and `errorForbidden` were declared here and REMOVED on 2026-09-10 rather\n// than wired. The start route really does answer 409 CONNECTION_NOT_ADMISSIBLE and 403 FORBIDDEN\n// with those two distinct meanings — but this panel's catch does `if (isWildoBackendError(e)) throw\n// e`, so a structured backend refusal propagates to the global error handler and no branch in this\n// component can ever render either message. Reintroducing them is a real option and it is a\n// DECISION, not a cleanup: it means this panel stops re-throwing those two statuses and reports\n// them itself, which departs from the repository-wide convention that a `WildoBackendError`\n// belongs to the global handler. Declare them again in the same change that makes them reachable.\nexport const AppLayoutsConnectedAccountsSettingsLabels: LabellingUnitaryDef[] = [\n { ref: 'pageTitle', kind: LabelKind.HEADING, purpose: 'Heading for the panel where a person connects their own third-party accounts' },\n { ref: 'pageDescription', kind: LabelKind.DESCRIPTION, purpose: 'Sub-heading explaining that connecting an account lets this application act as that account on the person’s behalf, and that they can disconnect at any time' },\n { ref: 'loading', kind: LabelKind.MESSAGE, purpose: 'Shown while the list of connectable providers is being loaded' },\n { ref: 'empty', kind: LabelKind.MESSAGE, purpose: 'Shown when this application declares no provider a person may connect individually' },\n { ref: 'chooseProviderHeading', kind: LabelKind.HEADING, purpose: 'Heading above the control where somebody picks which third-party provider to connect' },\n { ref: 'choosePlaceholder', kind: LabelKind.LABEL, purpose: 'Placeholder shown in the provider chooser before anything is selected, inviting the person to pick a provider' },\n { ref: 'connectButton', kind: LabelKind.BUTTON, purpose: 'Button that starts connecting the named third-party account, sending the person to that vendor to grant consent' },\n { ref: 'connectingButton', kind: LabelKind.BUTTON, purpose: 'Button caption while the authorization URL is being obtained, before the browser leaves for the vendor' },\n { ref: 'delegationHeading', kind: LabelKind.HEADING, purpose: 'Heading above the control asking on whose behalf the connection will act — shown only for a provider that admits both a service identity and a user-delegated one at this scope' },\n { ref: 'delegationDescription', kind: LabelKind.DESCRIPTION, purpose: 'Explains that this provider can be connected either as the tenant itself or as the person acting, that these are two different accounts at the vendor, and that nobody may choose on the person’s behalf' },\n { ref: 'delegationPlaceholder', kind: LabelKind.LABEL, purpose: 'Placeholder in the on-whose-behalf chooser before either delegation is picked' },\n { ref: 'delegationServiceOption', kind: LabelKind.LABEL, purpose: 'Option naming the connection that acts as the organization or application itself, using a shared identity rather than any individual’s account' },\n { ref: 'delegationUserOption', kind: LabelKind.LABEL, purpose: 'Option naming the connection that acts as the individual person authorizing it, so anything it does at the vendor is attributed to them' },\n { ref: 'parametersHeading', kind: LabelKind.HEADING, purpose: 'Heading above the inputs a person must answer before connecting, such as which cloud or which directory their account lives in' },\n { ref: 'parametersDescription', kind: LabelKind.DESCRIPTION, purpose: 'Explains that these answers are facts about the account being connected and that the vendor’s own addresses cannot be built without them' },\n { ref: 'scopesPrefix', kind: LabelKind.LABEL, purpose: 'Prefix before the list of permissions the connection will ask the vendor for (e.g. \"Requests:\")' },\n { ref: 'credentialStoredNotice', kind: LabelKind.MESSAGE, purpose: 'Confirmation shown after a typed credential has been saved for a provider that has no authorization flow' },\n { ref: 'connectedNotice', kind: LabelKind.MESSAGE, purpose: 'Confirmation shown after returning from a vendor where the account was connected successfully' },\n { ref: 'declinedNotice', kind: LabelKind.MESSAGE, purpose: 'Shown after returning from a vendor where the person chose not to grant access — a decision, not an error' },\n { ref: 'failedNotice', kind: LabelKind.MESSAGE, purpose: 'Shown after returning from a vendor when the connection attempt could not be completed and should be started again' },\n { ref: 'errorGeneric', kind: LabelKind.MESSAGE, purpose: 'Generic error shown when listing connectable providers or starting a connection fails' },\n { ref: 'configurationGapsHeading', kind: LabelKind.HEADING, purpose: 'Heading of the block listing every provider whose application-level configuration is incomplete, shown before the chooser' },\n { ref: 'configurationGapsDescription', kind: LabelKind.DESCRIPTION, purpose: 'Explains that the providers listed below cannot be connected by anybody until an operator sets the named environment variables for this deployment, and that this is a configuration gap rather than a lack of support' },\n { ref: 'notRegisteredNotice', kind: LabelKind.MESSAGE, purpose: 'Explains that this application has not yet registered with the provider, so connecting is not possible until an operator creates an application at that vendor and configures its credentials — shown in place of the Connect button' },\n { ref: 'pastedCredentialNotice', kind: LabelKind.MESSAGE, purpose: 'Explains that this provider has no authorization flow because its credential is typed rather than granted, and points the person at the credentials tab' },\n { ref: 'disconnectNotice', kind: LabelKind.MESSAGE, purpose: 'Standing note explaining that removing a connection deletes this application\\u2019s copy of the authorization but does not withdraw it at the provider, and that the person should also remove the application in the provider\\u2019s own connected-applications settings if they want access ended there' },\n];\n\nregisterComponentLabels(FrontendComponentType.APP_LAYOUTS_CONNECTED_ACCOUNTS_SETTINGS, AppLayoutsConnectedAccountsSettingsLabels);\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"SettingsHub.d.ts","sourceRoot":"","sources":["../../../../src/components/settings/SettingsHub.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAoD,MAAM,OAAO,CAAC;AA+IzE,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAAE,UAAU,EAAE,EAAE,gBAAgB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA+F/E"}
1
+ {"version":3,"file":"SettingsHub.d.ts","sourceRoot":"","sources":["../../../../src/components/settings/SettingsHub.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAoD,MAAM,OAAO,CAAC;AAqJzE,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAAE,UAAU,EAAE,EAAE,gBAAgB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAoH/E"}
@@ -23,6 +23,7 @@ import { AppPage_SecuritySettings } from '../../components/auth/admin-config/App
23
23
  import { AppPage_AppearanceSettings } from './AppPage_AppearanceSettings.js';
24
24
  import { AppPage_InvitationsSettings } from './AppPage_InvitationsSettings.js';
25
25
  import { AppPage_BillingSettings } from './AppPage_BillingSettings.js';
26
+ import { ExternalProvider_Connection_OwnerScope } from '@wildo-ai/external-connectors-models';
26
27
  import { AppPage_ConnectedAccountsSettings } from './AppPage_ConnectedAccountsSettings.js';
27
28
  import { ComponentRegistryService } from '../../core/components-registry/component-registry.frontend.service.js';
28
29
  import { ComponentNotInjected } from '../../core/components-registry/ComponentNotInjected.js';
@@ -66,7 +67,12 @@ function SettingsEnginePanel({ panelRef }) {
66
67
  case SettingsPanelRef.BILLING:
67
68
  return _jsx(AppPage_BillingSettings, {});
68
69
  case SettingsPanelRef.CONNECTED_ACCOUNTS:
69
- return _jsx(AppPage_ConnectedAccountsSettings, {});
70
+ return _jsx(AppPage_ConnectedAccountsSettings, { ownerScope: ExternalProvider_Connection_OwnerScope.USER });
71
+ case SettingsPanelRef.ORGANIZATION_CONNECTED_ACCOUNTS:
72
+ // The scope is passed EXPLICITLY at both sites rather than left to the component's default.
73
+ // A default is invisible at the call site, and the one thing a reader must be able to see here
74
+ // is whose account each panel connects.
75
+ return _jsx(AppPage_ConnectedAccountsSettings, { ownerScope: ExternalProvider_Connection_OwnerScope.ORGANIZATION });
70
76
  }
71
77
  }
72
78
  function SettingsTargetRenderer({ target, resolveSubTabLabel, }) {
@@ -111,12 +117,30 @@ export function SettingsHub({ sectionRef }) {
111
117
  // required contract of `tSettingsHubCategory` / `tSettingsHubSection`).
112
118
  const t = useCallback((key) => tComponent(FrontendComponentType.APP_LAYOUTS_SETTINGS_HUB, key), [tComponent]);
113
119
  // Keep the rail in sync with URL-driven section changes (deep-link / browser
114
- // nav). setState bails out on an unchanged value, so this cannot loop.
120
+ // nav). Keyed on `sectionRef` ALONE — deliberately not on `config` as well.
121
+ // The gated config is derived from live signals (scope, roles, features,
122
+ // runtime capabilities), so its identity churns independently of its content;
123
+ // with `config` in the deps this ran after essentially every render and
124
+ // re-asserted the requested-or-default section, which overwrote the section
125
+ // the user had just clicked in the rail. The rail then looked inert: the
126
+ // click did select, and the effect immediately put it back.
115
127
  useEffect(() => {
116
- const next = resolveActiveSection(config, sectionRef);
117
- if (next)
118
- setActive(next);
119
- }, [config, sectionRef]);
128
+ if (!sectionRef)
129
+ return;
130
+ setActive(previous => (previous === sectionRef ? previous : sectionRef));
131
+ }, [sectionRef]);
132
+ // Adopt a section from the config ONLY when the current one is not (or is no
133
+ // longer) selectable — first resolve after an async gating signal lands, or a
134
+ // section disappearing because the user's roles/features changed. Anything
135
+ // broader would re-run the reset described above.
136
+ useEffect(() => {
137
+ setActive(previous => previous && config.sections.some(section => section.ref === previous)
138
+ ? previous
139
+ : resolveActiveSection(config, sectionRef));
140
+ // `sectionRef` is read as the fallback preference only; following ITS
141
+ // changes is the effect above.
142
+ // eslint-disable-next-line react-hooks/exhaustive-deps
143
+ }, [config]);
120
144
  // Gate on label readiness so the hub chrome never flashes raw key paths —
121
145
  // copy is pipeline-owned with no inline fallback, matching the hosted panels.
122
146
  if (!isReady)
@@ -1 +1 @@
1
- {"version":3,"file":"SettingsHub.js","sourceRoot":"","sources":["../../../../src/components/settings/SettingsHub.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * SettingsHub — the unified settings surface.\n *\n * Renders the declarative `ResolvedSettingsHubConfig` as a vertical `Tabs` rail beside a\n * content panel. Categories become labelled groups + separators rendered INSIDE\n * the `TabsList` (per the BetterStack reference) — the `Tabs` primitive stays the\n * section mechanism, so section state, keyboard roving, and `value`/\n * `onValueChange` all live on the primitive rather than a hand-rolled rail. A\n * section's `target` resolves to a framework panel, an auto-rendered resource\n * surface, a custom component, or a set of horizontal sub-tabs.\n *\n * Mounted by `NavigationContentRenderer` for `NavigationContentType.SETTINGS_HUB`\n * (always in the overlay zone). The `sectionRef` prop pre-selects the open\n * section and is kept in sync so URL-driven section changes re-select the rail.\n */\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport { DisplayDirection } from '@wildo-ai/zod-decorators';\nimport { CorePresetNames, FrontendComponentType } from '@wildo-ai/presets-components-models';\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '~wildo-frontend-lib/components/sections/tabs';\nimport { Separator } from '~wildo-frontend-lib/components/layout/separator';\nimport { AppPage_SecuritySettings } from '~wildo-frontend-lib/components/auth/admin-config/AppPage_SecuritySettings';\nimport { AppPage_AppearanceSettings } from './AppPage_AppearanceSettings';\nimport { AppPage_InvitationsSettings } from './AppPage_InvitationsSettings';\nimport { AppPage_BillingSettings } from './AppPage_BillingSettings';\nimport { AppPage_ConnectedAccountsSettings } from './AppPage_ConnectedAccountsSettings';\nimport { ComponentRegistryService } from '~wildo-frontend-lib/core/components-registry/component-registry.frontend.service';\nimport { ComponentNotInjected } from '~wildo-frontend-lib/core/components-registry/ComponentNotInjected';\nimport { SettingsPanelRef, SettingsSectionTargetKind } from '~wildo-frontend-lib/core/config/settings-hub.frontend.schemas';\nimport type {\n ResolvedSettingsHubConfig,\n SettingsCategory,\n SettingsSection,\n SettingsSectionTarget,\n SettingsSubTabsTarget,\n} from '~wildo-frontend-lib/core/config/settings-hub.frontend.schemas';\nimport { useVisibleSettingsHubConfig } from '~wildo-frontend-lib/core/config/useVisibleSettingsHubConfig';\nimport { useI18n } from '~wildo-frontend-lib/core/i18n/useI18n';\nimport { FeatureGate } from '~wildo-frontend-lib/core/features/FeatureGate';\nimport { SettingsResourceOperationPanel } from './SettingsResourceOperationPanel';\n\n// ──────────────────────────────────────────────────────────────\n// Config helpers\n// ──────────────────────────────────────────────────────────────\n\nfunction orderedCategories(config: ResolvedSettingsHubConfig): SettingsCategory[] {\n return [...config.categories].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\nfunction sectionsForCategory(config: ResolvedSettingsHubConfig, categoryRef: string): SettingsSection[] {\n return config.sections\n .filter(section => section.categoryRef === categoryRef)\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\n/** Resolve the section to open: requested → config default → first section. */\nfunction resolveActiveSection(config: ResolvedSettingsHubConfig, sectionRef?: string): string | undefined {\n if (sectionRef && config.sections.some(section => section.ref === sectionRef)) return sectionRef;\n if (config.defaultSectionRef && config.sections.some(section => section.ref === config.defaultSectionRef)) {\n return config.defaultSectionRef;\n }\n return config.sections[0]?.ref;\n}\n\n// ──────────────────────────────────────────────────────────────\n// Target rendering (function declarations → hoisted for mutual recursion\n// between a SUB_TABS target and its leaf targets)\n// ──────────────────────────────────────────────────────────────\n\nfunction SettingsEnginePanel({ panelRef }: { panelRef: SettingsPanelRef }): React.JSX.Element {\n switch (panelRef) {\n case SettingsPanelRef.SECURITY:\n return <AppPage_SecuritySettings />;\n case SettingsPanelRef.APPEARANCE:\n return <AppPage_AppearanceSettings />;\n case SettingsPanelRef.INVITATIONS:\n return <AppPage_InvitationsSettings />;\n case SettingsPanelRef.BILLING:\n return <AppPage_BillingSettings />;\n case SettingsPanelRef.CONNECTED_ACCOUNTS:\n return <AppPage_ConnectedAccountsSettings />;\n }\n}\n\n/** Resolves a display label for a section/sub-tab ref, falling back to the authored label. */\ntype SettingsLabelResolver = (ref: string, fallbackLabel: string) => string;\n\nfunction SettingsTargetRenderer({\n target,\n resolveSubTabLabel,\n}: {\n target: SettingsSectionTarget;\n resolveSubTabLabel: SettingsLabelResolver;\n}): React.JSX.Element {\n switch (target.kind) {\n case SettingsSectionTargetKind.ENGINE_PANEL:\n return <SettingsEnginePanel panelRef={target.panelRef} />;\n case SettingsSectionTargetKind.CUSTOM_COMPONENT: {\n const CustomComponent = ComponentRegistryService.resolve(\n target.componentRef as unknown as FrontendComponentType,\n CorePresetNames.DEFAULT,\n );\n if (!CustomComponent) {\n return <ComponentNotInjected componentType={target.componentRef} componentName={target.componentRef} />;\n }\n return (\n <React.Suspense fallback={<div className=\"h-8 animate-pulse motion-reduce:animate-none bg-muted rounded\" aria-hidden=\"true\" />}>\n <CustomComponent />\n </React.Suspense>\n );\n }\n case SettingsSectionTargetKind.RESOURCE_OPERATION:\n return (\n <SettingsResourceOperationPanel\n resourceType={target.resourceType}\n operation={target.operation}\n operationVariant={target.operationVariant}\n />\n );\n case SettingsSectionTargetKind.SUB_TABS:\n return <SettingsSubTabs target={target} resolveSubTabLabel={resolveSubTabLabel} />;\n }\n}\n\nfunction SettingsSubTabs({\n target,\n resolveSubTabLabel,\n}: {\n target: SettingsSubTabsTarget;\n resolveSubTabLabel: SettingsLabelResolver;\n}): React.JSX.Element | null {\n const [active, setActive] = useState<string | undefined>(target.subTabs[0]?.ref);\n if (target.subTabs.length === 0) return null;\n return (\n <Tabs value={active} onValueChange={setActive}>\n <TabsList>\n {target.subTabs.map(subTab => (\n // `data-ref` is the i18n-independent automation hook (labels are\n // runtime-translated; e2e drives must never key off them).\n <TabsTrigger key={subTab.ref} value={subTab.ref} data-ref={subTab.ref}>\n {resolveSubTabLabel(subTab.ref, subTab.label)}\n </TabsTrigger>\n ))}\n </TabsList>\n {target.subTabs.map(subTab => (\n <TabsContent key={subTab.ref} value={subTab.ref}>\n {/* Leaf targets only (schema forbids nested sub-tabs); the resolver is\n still threaded to satisfy the shared renderer signature. */}\n <SettingsTargetRenderer target={subTab.target} resolveSubTabLabel={resolveSubTabLabel} />\n </TabsContent>\n ))}\n </Tabs>\n );\n}\n\n// ──────────────────────────────────────────────────────────────\n// Hub\n// ──────────────────────────────────────────────────────────────\n\nexport interface SettingsHubProps {\n /** Section to pre-open; falls back to the config default. */\n sectionRef?: string;\n}\n\nexport function SettingsHub({ sectionRef }: SettingsHubProps): React.JSX.Element {\n const config = useVisibleSettingsHubConfig();\n const categories = useMemo(() => orderedCategories(config), [config]);\n const [active, setActive] = useState<string | undefined>(() => resolveActiveSection(config, sectionRef));\n\n const { tComponent, tSettingsHubCategory, tSettingsHubSection, isReady } = useI18n({\n component: FrontendComponentType.APP_LAYOUTS_SETTINGS_HUB,\n });\n // Hub chrome labels (title, rail aria-label) read from the scoped component\n // namespace. Copy is owned by the labelling pipeline (declared in the sibling\n // `.labels.ts`), so there are deliberately no inline fallback strings — the\n // hub gates on `isReady` below, the same convention as the panels it hosts\n // (`AppPage_SecuritySettings` / `AppPage_AppearanceSettings`). The dynamic\n // category/section labels keep their config-authored `fallbackLabel` (the\n // required contract of `tSettingsHubCategory` / `tSettingsHubSection`).\n const t = useCallback(\n (key: string) => tComponent(FrontendComponentType.APP_LAYOUTS_SETTINGS_HUB, key),\n [tComponent],\n );\n\n // Keep the rail in sync with URL-driven section changes (deep-link / browser\n // nav). setState bails out on an unchanged value, so this cannot loop.\n useEffect(() => {\n const next = resolveActiveSection(config, sectionRef);\n if (next) setActive(next);\n }, [config, sectionRef]);\n\n // Gate on label readiness so the hub chrome never flashes raw key paths —\n // copy is pipeline-owned with no inline fallback, matching the hosted panels.\n if (!isReady) return null;\n\n return (\n // `min-w-0` is REQUIRED: this is the grid item of the (fixed-width) dialog surface.\n // Without it the item keeps its default `min-width: auto` and cannot shrink below its\n // content's min-content width — a wide field row (e.g. a file card with a long\n // filename, or a text input) then pushes the whole two-pane body past the dialog edge,\n // and the dialog's `overflow-x: hidden` clips the right side of every field. `min-w-0`\n // lets the item fit the track so the content pane (and its form) reflow within it.\n <div className=\"flex h-full min-h-0 flex-col min-w-0\">\n <header className=\"flex h-14 shrink-0 items-center border-b px-card-lg\">\n <h2 className=\"text-base font-semibold tracking-tight\">{t('title')}</h2>\n </header>\n <Tabs\n orientation={DisplayDirection.VERTICAL}\n value={active}\n onValueChange={setActive}\n className=\"flex min-h-0 flex-1\"\n >\n <TabsList\n aria-label={t('sectionsNavLabel')}\n className=\"w-60 shrink-0 overflow-y-auto border-e px-card-sm py-card\"\n >\n {categories.map((category, index) => {\n const sections = sectionsForCategory(config, category.ref);\n if (sections.length === 0) return null;\n return (\n <React.Fragment key={category.ref}>\n {index > 0 && <Separator className=\"my-item\" />}\n <div\n role=\"presentation\"\n className=\"px-card-sm py-card-sm text-xs font-medium uppercase tracking-wider text-muted-foreground\"\n >\n {tSettingsHubCategory(category.ref, category.label)}\n </div>\n {sections.map(section => (\n // `data-ref` = i18n-independent automation hook (see sub-tabs above).\n <TabsTrigger key={section.ref} value={section.ref} data-ref={section.ref}>\n {tSettingsHubSection(section.ref, section.label)}\n </TabsTrigger>\n ))}\n </React.Fragment>\n );\n })}\n </TabsList>\n <div className=\"min-w-0 flex-1 overflow-y-auto p-card-lg\">\n {config.sections.map(section => (\n <TabsContent key={section.ref} value={section.ref} className=\"mt-0\">\n {section.entitlementFeatureId ? (\n // Section SURVIVED because the app OFFERS this feature\n // (`runtimeAvailability` capability = plan-independent\n // `isFeatureOffered`). Render its body through the entitlement gate:\n // entitled → the config surface; offered-but-not-entitled → the\n // policy-driven upgrade/add-on prompt (never a silent disappearance).\n <FeatureGate featureId={section.entitlementFeatureId}>\n <SettingsTargetRenderer target={section.target} resolveSubTabLabel={tSettingsHubSection} />\n </FeatureGate>\n ) : (\n <SettingsTargetRenderer target={section.target} resolveSubTabLabel={tSettingsHubSection} />\n )}\n </TabsContent>\n ))}\n </div>\n </Tabs>\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"SettingsHub.js","sourceRoot":"","sources":["../../../../src/components/settings/SettingsHub.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * SettingsHub — the unified settings surface.\n *\n * Renders the declarative `ResolvedSettingsHubConfig` as a vertical `Tabs` rail beside a\n * content panel. Categories become labelled groups + separators rendered INSIDE\n * the `TabsList` (per the BetterStack reference) — the `Tabs` primitive stays the\n * section mechanism, so section state, keyboard roving, and `value`/\n * `onValueChange` all live on the primitive rather than a hand-rolled rail. A\n * section's `target` resolves to a framework panel, an auto-rendered resource\n * surface, a custom component, or a set of horizontal sub-tabs.\n *\n * Mounted by `NavigationContentRenderer` for `NavigationContentType.SETTINGS_HUB`\n * (always in the overlay zone). The `sectionRef` prop pre-selects the open\n * section and is kept in sync so URL-driven section changes re-select the rail.\n */\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport { DisplayDirection } from '@wildo-ai/zod-decorators';\nimport { CorePresetNames, FrontendComponentType } from '@wildo-ai/presets-components-models';\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '~wildo-frontend-lib/components/sections/tabs';\nimport { Separator } from '~wildo-frontend-lib/components/layout/separator';\nimport { AppPage_SecuritySettings } from '~wildo-frontend-lib/components/auth/admin-config/AppPage_SecuritySettings';\nimport { AppPage_AppearanceSettings } from './AppPage_AppearanceSettings';\nimport { AppPage_InvitationsSettings } from './AppPage_InvitationsSettings';\nimport { AppPage_BillingSettings } from './AppPage_BillingSettings';\nimport { ExternalProvider_Connection_OwnerScope } from '@wildo-ai/external-connectors-models';\nimport { AppPage_ConnectedAccountsSettings } from './AppPage_ConnectedAccountsSettings';\nimport { ComponentRegistryService } from '~wildo-frontend-lib/core/components-registry/component-registry.frontend.service';\nimport { ComponentNotInjected } from '~wildo-frontend-lib/core/components-registry/ComponentNotInjected';\nimport { SettingsPanelRef, SettingsSectionTargetKind } from '~wildo-frontend-lib/core/config/settings-hub.frontend.schemas';\nimport type {\n ResolvedSettingsHubConfig,\n SettingsCategory,\n SettingsSection,\n SettingsSectionTarget,\n SettingsSubTabsTarget,\n} from '~wildo-frontend-lib/core/config/settings-hub.frontend.schemas';\nimport { useVisibleSettingsHubConfig } from '~wildo-frontend-lib/core/config/useVisibleSettingsHubConfig';\nimport { useI18n } from '~wildo-frontend-lib/core/i18n/useI18n';\nimport { FeatureGate } from '~wildo-frontend-lib/core/features/FeatureGate';\nimport { SettingsResourceOperationPanel } from './SettingsResourceOperationPanel';\n\n// ──────────────────────────────────────────────────────────────\n// Config helpers\n// ──────────────────────────────────────────────────────────────\n\nfunction orderedCategories(config: ResolvedSettingsHubConfig): SettingsCategory[] {\n return [...config.categories].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\nfunction sectionsForCategory(config: ResolvedSettingsHubConfig, categoryRef: string): SettingsSection[] {\n return config.sections\n .filter(section => section.categoryRef === categoryRef)\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\n/** Resolve the section to open: requested → config default → first section. */\nfunction resolveActiveSection(config: ResolvedSettingsHubConfig, sectionRef?: string): string | undefined {\n if (sectionRef && config.sections.some(section => section.ref === sectionRef)) return sectionRef;\n if (config.defaultSectionRef && config.sections.some(section => section.ref === config.defaultSectionRef)) {\n return config.defaultSectionRef;\n }\n return config.sections[0]?.ref;\n}\n\n// ──────────────────────────────────────────────────────────────\n// Target rendering (function declarations → hoisted for mutual recursion\n// between a SUB_TABS target and its leaf targets)\n// ──────────────────────────────────────────────────────────────\n\nfunction SettingsEnginePanel({ panelRef }: { panelRef: SettingsPanelRef }): React.JSX.Element {\n switch (panelRef) {\n case SettingsPanelRef.SECURITY:\n return <AppPage_SecuritySettings />;\n case SettingsPanelRef.APPEARANCE:\n return <AppPage_AppearanceSettings />;\n case SettingsPanelRef.INVITATIONS:\n return <AppPage_InvitationsSettings />;\n case SettingsPanelRef.BILLING:\n return <AppPage_BillingSettings />;\n case SettingsPanelRef.CONNECTED_ACCOUNTS:\n return <AppPage_ConnectedAccountsSettings ownerScope={ExternalProvider_Connection_OwnerScope.USER} />;\n case SettingsPanelRef.ORGANIZATION_CONNECTED_ACCOUNTS:\n // The scope is passed EXPLICITLY at both sites rather than left to the component's default.\n // A default is invisible at the call site, and the one thing a reader must be able to see here\n // is whose account each panel connects.\n return <AppPage_ConnectedAccountsSettings ownerScope={ExternalProvider_Connection_OwnerScope.ORGANIZATION} />;\n }\n}\n\n/** Resolves a display label for a section/sub-tab ref, falling back to the authored label. */\ntype SettingsLabelResolver = (ref: string, fallbackLabel: string) => string;\n\nfunction SettingsTargetRenderer({\n target,\n resolveSubTabLabel,\n}: {\n target: SettingsSectionTarget;\n resolveSubTabLabel: SettingsLabelResolver;\n}): React.JSX.Element {\n switch (target.kind) {\n case SettingsSectionTargetKind.ENGINE_PANEL:\n return <SettingsEnginePanel panelRef={target.panelRef} />;\n case SettingsSectionTargetKind.CUSTOM_COMPONENT: {\n const CustomComponent = ComponentRegistryService.resolve(\n target.componentRef as unknown as FrontendComponentType,\n CorePresetNames.DEFAULT,\n );\n if (!CustomComponent) {\n return <ComponentNotInjected componentType={target.componentRef} componentName={target.componentRef} />;\n }\n return (\n <React.Suspense fallback={<div className=\"h-8 animate-pulse motion-reduce:animate-none bg-muted rounded\" aria-hidden=\"true\" />}>\n <CustomComponent />\n </React.Suspense>\n );\n }\n case SettingsSectionTargetKind.RESOURCE_OPERATION:\n return (\n <SettingsResourceOperationPanel\n resourceType={target.resourceType}\n operation={target.operation}\n operationVariant={target.operationVariant}\n />\n );\n case SettingsSectionTargetKind.SUB_TABS:\n return <SettingsSubTabs target={target} resolveSubTabLabel={resolveSubTabLabel} />;\n }\n}\n\nfunction SettingsSubTabs({\n target,\n resolveSubTabLabel,\n}: {\n target: SettingsSubTabsTarget;\n resolveSubTabLabel: SettingsLabelResolver;\n}): React.JSX.Element | null {\n const [active, setActive] = useState<string | undefined>(target.subTabs[0]?.ref);\n if (target.subTabs.length === 0) return null;\n return (\n <Tabs value={active} onValueChange={setActive}>\n <TabsList>\n {target.subTabs.map(subTab => (\n // `data-ref` is the i18n-independent automation hook (labels are\n // runtime-translated; e2e drives must never key off them).\n <TabsTrigger key={subTab.ref} value={subTab.ref} data-ref={subTab.ref}>\n {resolveSubTabLabel(subTab.ref, subTab.label)}\n </TabsTrigger>\n ))}\n </TabsList>\n {target.subTabs.map(subTab => (\n <TabsContent key={subTab.ref} value={subTab.ref}>\n {/* Leaf targets only (schema forbids nested sub-tabs); the resolver is\n still threaded to satisfy the shared renderer signature. */}\n <SettingsTargetRenderer target={subTab.target} resolveSubTabLabel={resolveSubTabLabel} />\n </TabsContent>\n ))}\n </Tabs>\n );\n}\n\n// ──────────────────────────────────────────────────────────────\n// Hub\n// ──────────────────────────────────────────────────────────────\n\nexport interface SettingsHubProps {\n /** Section to pre-open; falls back to the config default. */\n sectionRef?: string;\n}\n\nexport function SettingsHub({ sectionRef }: SettingsHubProps): React.JSX.Element {\n const config = useVisibleSettingsHubConfig();\n const categories = useMemo(() => orderedCategories(config), [config]);\n const [active, setActive] = useState<string | undefined>(() => resolveActiveSection(config, sectionRef));\n\n const { tComponent, tSettingsHubCategory, tSettingsHubSection, isReady } = useI18n({\n component: FrontendComponentType.APP_LAYOUTS_SETTINGS_HUB,\n });\n // Hub chrome labels (title, rail aria-label) read from the scoped component\n // namespace. Copy is owned by the labelling pipeline (declared in the sibling\n // `.labels.ts`), so there are deliberately no inline fallback strings — the\n // hub gates on `isReady` below, the same convention as the panels it hosts\n // (`AppPage_SecuritySettings` / `AppPage_AppearanceSettings`). The dynamic\n // category/section labels keep their config-authored `fallbackLabel` (the\n // required contract of `tSettingsHubCategory` / `tSettingsHubSection`).\n const t = useCallback(\n (key: string) => tComponent(FrontendComponentType.APP_LAYOUTS_SETTINGS_HUB, key),\n [tComponent],\n );\n\n // Keep the rail in sync with URL-driven section changes (deep-link / browser\n // nav). Keyed on `sectionRef` ALONE — deliberately not on `config` as well.\n // The gated config is derived from live signals (scope, roles, features,\n // runtime capabilities), so its identity churns independently of its content;\n // with `config` in the deps this ran after essentially every render and\n // re-asserted the requested-or-default section, which overwrote the section\n // the user had just clicked in the rail. The rail then looked inert: the\n // click did select, and the effect immediately put it back.\n useEffect(() => {\n if (!sectionRef) return;\n setActive(previous => (previous === sectionRef ? previous : sectionRef));\n }, [sectionRef]);\n\n // Adopt a section from the config ONLY when the current one is not (or is no\n // longer) selectable — first resolve after an async gating signal lands, or a\n // section disappearing because the user's roles/features changed. Anything\n // broader would re-run the reset described above.\n useEffect(() => {\n setActive(previous =>\n previous && config.sections.some(section => section.ref === previous)\n ? previous\n : resolveActiveSection(config, sectionRef),\n );\n // `sectionRef` is read as the fallback preference only; following ITS\n // changes is the effect above.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [config]);\n\n // Gate on label readiness so the hub chrome never flashes raw key paths —\n // copy is pipeline-owned with no inline fallback, matching the hosted panels.\n if (!isReady) return null;\n\n return (\n // `min-w-0` is REQUIRED: this is the grid item of the (fixed-width) dialog surface.\n // Without it the item keeps its default `min-width: auto` and cannot shrink below its\n // content's min-content width — a wide field row (e.g. a file card with a long\n // filename, or a text input) then pushes the whole two-pane body past the dialog edge,\n // and the dialog's `overflow-x: hidden` clips the right side of every field. `min-w-0`\n // lets the item fit the track so the content pane (and its form) reflow within it.\n <div className=\"flex h-full min-h-0 flex-col min-w-0\">\n <header className=\"flex h-14 shrink-0 items-center border-b px-card-lg\">\n <h2 className=\"text-base font-semibold tracking-tight\">{t('title')}</h2>\n </header>\n <Tabs\n orientation={DisplayDirection.VERTICAL}\n value={active}\n onValueChange={setActive}\n className=\"flex min-h-0 flex-1\"\n >\n <TabsList\n aria-label={t('sectionsNavLabel')}\n className=\"w-60 shrink-0 overflow-y-auto border-e px-card-sm py-card\"\n >\n {categories.map((category, index) => {\n const sections = sectionsForCategory(config, category.ref);\n if (sections.length === 0) return null;\n return (\n <React.Fragment key={category.ref}>\n {index > 0 && <Separator className=\"my-item\" />}\n <div\n role=\"presentation\"\n className=\"px-card-sm py-card-sm text-xs font-medium uppercase tracking-wider text-muted-foreground\"\n >\n {tSettingsHubCategory(category.ref, category.label)}\n </div>\n {sections.map(section => (\n // `data-ref` = i18n-independent automation hook (see sub-tabs above).\n <TabsTrigger key={section.ref} value={section.ref} data-ref={section.ref}>\n {tSettingsHubSection(section.ref, section.label)}\n </TabsTrigger>\n ))}\n </React.Fragment>\n );\n })}\n </TabsList>\n <div className=\"min-w-0 flex-1 overflow-y-auto p-card-lg\">\n {config.sections.map(section => (\n <TabsContent key={section.ref} value={section.ref} className=\"mt-0\">\n {section.entitlementFeatureId ? (\n // Section SURVIVED because the app OFFERS this feature\n // (`runtimeAvailability` capability = plan-independent\n // `isFeatureOffered`). Render its body through the entitlement gate:\n // entitled → the config surface; offered-but-not-entitled → the\n // policy-driven upgrade/add-on prompt (never a silent disappearance).\n <FeatureGate featureId={section.entitlementFeatureId}>\n <SettingsTargetRenderer target={section.target} resolveSubTabLabel={tSettingsHubSection} />\n </FeatureGate>\n ) : (\n <SettingsTargetRenderer target={section.target} resolveSubTabLabel={tSettingsHubSection} />\n )}\n </TabsContent>\n ))}\n </div>\n </Tabs>\n </div>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"OnboardingView.d.ts","sourceRoot":"","sources":["../../../../../src/components/views/onboarding-view/OnboardingView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAA2D,MAAM,OAAO,CAAC;AAChF,OAAO,EAEL,gBAAgB,EAGhB,KAAK,qBAAqB,EAE3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kEAAkE,CAAC;AAqCjH,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,QAAQ,EAAE,wBAAwB,CAAC;IACnC,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACzC,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACxE,wCAAwC;IACxC,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;OAUG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAID,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA4YxD,CAAC"}
1
+ {"version":3,"file":"OnboardingView.d.ts","sourceRoot":"","sources":["../../../../../src/components/views/onboarding-view/OnboardingView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAA2D,MAAM,OAAO,CAAC;AAChF,OAAO,EAEL,gBAAgB,EAGhB,KAAK,qBAAqB,EAE3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kEAAkE,CAAC;AAqCjH,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,QAAQ,EAAE,wBAAwB,CAAC;IACnC,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACzC,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACxE,wCAAwC;IACxC,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;OAUG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAID,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAkZxD,CAAC"}
@@ -261,11 +261,18 @@ export const OnboardingView = ({ document: doc, options: optionsOverride = {}, c
261
261
  _jsx("button", { type: "button", onClick: handleBack, className: "px-card py-item text-[0.8125rem] font-medium text-muted-foreground bg-transparent border border-border rounded-md cursor-pointer motion-safe:transition-colors hover:bg-muted focus-ring-offset pointer-coarse:min-h-11", children: tComponent(FrontendComponentType.GUIDANCE_ONBOARDING_VIEW, 'back') })) }), _jsxs("div", { className: "flex gap-item items-center", children: [mergedOptions.allowSkip && (
262
262
  // V-5: candidate for Button/IconButton migration — see audit doc
263
263
  // (raw <button> reimplements GHOST recipe with non-ladder text-[0.8125rem])
264
- _jsx("button", { type: "button", onClick: handleSkip, className: "px-card-sm py-item text-[0.8125rem] font-medium text-muted-foreground/70 bg-transparent border-none cursor-pointer motion-safe:transition-colors hover:text-muted-foreground focus-ring-offset pointer-coarse:min-h-11", children: tComponent(FrontendComponentType.GUIDANCE_ONBOARDING_VIEW, 'skip') })), _jsx("button", { type: "button", onClick: handleNext, className: "px-card py-item text-[0.8125rem] font-medium text-primary-foreground bg-primary border-none rounded-md cursor-pointer motion-safe:transition-colors hover:bg-primary/90 focus-ring-offset pointer-coarse:min-h-11", children: currentStepIndex === totalSteps - 1
264
+ _jsx("button", { type: "button", onClick: handleSkip,
265
+ /*
266
+ * Quiet, but not below the contrast floor: at `text-muted-foreground/70` this
267
+ * composited to #7d899b on the light theme's #f8fafc — 3.38:1 where 4.5:1 is
268
+ * required (axe, live stack, 2026-09-09, #533). The full token is still visibly
269
+ * secondary to the primary action beside it.
270
+ */
271
+ className: "px-card-sm py-item text-[0.8125rem] font-medium text-muted-foreground bg-transparent border-none cursor-pointer motion-safe:transition-colors hover:text-muted-foreground focus-ring-offset pointer-coarse:min-h-11", children: tComponent(FrontendComponentType.GUIDANCE_ONBOARDING_VIEW, 'skip') })), _jsx("button", { type: "button", onClick: handleNext, className: "px-card py-item text-[0.8125rem] font-medium text-primary-foreground bg-primary border-none rounded-md cursor-pointer motion-safe:transition-colors hover:bg-primary/90 focus-ring-offset pointer-coarse:min-h-11", children: currentStepIndex === totalSteps - 1
265
272
  ? tComponent(FrontendComponentType.GUIDANCE_ONBOARDING_VIEW, 'complete')
266
273
  : tComponent(FrontendComponentType.GUIDANCE_ONBOARDING_VIEW, 'next') })] })] })), totalSteps === 1 && (_jsxs("div", { className: "flex justify-end gap-item items-center", children: [mergedOptions.allowDismiss && (
267
274
  // V-5: candidate for Button/IconButton migration — see audit doc
268
275
  // (raw <button> reimplements GHOST recipe with non-ladder text-[0.8125rem])
269
- _jsx("button", { type: "button", onClick: () => handleDismiss(currentElement.ref), className: "px-card-sm py-item text-[0.8125rem] font-medium text-muted-foreground/70 bg-transparent border-none cursor-pointer motion-safe:transition-colors hover:text-muted-foreground focus-ring-offset pointer-coarse:min-h-11", children: tComponent(FrontendComponentType.GUIDANCE_ONBOARDING_VIEW, 'dismiss') })), _jsx("button", { type: "button", onClick: handleNext, className: "px-card py-item text-[0.8125rem] font-medium text-primary-foreground bg-primary border-none rounded-md cursor-pointer motion-safe:transition-colors hover:bg-primary/90 focus-ring-offset pointer-coarse:min-h-11", children: tComponent(FrontendComponentType.GUIDANCE_ONBOARDING_VIEW, 'complete') })] }))] }));
276
+ _jsx("button", { type: "button", onClick: () => handleDismiss(currentElement.ref), className: "px-card-sm py-item text-[0.8125rem] font-medium text-muted-foreground bg-transparent border-none cursor-pointer motion-safe:transition-colors hover:text-muted-foreground focus-ring-offset pointer-coarse:min-h-11", children: tComponent(FrontendComponentType.GUIDANCE_ONBOARDING_VIEW, 'dismiss') })), _jsx("button", { type: "button", onClick: handleNext, className: "px-card py-item text-[0.8125rem] font-medium text-primary-foreground bg-primary border-none rounded-md cursor-pointer motion-safe:transition-colors hover:bg-primary/90 focus-ring-offset pointer-coarse:min-h-11", children: tComponent(FrontendComponentType.GUIDANCE_ONBOARDING_VIEW, 'complete') })] }))] }));
270
277
  };
271
278
  //# sourceMappingURL=OnboardingView.js.map