@stigmer/react 3.2.2 → 3.3.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 (513) hide show
  1. package/agent/AgentDetailView.d.ts.map +1 -1
  2. package/agent/AgentDetailView.js +6 -3
  3. package/agent/AgentDetailView.js.map +1 -1
  4. package/agent/steps/ReviewStep.d.ts.map +1 -1
  5. package/agent/steps/ReviewStep.js +2 -3
  6. package/agent/steps/ReviewStep.js.map +1 -1
  7. package/billing/BaselineEditor.d.ts +9 -0
  8. package/billing/BaselineEditor.d.ts.map +1 -0
  9. package/billing/BaselineEditor.js +253 -0
  10. package/billing/BaselineEditor.js.map +1 -0
  11. package/billing/ModelCatalogPanel.d.ts +28 -0
  12. package/billing/ModelCatalogPanel.d.ts.map +1 -0
  13. package/billing/ModelCatalogPanel.js +102 -0
  14. package/billing/ModelCatalogPanel.js.map +1 -0
  15. package/billing/ModelGovernanceDetail.d.ts +8 -0
  16. package/billing/ModelGovernanceDetail.d.ts.map +1 -0
  17. package/billing/ModelGovernanceDetail.js +64 -0
  18. package/billing/ModelGovernanceDetail.js.map +1 -0
  19. package/billing/OperatorAccessNotice.d.ts +12 -0
  20. package/billing/OperatorAccessNotice.d.ts.map +1 -0
  21. package/billing/OperatorAccessNotice.js +15 -0
  22. package/billing/OperatorAccessNotice.js.map +1 -0
  23. package/billing/PricingGovernanceConsole.d.ts +57 -0
  24. package/billing/PricingGovernanceConsole.d.ts.map +1 -0
  25. package/billing/PricingGovernanceConsole.js +164 -0
  26. package/billing/PricingGovernanceConsole.js.map +1 -0
  27. package/billing/PricingGovernancePanel.d.ts +26 -0
  28. package/billing/PricingGovernancePanel.d.ts.map +1 -0
  29. package/billing/PricingGovernancePanel.js +64 -0
  30. package/billing/PricingGovernancePanel.js.map +1 -0
  31. package/billing/RetireConfirm.d.ts +9 -0
  32. package/billing/RetireConfirm.d.ts.map +1 -0
  33. package/billing/RetireConfirm.js +19 -0
  34. package/billing/RetireConfirm.js.map +1 -0
  35. package/billing/form-primitives.d.ts +18 -0
  36. package/billing/form-primitives.d.ts.map +1 -0
  37. package/billing/form-primitives.js +19 -0
  38. package/billing/form-primitives.js.map +1 -0
  39. package/billing/governance-primitives.d.ts +33 -0
  40. package/billing/governance-primitives.d.ts.map +1 -0
  41. package/billing/governance-primitives.js +43 -0
  42. package/billing/governance-primitives.js.map +1 -0
  43. package/billing/index.d.ts +18 -0
  44. package/billing/index.d.ts.map +1 -1
  45. package/billing/index.js +9 -0
  46. package/billing/index.js.map +1 -1
  47. package/billing/pricing-format.d.ts +12 -0
  48. package/billing/pricing-format.d.ts.map +1 -0
  49. package/billing/pricing-format.js +50 -0
  50. package/billing/pricing-format.js.map +1 -0
  51. package/billing/useDecidePricingOverride.d.ts +46 -0
  52. package/billing/useDecidePricingOverride.d.ts.map +1 -0
  53. package/billing/useDecidePricingOverride.js +44 -0
  54. package/billing/useDecidePricingOverride.js.map +1 -0
  55. package/billing/useModelGovernanceView.d.ts +103 -0
  56. package/billing/useModelGovernanceView.d.ts.map +1 -0
  57. package/billing/useModelGovernanceView.js +144 -0
  58. package/billing/useModelGovernanceView.js.map +1 -0
  59. package/billing/useModelPricingBaselines.d.ts +40 -0
  60. package/billing/useModelPricingBaselines.d.ts.map +1 -0
  61. package/billing/useModelPricingBaselines.js +32 -0
  62. package/billing/useModelPricingBaselines.js.map +1 -0
  63. package/billing/usePricingGovernance.d.ts +39 -0
  64. package/billing/usePricingGovernance.d.ts.map +1 -0
  65. package/billing/usePricingGovernance.js +31 -0
  66. package/billing/usePricingGovernance.js.map +1 -0
  67. package/billing/useRetireModelPricingBaseline.d.ts +31 -0
  68. package/billing/useRetireModelPricingBaseline.d.ts.map +1 -0
  69. package/billing/useRetireModelPricingBaseline.js +36 -0
  70. package/billing/useRetireModelPricingBaseline.js.map +1 -0
  71. package/billing/useUpsertModelPricingBaseline.d.ts +38 -0
  72. package/billing/useUpsertModelPricingBaseline.d.ts.map +1 -0
  73. package/billing/useUpsertModelPricingBaseline.js +37 -0
  74. package/billing/useUpsertModelPricingBaseline.js.map +1 -0
  75. package/channel/AgentChannelsPanel.d.ts.map +1 -1
  76. package/channel/AgentChannelsPanel.js +11 -5
  77. package/channel/AgentChannelsPanel.js.map +1 -1
  78. package/composer/SessionComposer.d.ts +1 -1
  79. package/cursor-accounts/CursorAccountEditor.d.ts +28 -0
  80. package/cursor-accounts/CursorAccountEditor.d.ts.map +1 -0
  81. package/cursor-accounts/CursorAccountEditor.js +51 -0
  82. package/cursor-accounts/CursorAccountEditor.js.map +1 -0
  83. package/cursor-accounts/CursorAccountsAccessNotice.d.ts +11 -0
  84. package/cursor-accounts/CursorAccountsAccessNotice.d.ts.map +1 -0
  85. package/cursor-accounts/CursorAccountsAccessNotice.js +14 -0
  86. package/cursor-accounts/CursorAccountsAccessNotice.js.map +1 -0
  87. package/cursor-accounts/CursorAccountsConsole.d.ts +28 -0
  88. package/cursor-accounts/CursorAccountsConsole.d.ts.map +1 -0
  89. package/cursor-accounts/CursorAccountsConsole.js +275 -0
  90. package/cursor-accounts/CursorAccountsConsole.js.map +1 -0
  91. package/cursor-accounts/cursor-account-format.d.ts +10 -0
  92. package/cursor-accounts/cursor-account-format.d.ts.map +1 -0
  93. package/cursor-accounts/cursor-account-format.js +26 -0
  94. package/cursor-accounts/cursor-account-format.js.map +1 -0
  95. package/cursor-accounts/index.d.ts +18 -0
  96. package/cursor-accounts/index.d.ts.map +1 -0
  97. package/cursor-accounts/index.js +13 -0
  98. package/cursor-accounts/index.js.map +1 -0
  99. package/cursor-accounts/useCursorAccountView.d.ts +30 -0
  100. package/cursor-accounts/useCursorAccountView.d.ts.map +1 -0
  101. package/cursor-accounts/useCursorAccountView.js +25 -0
  102. package/cursor-accounts/useCursorAccountView.js.map +1 -0
  103. package/cursor-accounts/useCursorAccounts.d.ts +33 -0
  104. package/cursor-accounts/useCursorAccounts.d.ts.map +1 -0
  105. package/cursor-accounts/useCursorAccounts.js +25 -0
  106. package/cursor-accounts/useCursorAccounts.js.map +1 -0
  107. package/cursor-accounts/useCursorMemberKeyActions.d.ts +49 -0
  108. package/cursor-accounts/useCursorMemberKeyActions.d.ts.map +1 -0
  109. package/cursor-accounts/useCursorMemberKeyActions.js +38 -0
  110. package/cursor-accounts/useCursorMemberKeyActions.js.map +1 -0
  111. package/cursor-accounts/useDeleteCursorAccount.d.ts +30 -0
  112. package/cursor-accounts/useDeleteCursorAccount.d.ts.map +1 -0
  113. package/cursor-accounts/useDeleteCursorAccount.js +32 -0
  114. package/cursor-accounts/useDeleteCursorAccount.js.map +1 -0
  115. package/cursor-accounts/useSyncCursorAccount.d.ts +23 -0
  116. package/cursor-accounts/useSyncCursorAccount.d.ts.map +1 -0
  117. package/cursor-accounts/useSyncCursorAccount.js +31 -0
  118. package/cursor-accounts/useSyncCursorAccount.js.map +1 -0
  119. package/cursor-accounts/useUpsertCursorAccount.d.ts +26 -0
  120. package/cursor-accounts/useUpsertCursorAccount.d.ts.map +1 -0
  121. package/cursor-accounts/useUpsertCursorAccount.js +34 -0
  122. package/cursor-accounts/useUpsertCursorAccount.js.map +1 -0
  123. package/datastore/CollectionRecordsBrowser.d.ts +34 -0
  124. package/datastore/CollectionRecordsBrowser.d.ts.map +1 -0
  125. package/datastore/CollectionRecordsBrowser.js +209 -0
  126. package/datastore/CollectionRecordsBrowser.js.map +1 -0
  127. package/datastore/CollectionSchemaView.d.ts +29 -0
  128. package/datastore/CollectionSchemaView.d.ts.map +1 -0
  129. package/datastore/CollectionSchemaView.js +93 -0
  130. package/datastore/CollectionSchemaView.js.map +1 -0
  131. package/datastore/DatastoreDetailView.d.ts +44 -0
  132. package/datastore/DatastoreDetailView.d.ts.map +1 -0
  133. package/datastore/DatastoreDetailView.js +76 -0
  134. package/datastore/DatastoreDetailView.js.map +1 -0
  135. package/datastore/DatastoreSyncReport.d.ts +19 -0
  136. package/datastore/DatastoreSyncReport.d.ts.map +1 -0
  137. package/datastore/DatastoreSyncReport.js +45 -0
  138. package/datastore/DatastoreSyncReport.js.map +1 -0
  139. package/datastore/DeleteDatastoreDialog.d.ts +35 -0
  140. package/datastore/DeleteDatastoreDialog.d.ts.map +1 -0
  141. package/datastore/DeleteDatastoreDialog.js +90 -0
  142. package/datastore/DeleteDatastoreDialog.js.map +1 -0
  143. package/datastore/FieldValueControl.d.ts +55 -0
  144. package/datastore/FieldValueControl.d.ts.map +1 -0
  145. package/datastore/FieldValueControl.js +138 -0
  146. package/datastore/FieldValueControl.js.map +1 -0
  147. package/datastore/RecordFilterBuilder.d.ts +30 -0
  148. package/datastore/RecordFilterBuilder.d.ts.map +1 -0
  149. package/datastore/RecordFilterBuilder.js +122 -0
  150. package/datastore/RecordFilterBuilder.js.map +1 -0
  151. package/datastore/RecordFormPanel.d.ts +45 -0
  152. package/datastore/RecordFormPanel.d.ts.map +1 -0
  153. package/datastore/RecordFormPanel.js +215 -0
  154. package/datastore/RecordFormPanel.js.map +1 -0
  155. package/datastore/index.d.ts +43 -0
  156. package/datastore/index.d.ts.map +1 -0
  157. package/datastore/index.js +22 -0
  158. package/datastore/index.js.map +1 -0
  159. package/datastore/recordFilter.d.ts +54 -0
  160. package/datastore/recordFilter.d.ts.map +1 -0
  161. package/datastore/recordFilter.js +93 -0
  162. package/datastore/recordFilter.js.map +1 -0
  163. package/datastore/recordValues.d.ts +85 -0
  164. package/datastore/recordValues.d.ts.map +1 -0
  165. package/datastore/recordValues.js +282 -0
  166. package/datastore/recordValues.js.map +1 -0
  167. package/datastore/useDatastore.d.ts +39 -0
  168. package/datastore/useDatastore.d.ts.map +1 -0
  169. package/datastore/useDatastore.js +44 -0
  170. package/datastore/useDatastore.js.map +1 -0
  171. package/datastore/useDatastoreCount.d.ts +48 -0
  172. package/datastore/useDatastoreCount.d.ts.map +1 -0
  173. package/datastore/useDatastoreCount.js +27 -0
  174. package/datastore/useDatastoreCount.js.map +1 -0
  175. package/datastore/useDatastoreDescription.d.ts +54 -0
  176. package/datastore/useDatastoreDescription.d.ts.map +1 -0
  177. package/datastore/useDatastoreDescription.js +50 -0
  178. package/datastore/useDatastoreDescription.js.map +1 -0
  179. package/datastore/useDatastoreList.d.ts +57 -0
  180. package/datastore/useDatastoreList.d.ts.map +1 -0
  181. package/datastore/useDatastoreList.js +29 -0
  182. package/datastore/useDatastoreList.js.map +1 -0
  183. package/datastore/useDatastoreSearch.d.ts +19 -0
  184. package/datastore/useDatastoreSearch.d.ts.map +1 -0
  185. package/datastore/useDatastoreSearch.js +22 -0
  186. package/datastore/useDatastoreSearch.js.map +1 -0
  187. package/datastore/useDeleteDatastore.d.ts +53 -0
  188. package/datastore/useDeleteDatastore.d.ts.map +1 -0
  189. package/datastore/useDeleteDatastore.js +40 -0
  190. package/datastore/useDeleteDatastore.js.map +1 -0
  191. package/datastore/useDeleteRecord.d.ts +34 -0
  192. package/datastore/useDeleteRecord.d.ts.map +1 -0
  193. package/datastore/useDeleteRecord.js +43 -0
  194. package/datastore/useDeleteRecord.js.map +1 -0
  195. package/datastore/useInsertRecord.d.ts +50 -0
  196. package/datastore/useInsertRecord.d.ts.map +1 -0
  197. package/datastore/useInsertRecord.js +55 -0
  198. package/datastore/useInsertRecord.js.map +1 -0
  199. package/datastore/useRecordCollection.d.ts +104 -0
  200. package/datastore/useRecordCollection.d.ts.map +1 -0
  201. package/datastore/useRecordCollection.js +136 -0
  202. package/datastore/useRecordCollection.js.map +1 -0
  203. package/datastore/useRecordList.d.ts +66 -0
  204. package/datastore/useRecordList.d.ts.map +1 -0
  205. package/datastore/useRecordList.js +58 -0
  206. package/datastore/useRecordList.js.map +1 -0
  207. package/datastore/useUpdateRecord.d.ts +52 -0
  208. package/datastore/useUpdateRecord.d.ts.map +1 -0
  209. package/datastore/useUpdateRecord.js +55 -0
  210. package/datastore/useUpdateRecord.js.map +1 -0
  211. package/environment/EnvironmentListPanel.d.ts.map +1 -1
  212. package/environment/EnvironmentListPanel.js +12 -7
  213. package/environment/EnvironmentListPanel.js.map +1 -1
  214. package/execution/index.d.ts +1 -2
  215. package/execution/index.d.ts.map +1 -1
  216. package/execution/index.js +0 -1
  217. package/execution/index.js.map +1 -1
  218. package/execution/useLiveAgentExecution.d.ts +17 -1
  219. package/execution/useLiveAgentExecution.d.ts.map +1 -1
  220. package/execution/useLiveAgentExecution.js +19 -4
  221. package/execution/useLiveAgentExecution.js.map +1 -1
  222. package/iam-policy/index.d.ts +1 -1
  223. package/iam-policy/index.d.ts.map +1 -1
  224. package/iam-policy/index.js.map +1 -1
  225. package/iam-policy/useCheckPermission.d.ts +32 -11
  226. package/iam-policy/useCheckPermission.d.ts.map +1 -1
  227. package/iam-policy/useCheckPermission.js +24 -19
  228. package/iam-policy/useCheckPermission.js.map +1 -1
  229. package/index.d.ts +16 -10
  230. package/index.d.ts.map +1 -1
  231. package/index.js +16 -5
  232. package/index.js.map +1 -1
  233. package/internal/useInViewport.d.ts +24 -0
  234. package/internal/useInViewport.d.ts.map +1 -0
  235. package/internal/useInViewport.js +49 -0
  236. package/internal/useInViewport.js.map +1 -0
  237. package/library/VisibilitySelector.d.ts +22 -6
  238. package/library/VisibilitySelector.d.ts.map +1 -1
  239. package/library/VisibilitySelector.js +12 -4
  240. package/library/VisibilitySelector.js.map +1 -1
  241. package/library/index.d.ts +1 -8
  242. package/library/index.d.ts.map +1 -1
  243. package/library/index.js +0 -4
  244. package/library/index.js.map +1 -1
  245. package/library/useApplyResource.d.ts +12 -12
  246. package/library/useApplyResource.d.ts.map +1 -1
  247. package/library/useApplyResource.js +16 -25
  248. package/library/useApplyResource.js.map +1 -1
  249. package/library/useExportResource.d.ts +13 -9
  250. package/library/useExportResource.d.ts.map +1 -1
  251. package/library/useExportResource.js +18 -36
  252. package/library/useExportResource.js.map +1 -1
  253. package/manifest/ApplyManifestDialog.d.ts +48 -0
  254. package/manifest/ApplyManifestDialog.d.ts.map +1 -0
  255. package/manifest/ApplyManifestDialog.js +135 -0
  256. package/manifest/ApplyManifestDialog.js.map +1 -0
  257. package/manifest/EditResourceYamlDialog.d.ts +51 -0
  258. package/manifest/EditResourceYamlDialog.d.ts.map +1 -0
  259. package/manifest/EditResourceYamlDialog.js +104 -0
  260. package/manifest/EditResourceYamlDialog.js.map +1 -0
  261. package/manifest/RedactedSecretsNotice.d.ts +14 -0
  262. package/manifest/RedactedSecretsNotice.d.ts.map +1 -0
  263. package/manifest/RedactedSecretsNotice.js +14 -0
  264. package/manifest/RedactedSecretsNotice.js.map +1 -0
  265. package/manifest/YamlEditor.d.ts +44 -0
  266. package/manifest/YamlEditor.d.ts.map +1 -0
  267. package/manifest/YamlEditor.js +216 -0
  268. package/manifest/YamlEditor.js.map +1 -0
  269. package/manifest/index.d.ts +13 -0
  270. package/manifest/index.d.ts.map +1 -0
  271. package/manifest/index.js +13 -0
  272. package/manifest/index.js.map +1 -0
  273. package/manifest/useApplyManifest.d.ts +82 -0
  274. package/manifest/useApplyManifest.d.ts.map +1 -0
  275. package/manifest/useApplyManifest.js +180 -0
  276. package/manifest/useApplyManifest.js.map +1 -0
  277. package/manifest/useEditResourceYaml.d.ts +106 -0
  278. package/manifest/useEditResourceYaml.d.ts.map +1 -0
  279. package/manifest/useEditResourceYaml.js +168 -0
  280. package/manifest/useEditResourceYaml.js.map +1 -0
  281. package/mcp-server/McpServerDetailView.d.ts.map +1 -1
  282. package/mcp-server/McpServerDetailView.js +4 -3
  283. package/mcp-server/McpServerDetailView.js.map +1 -1
  284. package/mcp-server/steps/ReviewStep.d.ts.map +1 -1
  285. package/mcp-server/steps/ReviewStep.js +2 -3
  286. package/mcp-server/steps/ReviewStep.js.map +1 -1
  287. package/package.json +4 -4
  288. package/resource-creation/templates/workflow-templates.js +4 -4
  289. package/session/SessionViewer.js +8 -1
  290. package/session/SessionViewer.js.map +1 -1
  291. package/session/audience.d.ts +6 -1
  292. package/session/audience.d.ts.map +1 -1
  293. package/session/useEditSessionPrep.js +3 -3
  294. package/session/useEditSessionPrep.js.map +1 -1
  295. package/settings/index.d.ts +2 -1
  296. package/settings/index.d.ts.map +1 -1
  297. package/settings/index.js +2 -1
  298. package/settings/index.js.map +1 -1
  299. package/settings/settings-nav.d.ts +22 -0
  300. package/settings/settings-nav.d.ts.map +1 -1
  301. package/settings/settings-nav.js +32 -1
  302. package/settings/settings-nav.js.map +1 -1
  303. package/settings/useSettingsNavGroups.d.ts +29 -0
  304. package/settings/useSettingsNavGroups.d.ts.map +1 -0
  305. package/settings/useSettingsNavGroups.js +61 -0
  306. package/settings/useSettingsNavGroups.js.map +1 -0
  307. package/skill/SkillDetailView.d.ts.map +1 -1
  308. package/skill/SkillDetailView.js +4 -3
  309. package/skill/SkillDetailView.js.map +1 -1
  310. package/src/access/__tests__/useManageAccess.test.tsx +104 -0
  311. package/src/agent/AgentDetailView.tsx +9 -3
  312. package/src/agent/steps/ReviewStep.tsx +2 -3
  313. package/src/billing/BaselineEditor.tsx +619 -0
  314. package/src/billing/ModelCatalogPanel.tsx +283 -0
  315. package/src/billing/ModelGovernanceDetail.tsx +289 -0
  316. package/src/billing/OperatorAccessNotice.tsx +32 -0
  317. package/src/billing/PricingGovernanceConsole.tsx +465 -0
  318. package/src/billing/PricingGovernancePanel.tsx +166 -0
  319. package/src/billing/RetireConfirm.tsx +82 -0
  320. package/src/billing/__tests__/ModelCatalogPanel.test.tsx +253 -0
  321. package/src/billing/__tests__/PricingGovernanceConsole.test.tsx +410 -0
  322. package/src/billing/__tests__/useModelGovernanceView.test.tsx +308 -0
  323. package/src/billing/form-primitives.tsx +68 -0
  324. package/src/billing/governance-primitives.tsx +133 -0
  325. package/src/billing/index.ts +37 -0
  326. package/src/billing/pricing-format.ts +53 -0
  327. package/src/billing/useDecidePricingOverride.ts +78 -0
  328. package/src/billing/useModelGovernanceView.ts +290 -0
  329. package/src/billing/useModelPricingBaselines.ts +69 -0
  330. package/src/billing/usePricingGovernance.ts +57 -0
  331. package/src/billing/useRetireModelPricingBaseline.ts +65 -0
  332. package/src/billing/useUpsertModelPricingBaseline.ts +72 -0
  333. package/src/channel/AgentChannelsPanel.tsx +27 -1
  334. package/src/composer/SessionComposer.tsx +1 -1
  335. package/src/cursor-accounts/CursorAccountEditor.tsx +181 -0
  336. package/src/cursor-accounts/CursorAccountsAccessNotice.tsx +36 -0
  337. package/src/cursor-accounts/CursorAccountsConsole.tsx +810 -0
  338. package/src/cursor-accounts/__tests__/CursorAccountsConsole.test.tsx +384 -0
  339. package/src/cursor-accounts/cursor-account-format.ts +29 -0
  340. package/src/cursor-accounts/index.ts +29 -0
  341. package/src/cursor-accounts/useCursorAccountView.ts +49 -0
  342. package/src/cursor-accounts/useCursorAccounts.ts +49 -0
  343. package/src/cursor-accounts/useCursorMemberKeyActions.ts +106 -0
  344. package/src/cursor-accounts/useDeleteCursorAccount.ts +62 -0
  345. package/src/cursor-accounts/useSyncCursorAccount.ts +54 -0
  346. package/src/cursor-accounts/useUpsertCursorAccount.ts +57 -0
  347. package/src/datastore/CollectionRecordsBrowser.tsx +544 -0
  348. package/src/datastore/CollectionSchemaView.tsx +247 -0
  349. package/src/datastore/DatastoreDetailView.tsx +201 -0
  350. package/src/datastore/DatastoreSyncReport.tsx +105 -0
  351. package/src/datastore/DeleteDatastoreDialog.tsx +202 -0
  352. package/src/datastore/FieldValueControl.tsx +289 -0
  353. package/src/datastore/RecordFilterBuilder.tsx +411 -0
  354. package/src/datastore/RecordFormPanel.tsx +432 -0
  355. package/src/datastore/__tests__/CollectionRecordsBrowser.test.tsx +207 -0
  356. package/src/datastore/__tests__/DeleteDatastoreDialog.test.tsx +133 -0
  357. package/src/datastore/__tests__/FieldValueControl.test.tsx +160 -0
  358. package/src/datastore/__tests__/RecordFilterBuilder.test.tsx +141 -0
  359. package/src/datastore/__tests__/RecordFormPanel.test.tsx +227 -0
  360. package/src/datastore/__tests__/recordFilter.test.ts +156 -0
  361. package/src/datastore/__tests__/recordMutations.test.tsx +195 -0
  362. package/src/datastore/__tests__/recordValues.test.ts +359 -0
  363. package/src/datastore/__tests__/schemaAndSyncViews.test.tsx +142 -0
  364. package/src/datastore/__tests__/useDatastoreDescription.test.tsx +143 -0
  365. package/src/datastore/__tests__/useRecordCollection.test.tsx +250 -0
  366. package/src/datastore/__tests__/useRecordList.test.tsx +85 -0
  367. package/src/datastore/index.ts +111 -0
  368. package/src/datastore/recordFilter.ts +140 -0
  369. package/src/datastore/recordValues.ts +327 -0
  370. package/src/datastore/useDatastore.ts +67 -0
  371. package/src/datastore/useDatastoreCount.ts +67 -0
  372. package/src/datastore/useDatastoreDescription.ts +90 -0
  373. package/src/datastore/useDatastoreList.ts +79 -0
  374. package/src/datastore/useDatastoreSearch.ts +39 -0
  375. package/src/datastore/useDeleteDatastore.ts +87 -0
  376. package/src/datastore/useDeleteRecord.ts +77 -0
  377. package/src/datastore/useInsertRecord.ts +92 -0
  378. package/src/datastore/useRecordCollection.ts +256 -0
  379. package/src/datastore/useRecordList.ts +131 -0
  380. package/src/datastore/useUpdateRecord.ts +95 -0
  381. package/src/environment/EnvironmentListPanel.tsx +24 -0
  382. package/src/execution/__tests__/useArtifactInspection.test.tsx +12 -2
  383. package/src/execution/__tests__/useLiveAgentExecution.test.tsx +125 -0
  384. package/src/execution/index.ts +4 -7
  385. package/src/execution/useLiveAgentExecution.ts +41 -3
  386. package/src/iam-policy/__tests__/useCheckPermission.test.tsx +221 -0
  387. package/src/iam-policy/index.ts +1 -0
  388. package/src/iam-policy/useCheckPermission.ts +45 -19
  389. package/src/index.ts +167 -18
  390. package/src/internal/__tests__/useInViewport.test.tsx +115 -0
  391. package/src/internal/useInViewport.ts +63 -0
  392. package/src/library/VisibilitySelector.tsx +50 -9
  393. package/src/library/__tests__/VisibilitySelector.test.tsx +38 -0
  394. package/src/library/index.ts +4 -21
  395. package/src/library/useApplyResource.ts +27 -34
  396. package/src/library/useExportResource.ts +21 -40
  397. package/src/manifest/ApplyManifestDialog.tsx +315 -0
  398. package/src/manifest/EditResourceYamlDialog.tsx +265 -0
  399. package/src/manifest/RedactedSecretsNotice.tsx +30 -0
  400. package/src/manifest/YamlEditor.tsx +272 -0
  401. package/src/manifest/__tests__/EditResourceYamlDialog.test.tsx +118 -0
  402. package/src/manifest/__tests__/useApplyManifest.test.tsx +237 -0
  403. package/src/manifest/__tests__/useEditResourceYaml.test.tsx +252 -0
  404. package/src/manifest/index.ts +33 -0
  405. package/src/manifest/useApplyManifest.ts +270 -0
  406. package/src/manifest/useEditResourceYaml.ts +273 -0
  407. package/src/mcp-server/McpServerDetailView.tsx +7 -3
  408. package/src/mcp-server/steps/ReviewStep.tsx +2 -3
  409. package/src/resource-creation/templates/workflow-templates.ts +4 -4
  410. package/src/session/SessionViewer.tsx +7 -1
  411. package/src/session/__tests__/audienceWiring.test.tsx +31 -1
  412. package/src/session/audience.ts +6 -1
  413. package/src/session/useEditSessionPrep.ts +3 -3
  414. package/src/settings/__tests__/useSettingsNavGroups.test.tsx +138 -0
  415. package/src/settings/index.ts +5 -1
  416. package/src/settings/settings-nav.ts +43 -0
  417. package/src/settings/useSettingsNavGroups.ts +81 -0
  418. package/src/skill/SkillDetailView.tsx +7 -3
  419. package/src/workflow/WorkflowAgentCallTranscript.tsx +279 -0
  420. package/src/workflow/WorkflowDetailView.tsx +7 -3
  421. package/src/workflow/WorkflowExecutionViewer.tsx +20 -77
  422. package/src/workflow/WorkflowTaskApprovalSummary.tsx +45 -8
  423. package/src/workflow/WorkflowYamlEditor.tsx +6 -270
  424. package/src/workflow/__tests__/WorkflowAgentCallTranscript.liveregion.test.tsx +124 -0
  425. package/src/workflow/__tests__/{WorkflowAgentExecutionDocument.test.tsx → WorkflowAgentCallTranscript.test.tsx} +146 -121
  426. package/src/workflow/__tests__/WorkflowExecutionViewer.approvals.test.tsx +81 -220
  427. package/src/workflow/__tests__/WorkflowExecutionViewer.reconciliation.test.tsx +17 -16
  428. package/src/workflow/__tests__/WorkflowTaskApprovalSummary.test.tsx +52 -2
  429. package/src/workflow/__tests__/WorkflowTaskThread.test.tsx +168 -185
  430. package/src/workflow/__tests__/agent-call-live-experience.test.ts +4 -4
  431. package/src/workflow/__tests__/task-approval.test.ts +119 -0
  432. package/src/workflow/__tests__/task-presentation.test.ts +35 -1
  433. package/src/workflow/__tests__/useWorkflowExecutionPanel.test.ts +0 -57
  434. package/src/workflow/index.ts +6 -3
  435. package/src/workflow/task-detail/index.ts +3 -0
  436. package/src/workflow/task-detail/task-approval.ts +95 -1
  437. package/src/workflow/thread/WorkflowTaskThread.tsx +96 -252
  438. package/src/workflow/thread/task-presentation.ts +8 -2
  439. package/src/workflow/useWorkflowExecutionPanel.ts +0 -47
  440. package/styles.css +1 -1
  441. package/workflow/CanvasTransitionEdge.d.ts +1 -1
  442. package/workflow/WorkflowAgentCallTranscript.d.ts +87 -0
  443. package/workflow/WorkflowAgentCallTranscript.d.ts.map +1 -0
  444. package/workflow/WorkflowAgentCallTranscript.js +98 -0
  445. package/workflow/WorkflowAgentCallTranscript.js.map +1 -0
  446. package/workflow/WorkflowDetailView.d.ts.map +1 -1
  447. package/workflow/WorkflowDetailView.js +4 -3
  448. package/workflow/WorkflowDetailView.js.map +1 -1
  449. package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
  450. package/workflow/WorkflowExecutionViewer.js +23 -52
  451. package/workflow/WorkflowExecutionViewer.js.map +1 -1
  452. package/workflow/WorkflowTaskApprovalSummary.d.ts +1 -1
  453. package/workflow/WorkflowTaskApprovalSummary.d.ts.map +1 -1
  454. package/workflow/WorkflowTaskApprovalSummary.js +18 -1
  455. package/workflow/WorkflowTaskApprovalSummary.js.map +1 -1
  456. package/workflow/WorkflowYamlEditor.d.ts +2 -42
  457. package/workflow/WorkflowYamlEditor.d.ts.map +1 -1
  458. package/workflow/WorkflowYamlEditor.js +5 -214
  459. package/workflow/WorkflowYamlEditor.js.map +1 -1
  460. package/workflow/index.d.ts +2 -2
  461. package/workflow/index.d.ts.map +1 -1
  462. package/workflow/index.js +2 -2
  463. package/workflow/index.js.map +1 -1
  464. package/workflow/task-detail/index.d.ts +1 -1
  465. package/workflow/task-detail/index.d.ts.map +1 -1
  466. package/workflow/task-detail/index.js +1 -1
  467. package/workflow/task-detail/index.js.map +1 -1
  468. package/workflow/task-detail/task-approval.d.ts +44 -1
  469. package/workflow/task-detail/task-approval.d.ts.map +1 -1
  470. package/workflow/task-detail/task-approval.js +47 -0
  471. package/workflow/task-detail/task-approval.js.map +1 -1
  472. package/workflow/thread/WorkflowTaskThread.d.ts +17 -25
  473. package/workflow/thread/WorkflowTaskThread.d.ts.map +1 -1
  474. package/workflow/thread/WorkflowTaskThread.js +60 -105
  475. package/workflow/thread/WorkflowTaskThread.js.map +1 -1
  476. package/workflow/thread/task-presentation.d.ts.map +1 -1
  477. package/workflow/thread/task-presentation.js +7 -2
  478. package/workflow/thread/task-presentation.js.map +1 -1
  479. package/workflow/useWorkflowExecutionPanel.d.ts +0 -12
  480. package/workflow/useWorkflowExecutionPanel.d.ts.map +1 -1
  481. package/workflow/useWorkflowExecutionPanel.js +0 -12
  482. package/workflow/useWorkflowExecutionPanel.js.map +1 -1
  483. package/execution/agent-execution-document.d.ts +0 -31
  484. package/execution/agent-execution-document.d.ts.map +0 -1
  485. package/execution/agent-execution-document.js +0 -48
  486. package/execution/agent-execution-document.js.map +0 -1
  487. package/library/ImportResourceDialog.d.ts +0 -43
  488. package/library/ImportResourceDialog.d.ts.map +0 -1
  489. package/library/ImportResourceDialog.js +0 -90
  490. package/library/ImportResourceDialog.js.map +0 -1
  491. package/library/parse-resource-yaml.d.ts +0 -63
  492. package/library/parse-resource-yaml.d.ts.map +0 -1
  493. package/library/parse-resource-yaml.js +0 -407
  494. package/library/parse-resource-yaml.js.map +0 -1
  495. package/library/serialize-resource-yaml.d.ts +0 -103
  496. package/library/serialize-resource-yaml.d.ts.map +0 -1
  497. package/library/serialize-resource-yaml.js +0 -565
  498. package/library/serialize-resource-yaml.js.map +0 -1
  499. package/library/useImportResource.d.ts +0 -84
  500. package/library/useImportResource.d.ts.map +0 -1
  501. package/library/useImportResource.js +0 -188
  502. package/library/useImportResource.js.map +0 -1
  503. package/src/execution/__tests__/agent-execution-document.test.ts +0 -45
  504. package/src/execution/agent-execution-document.ts +0 -54
  505. package/src/library/ImportResourceDialog.tsx +0 -227
  506. package/src/library/parse-resource-yaml.ts +0 -630
  507. package/src/library/serialize-resource-yaml.ts +0 -756
  508. package/src/library/useImportResource.ts +0 -253
  509. package/src/workflow/WorkflowAgentExecutionDocument.tsx +0 -283
  510. package/workflow/WorkflowAgentExecutionDocument.d.ts +0 -79
  511. package/workflow/WorkflowAgentExecutionDocument.d.ts.map +0 -1
  512. package/workflow/WorkflowAgentExecutionDocument.js +0 -87
  513. package/workflow/WorkflowAgentExecutionDocument.js.map +0 -1
@@ -0,0 +1,432 @@
1
+ "use client";
2
+
3
+ import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
4
+ import { cn } from "@stigmer/theme";
5
+ import type { JsonObject, JsonValue } from "@bufbuild/protobuf";
6
+ import { timestampDate } from "@bufbuild/protobuf/wkt";
7
+ import { getRecordConstraint, getUserMessage } from "@stigmer/sdk";
8
+ import type {
9
+ CollectionDeclaration,
10
+ FieldDeclaration,
11
+ } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/spec_pb";
12
+ import type { RecordEnvelope } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/record_io_pb";
13
+ import { FieldValueControl } from "./FieldValueControl.js";
14
+ import {
15
+ buildUpdateFields,
16
+ coerceFieldValue,
17
+ formatSystemTimestamp,
18
+ } from "./recordValues.js";
19
+ import { formatSubject } from "./CollectionSchemaView.js";
20
+ import { useInsertRecord } from "./useInsertRecord.js";
21
+ import { useUpdateRecord } from "./useUpdateRecord.js";
22
+ import type { RecordScope } from "./useRecordList.js";
23
+
24
+ /** Props for {@link RecordFormPanel}. */
25
+ export interface RecordFormPanelProps {
26
+ /** Whether the panel is open. */
27
+ readonly open: boolean;
28
+ /** Called when the panel requests to close (Escape, Cancel, or save). */
29
+ readonly onOpenChange: (open: boolean) => void;
30
+ /** Record addressing: org, datastore, collection, partition. */
31
+ readonly scope: RecordScope;
32
+ /** The collection declaration driving the form's typed controls. */
33
+ readonly collection: CollectionDeclaration;
34
+ /**
35
+ * The record to edit, or `null`/`undefined` to insert a new one.
36
+ * Edit submits a partial merge of dirty fields only.
37
+ */
38
+ readonly record?: RecordEnvelope | null;
39
+ /** Called with the server-stamped envelope after a successful save. */
40
+ readonly onSaved?: (envelope: RecordEnvelope) => void;
41
+ }
42
+
43
+ /**
44
+ * Per-field edit state. `unset` distinguishes "never touched" from an
45
+ * explicit clear — the honest projection of the update RPC's tri-state
46
+ * (absent = unchanged, null = clear, value = replace).
47
+ */
48
+ type FieldEdit =
49
+ | { readonly kind: "value"; readonly value: JsonValue }
50
+ | { readonly kind: "cleared" };
51
+
52
+ /**
53
+ * The record write surface (DD-008 SD-4): one schema-generated panel
54
+ * form serving insert and edit, with typed controls dispatched from
55
+ * `FieldDeclaration`.
56
+ *
57
+ * - **Insert** submits every field the operator set; required fields
58
+ * gate the submit (error prevention — the server remains the
59
+ * enforcer).
60
+ * - **Edit** submits a **partial merge**: only dirty fields travel, and
61
+ * the per-field clear affordance sends an explicit `null` — the form
62
+ * is honest about the RPC's tri-state. System fields render read-only
63
+ * and never travel.
64
+ * - **Errors replay the DD-002/DD-005 contract for humans**: a
65
+ * constraint violation renders the declared message **verbatim** —
66
+ * field-adjacent when the `ErrorInfo` constraint name maps through
67
+ * the spec to declared fields (unique constraints), as a form-level
68
+ * banner otherwise. The console operator and the WhatsApp patient
69
+ * read the same bytes.
70
+ *
71
+ * All visual properties flow through `--stgm-*` design tokens.
72
+ * Zero Console dependencies — safe for platform builder embedding.
73
+ */
74
+ export function RecordFormPanel({
75
+ open,
76
+ onOpenChange,
77
+ scope,
78
+ collection,
79
+ record,
80
+ onSaved,
81
+ }: RecordFormPanelProps) {
82
+ const dialogRef = useRef<HTMLDialogElement>(null);
83
+ const isEdit = record != null;
84
+
85
+ const insert = useInsertRecord();
86
+ const update = useUpdateRecord();
87
+ const isSaving = insert.isInserting || update.isUpdating;
88
+
89
+ const [edits, setEdits] = useState<ReadonlyMap<string, FieldEdit>>(new Map());
90
+ const [fieldErrors, setFieldErrors] = useState<ReadonlyMap<string, string>>(new Map());
91
+ const [bannerError, setBannerError] = useState<string | null>(null);
92
+
93
+ // Reset form state whenever the panel opens (fresh draft per open).
94
+ // Deps narrowed to the stable clearError callbacks (DD-010).
95
+ const clearInsertError = insert.clearError;
96
+ const clearUpdateError = update.clearError;
97
+ useEffect(() => {
98
+ if (open) {
99
+ setEdits(new Map());
100
+ setFieldErrors(new Map());
101
+ setBannerError(null);
102
+ clearInsertError();
103
+ clearUpdateError();
104
+ }
105
+ }, [open, record?.id, clearInsertError, clearUpdateError]);
106
+
107
+ // Native <dialog> open/close sync (the ConfirmDialog pattern).
108
+ useEffect(() => {
109
+ const dialog = dialogRef.current;
110
+ if (!dialog) return;
111
+ if (open && !dialog.open) dialog.showModal();
112
+ else if (!open && dialog.open) dialog.close();
113
+ }, [open]);
114
+
115
+ const handleDialogCancel = useCallback(
116
+ (e: React.SyntheticEvent) => {
117
+ e.preventDefault();
118
+ onOpenChange(false);
119
+ },
120
+ [onOpenChange],
121
+ );
122
+
123
+ /** The effective value a field's control shows: edit > stored > empty. */
124
+ const effectiveValue = useCallback(
125
+ (field: FieldDeclaration): JsonValue | undefined => {
126
+ const edit = edits.get(field.name);
127
+ if (edit) return edit.kind === "cleared" ? undefined : edit.value;
128
+ if (isEdit) {
129
+ const stored = record?.fields?.[field.name];
130
+ return stored === null ? undefined : stored;
131
+ }
132
+ return undefined;
133
+ },
134
+ [edits, isEdit, record],
135
+ );
136
+
137
+ const setFieldValue = useCallback((name: string, value: JsonValue | undefined) => {
138
+ setEdits((prev) => {
139
+ const next = new Map(prev);
140
+ if (value === undefined) {
141
+ // Emptying the control: in insert mode the field simply won't
142
+ // travel; in edit mode an emptied control is an explicit clear.
143
+ next.set(name, { kind: "cleared" });
144
+ } else {
145
+ next.set(name, { kind: "value", value });
146
+ }
147
+ return next;
148
+ });
149
+ setFieldErrors((prev) => {
150
+ if (!prev.has(name)) return prev;
151
+ const next = new Map(prev);
152
+ next.delete(name);
153
+ return next;
154
+ });
155
+ }, []);
156
+
157
+ const clearField = useCallback((name: string) => {
158
+ setEdits((prev) => new Map(prev).set(name, { kind: "cleared" }));
159
+ }, []);
160
+
161
+ // Required fields gate the submit in insert mode (error prevention).
162
+ const missingRequired = useMemo(() => {
163
+ if (isEdit) return [];
164
+ return collection.fields
165
+ .filter((f) => f.required && f.default === undefined)
166
+ .filter((f) => {
167
+ const edit = edits.get(f.name);
168
+ return !edit || edit.kind === "cleared";
169
+ })
170
+ .map((f) => f.name);
171
+ }, [collection, edits, isEdit]);
172
+
173
+ const handleSubmit = useCallback(async () => {
174
+ setBannerError(null);
175
+
176
+ // Client-side coercion (a projection of the server contract): fail
177
+ // fast with field-adjacent messages; the server stays the enforcer.
178
+ const coerced = new Map<string, JsonValue | null>();
179
+ const errors = new Map<string, string>();
180
+ for (const field of collection.fields) {
181
+ const edit = edits.get(field.name);
182
+ if (!edit) continue;
183
+ if (edit.kind === "cleared") {
184
+ if (isEdit) coerced.set(field.name, null);
185
+ continue;
186
+ }
187
+ const result = coerceFieldValue(field, edit.value);
188
+ if (result.ok) {
189
+ coerced.set(field.name, result.value);
190
+ } else {
191
+ errors.set(field.name, result.error);
192
+ }
193
+ }
194
+ if (errors.size > 0) {
195
+ setFieldErrors(errors);
196
+ return;
197
+ }
198
+
199
+ try {
200
+ let saved: RecordEnvelope;
201
+ if (isEdit) {
202
+ if (coerced.size === 0) {
203
+ onOpenChange(false); // nothing dirty — an honest no-op
204
+ return;
205
+ }
206
+ saved = await update.updateRecord({
207
+ ...scope,
208
+ id: record.id,
209
+ fields: buildUpdateFields(coerced),
210
+ });
211
+ } else {
212
+ const payload: JsonObject = {};
213
+ for (const [name, value] of coerced) {
214
+ if (value !== null) payload[name] = value;
215
+ }
216
+ saved = await insert.insertRecord({ ...scope, record: payload });
217
+ }
218
+ onSaved?.(saved);
219
+ onOpenChange(false);
220
+ } catch (err) {
221
+ placeServerError(err, collection, setFieldErrors, setBannerError);
222
+ }
223
+ }, [collection, edits, isEdit, record, scope, insert, update, onSaved, onOpenChange]);
224
+
225
+ if (!open) return null;
226
+
227
+ return (
228
+ <dialog
229
+ ref={dialogRef}
230
+ onCancel={handleDialogCancel}
231
+ aria-label={
232
+ isEdit
233
+ ? `Edit record in ${collection.name}`
234
+ : `Insert record into ${collection.name}`
235
+ }
236
+ className={cn(
237
+ "fixed inset-0 z-50 m-auto w-full max-w-md rounded-lg border border-border bg-popover p-0 text-popover-foreground shadow-lg",
238
+ "backdrop:bg-black/50",
239
+ "open:animate-in open:fade-in-0 open:zoom-in-95",
240
+ )}
241
+ >
242
+ <div className="flex max-h-[80vh] flex-col gap-4 overflow-y-auto p-6">
243
+ <h3 className="text-base font-semibold text-foreground">
244
+ {isEdit ? "Edit record" : "Insert record"}
245
+ <span className="ml-2 font-mono text-xs font-normal text-muted-foreground">
246
+ {collection.name}
247
+ </span>
248
+ </h3>
249
+
250
+ {bannerError && (
251
+ <div
252
+ role="alert"
253
+ className="rounded-md border border-destructive bg-card px-3 py-2 text-sm text-destructive"
254
+ >
255
+ {bannerError}
256
+ </div>
257
+ )}
258
+
259
+ {isEdit && record && <SystemFieldsSummary record={record} />}
260
+
261
+ <div className="flex flex-col gap-3">
262
+ {collection.fields.map((field) => (
263
+ <FieldRow
264
+ key={field.name}
265
+ field={field}
266
+ value={effectiveValue(field)}
267
+ error={fieldErrors.get(field.name)}
268
+ isEdit={isEdit}
269
+ cleared={edits.get(field.name)?.kind === "cleared"}
270
+ onChange={(v) => setFieldValue(field.name, v)}
271
+ onClear={() => clearField(field.name)}
272
+ />
273
+ ))}
274
+ </div>
275
+
276
+ <div className="flex items-center justify-end gap-2">
277
+ {missingRequired.length > 0 && (
278
+ <span className="mr-auto text-xs text-muted-foreground">
279
+ Required: {missingRequired.join(", ")}
280
+ </span>
281
+ )}
282
+ <button
283
+ type="button"
284
+ onClick={() => onOpenChange(false)}
285
+ className={cn(
286
+ "rounded-md border border-input bg-background px-3 py-1.5 text-sm font-medium text-foreground",
287
+ "hover:bg-accent hover:text-accent-foreground",
288
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
289
+ )}
290
+ >
291
+ Cancel
292
+ </button>
293
+ <button
294
+ type="button"
295
+ onClick={handleSubmit}
296
+ disabled={isSaving || missingRequired.length > 0}
297
+ className={cn(
298
+ "rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground",
299
+ "hover:bg-primary-hover",
300
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
301
+ "disabled:pointer-events-none disabled:opacity-50",
302
+ )}
303
+ >
304
+ {isSaving ? "Saving…" : isEdit ? "Save changes" : "Insert"}
305
+ </button>
306
+ </div>
307
+ </div>
308
+ </dialog>
309
+ );
310
+ }
311
+
312
+ // ---------------------------------------------------------------------------
313
+ // Server-error placement (DD-008 SD-4)
314
+ // ---------------------------------------------------------------------------
315
+
316
+ /**
317
+ * Place a record-write error: field-adjacent when the ErrorInfo
318
+ * constraint name maps to a unique constraint's declared fields, a
319
+ * form-level banner otherwise. Either way the message is the server's
320
+ * bytes, verbatim.
321
+ */
322
+ function placeServerError(
323
+ err: unknown,
324
+ collection: CollectionDeclaration,
325
+ setFieldErrors: (errors: ReadonlyMap<string, string>) => void,
326
+ setBannerError: (message: string) => void,
327
+ ): void {
328
+ const message = getUserMessage(err);
329
+ const constraintName = getRecordConstraint(err);
330
+ if (constraintName) {
331
+ const unique = collection.uniques.find((u) => u.name === constraintName);
332
+ if (unique && unique.fields.length > 0) {
333
+ setFieldErrors(new Map(unique.fields.map((f) => [f, message])));
334
+ return;
335
+ }
336
+ }
337
+ setBannerError(message);
338
+ }
339
+
340
+ // ---------------------------------------------------------------------------
341
+ // Rows
342
+ // ---------------------------------------------------------------------------
343
+
344
+ function FieldRow({
345
+ field,
346
+ value,
347
+ error,
348
+ isEdit,
349
+ cleared,
350
+ onChange,
351
+ onClear,
352
+ }: {
353
+ readonly field: FieldDeclaration;
354
+ readonly value: JsonValue | undefined;
355
+ readonly error: string | undefined;
356
+ readonly isEdit: boolean;
357
+ readonly cleared: boolean;
358
+ readonly onChange: (value: JsonValue | undefined) => void;
359
+ readonly onClear: () => void;
360
+ }) {
361
+ const controlId = useId();
362
+ const showClear = isEdit && !field.required && !cleared && value !== undefined;
363
+
364
+ return (
365
+ <div className="flex flex-col gap-1">
366
+ <div className="flex items-baseline gap-1">
367
+ <label htmlFor={controlId} className="text-xs font-medium text-muted-foreground">
368
+ {field.name}
369
+ {field.required && (
370
+ <span className="text-destructive" aria-label="required">
371
+ {" "}
372
+ *
373
+ </span>
374
+ )}
375
+ </label>
376
+ {showClear && (
377
+ <button
378
+ type="button"
379
+ onClick={onClear}
380
+ aria-label={`Clear ${field.name}`}
381
+ className={cn(
382
+ "ml-auto text-xs text-muted-foreground underline-offset-2 hover:text-foreground hover:underline",
383
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
384
+ )}
385
+ >
386
+ Clear
387
+ </button>
388
+ )}
389
+ {cleared && (
390
+ <span className="ml-auto text-xs italic text-muted-foreground">
391
+ will be cleared
392
+ </span>
393
+ )}
394
+ </div>
395
+ {field.description && (
396
+ <p className="text-xs leading-tight text-muted-foreground">{field.description}</p>
397
+ )}
398
+ <FieldValueControl id={controlId} field={field} value={value} onChange={onChange} />
399
+ {error && (
400
+ <span role="alert" className="text-xs text-destructive">
401
+ {error}
402
+ </span>
403
+ )}
404
+ </div>
405
+ );
406
+ }
407
+
408
+ /** Read-only envelope columns shown in edit mode; never editable, never submitted. */
409
+ function SystemFieldsSummary({ record }: { readonly record: RecordEnvelope }) {
410
+ return (
411
+ <dl className="grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 rounded-md bg-muted p-3 text-xs">
412
+ <dt className="font-medium text-muted-foreground">id</dt>
413
+ <dd className="truncate font-mono text-foreground">{record.id}</dd>
414
+ <dt className="font-medium text-muted-foreground">created_at</dt>
415
+ <dd className="font-mono text-foreground">
416
+ {record.createdAt
417
+ ? formatSystemTimestamp(timestampDate(record.createdAt).toISOString())
418
+ : ""}
419
+ </dd>
420
+ <dt className="font-medium text-muted-foreground">updated_at</dt>
421
+ <dd className="font-mono text-foreground">
422
+ {record.updatedAt
423
+ ? formatSystemTimestamp(timestampDate(record.updatedAt).toISOString())
424
+ : ""}
425
+ </dd>
426
+ <dt className="font-medium text-muted-foreground">created_by</dt>
427
+ <dd className="truncate font-mono text-foreground">
428
+ {formatSubject(record.createdBy)}
429
+ </dd>
430
+ </dl>
431
+ );
432
+ }
@@ -0,0 +1,207 @@
1
+ // Tests for the records browser (DD-008 SD-3): the two denied-state
2
+ // branches, verb-gated write affordances, typed grid rendering, and the
3
+ // partition picker fed by the describe projection unioned with default.
4
+
5
+ import { describe, it, expect, vi, beforeAll, afterEach, beforeEach } from "vitest";
6
+ import { render, screen, cleanup, waitFor } from "@testing-library/react";
7
+ import type { ReactNode } from "react";
8
+ import { create } from "@bufbuild/protobuf";
9
+ import { Code, ConnectError } from "@connectrpc/connect";
10
+ import {
11
+ DatastoreSpecSchema,
12
+ DatastoreVerb,
13
+ } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/spec_pb";
14
+ import {
15
+ DatastoreDescriptionSchema,
16
+ RecordEnvelopeSchema,
17
+ RecordListSchema,
18
+ } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/record_io_pb";
19
+ import { StigmerError } from "@stigmer/sdk";
20
+ import { StigmerContext } from "../../context";
21
+ import { FetchCacheContext } from "../../internal/FetchCacheProvider";
22
+ import { CollectionRecordsBrowser } from "../CollectionRecordsBrowser";
23
+
24
+ beforeAll(() => {
25
+ HTMLDialogElement.prototype.showModal = function showModal() {
26
+ this.open = true;
27
+ };
28
+ HTMLDialogElement.prototype.close = function close() {
29
+ this.open = false;
30
+ };
31
+ });
32
+
33
+ afterEach(() => cleanup());
34
+ beforeEach(() => vi.restoreAllMocks());
35
+
36
+ const SPEC = create(DatastoreSpecSchema, {
37
+ collections: [
38
+ {
39
+ name: "bookings",
40
+ fields: [
41
+ { name: "slot_date", type: 6 /* date */, required: true },
42
+ { name: "status", type: 1 /* string */, enumValues: ["confirmed", "cancelled"] },
43
+ ],
44
+ },
45
+ ],
46
+ });
47
+
48
+ function fullAccessDescription(partitions: string[] = []) {
49
+ return create(DatastoreDescriptionSchema, {
50
+ datastore: "clinic",
51
+ partitions,
52
+ collections: [
53
+ {
54
+ name: "bookings",
55
+ access: [
56
+ { verb: DatastoreVerb.read },
57
+ { verb: DatastoreVerb.insert },
58
+ { verb: DatastoreVerb.update },
59
+ { verb: DatastoreVerb.delete },
60
+ ],
61
+ },
62
+ ],
63
+ });
64
+ }
65
+
66
+ function renderBrowser(client: {
67
+ describeDatastore: (...a: unknown[]) => Promise<unknown>;
68
+ findRecords?: (...a: unknown[]) => Promise<unknown>;
69
+ deleteRecord?: (...a: unknown[]) => Promise<unknown>;
70
+ }) {
71
+ const stigmer = {
72
+ datastore: {
73
+ describeDatastore: client.describeDatastore,
74
+ findRecords: client.findRecords ?? vi.fn().mockResolvedValue(create(RecordListSchema, {})),
75
+ deleteRecord: client.deleteRecord ?? vi.fn(),
76
+ insertRecord: vi.fn(),
77
+ updateRecord: vi.fn(),
78
+ },
79
+ };
80
+ function Wrapper({ children }: { children: ReactNode }) {
81
+ return (
82
+ <FetchCacheContext.Provider value={null}>
83
+ <StigmerContext.Provider value={stigmer as never}>{children}</StigmerContext.Provider>
84
+ </FetchCacheContext.Provider>
85
+ );
86
+ }
87
+ return render(
88
+ <CollectionRecordsBrowser org="acme" datastoreSlug="clinic" spec={SPEC} />,
89
+ { wrapper: Wrapper },
90
+ );
91
+ }
92
+
93
+ describe("CollectionRecordsBrowser — denied states (first-class renders)", () => {
94
+ it("renders the denied panel on empty access lists — the primary branch", async () => {
95
+ // Deny-by-default renders as empty access, never an error: a viewer
96
+ // with no record grants gets a successful describe with no verbs.
97
+ const describeDatastore = vi.fn().mockResolvedValue(
98
+ create(DatastoreDescriptionSchema, {
99
+ datastore: "clinic",
100
+ collections: [{ name: "bookings", access: [] }],
101
+ }),
102
+ );
103
+ const findRecords = vi.fn();
104
+ renderBrowser({ describeDatastore, findRecords });
105
+
106
+ await waitFor(() =>
107
+ expect(
108
+ screen.getByText(/You do not have record access to “bookings”/),
109
+ ).toBeTruthy(),
110
+ );
111
+ // Operator guidance, not a silently empty grid.
112
+ expect(screen.getByText(/default_role/)).toBeTruthy();
113
+ // No query is fired without read access.
114
+ expect(findRecords).not.toHaveBeenCalled();
115
+ });
116
+
117
+ it("renders the denied panel on a reach-level PERMISSION_DENIED — the defensive branch", async () => {
118
+ const denial = new StigmerError(
119
+ "permission-denied",
120
+ "unauthorized to use records in this datastore",
121
+ Code.PermissionDenied,
122
+ {
123
+ cause: new ConnectError(
124
+ "unauthorized to use records in this datastore",
125
+ Code.PermissionDenied,
126
+ ),
127
+ },
128
+ );
129
+ const describeDatastore = vi.fn().mockRejectedValue(denial);
130
+ renderBrowser({ describeDatastore });
131
+
132
+ await waitFor(() =>
133
+ expect(
134
+ screen.getByText("unauthorized to use records in this datastore"),
135
+ ).toBeTruthy(),
136
+ );
137
+ });
138
+ });
139
+
140
+ describe("CollectionRecordsBrowser — grid and affordances", () => {
141
+ it("renders typed cells and verb-gated write affordances", async () => {
142
+ const describeDatastore = vi.fn().mockResolvedValue(fullAccessDescription());
143
+ const findRecords = vi.fn().mockResolvedValue(
144
+ create(RecordListSchema, {
145
+ records: [
146
+ create(RecordEnvelopeSchema, {
147
+ id: "dsr_1",
148
+ fields: { slot_date: "2026-07-22", status: "confirmed" } as never,
149
+ }),
150
+ ],
151
+ total: 1,
152
+ }),
153
+ );
154
+ renderBrowser({ describeDatastore, findRecords });
155
+
156
+ await waitFor(() => expect(screen.getByText("2026-07-22")).toBeTruthy());
157
+ expect(screen.getByText("confirmed")).toBeTruthy();
158
+ expect(screen.getByRole("button", { name: "Insert record" })).toBeTruthy();
159
+ expect(screen.getByRole("button", { name: "Edit record dsr_1" })).toBeTruthy();
160
+ expect(screen.getByRole("button", { name: "Delete record dsr_1" })).toBeTruthy();
161
+ });
162
+
163
+ it("hides write affordances the caller's verbs do not include", async () => {
164
+ const describeDatastore = vi.fn().mockResolvedValue(
165
+ create(DatastoreDescriptionSchema, {
166
+ datastore: "clinic",
167
+ collections: [
168
+ { name: "bookings", access: [{ verb: DatastoreVerb.read }] },
169
+ ],
170
+ }),
171
+ );
172
+ const findRecords = vi.fn().mockResolvedValue(
173
+ create(RecordListSchema, {
174
+ records: [create(RecordEnvelopeSchema, { id: "dsr_1" })],
175
+ total: 1,
176
+ }),
177
+ );
178
+ renderBrowser({ describeDatastore, findRecords });
179
+
180
+ await waitFor(() => expect(findRecords).toHaveBeenCalled());
181
+ expect(screen.queryByRole("button", { name: "Insert record" })).toBeNull();
182
+ expect(screen.queryByRole("button", { name: "Edit record dsr_1" })).toBeNull();
183
+ expect(screen.queryByRole("button", { name: "Delete record dsr_1" })).toBeNull();
184
+ });
185
+
186
+ it("offers the partition catalog unioned with default and threads the selection", async () => {
187
+ const describeDatastore = vi
188
+ .fn()
189
+ .mockResolvedValue(fullAccessDescription(["dr-alt"]));
190
+ const findRecords = vi.fn().mockResolvedValue(create(RecordListSchema, {}));
191
+ renderBrowser({ describeDatastore, findRecords });
192
+
193
+ const picker = (await screen.findByLabelText(/Partition/)) as HTMLSelectElement;
194
+ const options = Array.from(picker.options).map((o) => o.value);
195
+ expect(options).toEqual(["default", "dr-alt"]);
196
+ });
197
+
198
+ it("renders the filtered-empty state distinctly from the no-records state", async () => {
199
+ const describeDatastore = vi.fn().mockResolvedValue(fullAccessDescription());
200
+ const findRecords = vi.fn().mockResolvedValue(create(RecordListSchema, {}));
201
+ renderBrowser({ describeDatastore, findRecords });
202
+
203
+ await waitFor(() =>
204
+ expect(screen.getByText(/No records in “bookings” yet/)).toBeTruthy(),
205
+ );
206
+ });
207
+ });