@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
@@ -70,7 +70,7 @@ export declare function DropdownMenuSeparator({ preset, ...props }: DropdownMenu
70
70
  export declare function DropdownMenuShortcut({ preset, ...props }: DropdownMenuShortcutProps & ComponentPresetProps): React.JSX.Element;
71
71
  export declare function DropdownMenuSub({ preset, ...props }: DropdownMenuSubProps & ComponentPresetProps): React.JSX.Element;
72
72
  export declare function DropdownMenuSubTrigger({ preset, ...props }: DropdownMenuSubTriggerProps & ComponentPresetProps): React.JSX.Element;
73
- export declare const DropdownMenuSubContent: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & Pick<FloatingMenuContentBaseProps, "loop" | "sideOffset" | "alignOffset" | "avoidCollisions" | "collisionPadding" | "arrowPadding"> & {
73
+ export declare const DropdownMenuSubContent: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & Pick<FloatingMenuContentBaseProps, "sideOffset" | "alignOffset" | "avoidCollisions" | "collisionPadding" | "arrowPadding" | "loop"> & {
74
74
  asChild?: boolean;
75
75
  forceMount?: boolean;
76
76
  onEscapeKeyDown?: (event: KeyboardEvent) => void;
@@ -85,7 +85,7 @@ export const ResourceLayout_FilterChips = ({ resourceType, filterFields, current
85
85
  else if (field.fieldType === 'boolean') {
86
86
  displayValue = value ? tc('booleanYes') : tc('booleanNo');
87
87
  }
88
- return (_jsxs("span", { className: "inline-flex items-center gap-1 ps-element-sm pe-1 py-0.5 rounded-full text-xs font-medium bg-muted text-muted-foreground", children: [_jsxs("span", { className: "text-muted-foreground/70", children: [label, ":"] }), displayValue, _jsx(Button, { type: "button", variant: ButtonVariants_Variant.GHOST, size: ButtonSize.ICON_SM, onClick: () => handleRemoveFilter(key), className: "ms-0.5 h-4 w-4 p-0", "aria-label": tc('removeFilter'), children: removeIcon })] }, key));
88
+ return (_jsxs("span", { className: "inline-flex items-center gap-1 ps-element-sm pe-1 py-0.5 rounded-full text-xs font-medium bg-muted text-muted-foreground", children: [_jsxs("span", { className: "text-muted-foreground", children: [label, ":"] }), displayValue, _jsx(Button, { type: "button", variant: ButtonVariants_Variant.GHOST, size: ButtonSize.ICON_SM, onClick: () => handleRemoveFilter(key), className: "ms-0.5 h-4 w-4 p-0", "aria-label": tc('removeFilter'), children: removeIcon })] }, key));
89
89
  }), _jsx(Button, { type: "button", variant: ButtonVariants_Variant.GHOST, size: ButtonSize.SM, onClick: handleClearAll, className: "text-xs text-muted-foreground", children: tc('clearAll') })] }));
90
90
  };
91
91
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceLayout_FilterChips.js","sourceRoot":"","sources":["../../../../src/components/resources/ResourceLayout_FilterChips.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * ResourceLayout_FilterChips — the active-filter summary row for a collection.\n *\n * Renders one removable chip per active filter (with the resolved label/value —\n * FK chips resolve the target resource's display label, never a raw id) plus a\n * \"Clear all\" action. Hidden entirely when no filters are active.\n *\n * Split out of `ResourceLayout_FiltersControl` so the collection toolbar can host\n * the compact Filters TRIGGER while the chips occupy their own row below the\n * toolbar — keeping the toolbar itself uncluttered. `FiltersControl` re-uses this\n * component for its legacy inline placement.\n */\n\nimport React, { useCallback, useMemo } from 'react';\nimport { useI18n } from '~wildo-frontend-lib/core/i18n/useI18n';\nimport { cn } from '~wildo-frontend-lib/core/ui/cn';\nimport { useIconRegistry } from '~wildo-frontend-lib/core/icons/useIconRegistry';\nimport { StandardIconReference, IconSize } from '~wildo-frontend-lib/core/icons/icon-registry.frontend.schemas';\nimport { Button, ButtonVariants_Variant } from '~wildo-frontend-lib/components/actions/button';\nimport { useResourceSearch } from '~wildo-frontend-lib/components/resources-fields/resource-reference/useResourceSearch';\nimport { FrontendComponentType, ButtonSize } from '@wildo-ai/presets-components-models';\nimport type { FilterFieldDefinition, FilterValues } from './ResourceLayout_FiltersControl';\n\nexport interface ResourceLayout_FilterChipsProps {\n /** Resource type for i18n label resolution. */\n resourceType: string;\n /** Filter field definitions (drives per-field type → chip value formatting). */\n filterFields: readonly FilterFieldDefinition[];\n /** Current active filters. */\n currentFilters: FilterValues;\n /** Callback when filters change (used to remove one / clear all). */\n onFiltersChange: (filters: FilterValues) => void;\n /** Additional CSS classes. */\n className?: string;\n}\n\nexport const ResourceLayout_FilterChips = ({\n resourceType,\n filterFields,\n currentFilters,\n onFiltersChange,\n className,\n}: ResourceLayout_FilterChipsProps): React.JSX.Element | null => {\n const { tResourceFieldDisplay, tResourceFieldEnumValue, tComponent, isReady } = useI18n({\n component: FrontendComponentType.RESOURCES_LAYOUTS_FILTERS,\n resource: resourceType,\n });\n const { renderIcon } = useIconRegistry();\n\n const tc = (key: string): string => tComponent(FrontendComponentType.RESOURCES_LAYOUTS_FILTERS, key);\n\n // Count/render ONLY the fields this row is responsible for — the panel's\n // `filterFields`. A collection's `currentFilters` also carries the PROMOTED\n // quick-filter field's value (shared filter state, deliberately excluded from\n // `filterFields` so the tab strip owns that field's active-state display).\n // Iterating `currentFilters` here surfaced that field as a redundant chip whose\n // label/value could not be resolved (no field definition ⇒ raw \"status:completed\"),\n // and disagreed with the (correctly scoped) Filters badge. Stay in lockstep with\n // the panel and the badge: a chip renders iff the field is a panel field.\n const activeFilterFields = useMemo(\n () => filterFields.filter(f => {\n const v = currentFilters[f.fieldName];\n return v !== undefined && v !== null && v !== '';\n }),\n [filterFields, currentFilters],\n );\n\n const fieldLabels = useMemo(() => {\n const labels: Record<string, string> = {};\n for (const field of filterFields) {\n const label = tResourceFieldDisplay(resourceType, field.fieldName, 'label');\n labels[field.fieldName] = typeof label === 'string' ? label : field.fieldName;\n }\n return labels;\n }, [filterFields, resourceType, tResourceFieldDisplay]);\n\n // Clear ONLY the panel's own fields; PRESERVE any filter value this row does not\n // represent — the promoted quick-filter field, whose tab strip owns its reset via\n // its own \"All\" segment. \"Clear all\" is a chips/panel affordance, so it must be\n // symmetric with the panel, chips, and count, which all scope to `filterFields`;\n // reaching into the promoted field would silently reset a separate, still-visible\n // control the chips row never showed — the mutation-side mirror of the count/chips\n // display leak. (Industry precedent: Shopify/Notion clear the filter bar without\n // changing the selected view/status tab.) For the self-contained callers whose\n // values already align 1:1 with `filterFields`, this still clears everything.\n const handleClearAll = useCallback(() => {\n const next = { ...currentFilters };\n for (const field of filterFields) delete next[field.fieldName];\n onFiltersChange(next);\n }, [currentFilters, filterFields, onFiltersChange]);\n const handleRemoveFilter = useCallback((fieldName: string) => {\n const next = { ...currentFilters };\n delete next[fieldName];\n onFiltersChange(next);\n }, [currentFilters, onFiltersChange]);\n\n if (!isReady || activeFilterFields.length === 0) return null;\n\n const removeIcon = renderIcon(StandardIconReference.X_MARK, { size: IconSize.XS });\n\n return (\n <div className={cn('flex items-center gap-element-sm flex-wrap', className)}>\n {activeFilterFields.map((field) => {\n const key = field.fieldName;\n const value = currentFilters[key];\n const label = fieldLabels[key] || key;\n\n let displayValue: React.ReactNode = String(value);\n if (field.fieldType === 'reference') {\n displayValue = <ReferenceFilterChipValue field={field} value={String(value)} />;\n } else if (field.fieldType === 'enum') {\n const enumLabel = tResourceFieldEnumValue(resourceType, key, String(value));\n if (typeof enumLabel === 'string') displayValue = enumLabel;\n } else if (field.fieldType === 'boolean') {\n displayValue = value ? tc('booleanYes') : tc('booleanNo');\n }\n\n return (\n <span\n key={key}\n className=\"inline-flex items-center gap-1 ps-element-sm pe-1 py-0.5 rounded-full text-xs font-medium bg-muted text-muted-foreground\"\n >\n <span className=\"text-muted-foreground/70\">{label}:</span>\n {displayValue}\n <Button\n type=\"button\"\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.ICON_SM}\n onClick={() => handleRemoveFilter(key)}\n className=\"ms-0.5 h-4 w-4 p-0\"\n aria-label={tc('removeFilter')}\n >\n {removeIcon}\n </Button>\n </span>\n );\n })}\n <Button\n type=\"button\"\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n onClick={handleClearAll}\n className=\"text-xs text-muted-foreground\"\n >\n {tc('clearAll')}\n </Button>\n </div>\n );\n};\n\n// =============================================================================\n// REFERENCE FILTER CHIP VALUE — resolves an FK id to its display label\n// =============================================================================\n\ninterface ReferenceFilterChipValueProps {\n field: FilterFieldDefinition;\n value: string;\n}\n\n/**\n * Chip text for an active reference filter. Reuses `useResourceSearch`'s\n * current-value label resolution (READ on the target resource +\n * `getFrontendResourceLabel`); the only network activity is the one label READ,\n * cached for the chip's lifetime (a chip never opens the dropdown).\n */\nconst ReferenceFilterChipValue: React.FC<ReferenceFilterChipValueProps> = ({ field, value }) => {\n const { getDisplayLabel, isLoadingCurrentValue } = useResourceSearch({\n schema: field.schema,\n name: field.fieldName,\n value,\n targetResourceType: field.referenceTargetResourceType,\n });\n\n if (isLoadingCurrentValue) return <>…</>;\n return <>{getDisplayLabel(value)}</>;\n};\n"]}
1
+ {"version":3,"file":"ResourceLayout_FilterChips.js","sourceRoot":"","sources":["../../../../src/components/resources/ResourceLayout_FilterChips.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * ResourceLayout_FilterChips — the active-filter summary row for a collection.\n *\n * Renders one removable chip per active filter (with the resolved label/value —\n * FK chips resolve the target resource's display label, never a raw id) plus a\n * \"Clear all\" action. Hidden entirely when no filters are active.\n *\n * Split out of `ResourceLayout_FiltersControl` so the collection toolbar can host\n * the compact Filters TRIGGER while the chips occupy their own row below the\n * toolbar — keeping the toolbar itself uncluttered. `FiltersControl` re-uses this\n * component for its legacy inline placement.\n */\n\nimport React, { useCallback, useMemo } from 'react';\nimport { useI18n } from '~wildo-frontend-lib/core/i18n/useI18n';\nimport { cn } from '~wildo-frontend-lib/core/ui/cn';\nimport { useIconRegistry } from '~wildo-frontend-lib/core/icons/useIconRegistry';\nimport { StandardIconReference, IconSize } from '~wildo-frontend-lib/core/icons/icon-registry.frontend.schemas';\nimport { Button, ButtonVariants_Variant } from '~wildo-frontend-lib/components/actions/button';\nimport { useResourceSearch } from '~wildo-frontend-lib/components/resources-fields/resource-reference/useResourceSearch';\nimport { FrontendComponentType, ButtonSize } from '@wildo-ai/presets-components-models';\nimport type { FilterFieldDefinition, FilterValues } from './ResourceLayout_FiltersControl';\n\nexport interface ResourceLayout_FilterChipsProps {\n /** Resource type for i18n label resolution. */\n resourceType: string;\n /** Filter field definitions (drives per-field type → chip value formatting). */\n filterFields: readonly FilterFieldDefinition[];\n /** Current active filters. */\n currentFilters: FilterValues;\n /** Callback when filters change (used to remove one / clear all). */\n onFiltersChange: (filters: FilterValues) => void;\n /** Additional CSS classes. */\n className?: string;\n}\n\nexport const ResourceLayout_FilterChips = ({\n resourceType,\n filterFields,\n currentFilters,\n onFiltersChange,\n className,\n}: ResourceLayout_FilterChipsProps): React.JSX.Element | null => {\n const { tResourceFieldDisplay, tResourceFieldEnumValue, tComponent, isReady } = useI18n({\n component: FrontendComponentType.RESOURCES_LAYOUTS_FILTERS,\n resource: resourceType,\n });\n const { renderIcon } = useIconRegistry();\n\n const tc = (key: string): string => tComponent(FrontendComponentType.RESOURCES_LAYOUTS_FILTERS, key);\n\n // Count/render ONLY the fields this row is responsible for — the panel's\n // `filterFields`. A collection's `currentFilters` also carries the PROMOTED\n // quick-filter field's value (shared filter state, deliberately excluded from\n // `filterFields` so the tab strip owns that field's active-state display).\n // Iterating `currentFilters` here surfaced that field as a redundant chip whose\n // label/value could not be resolved (no field definition ⇒ raw \"status:completed\"),\n // and disagreed with the (correctly scoped) Filters badge. Stay in lockstep with\n // the panel and the badge: a chip renders iff the field is a panel field.\n const activeFilterFields = useMemo(\n () => filterFields.filter(f => {\n const v = currentFilters[f.fieldName];\n return v !== undefined && v !== null && v !== '';\n }),\n [filterFields, currentFilters],\n );\n\n const fieldLabels = useMemo(() => {\n const labels: Record<string, string> = {};\n for (const field of filterFields) {\n const label = tResourceFieldDisplay(resourceType, field.fieldName, 'label');\n labels[field.fieldName] = typeof label === 'string' ? label : field.fieldName;\n }\n return labels;\n }, [filterFields, resourceType, tResourceFieldDisplay]);\n\n // Clear ONLY the panel's own fields; PRESERVE any filter value this row does not\n // represent — the promoted quick-filter field, whose tab strip owns its reset via\n // its own \"All\" segment. \"Clear all\" is a chips/panel affordance, so it must be\n // symmetric with the panel, chips, and count, which all scope to `filterFields`;\n // reaching into the promoted field would silently reset a separate, still-visible\n // control the chips row never showed — the mutation-side mirror of the count/chips\n // display leak. (Industry precedent: Shopify/Notion clear the filter bar without\n // changing the selected view/status tab.) For the self-contained callers whose\n // values already align 1:1 with `filterFields`, this still clears everything.\n const handleClearAll = useCallback(() => {\n const next = { ...currentFilters };\n for (const field of filterFields) delete next[field.fieldName];\n onFiltersChange(next);\n }, [currentFilters, filterFields, onFiltersChange]);\n const handleRemoveFilter = useCallback((fieldName: string) => {\n const next = { ...currentFilters };\n delete next[fieldName];\n onFiltersChange(next);\n }, [currentFilters, onFiltersChange]);\n\n if (!isReady || activeFilterFields.length === 0) return null;\n\n const removeIcon = renderIcon(StandardIconReference.X_MARK, { size: IconSize.XS });\n\n return (\n <div className={cn('flex items-center gap-element-sm flex-wrap', className)}>\n {activeFilterFields.map((field) => {\n const key = field.fieldName;\n const value = currentFilters[key];\n const label = fieldLabels[key] || key;\n\n let displayValue: React.ReactNode = String(value);\n if (field.fieldType === 'reference') {\n displayValue = <ReferenceFilterChipValue field={field} value={String(value)} />;\n } else if (field.fieldType === 'enum') {\n const enumLabel = tResourceFieldEnumValue(resourceType, key, String(value));\n if (typeof enumLabel === 'string') displayValue = enumLabel;\n } else if (field.fieldType === 'boolean') {\n displayValue = value ? tc('booleanYes') : tc('booleanNo');\n }\n\n return (\n <span\n key={key}\n className=\"inline-flex items-center gap-1 ps-element-sm pe-1 py-0.5 rounded-full text-xs font-medium bg-muted text-muted-foreground\"\n >\n <span className=\"text-muted-foreground\">{label}:</span>\n {displayValue}\n <Button\n type=\"button\"\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.ICON_SM}\n onClick={() => handleRemoveFilter(key)}\n className=\"ms-0.5 h-4 w-4 p-0\"\n aria-label={tc('removeFilter')}\n >\n {removeIcon}\n </Button>\n </span>\n );\n })}\n <Button\n type=\"button\"\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n onClick={handleClearAll}\n className=\"text-xs text-muted-foreground\"\n >\n {tc('clearAll')}\n </Button>\n </div>\n );\n};\n\n// =============================================================================\n// REFERENCE FILTER CHIP VALUE — resolves an FK id to its display label\n// =============================================================================\n\ninterface ReferenceFilterChipValueProps {\n field: FilterFieldDefinition;\n value: string;\n}\n\n/**\n * Chip text for an active reference filter. Reuses `useResourceSearch`'s\n * current-value label resolution (READ on the target resource +\n * `getFrontendResourceLabel`); the only network activity is the one label READ,\n * cached for the chip's lifetime (a chip never opens the dropdown).\n */\nconst ReferenceFilterChipValue: React.FC<ReferenceFilterChipValueProps> = ({ field, value }) => {\n const { getDisplayLabel, isLoadingCurrentValue } = useResourceSearch({\n schema: field.schema,\n name: field.fieldName,\n value,\n targetResourceType: field.referenceTargetResourceType,\n });\n\n if (isLoadingCurrentValue) return <>…</>;\n return <>{getDisplayLabel(value)}</>;\n};\n"]}
@@ -58,7 +58,7 @@ export function FieldValueRenderer({ fieldName, value, fieldSchema, fieldLabel,
58
58
  }, [fieldSchema, resourceType, fieldName, tResourceFieldEnumValue]);
59
59
  if (value === null || value === undefined)
60
60
  return null;
61
- return (_jsxs("div", { className: "flex min-w-0 items-baseline gap-element-sm", children: [fieldLabel && _jsxs("span", { className: "text-xs text-muted-foreground/70", children: [fieldLabel, ":"] }), fieldSchema ? (
61
+ return (_jsxs("div", { className: "flex min-w-0 items-baseline gap-element-sm", children: [fieldLabel && _jsxs("span", { className: "text-xs text-muted-foreground", children: [fieldLabel, ":"] }), fieldSchema ? (
62
62
  // COMPACT chrome → bare value with the full decorator policy applied.
63
63
  _jsx(DisplayChromeProvider, { displayChromeMode: DisplayChromeMode.COMPACT, children: _jsx(DisplayField, { name: fieldName, schema: fieldSchema, value: value, enumLabels: enumLabels, disableInlineEdit: true, className: "min-w-0 truncate text-sm text-muted-foreground" }) })) : (
64
64
  // No schema resolved for this field — `DisplayField` requires a schema,
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceListItemRenderer.js","sourceRoot":"","sources":["../../../../src/components/resources/ResourceListItemRenderer.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,EAAE,OAAO,EAAe,MAAM,OAAO,CAAC;AAEpD,OAAO,EAGL,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAChI,OAAO,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,uDAAuD,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,0DAA0D,CAAC;AACxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0EAA0E,CAAC;AACjH,OAAO,EAAE,wBAAwB,EAAE,MAAM,sEAAsE,CAAC;AAChH,OAAO,EAAE,IAAI,EAAE,MAAM,gDAAgD,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAyB,MAAM,4DAA4D,CAAC;AAC1H,OAAO,EAAE,4BAA4B,EAAE,MAAM,2EAA2E,CAAC;AAEzH,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,+DAA+D,CAAC;AAE7F,OAAO,EAAE,iCAAiC,EAAE,MAAM,+BAA+B,CAAC;AAuElF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,SAAS,EACT,KAAK,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,uBAAuB,GACC;IACxB,wEAAwE;IACxE,2EAA2E;IAC3E,yEAAyE;IACzE,MAAM,UAAU,GAAG,OAAO,CAAqC,GAAG,EAAE;QAClE,IAAI,CAAC,WAAW,IAAI,aAAa,CAAC,WAAW,CAAC,KAAK,eAAe,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC;QAC1F,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC9C,OAAO,MAAM,CAAC,WAAW,CACvB,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,uBAAuB,CAAC,YAAY,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,CACxG,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,uBAAuB,CAAC,CAAC,CAAC;IAEpE,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAEvD,OAAO,CACL,eAAK,SAAS,EAAC,4CAA4C,aACxD,UAAU,IAAI,gBAAM,SAAS,EAAC,kCAAkC,aAAE,UAAU,SAAS,EACrF,WAAW,CAAC,CAAC,CAAC;YACb,sEAAsE;YACtE,KAAC,qBAAqB,IAAC,iBAAiB,EAAE,iBAAiB,CAAC,OAAO,YACjE,KAAC,YAAY,IACX,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,UAAU,EACtB,iBAAiB,QACjB,SAAS,EAAC,gDAAgD,GAC1D,GACoB,CACzB,CAAC,CAAC,CAAC;YACF,wEAAwE;YACxE,wEAAwE;YACxE,eAAM,SAAS,EAAC,gDAAgD,YAAE,MAAM,CAAC,KAAK,CAAC,GAAQ,CACxF,IACG,CACP,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF,MAAM,UAAU,wBAAwB,CAAC,EACvC,IAAI,EACJ,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,aAAa,EACb,cAAc,EACd,uBAAuB,EACvB,WAAW,EACX,cAAc,EACd,mBAAmB,EACnB,UAAU,GAAG,KAAK,EAClB,UAAU,GAAG,KAAK,EAClB,cAAc,EACd,eAAe,GAAG,KAAK,EACvB,eAAe,EACf,SAAS,EACT,kBAAkB,GACY;IAC9B,IAAI,CAAC,cAAc,EAAE,uBAAuB,EAAE,CAAC;QAC7C,MAAM,qBAAqB,CAAC,uBAAuB,CACjD,2BAA2B,CAAC,4CAA4C,EACxE,EAAE,YAAY,EAAE,SAAS,EAAE,0BAA0B,EAAE,CACxD,CAAC;IACJ,CAAC;IACD,MAAM,eAAe,GAAG,cAAc,CAAC,uBAAiC,CAAC;IACzE,+EAA+E;IAC/E,kEAAkE;IAClE,6CAA6C;IAC7C,MAAM,MAAM,GAAG,qBAAqB,CAAC,mBAAmB,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAEhF,2EAA2E;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,MAAM,YAAY,GAAG,OAAO,CAAC,GAAW,EAAE;QACxC,MAAM,KAAK,GAAG,qBAAqB,CAAC,4BAA4B,CAAC;YAC/D,YAAY;YACZ,QAAQ;YACR,aAAa,EAAE,IAAI;SACpB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,YAAY,KAAK,MAAM,EAAE,CAAC,CAAC;IACjF,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;IAE1D,4EAA4E;IAC5E,6EAA6E;IAC7E,uEAAuE;IACvE,gFAAgF;IAChF,4EAA4E;IAC5E,+EAA+E;IAC/E,+EAA+E;IAC/E,+EAA+E;IAC/E,2EAA2E;IAC3E,6EAA6E;IAC7E,+CAA+C;IAC/C,wEAAwE;IACxE,MAAM,eAAe,GAAG,OAAO,CAC7B,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;QAC9B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QACxD,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,YAAY,CAAC;IACxC,CAAC,CAAC,EACF,CAAC,aAAa,EAAE,IAAI,EAAE,YAAY,CAAC,CACpC,CAAC;IAEF,wCAAwC;IACxC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE;QAC/B,MAAM,UAAU,GAAG,cAAc,EAAE,UAAU,CAAC;QAC9C,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAC7B,mKAAmK;QACnK,OAAO,4BAA4B,CAAC,uBAAuB,CAAC,UAAU,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC;IACzG,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;IAErB,8EAA8E;IAC9E,+EAA+E;IAC/E,iFAAiF;IACjF,iFAAiF;IACjF,8EAA8E;IAC9E,iFAAiF;IACjF,+EAA+E;IAC/E,8DAA8D;IAC9D,EAAE;IACF,4EAA4E;IAC5E,0EAA0E;IAC1E,yEAAyE;IACzE,MAAM,uBAAuB,GAAG,cAAc,EAAE,qBAAqB,EAAE,MAAM,EAAE,OAAO,CAAC;IAEvF,MAAM,UAAU,GAAG,kBAAkB,EAAE,KAAK,IAAI,EAAE,CAAC;IACnD,MAAM,eAAe,GAAG,kBAAkB,EAAE,UAAU,IAAI,EAAE,CAAC;IAC7D,6EAA6E;IAC7E,4EAA4E;IAC5E,MAAM,SAAS,GAAG,iCAAiC,CAAC,mBAAmB,CAAC,CAAC;IAEzE,+EAA+E;IAC/E,0EAA0E;IAC1E,6EAA6E;IAC7E,6EAA6E;IAC7E,iDAAiD;IACjD,+EAA+E;IAC/E,yEAAyE;IACzE,qEAAqE;IACrE,MAAM,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,EAAE,EAAE,QAAQ,EAAE,iBAAiB,KAAK,kBAAkB,CAAC,MAAM,CAAC;IAC/E,MAAM,mBAAmB,GAAG,UAAU,IAAI,eAAe,IAAI,QAAQ,CAAC;IACtE,+EAA+E;IAC/E,+EAA+E;IAC/E,yEAAyE;IACzE,MAAM,SAAS,GAAG,YAAY,CAC5B,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,EAC5B,EAAE,OAAO,EAAE,UAAU,IAAI,CAAC,CAAC,cAAc,IAAI,QAAQ,EAAE,CACxD,CAAC;IAEF,MAAM,cAAc,GAAG,GAAG,EAAE;QAC1B,+EAA+E;QAC/E,IAAI,SAAS,CAAC,gBAAgB,EAAE;YAAE,OAAO;QACzC,IAAI,mBAAmB,EAAE,CAAC;YACxB,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC,CAAC;IAEF,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CACX,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EACvD,UAAU,IAAI,cAAc;QAC5B,oEAAoE;QACpE,UAAU,IAAI,aAAa,EAC3B,SAAS,CACV,EACD,OAAO,EAAE,cAAc,EACvB,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,CAAC,gBACC,MAAM,CAAC,YAAY,CAAC,KAC5B,SAAS,CAAC,QAAQ;QACtB,0EAA0E;QAC1E,yEAAyE;QACzE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;YACf,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBACvC,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,IAAI,mBAAmB,EAAE,CAAC;oBACxB,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC;gBACzB,CAAC;qBAAM,CAAC;oBACN,WAAW,CAAC,IAAI,CAAC,CAAC;gBACpB,CAAC;YACH,CAAC;QACH,CAAC,YAKD,eAAK,SAAS,EAAC,iCAAiC,aAK7C,UAAU,IAAI,CACb,cACE,SAAS,EAAC,iBAAiB,EAC3B,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,EACnC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,EACrC,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,YAExC,KAAC,YAAY,IACX,OAAO,EAAE,UAAU,EACnB,eAAe,EAAE,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,gBACjC,eAAe,IAAI,MAAM,CAAC,YAAY,CAAC,GACnD,GACE,CACP,EACD,eAAK,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,gBAAgB,CAAC,aAC5D,cAAK,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,YAAY,CAAC,YAC1D,uBAAuB,IAAI,cAAc,EAAE,UAAU,CAAC,CAAC,CAAC;4BACvD,4DAA4D;4BAC5D,mEAAmE;4BACnE,mEAAmE;4BACnE,sEAAsE;4BACtE,qEAAqE;4BACrE,+CAA+C;4BAC/C,KAAC,wBAAwB,IACvB,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,cAAc,CAAC,UAAU,EACjC,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,YAAY,GAC1B,CACH,CAAC,CAAC,CAAC,CACF,8BACE,KAAC,IAAI,IAAC,EAAE,EAAC,GAAG,EAAC,SAAS,EAAC,6BAA6B,EAAC,QAAQ,kBAAE,YAAY,GAAQ,EAClF,eAAe,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE;wCACjC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;wCAC9B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;4CAAE,OAAO,IAAI,CAAC;wCACvD,OAAO,CACL,wBACE,KAAC,kBAAkB,IACjB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW,EAAE,CAAC,SAAS,CAA6B,EACjE,UAAU,EAAE,cAAc,CAAC,SAAS,CAAC,EACrC,YAAY,EAAE,YAAY,EAC1B,uBAAuB,EAAE,uBAAuB,GAChD,IARM,SAAS,CASb,CACP,CAAC;oCACJ,CAAC,CAAC,IACD,CACJ,GACG,EACL,cAAc,IAAI;wBACjB,qEAAqE;wBACrE,sEAAsE;wBACtE,sEAAsE;wBACtE,mCAAmC;wBACnC,cACE,SAAS,EAAE,SAAS,CAAC,YAAY,EACjC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,EACnC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,EACrC,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,YAEvC,cAAc,GACX,CACP,IACG,IACF,GACF,CACP,CAAC;AACJ,CAAC","sourcesContent":["/**\n * ResourceListItemRenderer\n *\n * Shared item renderer for List and Search presets.\n * Encapsulates schema-aware field rendering (FK, enum, date, array),\n * primary/secondary field split, and per-item operations.\n *\n * Used by List_Default and Search_Default to ensure parity in how\n * resource items are displayed.\n */\n\nimport React, { useMemo, useCallback } from 'react';\nimport { z } from 'zod';\nimport {\n CoreResourceOperation,\n ResourceOperationDisplayMode,\n ErrorCustomMessageReference,\n} from '@wildo-ai/saas-models';\nimport type { AnyFrontendResourceConfiguration, FrontendResourcesRegistry } from '~wildo-frontend-lib/core/resources/resources.frontend.schemas';\nimport { getSchemaType, FieldSchemaType, getEnumValues, DisplayChromeMode, ViewportBreakpoint } from '@wildo-ai/zod-decorators';\nimport { UIContext } from '~wildo-frontend-lib/core/ui/UIContext';\nimport { useLongPress } from '~wildo-frontend-lib/components/resources/useLongPress';\nimport { DisplayField } from '~wildo-frontend-lib/components/data-display/DisplayField';\nimport { DisplayChromeProvider } from '~wildo-frontend-lib/components/data-display/chromes/DisplayChromeContext';\nimport { ResourceSummaryDisplayer } from '~wildo-frontend-lib/components/data-display/ResourceSummaryDisplayer';\nimport { Text } from '~wildo-frontend-lib/components/typography/text';\nimport { FrontendResourceUtils, frontendResourceUtils } from '~wildo-frontend-lib/core/resources/frontend-resource.utils';\nimport { AutomatedLayoutFrontendUtils } from '~wildo-frontend-lib/core/automated-layout/automated-layout.frontend.utils';\nimport type { FrontendResourceOperationContext } from '~wildo-frontend-lib/core/resources/resources.frontend.schemas';\nimport { cn } from '~wildo-frontend-lib/core/ui/cn';\nimport { CheckboxRoot } from '~wildo-frontend-lib/components/form/controls/boolean/checkbox';\nimport type { CardActionPlacement } from '~wildo-frontend-lib/core/resources/resources.frontend.schemas';\nimport { resolveCardActionPlacementClasses } from './card-action-placement.utils';\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface ResourceListItemRendererProps {\n /** The data item to render */\n item: Record<string, unknown>;\n /** Resource type */\n resourceType: string;\n /** Resource configuration */\n resourceConfig: AnyFrontendResourceConfiguration;\n /** Resource registry */\n registry: FrontendResourcesRegistry;\n /** Ordered list of summary fields to display */\n summaryFields: string[];\n /** Pre-resolved field labels (from i18n) */\n fieldLabelsMap: Record<string, string>;\n /** Function to resolve enum display values via i18n */\n tResourceFieldEnumValue: (resourceType: string, fieldName: string, enumValue: string) => string;\n /** Click handler when the item row is clicked */\n onItemClick: (item: Record<string, unknown>) => void;\n /** Optional operations component to render for this item */\n operationsSlot?: React.ReactNode;\n /**\n * Where the per-item operations sit within the card (2-axis anchor +\n * orientation). Resolved by the host from `collectionDisplayConfig.cardActionPlacement`.\n * Omitted → the default (inline-end, vertically centered, horizontal row).\n */\n cardActionPlacement?: CardActionPlacement;\n /**\n * Selection affordance. When `selectable`, a leading checkbox renders and\n * toggles selection via `onToggleSelect` (independent of the row click, which\n * still navigates). `isSelected` drives the checkbox + a selected highlight.\n */\n selectable?: boolean;\n isSelected?: boolean;\n onToggleSelect?: (item: Record<string, unknown>) => void;\n /**\n * Whether the collection is currently in SELECTION MODE (any item selected).\n * Mobile UX: a long-press enters selection mode, and while active a plain TAP\n * toggles selection instead of navigating (the \"long-press to multi-select\"\n * pattern). Gated to touch/mobile — on desktop a click always navigates and\n * the checkbox is the explicit toggle.\n */\n selectionActive?: boolean;\n /** Accessible label for the selection checkbox (host provides the i18n string). */\n selectAriaLabel?: string;\n /** Optional className for the root container */\n className?: string;\n /** Interactive CSS classes from design system (hover state, transition) */\n interactiveClasses?: {\n hover?: string;\n transition?: string;\n };\n}\n\n// =============================================================================\n// FIELD VALUE RENDERER\n// =============================================================================\n\nexport interface FieldValueRendererProps {\n fieldName: string;\n value: unknown;\n fieldSchema: z.ZodTypeAny | undefined;\n fieldLabel: string | undefined;\n resourceType: string;\n tResourceFieldEnumValue: (resourceType: string, fieldName: string, enumValue: string) => string;\n}\n\n/**\n * Renders a single summary field VALUE through the shared decorator-driven\n * display pipeline (`DisplayField` → `DisplayValueDispatcher` → presets) — the\n * SAME path the detail/read view uses — so the FULL zod-UI display policy is\n * honored in lists/tables by default: enum → badge (+ per-value colors),\n * boolean → checkmark / yes-no, string → truncate / multiline, FK → reference,\n * date → formatted, money/bigdecimal/duration/etc.\n *\n * Previously this re-implemented a weak subset (enum-as-plain-text, naive array\n * join, `String(value)` fallback) that silently ignored every\n * `{primitive}UI().display` decorator, so listings/tables diverged from the\n * detail view (e.g. a `displayMode: BADGE` enum rendered as plain text). Routing\n * through `DisplayField` removes that divergence and the maintenance burden of a\n * parallel renderer.\n *\n * The card (\"Label:\" prefix) and the table (column header) own the label, so the\n * value is rendered under COMPACT chrome — a bare value with no framework\n * label/description wrapper. i18n enum labels are threaded explicitly via\n * `enumLabels` because there is no surrounding `DisplayTemplateContext`\n * (which is what supplies them inside `AutomaticDisplayer`).\n */\nexport function FieldValueRenderer({\n fieldName,\n value,\n fieldSchema,\n fieldLabel,\n resourceType,\n tResourceFieldEnumValue,\n}: FieldValueRendererProps): React.JSX.Element | null {\n // Build the enum value→label map from the same i18n translator the list\n // already uses, so enum badges show translated labels rather than raw enum\n // values. Hook runs unconditionally, before the null-value early return.\n const enumLabels = useMemo<Record<string, string> | undefined>(() => {\n if (!fieldSchema || getSchemaType(fieldSchema) !== FieldSchemaType.ENUM) return undefined;\n const enumValues = getEnumValues(fieldSchema);\n if (enumValues.length === 0) return undefined;\n return Object.fromEntries(\n enumValues.map((enumValue) => [enumValue, tResourceFieldEnumValue(resourceType, fieldName, enumValue)]),\n );\n }, [fieldSchema, resourceType, fieldName, tResourceFieldEnumValue]);\n\n if (value === null || value === undefined) return null;\n\n return (\n <div className=\"flex min-w-0 items-baseline gap-element-sm\">\n {fieldLabel && <span className=\"text-xs text-muted-foreground/70\">{fieldLabel}:</span>}\n {fieldSchema ? (\n // COMPACT chrome → bare value with the full decorator policy applied.\n <DisplayChromeProvider displayChromeMode={DisplayChromeMode.COMPACT}>\n <DisplayField\n name={fieldName}\n schema={fieldSchema}\n value={value}\n enumLabels={enumLabels}\n disableInlineEdit\n className=\"min-w-0 truncate text-sm text-muted-foreground\"\n />\n </DisplayChromeProvider>\n ) : (\n // No schema resolved for this field — `DisplayField` requires a schema,\n // so fall back to a plain string (matches the previous default branch).\n <span className=\"min-w-0 truncate text-sm text-muted-foreground\">{String(value)}</span>\n )}\n </div>\n );\n}\n\n// =============================================================================\n// MAIN COMPONENT\n// =============================================================================\n\nexport function ResourceListItemRenderer({\n item,\n resourceType,\n resourceConfig,\n registry,\n summaryFields,\n fieldLabelsMap,\n tResourceFieldEnumValue,\n onItemClick,\n operationsSlot,\n cardActionPlacement,\n selectable = false,\n isSelected = false,\n onToggleSelect,\n selectionActive = false,\n selectAriaLabel,\n className,\n interactiveClasses,\n}: ResourceListItemRendererProps): React.JSX.Element {\n if (!resourceConfig?.resourceFieldIdentifier) {\n throw FrontendResourceUtils.buildConfigurationError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_FIELD_IDENTIFIER_NOT_FOUND,\n { resourceType, component: 'ResourceListItemRenderer' }\n );\n }\n const fieldIdentifier = resourceConfig.resourceFieldIdentifier as string;\n // Resolve the record's own id (`_id`), not the cross-resource field-identifier\n // name (`<resource>Id`) which is absent from a plain record — see\n // FrontendResourceUtils.getResourceObjectId.\n const itemId = FrontendResourceUtils.getResourceObjectId(item, fieldIdentifier);\n\n // Primary display: use computeFrontendResourceLabel for the primary value.\n // For a junction this resolves the server-projected instance label (e.g. a\n // `forwardedLabel` virtual field referenced by `getFrontendResourceLabel`).\n const primaryLabel = useMemo((): string => {\n const label = FrontendResourceUtils.computeFrontendResourceLabel({\n resourceType,\n registry,\n currentObject: item,\n });\n return String(label || item[summaryFields[0]] || `${resourceType} #${itemId}`);\n }, [item, resourceType, registry, summaryFields, itemId]);\n\n // Secondary fields: every summary field EXCEPT the one already shown as the\n // primary label (title). The title comes from `computeFrontendResourceLabel`\n // — an arbitrary label strategy (a `string[]` join or a function), NOT\n // necessarily `summaryFields[0]`. Excluding the title positionally (`slice(1)`)\n // had two bugs: (a) it REPEATED the title when the label field wasn't first\n // (e.g. a list whose label is `name` but whose first summary field is `status`\n // → \"Name: …\" rendered under the identical title), and (b) it silently DROPPED\n // `summaryFields[0]` whenever that field wasn't the label. Excluding the title\n // by VALUE fixes both: the field whose value equals the title is the label\n // field wherever it sits, and every genuine non-label summary field is kept.\n // (The primary-scope FK is dropped upstream by\n // `ResourceLayoutUtils.detectSummaryFields`, so it never reaches here.)\n const secondaryFields = useMemo(\n () => summaryFields.filter((fieldName) => {\n const value = item[fieldName];\n if (value === null || value === undefined) return false;\n return String(value) !== primaryLabel;\n }),\n [summaryFields, item, primaryLabel],\n );\n\n // Schema shape for field type detection\n const schemaShape = useMemo(() => {\n const mainSchema = resourceConfig?.mainSchema;\n if (!mainSchema) return null;\n // Polymorphic resources feed a discriminated-union schema; resolve the union-aware field shape (else getObjectShape returns null for the union → no field labels).\n return AutomatedLayoutFrontendUtils.getObjectLikeFieldShape(mainSchema, { commonOnly: false }) ?? null;\n }, [resourceConfig]);\n\n // AUTHORED summary template — the `layout.summary` contract promises coverage\n // of \"cards, list items, FK references\". When a resource authors one, the card\n // defers its ENTIRE content region (title + body) to `ResourceSummaryDisplayer`:\n // the title is now a first-class template element (`<SummaryTitle />`, placed by\n // `<SummaryLayout>`), so a status badge can sit inline with the title and the\n // exact same composition renders in the FK popover. We pass the primary label we\n // already computed (correct `t`, junction forwardedLabel) into the displayer's\n // SummaryContext instead of rendering our own title above it.\n //\n // Resources WITHOUT an authored template keep the legacy host-owned title +\n // generic \"Label: value\" body: routing them through the GENERATED default\n // template would restyle every list in every app for no authored reason.\n const authoredSummaryTemplate = resourceConfig?.frontendConfiguration?.layout?.summary;\n\n const hoverClass = interactiveClasses?.hover ?? '';\n const transitionClass = interactiveClasses?.transition ?? '';\n // Resolve where the per-item actions sit (2-axis anchor → flex classes). The\n // content + actions share one flex container so actions never overlap text.\n const placement = resolveCardActionPlacementClasses(cardActionPlacement);\n\n // Mobile multi-select: a long-press ENTERS selection mode (selects this item);\n // while selection mode is active (`selectionActive`), a plain TAP toggles\n // selection instead of navigating. Gated to a mobile viewport — on desktop a\n // click always navigates and the checkbox is the explicit toggle. Long-press\n // is touch-only (the hook binds touch handlers).\n // Optional UIContext read: a rendering leaf shouldn't hard-require the shell's\n // UIProvider just to check the breakpoint — outside a provider (isolated\n // renders/tests) it degrades to desktop behavior (isMobile = false).\n const ui = React.useContext(UIContext);\n const isMobile = ui?.UIConfig?.currentBreakpoint === ViewportBreakpoint.MOBILE;\n const tapTogglesSelection = selectable && selectionActive && isMobile;\n // Long-press ENTERS selection mode — gated to the SAME condition as tap-toggle\n // (selectable + mobile viewport) so the two can't disagree (e.g. enter mode on\n // a tablet where tap-toggle is off, stranding the user mid-multiselect).\n const longPress = useLongPress(\n () => onToggleSelect?.(item),\n { enabled: selectable && !!onToggleSelect && isMobile },\n );\n\n const handleActivate = () => {\n // Swallow the synthetic click that follows a long-press (it already selected).\n if (longPress.consumeLongPress()) return;\n if (tapTogglesSelection) {\n onToggleSelect?.(item);\n return;\n }\n onItemClick(item);\n };\n\n return (\n <div\n className={cn(\n 'p-card', hoverClass, 'cursor-pointer', transitionClass,\n isSelected && 'bg-primary/5',\n // Prevent the browser text-selection that a long-press would start.\n selectable && 'select-none',\n className,\n )}\n onClick={handleActivate}\n role=\"button\"\n tabIndex={0}\n aria-label={String(primaryLabel)}\n {...longPress.handlers}\n // Selection state is conveyed by the row's checkbox (aria-selected is not\n // valid on role=\"button\"); the bg tint is a purely visual reinforcement.\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n if (tapTogglesSelection) {\n onToggleSelect?.(item);\n } else {\n onItemClick(item);\n }\n }\n }}\n >\n {/* Leading selection rail (only when the view is selectable). The checkbox\n toggles selection and stops propagation so it never triggers the row's\n navigation — mirrors the table select-cell contract. */}\n <div className=\"flex items-start gap-element-sm\">\n {/* stopPropagation on click, keydown AND touchstart: the row is a\n role=\"button\" with Enter/Space navigation and a touch long-press, so\n without these guards toggling the checkbox (tap/keyboard) would also\n navigate, and a hold over it would arm the row's long-press. */}\n {selectable && (\n <div\n className=\"shrink-0 pt-0.5\"\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n onTouchStart={(e) => e.stopPropagation()}\n >\n <CheckboxRoot\n checked={isSelected}\n onCheckedChange={() => onToggleSelect?.(item)}\n aria-label={selectAriaLabel ?? String(primaryLabel)}\n />\n </div>\n )}\n <div className={cn(placement.containerClass, 'min-w-0 flex-1')}>\n <div className={cn('space-y-item-xs', placement.contentClass)}>\n {authoredSummaryTemplate && resourceConfig?.mainSchema ? (\n // Authored template owns title + body. The title is fed via\n // SummaryContext (primaryLabel) and rendered by `<SummaryTitle />`\n // inside the template, so we do NOT render our own title here. The\n // region stays click-through so the whole card navigates (same as the\n // legacy body); an author who embeds a genuinely interactive control\n // stops propagation within their own template.\n <ResourceSummaryDisplayer\n resourceType={resourceType}\n schema={resourceConfig.mainSchema}\n data={item}\n primaryLabel={primaryLabel}\n />\n ) : (\n <>\n <Text as=\"p\" className=\"font-medium text-foreground\" truncate>{primaryLabel}</Text>\n {secondaryFields.map((fieldName) => {\n const value = item[fieldName];\n if (value === null || value === undefined) return null;\n return (\n <div key={fieldName}>\n <FieldValueRenderer\n fieldName={fieldName}\n value={value}\n fieldSchema={schemaShape?.[fieldName] as z.ZodTypeAny | undefined}\n fieldLabel={fieldLabelsMap[fieldName]}\n resourceType={resourceType}\n tResourceFieldEnumValue={tResourceFieldEnumValue}\n />\n </div>\n );\n })}\n </>\n )}\n </div>\n {operationsSlot && (\n // stopPropagation on click, keydown AND touchstart: an action tap or\n // keyboard activation must not also navigate the row, and a hold over\n // an action must not arm the row's long-press selection. (Mirrors the\n // checkbox rail — all three axes.)\n <div\n className={placement.actionsClass}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n onTouchStart={(e) => e.stopPropagation()}\n >\n {operationsSlot}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"ResourceListItemRenderer.js","sourceRoot":"","sources":["../../../../src/components/resources/ResourceListItemRenderer.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * ResourceListItemRenderer\n *\n * Shared item renderer for List and Search presets.\n * Encapsulates schema-aware field rendering (FK, enum, date, array),\n * primary/secondary field split, and per-item operations.\n *\n * Used by List_Default and Search_Default to ensure parity in how\n * resource items are displayed.\n */\n\nimport React, { useMemo, useCallback } from 'react';\nimport { z } from 'zod';\nimport {\n CoreResourceOperation,\n ResourceOperationDisplayMode,\n ErrorCustomMessageReference,\n} from '@wildo-ai/saas-models';\nimport type { AnyFrontendResourceConfiguration, FrontendResourcesRegistry } from '~wildo-frontend-lib/core/resources/resources.frontend.schemas';\nimport { getSchemaType, FieldSchemaType, getEnumValues, DisplayChromeMode, ViewportBreakpoint } from '@wildo-ai/zod-decorators';\nimport { UIContext } from '~wildo-frontend-lib/core/ui/UIContext';\nimport { useLongPress } from '~wildo-frontend-lib/components/resources/useLongPress';\nimport { DisplayField } from '~wildo-frontend-lib/components/data-display/DisplayField';\nimport { DisplayChromeProvider } from '~wildo-frontend-lib/components/data-display/chromes/DisplayChromeContext';\nimport { ResourceSummaryDisplayer } from '~wildo-frontend-lib/components/data-display/ResourceSummaryDisplayer';\nimport { Text } from '~wildo-frontend-lib/components/typography/text';\nimport { FrontendResourceUtils, frontendResourceUtils } from '~wildo-frontend-lib/core/resources/frontend-resource.utils';\nimport { AutomatedLayoutFrontendUtils } from '~wildo-frontend-lib/core/automated-layout/automated-layout.frontend.utils';\nimport type { FrontendResourceOperationContext } from '~wildo-frontend-lib/core/resources/resources.frontend.schemas';\nimport { cn } from '~wildo-frontend-lib/core/ui/cn';\nimport { CheckboxRoot } from '~wildo-frontend-lib/components/form/controls/boolean/checkbox';\nimport type { CardActionPlacement } from '~wildo-frontend-lib/core/resources/resources.frontend.schemas';\nimport { resolveCardActionPlacementClasses } from './card-action-placement.utils';\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface ResourceListItemRendererProps {\n /** The data item to render */\n item: Record<string, unknown>;\n /** Resource type */\n resourceType: string;\n /** Resource configuration */\n resourceConfig: AnyFrontendResourceConfiguration;\n /** Resource registry */\n registry: FrontendResourcesRegistry;\n /** Ordered list of summary fields to display */\n summaryFields: string[];\n /** Pre-resolved field labels (from i18n) */\n fieldLabelsMap: Record<string, string>;\n /** Function to resolve enum display values via i18n */\n tResourceFieldEnumValue: (resourceType: string, fieldName: string, enumValue: string) => string;\n /** Click handler when the item row is clicked */\n onItemClick: (item: Record<string, unknown>) => void;\n /** Optional operations component to render for this item */\n operationsSlot?: React.ReactNode;\n /**\n * Where the per-item operations sit within the card (2-axis anchor +\n * orientation). Resolved by the host from `collectionDisplayConfig.cardActionPlacement`.\n * Omitted → the default (inline-end, vertically centered, horizontal row).\n */\n cardActionPlacement?: CardActionPlacement;\n /**\n * Selection affordance. When `selectable`, a leading checkbox renders and\n * toggles selection via `onToggleSelect` (independent of the row click, which\n * still navigates). `isSelected` drives the checkbox + a selected highlight.\n */\n selectable?: boolean;\n isSelected?: boolean;\n onToggleSelect?: (item: Record<string, unknown>) => void;\n /**\n * Whether the collection is currently in SELECTION MODE (any item selected).\n * Mobile UX: a long-press enters selection mode, and while active a plain TAP\n * toggles selection instead of navigating (the \"long-press to multi-select\"\n * pattern). Gated to touch/mobile — on desktop a click always navigates and\n * the checkbox is the explicit toggle.\n */\n selectionActive?: boolean;\n /** Accessible label for the selection checkbox (host provides the i18n string). */\n selectAriaLabel?: string;\n /** Optional className for the root container */\n className?: string;\n /** Interactive CSS classes from design system (hover state, transition) */\n interactiveClasses?: {\n hover?: string;\n transition?: string;\n };\n}\n\n// =============================================================================\n// FIELD VALUE RENDERER\n// =============================================================================\n\nexport interface FieldValueRendererProps {\n fieldName: string;\n value: unknown;\n fieldSchema: z.ZodTypeAny | undefined;\n fieldLabel: string | undefined;\n resourceType: string;\n tResourceFieldEnumValue: (resourceType: string, fieldName: string, enumValue: string) => string;\n}\n\n/**\n * Renders a single summary field VALUE through the shared decorator-driven\n * display pipeline (`DisplayField` → `DisplayValueDispatcher` → presets) — the\n * SAME path the detail/read view uses — so the FULL zod-UI display policy is\n * honored in lists/tables by default: enum → badge (+ per-value colors),\n * boolean → checkmark / yes-no, string → truncate / multiline, FK → reference,\n * date → formatted, money/bigdecimal/duration/etc.\n *\n * Previously this re-implemented a weak subset (enum-as-plain-text, naive array\n * join, `String(value)` fallback) that silently ignored every\n * `{primitive}UI().display` decorator, so listings/tables diverged from the\n * detail view (e.g. a `displayMode: BADGE` enum rendered as plain text). Routing\n * through `DisplayField` removes that divergence and the maintenance burden of a\n * parallel renderer.\n *\n * The card (\"Label:\" prefix) and the table (column header) own the label, so the\n * value is rendered under COMPACT chrome — a bare value with no framework\n * label/description wrapper. i18n enum labels are threaded explicitly via\n * `enumLabels` because there is no surrounding `DisplayTemplateContext`\n * (which is what supplies them inside `AutomaticDisplayer`).\n */\nexport function FieldValueRenderer({\n fieldName,\n value,\n fieldSchema,\n fieldLabel,\n resourceType,\n tResourceFieldEnumValue,\n}: FieldValueRendererProps): React.JSX.Element | null {\n // Build the enum value→label map from the same i18n translator the list\n // already uses, so enum badges show translated labels rather than raw enum\n // values. Hook runs unconditionally, before the null-value early return.\n const enumLabels = useMemo<Record<string, string> | undefined>(() => {\n if (!fieldSchema || getSchemaType(fieldSchema) !== FieldSchemaType.ENUM) return undefined;\n const enumValues = getEnumValues(fieldSchema);\n if (enumValues.length === 0) return undefined;\n return Object.fromEntries(\n enumValues.map((enumValue) => [enumValue, tResourceFieldEnumValue(resourceType, fieldName, enumValue)]),\n );\n }, [fieldSchema, resourceType, fieldName, tResourceFieldEnumValue]);\n\n if (value === null || value === undefined) return null;\n\n return (\n <div className=\"flex min-w-0 items-baseline gap-element-sm\">\n {fieldLabel && <span className=\"text-xs text-muted-foreground\">{fieldLabel}:</span>}\n {fieldSchema ? (\n // COMPACT chrome → bare value with the full decorator policy applied.\n <DisplayChromeProvider displayChromeMode={DisplayChromeMode.COMPACT}>\n <DisplayField\n name={fieldName}\n schema={fieldSchema}\n value={value}\n enumLabels={enumLabels}\n disableInlineEdit\n className=\"min-w-0 truncate text-sm text-muted-foreground\"\n />\n </DisplayChromeProvider>\n ) : (\n // No schema resolved for this field — `DisplayField` requires a schema,\n // so fall back to a plain string (matches the previous default branch).\n <span className=\"min-w-0 truncate text-sm text-muted-foreground\">{String(value)}</span>\n )}\n </div>\n );\n}\n\n// =============================================================================\n// MAIN COMPONENT\n// =============================================================================\n\nexport function ResourceListItemRenderer({\n item,\n resourceType,\n resourceConfig,\n registry,\n summaryFields,\n fieldLabelsMap,\n tResourceFieldEnumValue,\n onItemClick,\n operationsSlot,\n cardActionPlacement,\n selectable = false,\n isSelected = false,\n onToggleSelect,\n selectionActive = false,\n selectAriaLabel,\n className,\n interactiveClasses,\n}: ResourceListItemRendererProps): React.JSX.Element {\n if (!resourceConfig?.resourceFieldIdentifier) {\n throw FrontendResourceUtils.buildConfigurationError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_FIELD_IDENTIFIER_NOT_FOUND,\n { resourceType, component: 'ResourceListItemRenderer' }\n );\n }\n const fieldIdentifier = resourceConfig.resourceFieldIdentifier as string;\n // Resolve the record's own id (`_id`), not the cross-resource field-identifier\n // name (`<resource>Id`) which is absent from a plain record — see\n // FrontendResourceUtils.getResourceObjectId.\n const itemId = FrontendResourceUtils.getResourceObjectId(item, fieldIdentifier);\n\n // Primary display: use computeFrontendResourceLabel for the primary value.\n // For a junction this resolves the server-projected instance label (e.g. a\n // `forwardedLabel` virtual field referenced by `getFrontendResourceLabel`).\n const primaryLabel = useMemo((): string => {\n const label = FrontendResourceUtils.computeFrontendResourceLabel({\n resourceType,\n registry,\n currentObject: item,\n });\n return String(label || item[summaryFields[0]] || `${resourceType} #${itemId}`);\n }, [item, resourceType, registry, summaryFields, itemId]);\n\n // Secondary fields: every summary field EXCEPT the one already shown as the\n // primary label (title). The title comes from `computeFrontendResourceLabel`\n // — an arbitrary label strategy (a `string[]` join or a function), NOT\n // necessarily `summaryFields[0]`. Excluding the title positionally (`slice(1)`)\n // had two bugs: (a) it REPEATED the title when the label field wasn't first\n // (e.g. a list whose label is `name` but whose first summary field is `status`\n // → \"Name: …\" rendered under the identical title), and (b) it silently DROPPED\n // `summaryFields[0]` whenever that field wasn't the label. Excluding the title\n // by VALUE fixes both: the field whose value equals the title is the label\n // field wherever it sits, and every genuine non-label summary field is kept.\n // (The primary-scope FK is dropped upstream by\n // `ResourceLayoutUtils.detectSummaryFields`, so it never reaches here.)\n const secondaryFields = useMemo(\n () => summaryFields.filter((fieldName) => {\n const value = item[fieldName];\n if (value === null || value === undefined) return false;\n return String(value) !== primaryLabel;\n }),\n [summaryFields, item, primaryLabel],\n );\n\n // Schema shape for field type detection\n const schemaShape = useMemo(() => {\n const mainSchema = resourceConfig?.mainSchema;\n if (!mainSchema) return null;\n // Polymorphic resources feed a discriminated-union schema; resolve the union-aware field shape (else getObjectShape returns null for the union → no field labels).\n return AutomatedLayoutFrontendUtils.getObjectLikeFieldShape(mainSchema, { commonOnly: false }) ?? null;\n }, [resourceConfig]);\n\n // AUTHORED summary template — the `layout.summary` contract promises coverage\n // of \"cards, list items, FK references\". When a resource authors one, the card\n // defers its ENTIRE content region (title + body) to `ResourceSummaryDisplayer`:\n // the title is now a first-class template element (`<SummaryTitle />`, placed by\n // `<SummaryLayout>`), so a status badge can sit inline with the title and the\n // exact same composition renders in the FK popover. We pass the primary label we\n // already computed (correct `t`, junction forwardedLabel) into the displayer's\n // SummaryContext instead of rendering our own title above it.\n //\n // Resources WITHOUT an authored template keep the legacy host-owned title +\n // generic \"Label: value\" body: routing them through the GENERATED default\n // template would restyle every list in every app for no authored reason.\n const authoredSummaryTemplate = resourceConfig?.frontendConfiguration?.layout?.summary;\n\n const hoverClass = interactiveClasses?.hover ?? '';\n const transitionClass = interactiveClasses?.transition ?? '';\n // Resolve where the per-item actions sit (2-axis anchor → flex classes). The\n // content + actions share one flex container so actions never overlap text.\n const placement = resolveCardActionPlacementClasses(cardActionPlacement);\n\n // Mobile multi-select: a long-press ENTERS selection mode (selects this item);\n // while selection mode is active (`selectionActive`), a plain TAP toggles\n // selection instead of navigating. Gated to a mobile viewport — on desktop a\n // click always navigates and the checkbox is the explicit toggle. Long-press\n // is touch-only (the hook binds touch handlers).\n // Optional UIContext read: a rendering leaf shouldn't hard-require the shell's\n // UIProvider just to check the breakpoint — outside a provider (isolated\n // renders/tests) it degrades to desktop behavior (isMobile = false).\n const ui = React.useContext(UIContext);\n const isMobile = ui?.UIConfig?.currentBreakpoint === ViewportBreakpoint.MOBILE;\n const tapTogglesSelection = selectable && selectionActive && isMobile;\n // Long-press ENTERS selection mode — gated to the SAME condition as tap-toggle\n // (selectable + mobile viewport) so the two can't disagree (e.g. enter mode on\n // a tablet where tap-toggle is off, stranding the user mid-multiselect).\n const longPress = useLongPress(\n () => onToggleSelect?.(item),\n { enabled: selectable && !!onToggleSelect && isMobile },\n );\n\n const handleActivate = () => {\n // Swallow the synthetic click that follows a long-press (it already selected).\n if (longPress.consumeLongPress()) return;\n if (tapTogglesSelection) {\n onToggleSelect?.(item);\n return;\n }\n onItemClick(item);\n };\n\n return (\n <div\n className={cn(\n 'p-card', hoverClass, 'cursor-pointer', transitionClass,\n isSelected && 'bg-primary/5',\n // Prevent the browser text-selection that a long-press would start.\n selectable && 'select-none',\n className,\n )}\n onClick={handleActivate}\n role=\"button\"\n tabIndex={0}\n aria-label={String(primaryLabel)}\n {...longPress.handlers}\n // Selection state is conveyed by the row's checkbox (aria-selected is not\n // valid on role=\"button\"); the bg tint is a purely visual reinforcement.\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n if (tapTogglesSelection) {\n onToggleSelect?.(item);\n } else {\n onItemClick(item);\n }\n }\n }}\n >\n {/* Leading selection rail (only when the view is selectable). The checkbox\n toggles selection and stops propagation so it never triggers the row's\n navigation — mirrors the table select-cell contract. */}\n <div className=\"flex items-start gap-element-sm\">\n {/* stopPropagation on click, keydown AND touchstart: the row is a\n role=\"button\" with Enter/Space navigation and a touch long-press, so\n without these guards toggling the checkbox (tap/keyboard) would also\n navigate, and a hold over it would arm the row's long-press. */}\n {selectable && (\n <div\n className=\"shrink-0 pt-0.5\"\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n onTouchStart={(e) => e.stopPropagation()}\n >\n <CheckboxRoot\n checked={isSelected}\n onCheckedChange={() => onToggleSelect?.(item)}\n aria-label={selectAriaLabel ?? String(primaryLabel)}\n />\n </div>\n )}\n <div className={cn(placement.containerClass, 'min-w-0 flex-1')}>\n <div className={cn('space-y-item-xs', placement.contentClass)}>\n {authoredSummaryTemplate && resourceConfig?.mainSchema ? (\n // Authored template owns title + body. The title is fed via\n // SummaryContext (primaryLabel) and rendered by `<SummaryTitle />`\n // inside the template, so we do NOT render our own title here. The\n // region stays click-through so the whole card navigates (same as the\n // legacy body); an author who embeds a genuinely interactive control\n // stops propagation within their own template.\n <ResourceSummaryDisplayer\n resourceType={resourceType}\n schema={resourceConfig.mainSchema}\n data={item}\n primaryLabel={primaryLabel}\n />\n ) : (\n <>\n <Text as=\"p\" className=\"font-medium text-foreground\" truncate>{primaryLabel}</Text>\n {secondaryFields.map((fieldName) => {\n const value = item[fieldName];\n if (value === null || value === undefined) return null;\n return (\n <div key={fieldName}>\n <FieldValueRenderer\n fieldName={fieldName}\n value={value}\n fieldSchema={schemaShape?.[fieldName] as z.ZodTypeAny | undefined}\n fieldLabel={fieldLabelsMap[fieldName]}\n resourceType={resourceType}\n tResourceFieldEnumValue={tResourceFieldEnumValue}\n />\n </div>\n );\n })}\n </>\n )}\n </div>\n {operationsSlot && (\n // stopPropagation on click, keydown AND touchstart: an action tap or\n // keyboard activation must not also navigate the row, and a hold over\n // an action must not arm the row's long-press selection. (Mirrors the\n // checkbox rail — all three axes.)\n <div\n className={placement.actionsClass}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n onTouchStart={(e) => e.stopPropagation()}\n >\n {operationsSlot}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"]}
@@ -70,6 +70,18 @@ export interface ResourceHeaderTitleProps {
70
70
  * The record's name, rendered with the page-header typography the default
71
71
  * (template-less) header uses — so authoring a header template is visually
72
72
  * neutral for the title itself and only adds what the template places around it.
73
+ *
74
+ * ## It is an `h1`, and the level is not cosmetic
75
+ *
76
+ * This IS the page's title — the record's name on a record page, the collection's on a listing — and
77
+ * there is exactly one per surface, so it owns the top of the document outline. It was an `h2` until
78
+ * 2026-09-09, which left generated screens with NO level-one heading at all: the first accessibility
79
+ * audit ever run against a live stack reported `page-has-heading-one` on the collection listing,
80
+ * where this element was the only heading on the page (#533).
81
+ *
82
+ * The classes are unchanged, so nothing moves visually — `text-xl` still sets the size. A heading
83
+ * level is the document's structure, not its appearance, and the two are deliberately decoupled here
84
+ * exactly as the design system does elsewhere.
73
85
  */
74
86
  export declare function ResourceHeaderTitle({ className }: ResourceHeaderTitleProps): React.JSX.Element | null;
75
87
  /** @wildo_source:part:end saas.frontend.resource-header-title */
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceHeaderTitle.d.ts","sourceRoot":"","sources":["../../../../../src/components/resources/skeleton/ResourceHeaderTitle.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAoC,MAAM,OAAO,CAAC;AAQzD,MAAM,WAAW,0BAA0B;IACzC,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAErB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE;QAAE,YAAY,EAAE,OAAO,CAAA;KAAE,CAAC;CAC/C;AAID,MAAM,WAAW,kCAAkC;IACjD,KAAK,EAAE,0BAA0B,CAAC;IAClC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,8EAA8E;AAC9E,wBAAgB,6BAA6B,CAAC,EAC5C,KAAK,EACL,QAAQ,GACT,EAAE,kCAAkC,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAExD;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,IAAI,0BAA0B,GAAG,IAAI,CAEpF;AAMD,iHAAiH;AACjH,MAAM,WAAW,wBAAwB;IACvC,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,SAAS,EAAE,EAAE,wBAAwB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAoBrG;AACD,iEAAiE"}
1
+ {"version":3,"file":"ResourceHeaderTitle.d.ts","sourceRoot":"","sources":["../../../../../src/components/resources/skeleton/ResourceHeaderTitle.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAoC,MAAM,OAAO,CAAC;AAQzD,MAAM,WAAW,0BAA0B;IACzC,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAErB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE;QAAE,YAAY,EAAE,OAAO,CAAA;KAAE,CAAC;CAC/C;AAID,MAAM,WAAW,kCAAkC;IACjD,KAAK,EAAE,0BAA0B,CAAC;IAClC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,8EAA8E;AAC9E,wBAAgB,6BAA6B,CAAC,EAC5C,KAAK,EACL,QAAQ,GACT,EAAE,kCAAkC,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAExD;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,IAAI,0BAA0B,GAAG,IAAI,CAEpF;AAMD,iHAAiH;AACjH,MAAM,WAAW,wBAAwB;IACvC,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,SAAS,EAAE,EAAE,wBAAwB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAoBrG;AACD,iEAAiE"}
@@ -50,6 +50,18 @@ export function useOptionalResourceHeaderContext() {
50
50
  * The record's name, rendered with the page-header typography the default
51
51
  * (template-less) header uses — so authoring a header template is visually
52
52
  * neutral for the title itself and only adds what the template places around it.
53
+ *
54
+ * ## It is an `h1`, and the level is not cosmetic
55
+ *
56
+ * This IS the page's title — the record's name on a record page, the collection's on a listing — and
57
+ * there is exactly one per surface, so it owns the top of the document outline. It was an `h2` until
58
+ * 2026-09-09, which left generated screens with NO level-one heading at all: the first accessibility
59
+ * audit ever run against a live stack reported `page-has-heading-one` on the collection listing,
60
+ * where this element was the only heading on the page (#533).
61
+ *
62
+ * The classes are unchanged, so nothing moves visually — `text-xl` still sets the size. A heading
63
+ * level is the document's structure, not its appearance, and the two are deliberately decoupled here
64
+ * exactly as the design system does elsewhere.
53
65
  */
54
66
  export function ResourceHeaderTitle({ className }) {
55
67
  const header = useOptionalResourceHeaderContext();
@@ -67,6 +79,6 @@ export function ResourceHeaderTitle({ className }) {
67
79
  // only the space it needs, which is what keeps an authored badge HUGGING the
68
80
  // name rather than being flung to the far end of the row (the same
69
81
  // composition lesson recorded on `SummaryTitle`).
70
- _jsx("h2", { className: cn('min-w-0 truncate text-xl font-semibold text-foreground', className), children: title }));
82
+ _jsx("h1", { className: cn('min-w-0 truncate text-xl font-semibold text-foreground', className), children: title }));
71
83
  }
72
84
  //# sourceMappingURL=ResourceHeaderTitle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceHeaderTitle.js","sourceRoot":"","sources":["../../../../../src/components/resources/skeleton/ResourceHeaderTitle.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AA0BpD,MAAM,qBAAqB,GAAG,aAAa,CAAoC,IAAI,CAAC,CAAC;AAOrF,8EAA8E;AAC9E,MAAM,UAAU,6BAA6B,CAAC,EAC5C,KAAK,EACL,QAAQ,GAC2B;IACnC,OAAO,KAAC,qBAAqB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAkC,CAAC;AACnG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gCAAgC;IAC9C,OAAO,UAAU,CAAC,qBAAqB,CAAC,CAAC;AAC3C,CAAC;AAYD;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAE,SAAS,EAA4B;IACzE,MAAM,MAAM,GAAG,gCAAgC,EAAE,CAAC;IAClD,0EAA0E;IAC1E,4EAA4E;IAC5E,gFAAgF;IAChF,IAAI,MAAM,EAAE,iBAAiB;QAAE,MAAM,CAAC,iBAAiB,CAAC,YAAY,GAAG,IAAI,CAAC;IAE5E,MAAM,KAAK,GAAG,MAAM,EAAE,KAAK,CAAC;IAC5B,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,OAAO;IACL,4EAA4E;IAC5E,4EAA4E;IAC5E,6EAA6E;IAC7E,mEAAmE;IACnE,kDAAkD;IAClD,aAAI,SAAS,EAAE,EAAE,CAAC,wDAAwD,EAAE,SAAS,CAAC,YACnF,KAAK,GACH,CACN,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\n/**\n * ResourceHeaderTitle — the record's page TITLE as a first-class, composable\n * element of an authored `layout.header` template.\n *\n * ## Why the header needs a template flow at all\n *\n * The READ page header owns a fixed band: back button, breadcrumb, resource\n * icon, the record's name, and the operation action cluster. Everything a\n * resource wanted to show ABOUT the record (a status badge, a visibility\n * marker, an accent colour) could previously only render in the `layout.display`\n * body BELOW that band — so the identity line said the record's name and nothing\n * else, while \"is this archived? is it public?\" sat in a separate labelled strip\n * underneath.\n *\n * `layout.header` closes that by letting the resource compose the middle of the\n * band itself. It is the same shape the SUMMARY surface already uses\n * (`SummaryLayout` / `SummaryTitle`), for the same reason recorded there: a\n * host-owned title plus a bolt-on accessory slot cannot express \"badge AFTER the\n * name\" or \"swatch BEFORE it\", whereas a template that places the title element\n * itself can express any of them with no extra config axis.\n *\n * ## Contract\n *\n * The header cedes the middle region to the template the moment `layout.header`\n * exists, so a template that never mounts `<ResourceHeaderTitle />` renders a\n * page with NO record name. That is loud in development (see the diagnostic in\n * `ResourceLayout_Header`) rather than silent.\n *\n * Renders nothing when the host resolved no label (a surface that shows a\n * generic operation title rather than one record's name) — the presence of a\n * label is the single data-driven signal that there is a title to place.\n */\n\nimport React, { createContext, useContext } from 'react';\n\nimport { cn } from '~wildo-frontend-lib/core/ui/cn';\n\n// =============================================================================\n// CONTEXT\n// =============================================================================\n\nexport interface ResourceHeaderContextValue {\n /** Resource type key of the record whose header is rendering. */\n resourceType: string;\n\n /**\n * Resolved record title (the `getFrontendResourceLabel` result, or the\n * operation/resource title fallback), or `null` when this surface has no\n * record-specific name to show — `<ResourceHeaderTitle />` then renders nothing.\n */\n title: string | null;\n\n /**\n * Dev-diagnostic seam: `<ResourceHeaderTitle />` flips `titleMounted` when it\n * renders, letting the header detect an authored template that never places\n * the title. Mutable-ref shape (not state) on purpose — the flag is read only\n * after render and must never schedule a re-render.\n */\n titleMountTracker?: { titleMounted: boolean };\n}\n\nconst ResourceHeaderContext = createContext<ResourceHeaderContextValue | null>(null);\n\nexport interface ResourceHeaderContextProviderProps {\n value: ResourceHeaderContextValue;\n children: React.ReactNode;\n}\n\n/** Provides the resolved record title to an authored header template tree. */\nexport function ResourceHeaderContextProvider({\n value,\n children,\n}: ResourceHeaderContextProviderProps): React.JSX.Element {\n return <ResourceHeaderContext.Provider value={value}>{children}</ResourceHeaderContext.Provider>;\n}\n\n/**\n * Read the header context, or `null` when a header template is rendered outside\n * `ResourceLayout_Header` (e.g. previewed in isolation).\n */\nexport function useOptionalResourceHeaderContext(): ResourceHeaderContextValue | null {\n return useContext(ResourceHeaderContext);\n}\n\n// =============================================================================\n// TITLE ELEMENT\n// =============================================================================\n\n/** @wildo_source:part:start saas.frontend.resource-header-title facet:layer:frontend facet:family:resource-ui */\nexport interface ResourceHeaderTitleProps {\n /** Extra classes merged over the default page-title styling. */\n className?: string;\n}\n\n/**\n * The record's name, rendered with the page-header typography the default\n * (template-less) header uses — so authoring a header template is visually\n * neutral for the title itself and only adds what the template places around it.\n */\nexport function ResourceHeaderTitle({ className }: ResourceHeaderTitleProps): React.JSX.Element | null {\n const header = useOptionalResourceHeaderContext();\n // Register with the missing-title diagnostic BEFORE the empty-title early\n // return: mounting the element discharges the template's contract even when\n // this particular record resolves no label (data-driven, not an authoring bug).\n if (header?.titleMountTracker) header.titleMountTracker.titleMounted = true;\n\n const title = header?.title;\n if (!title) return null;\n\n return (\n // `min-w-0` + truncate so a long record name shrinks instead of pushing the\n // template's trailing badges out of the band. No `flex-1`: the title claims\n // only the space it needs, which is what keeps an authored badge HUGGING the\n // name rather than being flung to the far end of the row (the same\n // composition lesson recorded on `SummaryTitle`).\n <h2 className={cn('min-w-0 truncate text-xl font-semibold text-foreground', className)}>\n {title}\n </h2>\n );\n}\n/** @wildo_source:part:end saas.frontend.resource-header-title */\n"]}
1
+ {"version":3,"file":"ResourceHeaderTitle.js","sourceRoot":"","sources":["../../../../../src/components/resources/skeleton/ResourceHeaderTitle.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AA0BpD,MAAM,qBAAqB,GAAG,aAAa,CAAoC,IAAI,CAAC,CAAC;AAOrF,8EAA8E;AAC9E,MAAM,UAAU,6BAA6B,CAAC,EAC5C,KAAK,EACL,QAAQ,GAC2B;IACnC,OAAO,KAAC,qBAAqB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAkC,CAAC;AACnG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gCAAgC;IAC9C,OAAO,UAAU,CAAC,qBAAqB,CAAC,CAAC;AAC3C,CAAC;AAYD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAE,SAAS,EAA4B;IACzE,MAAM,MAAM,GAAG,gCAAgC,EAAE,CAAC;IAClD,0EAA0E;IAC1E,4EAA4E;IAC5E,gFAAgF;IAChF,IAAI,MAAM,EAAE,iBAAiB;QAAE,MAAM,CAAC,iBAAiB,CAAC,YAAY,GAAG,IAAI,CAAC;IAE5E,MAAM,KAAK,GAAG,MAAM,EAAE,KAAK,CAAC;IAC5B,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,OAAO;IACL,4EAA4E;IAC5E,4EAA4E;IAC5E,6EAA6E;IAC7E,mEAAmE;IACnE,kDAAkD;IAClD,aAAI,SAAS,EAAE,EAAE,CAAC,wDAAwD,EAAE,SAAS,CAAC,YACnF,KAAK,GACH,CACN,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\n/**\n * ResourceHeaderTitle — the record's page TITLE as a first-class, composable\n * element of an authored `layout.header` template.\n *\n * ## Why the header needs a template flow at all\n *\n * The READ page header owns a fixed band: back button, breadcrumb, resource\n * icon, the record's name, and the operation action cluster. Everything a\n * resource wanted to show ABOUT the record (a status badge, a visibility\n * marker, an accent colour) could previously only render in the `layout.display`\n * body BELOW that band — so the identity line said the record's name and nothing\n * else, while \"is this archived? is it public?\" sat in a separate labelled strip\n * underneath.\n *\n * `layout.header` closes that by letting the resource compose the middle of the\n * band itself. It is the same shape the SUMMARY surface already uses\n * (`SummaryLayout` / `SummaryTitle`), for the same reason recorded there: a\n * host-owned title plus a bolt-on accessory slot cannot express \"badge AFTER the\n * name\" or \"swatch BEFORE it\", whereas a template that places the title element\n * itself can express any of them with no extra config axis.\n *\n * ## Contract\n *\n * The header cedes the middle region to the template the moment `layout.header`\n * exists, so a template that never mounts `<ResourceHeaderTitle />` renders a\n * page with NO record name. That is loud in development (see the diagnostic in\n * `ResourceLayout_Header`) rather than silent.\n *\n * Renders nothing when the host resolved no label (a surface that shows a\n * generic operation title rather than one record's name) — the presence of a\n * label is the single data-driven signal that there is a title to place.\n */\n\nimport React, { createContext, useContext } from 'react';\n\nimport { cn } from '~wildo-frontend-lib/core/ui/cn';\n\n// =============================================================================\n// CONTEXT\n// =============================================================================\n\nexport interface ResourceHeaderContextValue {\n /** Resource type key of the record whose header is rendering. */\n resourceType: string;\n\n /**\n * Resolved record title (the `getFrontendResourceLabel` result, or the\n * operation/resource title fallback), or `null` when this surface has no\n * record-specific name to show — `<ResourceHeaderTitle />` then renders nothing.\n */\n title: string | null;\n\n /**\n * Dev-diagnostic seam: `<ResourceHeaderTitle />` flips `titleMounted` when it\n * renders, letting the header detect an authored template that never places\n * the title. Mutable-ref shape (not state) on purpose — the flag is read only\n * after render and must never schedule a re-render.\n */\n titleMountTracker?: { titleMounted: boolean };\n}\n\nconst ResourceHeaderContext = createContext<ResourceHeaderContextValue | null>(null);\n\nexport interface ResourceHeaderContextProviderProps {\n value: ResourceHeaderContextValue;\n children: React.ReactNode;\n}\n\n/** Provides the resolved record title to an authored header template tree. */\nexport function ResourceHeaderContextProvider({\n value,\n children,\n}: ResourceHeaderContextProviderProps): React.JSX.Element {\n return <ResourceHeaderContext.Provider value={value}>{children}</ResourceHeaderContext.Provider>;\n}\n\n/**\n * Read the header context, or `null` when a header template is rendered outside\n * `ResourceLayout_Header` (e.g. previewed in isolation).\n */\nexport function useOptionalResourceHeaderContext(): ResourceHeaderContextValue | null {\n return useContext(ResourceHeaderContext);\n}\n\n// =============================================================================\n// TITLE ELEMENT\n// =============================================================================\n\n/** @wildo_source:part:start saas.frontend.resource-header-title facet:layer:frontend facet:family:resource-ui */\nexport interface ResourceHeaderTitleProps {\n /** Extra classes merged over the default page-title styling. */\n className?: string;\n}\n\n/**\n * The record's name, rendered with the page-header typography the default\n * (template-less) header uses — so authoring a header template is visually\n * neutral for the title itself and only adds what the template places around it.\n *\n * ## It is an `h1`, and the level is not cosmetic\n *\n * This IS the page's title — the record's name on a record page, the collection's on a listing — and\n * there is exactly one per surface, so it owns the top of the document outline. It was an `h2` until\n * 2026-09-09, which left generated screens with NO level-one heading at all: the first accessibility\n * audit ever run against a live stack reported `page-has-heading-one` on the collection listing,\n * where this element was the only heading on the page (#533).\n *\n * The classes are unchanged, so nothing moves visually — `text-xl` still sets the size. A heading\n * level is the document's structure, not its appearance, and the two are deliberately decoupled here\n * exactly as the design system does elsewhere.\n */\nexport function ResourceHeaderTitle({ className }: ResourceHeaderTitleProps): React.JSX.Element | null {\n const header = useOptionalResourceHeaderContext();\n // Register with the missing-title diagnostic BEFORE the empty-title early\n // return: mounting the element discharges the template's contract even when\n // this particular record resolves no label (data-driven, not an authoring bug).\n if (header?.titleMountTracker) header.titleMountTracker.titleMounted = true;\n\n const title = header?.title;\n if (!title) return null;\n\n return (\n // `min-w-0` + truncate so a long record name shrinks instead of pushing the\n // template's trailing badges out of the band. No `flex-1`: the title claims\n // only the space it needs, which is what keeps an authored badge HUGGING the\n // name rather than being flung to the far end of the row (the same\n // composition lesson recorded on `SummaryTitle`).\n <h1 className={cn('min-w-0 truncate text-xl font-semibold text-foreground', className)}>\n {title}\n </h1>\n );\n}\n/** @wildo_source:part:end saas.frontend.resource-header-title */\n"]}
@@ -1,64 +1,121 @@
1
1
  /**
2
- * AppPage_ConnectedAccountsSettings — the Settings Hub "Connected accounts" connect panel.
2
+ * AppPage_ConnectedAccountsSettings — connecting a third-party account, at either owner scope.
3
3
  *
4
4
  * A bespoke `ENGINE_PANEL`, and the reason is the shape of the act rather than the shape of the data.
5
- * The stored credentials ARE a resource, and the generic surface beside this one lists, inspects and
5
+ * The stored credentials ARE a resource and the generic surface beside this one lists, inspects and
6
6
  * deletes them perfectly. What it cannot do is CONNECT: that is not a row somebody creates, it is a
7
7
  * flow that leaves the application, obtains consent at a vendor, and returns with a grant nobody
8
- * typed. A resource screen has no mechanism for an action of that shape, so until this existed the
9
- * whole outbound-authorization lane — controller, exchange, refresher, encrypted store, migrations —
10
- * had no surface that could begin it.
11
- *
12
- * ## Two reads, deliberately not one
13
- *
14
- * `listConnectableProviders()` answers what MAY be connected; the sibling resource list answers what
15
- * IS. Merging them would make "you have connected nothing" and "there is nothing to connect"
16
- * indistinguishable — and the first of those is the state every person starts in, which is precisely
17
- * when they need the second question answered.
18
- *
19
- * ## USER scope only, and that is not a simplification
20
- *
21
- * This panel lives under the person's own settings, so it offers only connections the provider admits
22
- * as USER-owned. A tenant's shared integration is the administrator's screen next door
23
- * (`provider-credentials`), and the two must never be merged: one is an individual's own account that
24
- * nobody else may see or spend, the other is a shared credential an administrator configures for
25
- * everyone. There is no cross-scope defaulting anywhere in this lane — a person with no credential of
26
- * their own is refused rather than quietly spending the organization's.
27
- *
28
- * ## Why it navigates instead of following a redirect
29
- *
30
- * The start leg answers with a URL. A 302 would be followed by this fetch, produce an opaque
31
- * cross-origin response, and render the vendor's consent screen into a response body nobody sees. So
32
- * the panel assigns `window.location.href` and the browser leaves — which is also why the OUTCOME
33
- * arrives back as a query parameter rather than as a promise resolving: the return trip is a fresh
34
- * page load from the vendor, not a continuation of this component.
35
- *
36
- * i18n follows the framework convention: `useI18n({ component })` requests this component's label
37
- * namespace, the panel gates rendering on `isReady` so it never flashes raw key paths, and a thin
38
- * `t(key)` reads each label. Copy is owned by the labelling pipeline (sibling `.labels.ts`) — no
39
- * hardcoded strings, and no humanized provider ref either: a provider identifier is an open
40
- * vocabulary with no authored label, so it is rendered verbatim rather than invented from its own
41
- * characters.
42
- *
43
- * assurance-control: WILDO.IDENTITY.DELEGATED_AUTHORIZATION — the surface on which a person
8
+ * typed. A resource screen has no mechanism for an action of that shape.
9
+ *
10
+ * ## Nothing is typed by hand
11
+ *
12
+ * The provider comes from a SELECT over what the application declares; the credential fields come
13
+ * from that provider's own secrets contract. Both were free text until this panel existed, which is
14
+ * how somebody ends up typing `secretSlug` into a box and storing a grant in a slot nothing reads.
15
+ *
16
+ * ## The flow follows the AUTH METHOD
17
+ *
18
+ * A connect surface cannot be one form. A vendor with an authorization flow gets the consent round
19
+ * trip; a vendor whose credential is typed gets a form over the fields IT declares. One button for
20
+ * both would be wrong for whichever it was not built around.
21
+ *
22
+ * ## A provider this deployment cannot connect is SHOWN, never hidden
23
+ *
24
+ * When the application has not registered with a vendor, the panel names the environment variables an
25
+ * operator must set. Removing the provider would answer "we do not support Asana", which is false and
26
+ * unfixable; naming `ASANA_CLIENT_ID` is true and is the thing that gets it set.
27
+ *
28
+ * ## One component, both scopes
29
+ *
30
+ * `ownerScope` decides whose account is being connected — a person's own, or the tenant's. The panel
31
+ * is otherwise identical because the ACT is identical, and duplicating it would guarantee the two
32
+ * drift. What must never be shared is the DATA: a person's connection and a tenant's shared
33
+ * integration have different owners, different authorization and different readers, and the scope is
34
+ * what keeps them apart at every call this panel makes.
35
+ *
36
+ * assurance-control: WILDO.IDENTITY.DELEGATED_AUTHORIZATION — the surface on which a principal
44
37
  * authorizes this application to act toward a named third party on their behalf.
45
38
  */
46
39
  import React from 'react';
40
+ import { ExternalProvider_Connection_DelegationMode, ExternalProvider_Connection_OwnerScope } from '@wildo-ai/external-connectors-models';
47
41
  import { type ConnectableProviderView } from '../../core/requests/wildo-http-client-manual-calls.frontend.service';
48
42
  /**
49
- * The providers THIS person may connect for themselves.
43
+ * The providers connectable AT THIS SCOPE.
44
+ *
45
+ * Exported and named because it is the panel's one substantive claim: a provider admitting only
46
+ * ORGANIZATION connections must never be offered on a person's screen, and vice versa — offering it
47
+ * renders an action that answers 403 at the start leg.
48
+ *
49
+ * It deliberately does NOT filter on `connectable`. A provider this deployment cannot connect is
50
+ * still offered, because the panel's answer for it is the missing configuration rather than silence.
51
+ */
52
+ export declare const selectProvidersForScope: (providers: readonly ConnectableProviderView[], ownerScope: ExternalProvider_Connection_OwnerScope) => ConnectableProviderView[];
53
+ /**
54
+ * ON WHOSE BEHALF this provider admits a connection at this scope — DERIVED, never assumed.
55
+ *
56
+ * The panel used to send `delegation: SERVICE` for every connect, at both scopes. That is one of the
57
+ * five declared shapes, so it worked by coincidence for the providers that happen to declare it and
58
+ * answered `409 CONNECTION_NOT_ADMISSIBLE` for the rest — the start leg checks the exact
59
+ * (ownerScope, delegation) PAIR against what the provider admits, and a scope does not imply a
60
+ * delegation.
61
+ *
62
+ * Measured across the generated catalogue on 2026-09-10, which is why this is a derivation rather
63
+ * than a better constant: at ORGANIZATION scope, 75 vendors declare `USER` and 39 declare `SERVICE`.
64
+ * A hard-coded `SERVICE` was therefore wrong for the larger half — `asana` among them, which is how
65
+ * this surfaced: the provider was listed, the button rendered, and the vendor was never reached.
66
+ *
67
+ * The pair is the provider's own statement, so the panel reads it rather than the person supplying
68
+ * it. Where a provider declares BOTH delegations for one scope — 27 vendors do, `box`, `dropbox`,
69
+ * `gmail` and `google-calendar` among them — the declaration genuinely does not decide, and only
70
+ * then is there a question to put to anybody. See `.claude/rules/derive-before-you-ask.md`.
71
+ */
72
+ export declare const admissibleDelegationsForScope: (provider: ConnectableProviderView, ownerScope: ExternalProvider_Connection_OwnerScope) => ExternalProvider_Connection_DelegationMode[];
73
+ /**
74
+ * The target the start leg is given — assembled here so the shape is TESTABLE, not inlined.
75
+ *
76
+ * `ExternalProvider_ConnectionTargetSchema` refines two fields the panel cannot leave to be
77
+ * inferred, and it refuses in BOTH directions:
78
+ *
79
+ * - a `USER`-delegated call MUST name `actingForUserId` — "a delegated call acts FOR someone, and
80
+ * the user it acts for is what makes it permissible";
81
+ * - a `SERVICE` call MUST NOT, because naming a person there "reads as delegation the runtime will
82
+ * not perform, which is worse than an error: the call succeeds as the wrong identity".
50
83
  *
51
- * Named and exported rather than inlined because it is the panel's one substantive claim, and both
52
- * halves of it are a way for a button to be DEAD on press:
84
+ * The panel sent neither until 2026-09-10, so every `USER`-delegated connect answered
85
+ * `400 VALIDATION_FAILED` — and that refusal names no field, so the screen could only report a
86
+ * generic failure. It was invisible because the shape that WORKS is `SERVICE`-delegated: `USER` at
87
+ * ORGANIZATION scope is what 75 of the harvested vendors declare, `asana` among them, and it is
88
+ * exactly the half nobody had driven.
53
89
  *
54
- * - a provider admitting only ORGANIZATION-owned connections belongs on the administrator's screen
55
- * next door; offering it here renders a Connect button that answers 403;
56
- * - a provider whose credential is pasted has no authorization flow to start, so its button would
57
- * have nowhere to navigate.
90
+ * `actingForUserId` is the SIGNED-IN person and is independent of `ownerId`: a tenant-owned
91
+ * connection acting for one of its members carries the organization in `ownerId` and the person
92
+ * here. At USER scope the two coincide, which is why one field cannot serve both.
58
93
  *
59
- * The two filters look interchangeable and are not: dropping the first shows an action the person is
60
- * not entitled to, dropping the second shows an action that does not exist.
94
+ * `ownerId` is omitted for APPLICATION, which the schema likewise refuses — "an application-owned
95
+ * connection has exactly one instance, so an ownerId here names something that does not exist".
96
+ * The Settings Hub renders only USER and ORGANIZATION today, so that arm is unreachable from this
97
+ * panel; it is handled because the function is the shape's one statement, and a caller that grows
98
+ * the third scope should not have to rediscover the rule.
61
99
  */
62
- export declare const selectPersonallyConnectableProviders: (providers: readonly ConnectableProviderView[]) => ConnectableProviderView[];
63
- export declare const AppPage_ConnectedAccountsSettings: React.FC;
100
+ export declare const buildConnectionTarget: (input: {
101
+ ownerScope: ExternalProvider_Connection_OwnerScope;
102
+ ownerId: string | null;
103
+ delegation: ExternalProvider_Connection_DelegationMode;
104
+ signedInUserId: string | null;
105
+ }) => {
106
+ ownerScope: ExternalProvider_Connection_OwnerScope;
107
+ delegation: ExternalProvider_Connection_DelegationMode;
108
+ ownerId?: string;
109
+ actingForUserId?: string;
110
+ };
111
+ export interface ConnectedAccountsSettingsProps {
112
+ /**
113
+ * WHOSE account is being connected.
114
+ *
115
+ * A prop rather than two components: the act is identical and duplicating it would guarantee the
116
+ * two screens drift. The DATA never mixes — every call this panel makes carries the scope.
117
+ */
118
+ ownerScope: ExternalProvider_Connection_OwnerScope;
119
+ }
120
+ export declare const AppPage_ConnectedAccountsSettings: React.FC<Partial<ConnectedAccountsSettingsProps>>;
64
121
  //# sourceMappingURL=AppPage_ConnectedAccountsSettings.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppPage_ConnectedAccountsSettings.d.ts","sourceRoot":"","sources":["../../../../src/components/settings/AppPage_ConnectedAccountsSettings.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,KAAoD,MAAM,OAAO,CAAC;AAczE,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,mFAAmF,CAAC;AAqB3F;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oCAAoC,GAC/C,WAAW,SAAS,uBAAuB,EAAE,KAC5C,uBAAuB,EAItB,CAAC;AAEL,eAAO,MAAM,iCAAiC,EAAE,KAAK,CAAC,EAwMrD,CAAC"}
1
+ {"version":3,"file":"AppPage_ConnectedAccountsSettings.d.ts","sourceRoot":"","sources":["../../../../src/components/settings/AppPage_ConnectedAccountsSettings.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,KAA4D,MAAM,OAAO,CAAC;AAIjF,OAAO,EACL,0CAA0C,EAC1C,sCAAsC,EACvC,MAAM,sCAAsC,CAAC;AAS9C,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,mFAAmF,CAAC;AAS3F;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,GAClC,WAAW,SAAS,uBAAuB,EAAE,EAC7C,YAAY,sCAAsC,KACjD,uBAAuB,EAExB,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,6BAA6B,GACxC,UAAU,uBAAuB,EACjC,YAAY,sCAAsC,KACjD,0CAA0C,EAY5C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO;IAC3C,UAAU,EAAE,sCAAsC,CAAC;IACnD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,0CAA0C,CAAC;IACvD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,KAAG;IACF,UAAU,EAAE,sCAAsC,CAAC;IACnD,UAAU,EAAE,0CAA0C,CAAC;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;CAUzB,CAAC;AA0CH,MAAM,WAAW,8BAA8B;IAC7C;;;;;OAKG;IACH,UAAU,EAAE,sCAAsC,CAAC;CACpD;AAED,eAAO,MAAM,iCAAiC,EAAE,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAia/F,CAAC"}