@gntik-ai/blocks 0.0.0-stage → 0.6.0

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 (397) hide show
  1. package/dist/index.d.ts +3626 -0
  2. package/dist/index.js +15417 -0
  3. package/dist/index.js.map +1 -0
  4. package/package.json +62 -3
  5. package/src/ai/AssistantCardGrid/AssistantCardGrid.test.tsx +32 -0
  6. package/src/ai/AssistantCardGrid/AssistantCardGrid.tsx +98 -0
  7. package/src/ai/AssistantCardGrid/block.meta.ts +10 -0
  8. package/src/ai/AssistantCardGrid/fixtures.ts +72 -0
  9. package/src/ai/EvaluationScorecard/EvaluationScorecard.test.tsx +39 -0
  10. package/src/ai/EvaluationScorecard/EvaluationScorecard.tsx +233 -0
  11. package/src/ai/EvaluationScorecard/block.meta.ts +10 -0
  12. package/src/ai/EvaluationScorecard/fixtures.ts +79 -0
  13. package/src/ai/ModelKeysList/ModelKeysList.test.tsx +44 -0
  14. package/src/ai/ModelKeysList/ModelKeysList.tsx +203 -0
  15. package/src/ai/ModelKeysList/block.meta.ts +10 -0
  16. package/src/ai/ModelKeysList/fixtures.ts +44 -0
  17. package/src/ai/PromptEditor/PromptEditor.test.tsx +97 -0
  18. package/src/ai/PromptEditor/PromptEditor.tsx +202 -0
  19. package/src/ai/PromptEditor/block.meta.ts +10 -0
  20. package/src/ai/PromptEditor/examples/controlled-variables.tsx +23 -0
  21. package/src/ai/PromptEditor/fixtures.ts +12 -0
  22. package/src/ai/TokenCostCard/TokenCostCard.test.tsx +36 -0
  23. package/src/ai/TokenCostCard/TokenCostCard.tsx +130 -0
  24. package/src/ai/TokenCostCard/block.meta.ts +9 -0
  25. package/src/ai/TokenCostCard/fixtures.ts +18 -0
  26. package/src/ai/TraceWaterfall/TraceWaterfall.test.tsx +119 -0
  27. package/src/ai/TraceWaterfall/TraceWaterfall.tsx +317 -0
  28. package/src/ai/TraceWaterfall/block.meta.ts +10 -0
  29. package/src/ai/TraceWaterfall/examples/no-details.tsx +6 -0
  30. package/src/ai/TraceWaterfall/examples/running.tsx +16 -0
  31. package/src/ai/TraceWaterfall/fixtures.ts +133 -0
  32. package/src/ai/TraceWaterfall/span-details.tsx +51 -0
  33. package/src/ai/index.ts +13 -0
  34. package/src/auth/ForgotPasswordForm/ForgotPasswordForm.test.tsx +209 -0
  35. package/src/auth/ForgotPasswordForm/ForgotPasswordForm.tsx +211 -0
  36. package/src/auth/ForgotPasswordForm/block.meta.ts +10 -0
  37. package/src/auth/ForgotPasswordForm/examples/UsernameOrEmail.tsx +24 -0
  38. package/src/auth/MfaChallenge/MfaChallenge.test.tsx +35 -0
  39. package/src/auth/MfaChallenge/MfaChallenge.tsx +170 -0
  40. package/src/auth/MfaChallenge/block.meta.ts +9 -0
  41. package/src/auth/ResetPasswordForm/ResetPasswordForm.test.tsx +27 -0
  42. package/src/auth/ResetPasswordForm/ResetPasswordForm.tsx +100 -0
  43. package/src/auth/ResetPasswordForm/block.meta.ts +10 -0
  44. package/src/auth/SignInForm/SignInForm.test.tsx +222 -0
  45. package/src/auth/SignInForm/SignInForm.tsx +226 -0
  46. package/src/auth/SignInForm/block.meta.ts +22 -0
  47. package/src/auth/SignInForm/examples/Username.tsx +26 -0
  48. package/src/auth/SignUpForm/SignUpForm.configured.test.tsx +316 -0
  49. package/src/auth/SignUpForm/SignUpForm.test.tsx +33 -0
  50. package/src/auth/SignUpForm/SignUpForm.tsx +298 -0
  51. package/src/auth/SignUpForm/block.meta.ts +22 -0
  52. package/src/auth/SignUpForm/examples/CustomFields.tsx +56 -0
  53. package/src/auth/SignUpForm/examples/Error.tsx +5 -0
  54. package/src/auth/SignUpForm/examples/Loading.tsx +6 -0
  55. package/src/auth/SignUpForm/examples/NoTerms.tsx +6 -0
  56. package/src/auth/SignUpForm/examples/Submitting.tsx +5 -0
  57. package/src/auth/SignUpForm/examples/Unavailable.tsx +15 -0
  58. package/src/auth/SsoButtons/SsoButtons.test.tsx +23 -0
  59. package/src/auth/SsoButtons/SsoButtons.tsx +52 -0
  60. package/src/auth/SsoButtons/block.meta.ts +9 -0
  61. package/src/auth/SsoButtons/fixtures.ts +15 -0
  62. package/src/auth/index.ts +16 -0
  63. package/src/auth/shared.tsx +147 -0
  64. package/src/billing/CostBreakdown/CostBreakdown.test.tsx +24 -0
  65. package/src/billing/CostBreakdown/CostBreakdown.tsx +95 -0
  66. package/src/billing/CostBreakdown/block.meta.ts +10 -0
  67. package/src/billing/CostBreakdown/fixtures.ts +9 -0
  68. package/src/billing/InvoiceTable/InvoiceTable.test.tsx +29 -0
  69. package/src/billing/InvoiceTable/InvoiceTable.tsx +130 -0
  70. package/src/billing/InvoiceTable/block.meta.ts +10 -0
  71. package/src/billing/InvoiceTable/fixtures.ts +38 -0
  72. package/src/billing/PaymentMethodCard/PaymentMethodCard.test.tsx +28 -0
  73. package/src/billing/PaymentMethodCard/PaymentMethodCard.tsx +103 -0
  74. package/src/billing/PaymentMethodCard/block.meta.ts +10 -0
  75. package/src/billing/PaymentMethodCard/fixtures.ts +12 -0
  76. package/src/billing/PlanCard/PlanCard.baseline.test.tsx +26 -0
  77. package/src/billing/PlanCard/PlanCard.summary.test.tsx +227 -0
  78. package/src/billing/PlanCard/PlanCard.test.tsx +27 -0
  79. package/src/billing/PlanCard/PlanCard.tsx +140 -0
  80. package/src/billing/PlanCard/PlanSummary.tsx +101 -0
  81. package/src/billing/PlanCard/README.md +23 -0
  82. package/src/billing/PlanCard/__snapshots__/PlanCard.baseline.test.tsx.snap +5 -0
  83. package/src/billing/PlanCard/block.meta.ts +60 -0
  84. package/src/billing/PlanCard/examples/SummaryActionsOnly.tsx +12 -0
  85. package/src/billing/PlanCard/examples/SummaryFeaturesOnly.tsx +14 -0
  86. package/src/billing/PlanCard/examples/SummaryFull.tsx +28 -0
  87. package/src/billing/PlanCard/examples/SummaryMinimal.tsx +5 -0
  88. package/src/billing/PlanCard/examples/SummaryPriceOnly.tsx +15 -0
  89. package/src/billing/PlanCard/examples/SummaryRenewalOnly.tsx +14 -0
  90. package/src/billing/PlanCard/examples/SummaryUnassigned.tsx +5 -0
  91. package/src/billing/PlanCard/examples/SummaryUnassignedNoLabel.tsx +5 -0
  92. package/src/billing/PlanCard/examples/SummaryZeroPrice.tsx +15 -0
  93. package/src/billing/PlanCard/fixtures.ts +19 -0
  94. package/src/billing/PlanDefinitionCard/PlanDefinitionCard.test.tsx +111 -0
  95. package/src/billing/PlanDefinitionCard/PlanDefinitionCard.tsx +86 -0
  96. package/src/billing/PlanDefinitionCard/README.md +29 -0
  97. package/src/billing/PlanDefinitionCard/block.meta.ts +46 -0
  98. package/src/billing/PlanDefinitionCard/examples/Compact.tsx +23 -0
  99. package/src/billing/PlanDefinitionCard/examples/Full.tsx +23 -0
  100. package/src/billing/PlanDefinitionCard/fixtures.ts +12 -0
  101. package/src/billing/QuotaMeters/QuotaMeters.test.tsx +23 -0
  102. package/src/billing/QuotaMeters/QuotaMeters.tsx +92 -0
  103. package/src/billing/QuotaMeters/block.meta.ts +10 -0
  104. package/src/billing/QuotaMeters/fixtures.ts +9 -0
  105. package/src/billing/SpendVsBudget/SpendVsBudget.test.tsx +24 -0
  106. package/src/billing/SpendVsBudget/SpendVsBudget.tsx +105 -0
  107. package/src/billing/SpendVsBudget/block.meta.ts +10 -0
  108. package/src/billing/SpendVsBudget/fixtures.ts +18 -0
  109. package/src/billing/format.ts +42 -0
  110. package/src/billing/index.ts +21 -0
  111. package/src/builders/CodePanel/CodePanel.test.tsx +280 -0
  112. package/src/builders/CodePanel/CodePanel.tsx +239 -0
  113. package/src/builders/CodePanel/block.meta.ts +10 -0
  114. package/src/builders/CodePanel/examples/controlled.tsx +15 -0
  115. package/src/builders/CodePanel/examples/diagnostics.tsx +40 -0
  116. package/src/builders/CodePanel/fixtures.ts +95 -0
  117. package/src/builders/CodePanel/marker-store.ts +90 -0
  118. package/src/builders/CodePanel/markers.ts +62 -0
  119. package/src/builders/FlowBuilder/FlowBuilder.test.tsx +480 -0
  120. package/src/builders/FlowBuilder/FlowBuilder.tsx +343 -0
  121. package/src/builders/FlowBuilder/block.meta.ts +20 -0
  122. package/src/builders/FlowBuilder/connections.ts +67 -0
  123. package/src/builders/FlowBuilder/decorated-nodes.ts +80 -0
  124. package/src/builders/FlowBuilder/examples/extensions.tsx +120 -0
  125. package/src/builders/FlowBuilder/extensions.ts +37 -0
  126. package/src/builders/FlowBuilder/fixtures.ts +80 -0
  127. package/src/builders/FlowBuilder/parts.tsx +196 -0
  128. package/src/builders/FlowBuilder/problems.tsx +40 -0
  129. package/src/builders/LogViewer/LogViewer.test.tsx +97 -0
  130. package/src/builders/LogViewer/LogViewer.tsx +253 -0
  131. package/src/builders/LogViewer/block.meta.ts +10 -0
  132. package/src/builders/LogViewer/fixtures.ts +49 -0
  133. package/src/builders/index.ts +15 -0
  134. package/src/data-display/ActivityFeed/ActivityFeed.test.tsx +62 -0
  135. package/src/data-display/ActivityFeed/ActivityFeed.tsx +118 -0
  136. package/src/data-display/ActivityFeed/block.meta.ts +10 -0
  137. package/src/data-display/ActivityFeed/fixtures.ts +29 -0
  138. package/src/data-display/ChartCard/ChartCard.ranges.test.tsx +282 -0
  139. package/src/data-display/ChartCard/ChartCard.test.tsx +54 -0
  140. package/src/data-display/ChartCard/ChartCard.tsx +218 -0
  141. package/src/data-display/ChartCard/block.meta.ts +10 -0
  142. package/src/data-display/ChartCard/examples/custom-ranges.tsx +37 -0
  143. package/src/data-display/ChartCard/examples/heatmap.tsx +20 -0
  144. package/src/data-display/ChartCard/examples/toolbar-owned-range.tsx +34 -0
  145. package/src/data-display/ChartCard/fixtures.ts +82 -0
  146. package/src/data-display/CommentThread/CommentThread.test.tsx +29 -0
  147. package/src/data-display/CommentThread/CommentThread.tsx +120 -0
  148. package/src/data-display/CommentThread/block.meta.ts +10 -0
  149. package/src/data-display/CommentThread/fixtures.ts +28 -0
  150. package/src/data-display/DescriptionListCard/DescriptionListCard.test.tsx +28 -0
  151. package/src/data-display/DescriptionListCard/DescriptionListCard.tsx +120 -0
  152. package/src/data-display/DescriptionListCard/block.meta.ts +9 -0
  153. package/src/data-display/DescriptionListCard/fixtures.ts +12 -0
  154. package/src/data-display/KpiRow/KpiRow.test.tsx +29 -0
  155. package/src/data-display/KpiRow/KpiRow.tsx +101 -0
  156. package/src/data-display/KpiRow/block.meta.ts +10 -0
  157. package/src/data-display/KpiRow/fixtures.ts +34 -0
  158. package/src/data-display/ResourceCardGrid/ResourceCardGrid.test.tsx +22 -0
  159. package/src/data-display/ResourceCardGrid/ResourceCardGrid.tsx +98 -0
  160. package/src/data-display/ResourceCardGrid/block.meta.ts +10 -0
  161. package/src/data-display/ResourceCardGrid/fixtures.ts +72 -0
  162. package/src/data-display/StatCard/StatCard.test.tsx +30 -0
  163. package/src/data-display/StatCard/StatCard.tsx +138 -0
  164. package/src/data-display/StatCard/block.meta.ts +10 -0
  165. package/src/data-display/StatCard/fixtures.ts +26 -0
  166. package/src/data-display/StatusTimeline/StatusTimeline.test.tsx +153 -0
  167. package/src/data-display/StatusTimeline/StatusTimeline.tsx +114 -0
  168. package/src/data-display/StatusTimeline/block.meta.ts +10 -0
  169. package/src/data-display/StatusTimeline/examples/Empty.tsx +6 -0
  170. package/src/data-display/StatusTimeline/fixtures.ts +62 -0
  171. package/src/data-display/index.ts +34 -0
  172. package/src/data-display/shared/TrendDelta.tsx +60 -0
  173. package/src/feedback/ConfirmDestructive/ConfirmDestructive.test.tsx +47 -0
  174. package/src/feedback/ConfirmDestructive/ConfirmDestructive.tsx +145 -0
  175. package/src/feedback/ConfirmDestructive/block.meta.ts +10 -0
  176. package/src/feedback/EmptyStates/EmptyStates.test.tsx +48 -0
  177. package/src/feedback/EmptyStates/EmptyStates.tsx +191 -0
  178. package/src/feedback/EmptyStates/block.meta.ts +10 -0
  179. package/src/feedback/EmptyStates/fixtures.ts +6 -0
  180. package/src/feedback/ErrorPanel/ErrorPanel.test.tsx +37 -0
  181. package/src/feedback/ErrorPanel/ErrorPanel.tsx +146 -0
  182. package/src/feedback/ErrorPanel/block.meta.ts +10 -0
  183. package/src/feedback/InlineCallout/InlineCallout.test.tsx +33 -0
  184. package/src/feedback/InlineCallout/InlineCallout.tsx +81 -0
  185. package/src/feedback/InlineCallout/block.meta.ts +9 -0
  186. package/src/feedback/Skeletons/Skeletons.test.tsx +25 -0
  187. package/src/feedback/Skeletons/Skeletons.tsx +142 -0
  188. package/src/feedback/Skeletons/block.meta.ts +10 -0
  189. package/src/feedback/SystemBanner/SystemBanner.test.tsx +29 -0
  190. package/src/feedback/SystemBanner/SystemBanner.tsx +105 -0
  191. package/src/feedback/SystemBanner/block.meta.ts +9 -0
  192. package/src/feedback/index.ts +14 -0
  193. package/src/feedback/types.ts +13 -0
  194. package/src/forms/CreateApiKeyDialog/CreateApiKeyDialog.test.tsx +36 -0
  195. package/src/forms/CreateApiKeyDialog/CreateApiKeyDialog.tsx +197 -0
  196. package/src/forms/CreateApiKeyDialog/block.meta.ts +10 -0
  197. package/src/forms/CreateApiKeyDialog/fixtures.ts +31 -0
  198. package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.test.tsx +339 -0
  199. package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.tsx +193 -0
  200. package/src/forms/CredentialDisclosureDialog/block.meta.ts +10 -0
  201. package/src/forms/CredentialDisclosureDialog/examples/Fresh.tsx +32 -0
  202. package/src/forms/CredentialDisclosureDialog/examples/ResponseGating.tsx +69 -0
  203. package/src/forms/CredentialDisclosureDialog/examples/Stored.tsx +32 -0
  204. package/src/forms/CredentialDisclosureDialog/fixtures.ts +14 -0
  205. package/src/forms/DangerZone/ConfirmDestructiveDialog.tsx +101 -0
  206. package/src/forms/DangerZone/DangerZone.test.tsx +28 -0
  207. package/src/forms/DangerZone/DangerZone.tsx +86 -0
  208. package/src/forms/DangerZone/block.meta.ts +10 -0
  209. package/src/forms/DangerZone/fixtures.ts +36 -0
  210. package/src/forms/DateRangeFilter/DateRangeFilter.test.tsx +26 -0
  211. package/src/forms/DateRangeFilter/DateRangeFilter.tsx +83 -0
  212. package/src/forms/DateRangeFilter/block.meta.ts +9 -0
  213. package/src/forms/DialogWizard/DialogWizard.test.tsx +95 -0
  214. package/src/forms/DialogWizard/DialogWizard.tsx +39 -0
  215. package/src/forms/DialogWizard/block.meta.ts +10 -0
  216. package/src/forms/DialogWizard/examples/CreateResource.tsx +65 -0
  217. package/src/forms/DialogWizard/fixtures.ts +20 -0
  218. package/src/forms/FileUploadPanel/FileUploadPanel.test.tsx +43 -0
  219. package/src/forms/FileUploadPanel/FileUploadPanel.tsx +244 -0
  220. package/src/forms/FileUploadPanel/block.meta.ts +10 -0
  221. package/src/forms/FileUploadPanel/fixtures.ts +66 -0
  222. package/src/forms/FormSection/FormSection.test.tsx +34 -0
  223. package/src/forms/FormSection/FormSection.tsx +77 -0
  224. package/src/forms/FormSection/block.meta.ts +9 -0
  225. package/src/forms/InviteMembersDialog/InviteMembersDialog.test.tsx +37 -0
  226. package/src/forms/InviteMembersDialog/InviteMembersDialog.tsx +183 -0
  227. package/src/forms/InviteMembersDialog/block.meta.ts +10 -0
  228. package/src/forms/InviteMembersDialog/fixtures.ts +14 -0
  229. package/src/forms/SettingsRow/SettingsRow.test.tsx +50 -0
  230. package/src/forms/SettingsRow/SettingsRow.tsx +74 -0
  231. package/src/forms/SettingsRow/block.meta.ts +9 -0
  232. package/src/forms/ValidationSummary/ValidationSummary.test.tsx +46 -0
  233. package/src/forms/ValidationSummary/ValidationSummary.tsx +75 -0
  234. package/src/forms/ValidationSummary/block.meta.ts +9 -0
  235. package/src/forms/ValidationSummary/fixtures.ts +13 -0
  236. package/src/forms/index.ts +27 -0
  237. package/src/index.ts +14 -0
  238. package/src/marketing/ComparisonTable/ComparisonTable.test.tsx +69 -0
  239. package/src/marketing/ComparisonTable/ComparisonTable.tsx +245 -0
  240. package/src/marketing/ComparisonTable/block.meta.ts +10 -0
  241. package/src/marketing/ComparisonTable/examples/options.tsx +48 -0
  242. package/src/marketing/ComparisonTable/fixtures.ts +83 -0
  243. package/src/marketing/Faq/Faq.test.tsx +25 -0
  244. package/src/marketing/Faq/Faq.tsx +68 -0
  245. package/src/marketing/Faq/block.meta.ts +10 -0
  246. package/src/marketing/Faq/fixtures.ts +32 -0
  247. package/src/marketing/FeatureGrid/FeatureGrid.test.tsx +19 -0
  248. package/src/marketing/FeatureGrid/FeatureGrid.tsx +79 -0
  249. package/src/marketing/FeatureGrid/block.meta.ts +10 -0
  250. package/src/marketing/FeatureGrid/fixtures.ts +36 -0
  251. package/src/marketing/Hero/Hero.test.tsx +33 -0
  252. package/src/marketing/Hero/Hero.tsx +107 -0
  253. package/src/marketing/Hero/block.meta.ts +10 -0
  254. package/src/marketing/PricingTable/PricingTable.test.tsx +92 -0
  255. package/src/marketing/PricingTable/PricingTable.tsx +323 -0
  256. package/src/marketing/PricingTable/block.meta.ts +10 -0
  257. package/src/marketing/PricingTable/fixtures.ts +34 -0
  258. package/src/marketing/actions.tsx +40 -0
  259. package/src/marketing/index.ts +15 -0
  260. package/src/meta.ts +25 -0
  261. package/src/page-chrome/BulkActionBar/BulkActionBar.test.tsx +34 -0
  262. package/src/page-chrome/BulkActionBar/BulkActionBar.tsx +76 -0
  263. package/src/page-chrome/BulkActionBar/block.meta.ts +9 -0
  264. package/src/page-chrome/PageHeader/PageHeader.test.tsx +68 -0
  265. package/src/page-chrome/PageHeader/PageHeader.tsx +152 -0
  266. package/src/page-chrome/PageHeader/block.meta.ts +10 -0
  267. package/src/page-chrome/PageHeader/fixtures.ts +29 -0
  268. package/src/page-chrome/PageToolbar/PageToolbar.test.tsx +38 -0
  269. package/src/page-chrome/PageToolbar/PageToolbar.tsx +138 -0
  270. package/src/page-chrome/PageToolbar/block.meta.ts +10 -0
  271. package/src/page-chrome/PageToolbar/fixtures.ts +8 -0
  272. package/src/page-chrome/SectionHeader/SectionHeader.test.tsx +28 -0
  273. package/src/page-chrome/SectionHeader/SectionHeader.tsx +73 -0
  274. package/src/page-chrome/SectionHeader/block.meta.ts +9 -0
  275. package/src/page-chrome/StickyActionBar/StickyActionBar.test.tsx +29 -0
  276. package/src/page-chrome/StickyActionBar/StickyActionBar.tsx +66 -0
  277. package/src/page-chrome/StickyActionBar/block.meta.ts +9 -0
  278. package/src/page-chrome/index.ts +13 -0
  279. package/src/page-chrome/types.ts +25 -0
  280. package/src/scheduling/AgendaList/AgendaList.test.tsx +28 -0
  281. package/src/scheduling/AgendaList/AgendaList.tsx +165 -0
  282. package/src/scheduling/AgendaList/block.meta.ts +10 -0
  283. package/src/scheduling/MonthCalendar/MonthCalendar.test.tsx +32 -0
  284. package/src/scheduling/MonthCalendar/MonthCalendar.tsx +223 -0
  285. package/src/scheduling/MonthCalendar/block.meta.ts +10 -0
  286. package/src/scheduling/TimeSlotPicker/TimeSlotPicker.test.tsx +26 -0
  287. package/src/scheduling/TimeSlotPicker/TimeSlotPicker.tsx +115 -0
  288. package/src/scheduling/TimeSlotPicker/block.meta.ts +10 -0
  289. package/src/scheduling/TimeSlotPicker/fixtures.ts +10 -0
  290. package/src/scheduling/WeekCalendar/WeekCalendar.test.tsx +27 -0
  291. package/src/scheduling/WeekCalendar/WeekCalendar.tsx +274 -0
  292. package/src/scheduling/WeekCalendar/block.meta.ts +10 -0
  293. package/src/scheduling/index.ts +11 -0
  294. package/src/scheduling/shared/CalendarHeader.tsx +54 -0
  295. package/src/scheduling/shared/EventTile.tsx +21 -0
  296. package/src/scheduling/shared/dates.ts +98 -0
  297. package/src/scheduling/shared/events.ts +90 -0
  298. package/src/scheduling/shared/fixtures.ts +54 -0
  299. package/src/shell/AppSidebar/AppSidebar.test.tsx +38 -0
  300. package/src/shell/AppSidebar/AppSidebar.tsx +226 -0
  301. package/src/shell/AppSidebar/block.meta.ts +10 -0
  302. package/src/shell/AppSidebar/fixtures.ts +58 -0
  303. package/src/shell/AppTopbar/AppTopbar.test.tsx +41 -0
  304. package/src/shell/AppTopbar/AppTopbar.tsx +82 -0
  305. package/src/shell/AppTopbar/block.meta.ts +19 -0
  306. package/src/shell/AppTopbar/fixtures.ts +22 -0
  307. package/src/shell/EnvironmentBadge/EnvironmentBadge.test.tsx +22 -0
  308. package/src/shell/EnvironmentBadge/EnvironmentBadge.tsx +55 -0
  309. package/src/shell/EnvironmentBadge/block.meta.ts +10 -0
  310. package/src/shell/GlobalSearch/GlobalSearch.test.tsx +28 -0
  311. package/src/shell/GlobalSearch/GlobalSearch.tsx +80 -0
  312. package/src/shell/GlobalSearch/block.meta.ts +10 -0
  313. package/src/shell/GlobalSearch/fixtures.ts +64 -0
  314. package/src/shell/index.ts +11 -0
  315. package/src/styles.css +2 -0
  316. package/src/tables/DataTable/DataTable.edit-views.test.tsx +249 -0
  317. package/src/tables/DataTable/DataTable.labels.test.tsx +291 -0
  318. package/src/tables/DataTable/DataTable.layout.test.tsx +188 -0
  319. package/src/tables/DataTable/DataTable.overflow-labels.test.tsx +59 -0
  320. package/src/tables/DataTable/DataTable.single-select.test.tsx +501 -0
  321. package/src/tables/DataTable/DataTable.test.tsx +268 -0
  322. package/src/tables/DataTable/DataTable.tsx +531 -0
  323. package/src/tables/DataTable/block.meta.ts +129 -0
  324. package/src/tables/DataTable/column-menu.tsx +112 -0
  325. package/src/tables/DataTable/column-sizing.ts +166 -0
  326. package/src/tables/DataTable/data-table-body.tsx +195 -0
  327. package/src/tables/DataTable/data-table-props.ts +159 -0
  328. package/src/tables/DataTable/data-table-row.tsx +231 -0
  329. package/src/tables/DataTable/data-table-utils.ts +195 -0
  330. package/src/tables/DataTable/density-toggle.tsx +33 -0
  331. package/src/tables/DataTable/editable-cell.tsx +287 -0
  332. package/src/tables/DataTable/examples/editable.tsx +71 -0
  333. package/src/tables/DataTable/examples/grouped.tsx +18 -0
  334. package/src/tables/DataTable/examples/resizable-pinned.tsx +20 -0
  335. package/src/tables/DataTable/examples/saved-views.tsx +61 -0
  336. package/src/tables/DataTable/examples/single-selection.tsx +55 -0
  337. package/src/tables/DataTable/examples/virtualized.tsx +20 -0
  338. package/src/tables/DataTable/fixtures.ts +119 -0
  339. package/src/tables/DataTable/header-cell.tsx +90 -0
  340. package/src/tables/DataTable/labels.ts +54 -0
  341. package/src/tables/DataTable/resize-handle.tsx +91 -0
  342. package/src/tables/DataTable/single-selection.tsx +149 -0
  343. package/src/tables/DataTable/use-table-views.ts +79 -0
  344. package/src/tables/DataTable/use-virtual-rows.ts +83 -0
  345. package/src/tables/DataTable/views.tsx +193 -0
  346. package/src/tables/FilterBar/FilterBar.labels.test.tsx +69 -0
  347. package/src/tables/FilterBar/FilterBar.test.tsx +43 -0
  348. package/src/tables/FilterBar/FilterBar.tsx +232 -0
  349. package/src/tables/FilterBar/block.meta.ts +32 -0
  350. package/src/tables/FilterBar/fixtures.ts +32 -0
  351. package/src/tables/InlineEditRow/InlineEditRow.test.tsx +41 -0
  352. package/src/tables/InlineEditRow/InlineEditRow.tsx +215 -0
  353. package/src/tables/InlineEditRow/block.meta.ts +10 -0
  354. package/src/tables/InlineEditRow/fixtures.ts +28 -0
  355. package/src/tables/PaginationFooter/PaginationFooter.labels.test.tsx +57 -0
  356. package/src/tables/PaginationFooter/PaginationFooter.test.tsx +29 -0
  357. package/src/tables/PaginationFooter/PaginationFooter.tsx +118 -0
  358. package/src/tables/PaginationFooter/block.meta.ts +33 -0
  359. package/src/tables/SubordinateList/SubordinateList.test.tsx +351 -0
  360. package/src/tables/SubordinateList/SubordinateList.tsx +140 -0
  361. package/src/tables/SubordinateList/block.meta.ts +10 -0
  362. package/src/tables/SubordinateList/examples/ResourceForm.tsx +129 -0
  363. package/src/tables/SubordinateList/examples/empty.tsx +5 -0
  364. package/src/tables/SubordinateList/examples/error.tsx +5 -0
  365. package/src/tables/SubordinateList/examples/loading.tsx +5 -0
  366. package/src/tables/TruncatedCollectionFooter/TruncatedCollectionFooter.test.tsx +159 -0
  367. package/src/tables/TruncatedCollectionFooter/TruncatedCollectionFooter.tsx +60 -0
  368. package/src/tables/TruncatedCollectionFooter/block.meta.ts +10 -0
  369. package/src/tables/TruncatedCollectionFooter/examples/exact.tsx +6 -0
  370. package/src/tables/TruncatedCollectionFooter/examples/has-more.tsx +12 -0
  371. package/src/tables/TruncatedCollectionFooter/fixtures.ts +2 -0
  372. package/src/tables/index.ts +45 -0
  373. package/src/team/MembersTable/MembersTable.test.tsx +29 -0
  374. package/src/team/MembersTable/MembersTable.tsx +141 -0
  375. package/src/team/MembersTable/block.meta.ts +9 -0
  376. package/src/team/MembersTable/fixtures.ts +19 -0
  377. package/src/team/NotificationMatrix/NotificationMatrix.test.tsx +36 -0
  378. package/src/team/NotificationMatrix/NotificationMatrix.tsx +144 -0
  379. package/src/team/NotificationMatrix/block.meta.ts +9 -0
  380. package/src/team/NotificationMatrix/fixtures.ts +43 -0
  381. package/src/team/PendingInvitations/PendingInvitations.test.tsx +30 -0
  382. package/src/team/PendingInvitations/PendingInvitations.tsx +132 -0
  383. package/src/team/PendingInvitations/block.meta.ts +9 -0
  384. package/src/team/PendingInvitations/fixtures.ts +39 -0
  385. package/src/team/ProfileHeader/ProfileHeader.test.tsx +29 -0
  386. package/src/team/ProfileHeader/ProfileHeader.tsx +106 -0
  387. package/src/team/ProfileHeader/block.meta.ts +10 -0
  388. package/src/team/ProfileHeader/fixtures.ts +28 -0
  389. package/src/team/SessionsDevices/SessionsDevices.test.tsx +30 -0
  390. package/src/team/SessionsDevices/SessionsDevices.tsx +126 -0
  391. package/src/team/SessionsDevices/block.meta.ts +10 -0
  392. package/src/team/SessionsDevices/fixtures.ts +58 -0
  393. package/src/team/index.ts +15 -0
  394. package/src/test/a11y.ts +18 -0
  395. package/src/test/heading-levels.test.tsx +69 -0
  396. package/src/test/setup.ts +36 -0
  397. package/README.md +0 -3
@@ -0,0 +1,351 @@
1
+ import { render, screen, within } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { I18nProvider } from '@gntik-ai/ui';
4
+ import { expectNoAxeViolations } from '../../test/a11y';
5
+ import type { DataTableColumn } from '../DataTable/data-table-utils';
6
+ import { SubordinateList, type SubordinateListProps } from './SubordinateList';
7
+ import ResourceFormExample from './examples/ResourceForm';
8
+
9
+ interface Row {
10
+ id: string;
11
+ name: string;
12
+ }
13
+ const columns: DataTableColumn<Row>[] = [{ id: 'name', header: 'Name', accessor: (row) => row.name, sortable: true }];
14
+ const rows: Row[] = Array.from({ length: 12 }, (_, i) => ({
15
+ id: String(i),
16
+ name: `Record ${i + 1}`,
17
+ }));
18
+ const props: SubordinateListProps<Row> = {
19
+ title: 'History',
20
+ headingLevel: 'h2',
21
+ count: 37,
22
+ columns,
23
+ rows,
24
+ getRowId: (row) => row.id,
25
+ pagination: null,
26
+ loading: false,
27
+ error: null,
28
+ onRetry: () => {},
29
+ emptyState: <p>No history yet</p>,
30
+ };
31
+
32
+ // The public prop contract: every omitted input must be a type error.
33
+ function requiredProps(input: SubordinateListProps<Row>) {
34
+ const { title, headingLevel, count, columns, rows, getRowId, pagination, loading, error, onRetry, emptyState } =
35
+ input;
36
+ // @ts-expect-error title is required
37
+ <SubordinateList
38
+ headingLevel={headingLevel}
39
+ count={count}
40
+ columns={columns}
41
+ rows={rows}
42
+ getRowId={getRowId}
43
+ pagination={pagination}
44
+ loading={loading}
45
+ error={error}
46
+ onRetry={onRetry}
47
+ emptyState={emptyState}
48
+ />;
49
+ // @ts-expect-error headingLevel is required
50
+ <SubordinateList
51
+ title={title}
52
+ count={count}
53
+ columns={columns}
54
+ rows={rows}
55
+ getRowId={getRowId}
56
+ pagination={pagination}
57
+ loading={loading}
58
+ error={error}
59
+ onRetry={onRetry}
60
+ emptyState={emptyState}
61
+ />;
62
+ // @ts-expect-error count is required
63
+ <SubordinateList
64
+ title={title}
65
+ headingLevel={headingLevel}
66
+ columns={columns}
67
+ rows={rows}
68
+ getRowId={getRowId}
69
+ pagination={pagination}
70
+ loading={loading}
71
+ error={error}
72
+ onRetry={onRetry}
73
+ emptyState={emptyState}
74
+ />;
75
+ // @ts-expect-error columns are required
76
+ <SubordinateList
77
+ title={title}
78
+ headingLevel={headingLevel}
79
+ count={count}
80
+ rows={rows}
81
+ getRowId={getRowId}
82
+ pagination={pagination}
83
+ loading={loading}
84
+ error={error}
85
+ onRetry={onRetry}
86
+ emptyState={emptyState}
87
+ />;
88
+ // @ts-expect-error rows are required
89
+ <SubordinateList
90
+ title={title}
91
+ headingLevel={headingLevel}
92
+ count={count}
93
+ columns={columns}
94
+ getRowId={getRowId}
95
+ pagination={pagination}
96
+ loading={loading}
97
+ error={error}
98
+ onRetry={onRetry}
99
+ emptyState={emptyState}
100
+ />;
101
+ // @ts-expect-error getRowId is required
102
+ <SubordinateList
103
+ title={title}
104
+ headingLevel={headingLevel}
105
+ count={count}
106
+ columns={columns}
107
+ rows={rows}
108
+ pagination={pagination}
109
+ loading={loading}
110
+ error={error}
111
+ onRetry={onRetry}
112
+ emptyState={emptyState}
113
+ />;
114
+ // @ts-expect-error pagination is required
115
+ <SubordinateList
116
+ title={title}
117
+ headingLevel={headingLevel}
118
+ count={count}
119
+ columns={columns}
120
+ rows={rows}
121
+ getRowId={getRowId}
122
+ loading={loading}
123
+ error={error}
124
+ onRetry={onRetry}
125
+ emptyState={emptyState}
126
+ />;
127
+ // @ts-expect-error loading is required
128
+ <SubordinateList
129
+ title={title}
130
+ headingLevel={headingLevel}
131
+ count={count}
132
+ columns={columns}
133
+ rows={rows}
134
+ getRowId={getRowId}
135
+ pagination={pagination}
136
+ error={error}
137
+ onRetry={onRetry}
138
+ emptyState={emptyState}
139
+ />;
140
+ // @ts-expect-error error is required
141
+ <SubordinateList
142
+ title={title}
143
+ headingLevel={headingLevel}
144
+ count={count}
145
+ columns={columns}
146
+ rows={rows}
147
+ getRowId={getRowId}
148
+ pagination={pagination}
149
+ loading={loading}
150
+ onRetry={onRetry}
151
+ emptyState={emptyState}
152
+ />;
153
+ // @ts-expect-error onRetry is required
154
+ <SubordinateList
155
+ title={title}
156
+ headingLevel={headingLevel}
157
+ count={count}
158
+ columns={columns}
159
+ rows={rows}
160
+ getRowId={getRowId}
161
+ pagination={pagination}
162
+ loading={loading}
163
+ error={error}
164
+ emptyState={emptyState}
165
+ />;
166
+ // @ts-expect-error emptyState is required
167
+ <SubordinateList
168
+ title={title}
169
+ headingLevel={headingLevel}
170
+ count={count}
171
+ columns={columns}
172
+ rows={rows}
173
+ getRowId={getRowId}
174
+ pagination={pagination}
175
+ loading={loading}
176
+ error={error}
177
+ onRetry={onRetry}
178
+ />;
179
+ }
180
+ void requiredProps;
181
+
182
+ describe('SubordinateList', () => {
183
+ it('embeds a paginated history and an unpaginated consumer section in a resource-form host', async () => {
184
+ render(<ResourceFormExample />);
185
+ expect(screen.getByRole('form', { name: 'Resource settings' })).toBeVisible();
186
+ const history = screen.getByRole('region', { name: 'History' });
187
+ const consumers = screen.getByRole('region', { name: 'Consumers' });
188
+ expect(within(history).getByRole('navigation', { name: 'History pagination' })).toBeVisible();
189
+ expect(within(consumers).queryByRole('navigation')).not.toBeInTheDocument();
190
+ await expectNoAxeViolations(document.body);
191
+ });
192
+
193
+ for (const theme of ['dark', 'light', 'high_contrast']) {
194
+ it.each(['default', 'loading', 'empty', 'error'] as const)(
195
+ `has no axe violations in ${theme} / %s`,
196
+ async (state) => {
197
+ document.documentElement.className = theme;
198
+ const { container } = render(
199
+ <SubordinateList
200
+ {...props}
201
+ loading={state === 'loading'}
202
+ rows={state === 'empty' ? [] : rows}
203
+ error={
204
+ state === 'error'
205
+ ? {
206
+ title: 'History unavailable',
207
+ message: 'Please retry.',
208
+ code: null,
209
+ }
210
+ : null
211
+ }
212
+ pagination={{
213
+ limit: 10,
214
+ offset: 0,
215
+ total: state === 'empty' ? 0 : 37,
216
+ onPageChange: () => {},
217
+ }}
218
+ />,
219
+ );
220
+ await expectNoAxeViolations(container);
221
+ },
222
+ );
223
+ }
224
+
225
+ it.each(['en', 'es'])('shows only the supplied error and retries the failing section once in %s', async (locale) => {
226
+ const user = userEvent.setup();
227
+ const onRetry = vi.fn();
228
+ render(
229
+ <I18nProvider locale={locale}>
230
+ <SubordinateList
231
+ {...props}
232
+ error={{
233
+ title: 'History unavailable',
234
+ message: 'Please retry this section.',
235
+ code: null,
236
+ }}
237
+ onRetry={onRetry}
238
+ />
239
+ <SubordinateList {...props} title="Consumers" headingLevel="h3" />
240
+ </I18nProvider>,
241
+ );
242
+ const failed = screen.getByRole('region', { name: 'History' });
243
+ expect(
244
+ within(failed).getByRole('heading', {
245
+ name: 'History unavailable',
246
+ level: 3,
247
+ }),
248
+ ).toBeVisible();
249
+ expect(failed).toHaveTextContent('Please retry this section.');
250
+ expect(failed).not.toHaveTextContent(/503|req_|Contact support|deployments|Add policy/i);
251
+ expect(within(failed).queryByRole('table')).not.toBeInTheDocument();
252
+ expect(within(failed).queryByRole('navigation')).not.toBeInTheDocument();
253
+ const retryLabel = locale === 'es' ? 'Reintentar' : 'Try again';
254
+ await user.click(within(failed).getByRole('button', { name: retryLabel }));
255
+ expect(onRetry).toHaveBeenCalledTimes(1);
256
+ const healthy = screen.getByRole('region', { name: 'Consumers' });
257
+ expect(within(healthy).getByRole('table', { name: 'Consumers' })).toBeVisible();
258
+ expect(within(healthy).queryByRole('button', { name: retryLabel })).not.toBeInTheDocument();
259
+ });
260
+
261
+ it('shows an explicit error code and keeps the header while a section has failed', () => {
262
+ render(
263
+ <SubordinateList
264
+ {...props}
265
+ error={{
266
+ title: 'History unavailable',
267
+ message: 'Try later.',
268
+ code: 'E_LOAD',
269
+ }}
270
+ />,
271
+ );
272
+ expect(screen.getByText('E_LOAD')).toBeVisible();
273
+ expect(screen.getByRole('heading', { name: 'History', level: 2 })).toBeVisible();
274
+ });
275
+
276
+ it('replaces the table and pagination with a busy TableSkeleton while loading', () => {
277
+ render(
278
+ <SubordinateList
279
+ {...props}
280
+ loading={true}
281
+ pagination={{ limit: 10, offset: 0, total: 37, onPageChange: () => {} }}
282
+ />,
283
+ );
284
+ expect(screen.getByRole('region', { name: 'History' })).toHaveAttribute('aria-busy', 'true');
285
+ expect(screen.getByRole('status')).toHaveTextContent('Loading table');
286
+ expect(screen.queryByRole('table')).not.toBeInTheDocument();
287
+ expect(screen.queryByRole('navigation')).not.toBeInTheDocument();
288
+ });
289
+
290
+ it('renders the host empty state instead of a table when rows are empty', () => {
291
+ render(<SubordinateList {...props} rows={[]} count={0} />);
292
+ expect(screen.getByText('No history yet')).toBeVisible();
293
+ expect(screen.queryByRole('table')).not.toBeInTheDocument();
294
+ expect(screen.getByRole('region', { name: 'History' })).toHaveAttribute('aria-busy', 'false');
295
+ });
296
+
297
+ it('renders every supplied row with server pagination and translates page 2 to offset 10', async () => {
298
+ const user = userEvent.setup();
299
+ const onPageChange = vi.fn();
300
+ const { rerender } = render(
301
+ <SubordinateList {...props} pagination={{ limit: 10, offset: 0, total: 37, onPageChange }} />,
302
+ );
303
+ expect(screen.getAllByRole('row')).toHaveLength(13);
304
+ expect(screen.getByRole('region', { name: 'History' })).toHaveTextContent('1–10 of 37');
305
+ expect(screen.getByRole('navigation', { name: 'History pagination' })).toBeVisible();
306
+ await user.click(screen.getByRole('button', { name: 'Page 2' }));
307
+ expect(onPageChange).toHaveBeenCalledExactlyOnceWith(10);
308
+ // Controlled: only a new host offset changes the page summary.
309
+ expect(screen.getByText('1–10')).toBeVisible();
310
+ rerender(<SubordinateList {...props} pagination={{ limit: 10, offset: 10, total: 37, onPageChange }} />);
311
+ expect(screen.getByText('11–20')).toBeVisible();
312
+ await user.click(screen.getByRole('combobox', { name: 'Rows per page' }));
313
+ expect(await screen.findAllByRole('option')).toHaveLength(1);
314
+ expect(screen.getByRole('option', { name: '10' })).toBeVisible();
315
+ });
316
+
317
+ it('renders a large unpaginated collection without list controls, sorting, virtualization or sticky elements', () => {
318
+ const largeRows = Array.from({ length: 120 }, (_, i) => ({
319
+ id: String(i),
320
+ name: `Entry ${i}`,
321
+ }));
322
+ const { container } = render(<SubordinateList {...props} rows={largeRows} count={120} />);
323
+ expect(screen.getAllByRole('row')).toHaveLength(121);
324
+ expect(screen.queryByRole('navigation')).not.toBeInTheDocument();
325
+ expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
326
+ expect(screen.queryByRole('button')).not.toBeInTheDocument();
327
+ expect(screen.queryByRole('toolbar')).not.toBeInTheDocument();
328
+ expect(screen.queryByRole('searchbox')).not.toBeInTheDocument();
329
+ expect(screen.getByRole('table', { name: 'History' })).not.toHaveAttribute('data-virtualized');
330
+ for (const element of container.querySelectorAll<HTMLElement>('*')) {
331
+ expect(element.classList.contains('sticky')).toBe(false);
332
+ expect(getComputedStyle(element).position).not.toBe('sticky');
333
+ }
334
+ });
335
+
336
+ it.each(['h2', 'h3'] as const)(
337
+ 'labels the section with its %s heading and shows count 0 without fixture actions or description',
338
+ (headingLevel) => {
339
+ render(<SubordinateList {...props} headingLevel={headingLevel} count={0} />);
340
+ const region = screen.getByRole('region', { name: 'History' });
341
+ const heading = within(region).getByRole('heading', {
342
+ name: 'History',
343
+ level: headingLevel === 'h2' ? 2 : 3,
344
+ });
345
+ expect(region).toHaveAttribute('aria-labelledby', heading.id);
346
+ expect(within(region).getByText('0')).toBeVisible();
347
+ expect(within(region).queryByRole('button')).not.toBeInTheDocument();
348
+ expect(region).not.toHaveTextContent(/Add policy|Guardrails|deployments/i);
349
+ },
350
+ );
351
+ });
@@ -0,0 +1,140 @@
1
+ import { useId, type ReactNode } from 'react';
2
+ import { SectionHeader } from '../../page-chrome/SectionHeader/SectionHeader';
3
+ import { TableSkeleton } from '../../feedback/Skeletons/Skeletons';
4
+ import { ErrorPanel } from '../../feedback/ErrorPanel/ErrorPanel';
5
+ import { ServerCrash } from '@gntik-ai/icons';
6
+ import { DataTable } from '../DataTable/DataTable';
7
+ import type { DataTableColumn } from '../DataTable/data-table-utils';
8
+ import { PaginationFooter } from '../PaginationFooter/PaginationFooter';
9
+ import { useI18n } from '@gntik-ai/ui';
10
+
11
+ export interface SubordinateListPagination {
12
+ /** Positive server page size. */
13
+ limit: number;
14
+ /** Zero-based server offset. */
15
+ offset: number;
16
+ total: number;
17
+ onPageChange: (offset: number) => void;
18
+ }
19
+
20
+ export interface SubordinateListError {
21
+ title: string;
22
+ message: string;
23
+ /** null hides the error code chip. */
24
+ code: string | number | null;
25
+ }
26
+
27
+ export interface SubordinateListProps<T> {
28
+ title: string;
29
+ headingLevel: 'h2' | 'h3';
30
+ /** Server total, or the length of an unpaginated collection (including zero). */
31
+ count: number;
32
+ columns: ReadonlyArray<DataTableColumn<T>>;
33
+ rows: readonly T[];
34
+ getRowId: (row: T) => string;
35
+ pagination: SubordinateListPagination | null;
36
+ loading: boolean;
37
+ error: SubordinateListError | null;
38
+ onRetry: () => void | Promise<void>;
39
+ /** Host-supplied EmptyStates composition. */
40
+ emptyState: ReactNode;
41
+ }
42
+
43
+ /** Read-only list section with explicit host data and no demo defaults. */
44
+ export function SubordinateList<T>({
45
+ title,
46
+ headingLevel,
47
+ count,
48
+ columns,
49
+ rows,
50
+ getRowId,
51
+ pagination,
52
+ loading,
53
+ error,
54
+ onRetry,
55
+ emptyState,
56
+ }: SubordinateListProps<T>) {
57
+ const headingId = useId();
58
+ const { locale, t } = useI18n();
59
+ return (
60
+ <section aria-labelledby={headingId} aria-busy={loading} className="space-y-4">
61
+ <SectionHeader
62
+ title={title}
63
+ as={headingLevel}
64
+ count={count}
65
+ description={null}
66
+ actions={[]}
67
+ bordered={true}
68
+ headingId={headingId}
69
+ className=""
70
+ />
71
+ {error !== null ? (
72
+ <ErrorPanel
73
+ icon={ServerCrash}
74
+ title={error.title}
75
+ message={error.message}
76
+ code={error.code}
77
+ requestId=""
78
+ details=""
79
+ onRetry={onRetry}
80
+ retrying={undefined}
81
+ retryLabel={t('error.retry')}
82
+ secondaryAction={null}
83
+ titleAs="h3"
84
+ className=""
85
+ />
86
+ ) : loading ? (
87
+ <TableSkeleton rows={pagination?.limit ?? 5} columns={columns.length} label={t('loading.table')} className="" />
88
+ ) : rows.length === 0 ? (
89
+ emptyState
90
+ ) : (
91
+ <DataTable
92
+ rows={rows}
93
+ columns={columns.map((column) => ({
94
+ ...column,
95
+ sortable: false,
96
+ editable: false,
97
+ }))}
98
+ getRowId={getRowId}
99
+ caption={title}
100
+ showCaption={false}
101
+ paginated={false}
102
+ selectable={false}
103
+ selectedIds={[]}
104
+ selectionSummary={false}
105
+ sort={null}
106
+ defaultSort={null}
107
+ manualSorting={true}
108
+ showColumnMenu={false}
109
+ showDensityToggle={false}
110
+ showViewSwitcher={false}
111
+ resizable={false}
112
+ pinnedColumns={{}}
113
+ showPinMenu={false}
114
+ virtualize={false}
115
+ hiddenColumns={[]}
116
+ toolbar={null}
117
+ loading={false}
118
+ loadingRows={0}
119
+ emptyState={emptyState}
120
+ className=""
121
+ />
122
+ )}
123
+ {error === null && !loading && pagination !== null && (
124
+ <PaginationFooter
125
+ total={pagination.total}
126
+ page={Math.floor(pagination.offset / pagination.limit) + 1}
127
+ defaultPage={1}
128
+ onPageChange={(page) => pagination.onPageChange((page - 1) * pagination.limit)}
129
+ pageSize={pagination.limit}
130
+ defaultPageSize={pagination.limit}
131
+ onPageSizeChange={() => {}}
132
+ pageSizeOptions={[pagination.limit]}
133
+ noun={title}
134
+ locale={locale}
135
+ className=""
136
+ />
137
+ )}
138
+ </section>
139
+ );
140
+ }
@@ -0,0 +1,10 @@
1
+ import type { BlockMeta } from '../../meta';
2
+
3
+ export const meta: BlockMeta = {
4
+ name: 'Subordinate list',
5
+ family: 'tables',
6
+ status: 'beta',
7
+ description:
8
+ 'Read-only list section inside a resource-form host, composing section-header, data-table, pagination-footer, empty-states, skeletons and error-panel. All props are required: title (string), headingLevel (h2 or h3), count (number, including 0), columns (typed DataTableColumn<T>[]), rows (readonly T[]), getRowId, pagination ({limit, offset, total, onPageChange(offset)} or null), loading (boolean), error ({title, message, code: string | number | null} or null), onRetry and emptyState (host-supplied ReactNode). Every supplied row renders; server pagination converts the zero-based offset to a 1-based footer page and fixes pageSizeOptions to [limit]. No filtering, sorting, selection, create action, toolbar, virtualization, pinning or sticky region. Error takes precedence over loading, then empty and data; retry uses the current i18n locale. Error headings use h3 for either section heading level. Composition example: packages/blocks/src/tables/SubordinateList/examples/ResourceForm.tsx uses the resource-form form sections and sticky save bar with a server-paginated History section and an unpaginated Consumers section.',
9
+ uses: ['section-header', 'data-table', 'pagination-footer', 'empty-states', 'skeletons', 'error-panel'],
10
+ };
@@ -0,0 +1,129 @@
1
+ import { Field, FieldLabel, Input, Page, Stack } from '@gntik-ai/ui';
2
+ import { useState } from 'react';
3
+ import { FormSection } from '../../../forms/FormSection/FormSection';
4
+ import { NoResultsEmpty } from '../../../feedback/EmptyStates/EmptyStates';
5
+ import { StickyActionBar } from '../../../page-chrome/StickyActionBar/StickyActionBar';
6
+ import { SubordinateList } from '../SubordinateList';
7
+ import type { DataTableColumn } from '../../DataTable/data-table-utils';
8
+
9
+ interface RecordRow {
10
+ id: string;
11
+ name: string;
12
+ status: string;
13
+ }
14
+ const columns: DataTableColumn<RecordRow>[] = [
15
+ { id: 'name', header: 'Name', accessor: (row) => row.name },
16
+ { id: 'status', header: 'Status', accessor: (row) => row.status },
17
+ ];
18
+ const history: RecordRow[] = Array.from({ length: 37 }, (_, i) => ({
19
+ id: `record-${i}`,
20
+ name: `Revision ${i + 1}`,
21
+ status: 'Completed',
22
+ }));
23
+ const consumers: RecordRow[] = [
24
+ { id: 'worker', name: 'Worker', status: 'Current' },
25
+ { id: 'scheduler', name: 'Scheduler', status: 'Current' },
26
+ ];
27
+
28
+ export type ExampleState = 'default' | 'loading' | 'empty' | 'error';
29
+
30
+ /** A resource-form host owns the form and sticky save bar; its two lists load independently. */
31
+ export default function ResourceFormExample({ state = 'default' }: { state?: ExampleState }) {
32
+ const [name, setName] = useState('Shared resource');
33
+ const [savedName, setSavedName] = useState(name);
34
+ const [offset, setOffset] = useState(0);
35
+ const [failed, setFailed] = useState(state === 'error');
36
+ return (
37
+ <Page title="Resource settings" description="Edit a resource and review its related records.">
38
+ <form
39
+ aria-label="Resource settings"
40
+ onSubmit={(event) => {
41
+ event.preventDefault();
42
+ setSavedName(name);
43
+ }}
44
+ >
45
+ <Stack gap={8}>
46
+ <FormSection
47
+ title="General"
48
+ description="Settings for this resource."
49
+ actions={null}
50
+ headingLevel="h2"
51
+ divided={false}
52
+ >
53
+ <Field>
54
+ <FieldLabel>Resource name</FieldLabel>
55
+ <Input value={name} onValueChange={setName} />
56
+ </Field>
57
+ </FormSection>
58
+ <SubordinateList
59
+ title="History"
60
+ headingLevel="h2"
61
+ count={state === 'empty' ? 0 : history.length}
62
+ columns={columns}
63
+ rows={state === 'empty' ? [] : history.slice(offset, offset + 10)}
64
+ getRowId={(row) => row.id}
65
+ pagination={{
66
+ limit: 10,
67
+ offset,
68
+ total: state === 'empty' ? 0 : history.length,
69
+ onPageChange: setOffset,
70
+ }}
71
+ loading={state === 'loading'}
72
+ error={
73
+ failed
74
+ ? {
75
+ title: 'History unavailable',
76
+ message: 'Please retry to load the history.',
77
+ code: null,
78
+ }
79
+ : null
80
+ }
81
+ onRetry={() => setFailed(false)}
82
+ emptyState={
83
+ <NoResultsEmpty
84
+ query=""
85
+ filterCount={0}
86
+ entity="history records"
87
+ titleAs="h3"
88
+ bordered={true}
89
+ className=""
90
+ onClearFilters={() => {}}
91
+ onClearSearch={() => {}}
92
+ />
93
+ }
94
+ />
95
+ <SubordinateList
96
+ title="Consumers"
97
+ headingLevel="h2"
98
+ count={consumers.length}
99
+ columns={columns}
100
+ rows={consumers}
101
+ getRowId={(row) => row.id}
102
+ pagination={null}
103
+ loading={false}
104
+ error={null}
105
+ onRetry={() => {}}
106
+ emptyState={
107
+ <NoResultsEmpty
108
+ query=""
109
+ filterCount={0}
110
+ entity="consumers"
111
+ titleAs="h3"
112
+ bordered={true}
113
+ className=""
114
+ onClearFilters={() => {}}
115
+ onClearSearch={() => {}}
116
+ />
117
+ }
118
+ />
119
+ <StickyActionBar
120
+ dirty={name !== savedName}
121
+ saving={false}
122
+ onSave={() => setSavedName(name)}
123
+ onCancel={() => setName(savedName)}
124
+ />
125
+ </Stack>
126
+ </form>
127
+ </Page>
128
+ );
129
+ }
@@ -0,0 +1,5 @@
1
+ import ResourceFormExample from './ResourceForm';
2
+
3
+ export default function Empty() {
4
+ return <ResourceFormExample state="empty" />;
5
+ }
@@ -0,0 +1,5 @@
1
+ import ResourceFormExample from './ResourceForm';
2
+
3
+ export default function Error() {
4
+ return <ResourceFormExample state="error" />;
5
+ }
@@ -0,0 +1,5 @@
1
+ import ResourceFormExample from './ResourceForm';
2
+
3
+ export default function Loading() {
4
+ return <ResourceFormExample state="loading" />;
5
+ }