@rippling/rippling-sdk 0.2.0-alpha.34 → 0.2.0-alpha.36

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 (270) hide show
  1. package/client.d.mts +6 -0
  2. package/client.d.mts.map +1 -1
  3. package/client.d.ts +6 -0
  4. package/client.d.ts.map +1 -1
  5. package/client.js +6 -0
  6. package/client.js.map +1 -1
  7. package/client.mjs +6 -0
  8. package/client.mjs.map +1 -1
  9. package/examples/.keep +4 -0
  10. package/examples/manifest/dental-practice-management/dental-practice-management.ts +651 -0
  11. package/examples/manifest/dental-practice-management/manifest.json +1870 -0
  12. package/examples/manifest/gym-membership-management/gym-membership-management.ts +757 -0
  13. package/examples/manifest/gym-membership-management/manifest.json +1975 -0
  14. package/examples/sdui/sdui-crud-todo/rippling-function.ts +367 -0
  15. package/examples/sdui/sdui-crud-todo/sdui-crud-todo.ts +282 -0
  16. package/examples/sdui/sdui-showcase/rippling-function.ts +381 -0
  17. package/examples/sdui/sdui-showcase/sdui-showcase.ts +351 -0
  18. package/examples/sdui/sdui-tab-multi-view/rippling-function.ts +1061 -0
  19. package/examples/sdui/sdui-tab-multi-view/sdui-tab-multi-view.ts +924 -0
  20. package/examples/sdui/vote/rippling-function.ts +330 -0
  21. package/examples/sdui/vote/vote.ts +298 -0
  22. package/lib/manifest/app.d.mts +81 -13
  23. package/lib/manifest/app.d.mts.map +1 -1
  24. package/lib/manifest/app.d.ts +81 -13
  25. package/lib/manifest/app.d.ts.map +1 -1
  26. package/lib/manifest/app.js +37 -16
  27. package/lib/manifest/app.js.map +1 -1
  28. package/lib/manifest/app.mjs +37 -16
  29. package/lib/manifest/app.mjs.map +1 -1
  30. package/lib/manifest/category.d.mts +63 -7
  31. package/lib/manifest/category.d.mts.map +1 -1
  32. package/lib/manifest/category.d.ts +63 -7
  33. package/lib/manifest/category.d.ts.map +1 -1
  34. package/lib/manifest/category.js +45 -10
  35. package/lib/manifest/category.js.map +1 -1
  36. package/lib/manifest/category.mjs +43 -8
  37. package/lib/manifest/category.mjs.map +1 -1
  38. package/lib/manifest/custom-object-field-section.d.mts +56 -6
  39. package/lib/manifest/custom-object-field-section.d.mts.map +1 -1
  40. package/lib/manifest/custom-object-field-section.d.ts +56 -6
  41. package/lib/manifest/custom-object-field-section.d.ts.map +1 -1
  42. package/lib/manifest/custom-object-field-section.js +41 -14
  43. package/lib/manifest/custom-object-field-section.js.map +1 -1
  44. package/lib/manifest/custom-object-field-section.mjs +39 -12
  45. package/lib/manifest/custom-object-field-section.mjs.map +1 -1
  46. package/lib/manifest/custom-object-page-layout.d.mts +201 -41
  47. package/lib/manifest/custom-object-page-layout.d.mts.map +1 -1
  48. package/lib/manifest/custom-object-page-layout.d.ts +201 -41
  49. package/lib/manifest/custom-object-page-layout.d.ts.map +1 -1
  50. package/lib/manifest/custom-object-page-layout.js +76 -30
  51. package/lib/manifest/custom-object-page-layout.js.map +1 -1
  52. package/lib/manifest/custom-object-page-layout.mjs +74 -28
  53. package/lib/manifest/custom-object-page-layout.mjs.map +1 -1
  54. package/lib/manifest/custom-object.d.mts +128 -15
  55. package/lib/manifest/custom-object.d.mts.map +1 -1
  56. package/lib/manifest/custom-object.d.ts +128 -15
  57. package/lib/manifest/custom-object.d.ts.map +1 -1
  58. package/lib/manifest/custom-object.js +61 -26
  59. package/lib/manifest/custom-object.js.map +1 -1
  60. package/lib/manifest/custom-object.mjs +61 -26
  61. package/lib/manifest/custom-object.mjs.map +1 -1
  62. package/lib/manifest/field.d.mts +265 -54
  63. package/lib/manifest/field.d.mts.map +1 -1
  64. package/lib/manifest/field.d.ts +265 -54
  65. package/lib/manifest/field.d.ts.map +1 -1
  66. package/lib/manifest/field.js +100 -57
  67. package/lib/manifest/field.js.map +1 -1
  68. package/lib/manifest/field.mjs +100 -57
  69. package/lib/manifest/field.mjs.map +1 -1
  70. package/lib/manifest/list-view.d.mts +105 -14
  71. package/lib/manifest/list-view.d.mts.map +1 -1
  72. package/lib/manifest/list-view.d.ts +105 -14
  73. package/lib/manifest/list-view.d.ts.map +1 -1
  74. package/lib/manifest/list-view.js +50 -14
  75. package/lib/manifest/list-view.js.map +1 -1
  76. package/lib/manifest/list-view.mjs +48 -12
  77. package/lib/manifest/list-view.mjs.map +1 -1
  78. package/lib/manifest/manifest-builder.d.mts +77 -11
  79. package/lib/manifest/manifest-builder.d.mts.map +1 -1
  80. package/lib/manifest/manifest-builder.d.ts +77 -11
  81. package/lib/manifest/manifest-builder.d.ts.map +1 -1
  82. package/lib/manifest/manifest-builder.js +46 -24
  83. package/lib/manifest/manifest-builder.js.map +1 -1
  84. package/lib/manifest/manifest-builder.mjs +44 -22
  85. package/lib/manifest/manifest-builder.mjs.map +1 -1
  86. package/lib/manifest/manifest-function.d.mts +92 -12
  87. package/lib/manifest/manifest-function.d.mts.map +1 -1
  88. package/lib/manifest/manifest-function.d.ts +92 -12
  89. package/lib/manifest/manifest-function.d.ts.map +1 -1
  90. package/lib/manifest/manifest-function.js +40 -11
  91. package/lib/manifest/manifest-function.js.map +1 -1
  92. package/lib/manifest/manifest-function.mjs +38 -9
  93. package/lib/manifest/manifest-function.mjs.map +1 -1
  94. package/lib/manifest/rule.d.mts +94 -16
  95. package/lib/manifest/rule.d.mts.map +1 -1
  96. package/lib/manifest/rule.d.ts +94 -16
  97. package/lib/manifest/rule.d.ts.map +1 -1
  98. package/lib/manifest/rule.js +36 -15
  99. package/lib/manifest/rule.js.map +1 -1
  100. package/lib/manifest/rule.mjs +36 -15
  101. package/lib/manifest/rule.mjs.map +1 -1
  102. package/lib/manifest/sdui-page.d.mts +67 -11
  103. package/lib/manifest/sdui-page.d.mts.map +1 -1
  104. package/lib/manifest/sdui-page.d.ts +67 -11
  105. package/lib/manifest/sdui-page.d.ts.map +1 -1
  106. package/lib/manifest/sdui-page.js +44 -13
  107. package/lib/manifest/sdui-page.js.map +1 -1
  108. package/lib/manifest/sdui-page.mjs +42 -11
  109. package/lib/manifest/sdui-page.mjs.map +1 -1
  110. package/lib/manifest/validation.d.mts +87 -12
  111. package/lib/manifest/validation.d.mts.map +1 -1
  112. package/lib/manifest/validation.d.ts +87 -12
  113. package/lib/manifest/validation.d.ts.map +1 -1
  114. package/lib/manifest/validation.js +41 -15
  115. package/lib/manifest/validation.js.map +1 -1
  116. package/lib/manifest/validation.mjs +39 -13
  117. package/lib/manifest/validation.mjs.map +1 -1
  118. package/lib/sdui/actions.d.mts +25 -0
  119. package/lib/sdui/actions.d.mts.map +1 -0
  120. package/lib/sdui/actions.d.ts +25 -0
  121. package/lib/sdui/actions.d.ts.map +1 -0
  122. package/lib/sdui/actions.js +53 -0
  123. package/lib/sdui/actions.js.map +1 -0
  124. package/lib/sdui/actions.mjs +42 -0
  125. package/lib/sdui/actions.mjs.map +1 -0
  126. package/lib/sdui/component.d.mts +41 -0
  127. package/lib/sdui/component.d.mts.map +1 -0
  128. package/lib/sdui/component.d.ts +41 -0
  129. package/lib/sdui/component.d.ts.map +1 -0
  130. package/lib/sdui/component.js +95 -0
  131. package/lib/sdui/component.js.map +1 -0
  132. package/lib/sdui/component.mjs +91 -0
  133. package/lib/sdui/component.mjs.map +1 -0
  134. package/lib/sdui/components.d.mts +149 -0
  135. package/lib/sdui/components.d.mts.map +1 -0
  136. package/lib/sdui/components.d.ts +149 -0
  137. package/lib/sdui/components.d.ts.map +1 -0
  138. package/lib/sdui/components.js +303 -0
  139. package/lib/sdui/components.js.map +1 -0
  140. package/lib/sdui/components.mjs +298 -0
  141. package/lib/sdui/components.mjs.map +1 -0
  142. package/lib/sdui/conditions.d.mts +25 -0
  143. package/lib/sdui/conditions.d.mts.map +1 -0
  144. package/lib/sdui/conditions.d.ts +25 -0
  145. package/lib/sdui/conditions.d.ts.map +1 -0
  146. package/lib/sdui/conditions.js +47 -0
  147. package/lib/sdui/conditions.js.map +1 -0
  148. package/lib/sdui/conditions.mjs +35 -0
  149. package/lib/sdui/conditions.mjs.map +1 -0
  150. package/lib/sdui/directives.d.mts +18 -0
  151. package/lib/sdui/directives.d.mts.map +1 -0
  152. package/lib/sdui/directives.d.ts +18 -0
  153. package/lib/sdui/directives.d.ts.map +1 -0
  154. package/lib/sdui/directives.js +28 -0
  155. package/lib/sdui/directives.js.map +1 -0
  156. package/lib/sdui/directives.mjs +21 -0
  157. package/lib/sdui/directives.mjs.map +1 -0
  158. package/lib/sdui/index.d.mts +362 -0
  159. package/lib/sdui/index.d.mts.map +1 -0
  160. package/lib/sdui/index.d.ts +362 -0
  161. package/lib/sdui/index.d.ts.map +1 -0
  162. package/lib/sdui/index.js +375 -0
  163. package/lib/sdui/index.js.map +1 -0
  164. package/lib/sdui/index.mjs +199 -0
  165. package/lib/sdui/index.mjs.map +1 -0
  166. package/lib/sdui/props.d.mts +12 -0
  167. package/lib/sdui/props.d.mts.map +1 -0
  168. package/lib/sdui/props.d.ts +12 -0
  169. package/lib/sdui/props.d.ts.map +1 -0
  170. package/lib/sdui/props.js +25 -0
  171. package/lib/sdui/props.js.map +1 -0
  172. package/lib/sdui/props.mjs +21 -0
  173. package/lib/sdui/props.mjs.map +1 -0
  174. package/lib/sdui/render.d.mts +23 -0
  175. package/lib/sdui/render.d.mts.map +1 -0
  176. package/lib/sdui/render.d.ts +23 -0
  177. package/lib/sdui/render.d.ts.map +1 -0
  178. package/lib/sdui/render.js +40 -0
  179. package/lib/sdui/render.js.map +1 -0
  180. package/lib/sdui/render.mjs +37 -0
  181. package/lib/sdui/render.mjs.map +1 -0
  182. package/lib/sdui/state.d.mts +22 -0
  183. package/lib/sdui/state.d.mts.map +1 -0
  184. package/lib/sdui/state.d.ts +22 -0
  185. package/lib/sdui/state.d.ts.map +1 -0
  186. package/lib/sdui/state.js +57 -0
  187. package/lib/sdui/state.js.map +1 -0
  188. package/lib/sdui/state.mjs +53 -0
  189. package/lib/sdui/state.mjs.map +1 -0
  190. package/package.json +11 -1
  191. package/resources/company-legal-entity-workers.d.mts +79 -0
  192. package/resources/company-legal-entity-workers.d.mts.map +1 -0
  193. package/resources/company-legal-entity-workers.d.ts +79 -0
  194. package/resources/company-legal-entity-workers.d.ts.map +1 -0
  195. package/resources/company-legal-entity-workers.js +30 -0
  196. package/resources/company-legal-entity-workers.js.map +1 -0
  197. package/resources/company-legal-entity-workers.mjs +26 -0
  198. package/resources/company-legal-entity-workers.mjs.map +1 -0
  199. package/resources/draft-hires.d.mts +4 -0
  200. package/resources/draft-hires.d.mts.map +1 -1
  201. package/resources/draft-hires.d.ts +4 -0
  202. package/resources/draft-hires.d.ts.map +1 -1
  203. package/resources/files.d.mts +16 -1
  204. package/resources/files.d.mts.map +1 -1
  205. package/resources/files.d.ts +16 -1
  206. package/resources/files.d.ts.map +1 -1
  207. package/resources/headcount-positions.d.mts +2 -2
  208. package/resources/headcount-positions.d.mts.map +1 -1
  209. package/resources/headcount-positions.d.ts +2 -2
  210. package/resources/headcount-positions.d.ts.map +1 -1
  211. package/resources/index.d.mts +1 -0
  212. package/resources/index.d.mts.map +1 -1
  213. package/resources/index.d.ts +1 -0
  214. package/resources/index.d.ts.map +1 -1
  215. package/resources/index.js +4 -2
  216. package/resources/index.js.map +1 -1
  217. package/resources/index.mjs +1 -0
  218. package/resources/index.mjs.map +1 -1
  219. package/resources/legal-entities.d.mts +1 -1
  220. package/resources/legal-entities.d.mts.map +1 -1
  221. package/resources/legal-entities.d.ts +1 -1
  222. package/resources/legal-entities.d.ts.map +1 -1
  223. package/resources/location-factors.d.mts +2 -2
  224. package/resources/location-factors.d.mts.map +1 -1
  225. package/resources/location-factors.d.ts +2 -2
  226. package/resources/location-factors.d.ts.map +1 -1
  227. package/resources/shared.d.mts +1 -1
  228. package/resources/shared.d.mts.map +1 -1
  229. package/resources/shared.d.ts +1 -1
  230. package/resources/shared.d.ts.map +1 -1
  231. package/resources/workers.d.mts +2 -2
  232. package/resources/workers.d.mts.map +1 -1
  233. package/resources/workers.d.ts +2 -2
  234. package/resources/workers.d.ts.map +1 -1
  235. package/src/client.ts +20 -0
  236. package/src/lib/manifest/app.ts +81 -26
  237. package/src/lib/manifest/category.ts +63 -14
  238. package/src/lib/manifest/custom-object-field-section.ts +56 -17
  239. package/src/lib/manifest/custom-object-page-layout.ts +201 -66
  240. package/src/lib/manifest/custom-object.ts +128 -37
  241. package/src/lib/manifest/field.ts +265 -75
  242. package/src/lib/manifest/list-view.ts +105 -25
  243. package/src/lib/manifest/manifest-builder.ts +75 -32
  244. package/src/lib/manifest/manifest-function.ts +92 -22
  245. package/src/lib/manifest/rule.ts +95 -29
  246. package/src/lib/manifest/sdui-page.ts +67 -21
  247. package/src/lib/manifest/validation.ts +87 -24
  248. package/src/lib/sdui/actions.ts +58 -0
  249. package/src/lib/sdui/component.ts +122 -0
  250. package/src/lib/sdui/components.ts +308 -0
  251. package/src/lib/sdui/conditions.ts +59 -0
  252. package/src/lib/sdui/directives.ts +42 -0
  253. package/src/lib/sdui/index.ts +365 -0
  254. package/src/lib/sdui/props.ts +32 -0
  255. package/src/lib/sdui/render.ts +58 -0
  256. package/src/lib/sdui/state.ts +60 -0
  257. package/src/resources/company-legal-entity-workers.ts +115 -0
  258. package/src/resources/draft-hires.ts +5 -0
  259. package/src/resources/files.ts +18 -1
  260. package/src/resources/headcount-positions.ts +2 -0
  261. package/src/resources/index.ts +7 -0
  262. package/src/resources/legal-entities.ts +1 -0
  263. package/src/resources/location-factors.ts +2 -0
  264. package/src/resources/shared.ts +1 -0
  265. package/src/resources/workers.ts +2 -0
  266. package/src/version.ts +1 -1
  267. package/version.d.mts +1 -1
  268. package/version.d.ts +1 -1
  269. package/version.js +1 -1
  270. package/version.mjs +1 -1
@@ -0,0 +1,367 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * PASTE THIS ENTIRE FILE INTO THE RIPPLING FUNCTION EDITOR TO PREVIEW RENDERED
4
+ * SDUI (CUSTOM PAGE). DEPENDS ON @rippling/rippling-sdk AND @rippling/sdui-builder.
5
+ * MOCK DATA ONLY — NO CUSTOM OBJECT API NAMES; SAFE TO RENDER WITHOUT CO DEFINITIONS.
6
+ * ----------------------------------------------------------------------------
7
+ * Pair file sdui-crud-todo.ts uses import from '@rippling/rippling-sdk/lib/sdui' for local runs.
8
+ */
9
+
10
+ /*
11
+ import SDUI from '@rippling/sdui-builder';
12
+ import { FunctionContext, FunctionEvent, FunctionResponse } from '@rippling/rippling-sdk';
13
+
14
+ const INITIAL_TODOS = [
15
+ {
16
+ id: 't1',
17
+ _key: 't1',
18
+ title__c: 'Ship SDK patch',
19
+ status__c: 'In Progress',
20
+ priority__c: 'High',
21
+ notes__c: 'Regression pass on SDUI examples',
22
+ },
23
+ {
24
+ id: 't2',
25
+ _key: 't2',
26
+ title__c: 'Document Function paste flow',
27
+ status__c: 'To Do',
28
+ priority__c: 'Medium',
29
+ notes__c: 'Caps comment on rippling-function.ts',
30
+ },
31
+ {
32
+ id: 't3',
33
+ _key: 't3',
34
+ title__c: 'Weekly sync',
35
+ status__c: 'Done',
36
+ priority__c: 'Low',
37
+ notes__c: '',
38
+ },
39
+ ];
40
+
41
+ let mutableTodos = INITIAL_TODOS.map((r) => ({ ...r }));
42
+
43
+ function renderSpec(functionId: string) {
44
+ const s = SDUI.createState({
45
+ todos: mutableTodos,
46
+ selectedRow: null as unknown,
47
+ showCreateModal: false,
48
+ showEditModal: false,
49
+ form: { title: '', status: '', priority: '', notes: '' },
50
+ });
51
+
52
+ const mainColumn = SDUI.components.VStack({
53
+ gap: 'space500',
54
+ children: [
55
+ SDUI.components.VStack({
56
+ gap: 'space300',
57
+ children: [
58
+ SDUI.components.HStack({
59
+ gap: 'space200',
60
+ align: 'center',
61
+ wrap: true,
62
+ children: [
63
+ SDUI.components.Heading({
64
+ level: '2',
65
+ text: 'Team todos',
66
+ }),
67
+ SDUI.components.Badge({
68
+ text: 'Demo data',
69
+ appearance: 'NEUTRAL',
70
+ size: 'S',
71
+ }),
72
+ ],
73
+ }),
74
+ SDUI.components.Text({
75
+ text: 'Create, edit, and delete call this Function; the grid below uses sample rows until you connect Custom Objects or your own API.',
76
+ typestyle: 'bodyMd',
77
+ color: 'secondary',
78
+ maxWidth: '720px',
79
+ }),
80
+ ],
81
+ }),
82
+ SDUI.components.Layout({
83
+ width: '100%',
84
+ children: [SDUI.components.Divider({})],
85
+ }),
86
+ SDUI.components.Grid({
87
+ data: s.todos,
88
+ columns: [
89
+ { id: 'title__c', header: 'Title', data: 'title__c' },
90
+ { id: 'status__c', header: 'Status', data: 'status__c', type: 'text' },
91
+ { id: 'priority__c', header: 'Priority', data: 'priority__c', type: 'text' },
92
+ { id: 'notes__c', header: 'Notes', data: 'notes__c' },
93
+ ],
94
+ selectedRow: s.selectedRow.$bind,
95
+ headerActions: [{ id: 'new', label: 'New Todo', icon: 'ADD', appearance: 'PRIMARY' }],
96
+ onHeaderAction: [
97
+ SDUI.actions.set(s.form, { title: '', status: '', priority: '', notes: '' }),
98
+ SDUI.actions.set(s.showCreateModal, true),
99
+ ],
100
+ rowActions: [
101
+ { id: 'edit', label: 'Edit', icon: 'EDIT_OUTLINE', placement: 'menu' },
102
+ { id: 'delete', label: 'Delete', icon: 'TRASH_OUTLINE', placement: 'menu' },
103
+ ],
104
+ onRowAction: [
105
+ SDUI.actions.set(s.form, {
106
+ title: s.selectedRow['title__c'],
107
+ status: s.selectedRow['status__c'],
108
+ priority: s.selectedRow['priority__c'],
109
+ notes: s.selectedRow['notes__c'],
110
+ }),
111
+ SDUI.actions.set(s.showEditModal, true),
112
+ ],
113
+ onRowClick: [
114
+ SDUI.actions.set(s.form, {
115
+ title: s.selectedRow['title__c'],
116
+ status: s.selectedRow['status__c'],
117
+ priority: s.selectedRow['priority__c'],
118
+ notes: s.selectedRow['notes__c'],
119
+ }),
120
+ SDUI.actions.set(s.showEditModal, true),
121
+ ],
122
+ }),
123
+ ],
124
+ });
125
+
126
+ const root = SDUI.components.VStack({
127
+ align: 'center',
128
+ gap: 'space0',
129
+ children: [
130
+ SDUI.components.Layout({
131
+ maxWidth: '1080px',
132
+ width: '100%',
133
+ margin: { left: 'auto', right: 'auto' },
134
+ padding: { top: 32, bottom: 40, left: 24, right: 24 },
135
+ children: [mainColumn],
136
+ }),
137
+
138
+ SDUI.components.Modal({
139
+ title: 'New Todo',
140
+ isOpen: s.showCreateModal.$bind,
141
+ onClose: SDUI.actions.set(s.showCreateModal, false),
142
+ children: [
143
+ SDUI.components.VStack({
144
+ gap: 'space300',
145
+ children: [
146
+ SDUI.components.TextInput({
147
+ label: 'Title',
148
+ name: 'title',
149
+ value: s.form.title.$bind,
150
+ isRequired: true,
151
+ }),
152
+ SDUI.components.Select({
153
+ label: 'Status',
154
+ name: 'status',
155
+ value: s.form.status.$bind,
156
+ options: [
157
+ { label: 'To Do', value: 'To Do' },
158
+ { label: 'In Progress', value: 'In Progress' },
159
+ { label: 'Done', value: 'Done' },
160
+ ],
161
+ }),
162
+ SDUI.components.Select({
163
+ label: 'Priority',
164
+ name: 'priority',
165
+ value: s.form.priority.$bind,
166
+ options: [
167
+ { label: 'Low', value: 'Low' },
168
+ { label: 'Medium', value: 'Medium' },
169
+ { label: 'High', value: 'High' },
170
+ ],
171
+ }),
172
+ SDUI.components.Textarea({
173
+ label: 'Notes',
174
+ name: 'notes',
175
+ value: s.form.notes.$bind,
176
+ }),
177
+ ],
178
+ }),
179
+ SDUI.components.HStack({
180
+ gap: 'space200',
181
+ justify: 'flex-end',
182
+ children: [
183
+ SDUI.components.Button({
184
+ label: 'Cancel',
185
+ appearance: 'OUTLINE',
186
+ onPress: SDUI.actions.set(s.showCreateModal, false),
187
+ }),
188
+ SDUI.components.Button({
189
+ label: 'Create',
190
+ appearance: 'PRIMARY',
191
+ onPress: SDUI.actions.callFunction(functionId, 'create', {
192
+ title: s.form.title,
193
+ status: s.form.status,
194
+ priority: s.form.priority,
195
+ notes: s.form.notes,
196
+ responsePath: '/todos',
197
+ onSuccess: { set: { '/showCreateModal': false } },
198
+ }),
199
+ }),
200
+ ],
201
+ }),
202
+ ],
203
+ }),
204
+
205
+ SDUI.components.Modal({
206
+ title: 'Edit Todo',
207
+ isOpen: s.showEditModal.$bind,
208
+ onClose: SDUI.actions.set(s.showEditModal, false),
209
+ children: [
210
+ SDUI.components.VStack({
211
+ gap: 'space300',
212
+ children: [
213
+ SDUI.components.TextInput({
214
+ label: 'Title',
215
+ name: 'edit_title',
216
+ value: s.form.title.$bind,
217
+ isRequired: true,
218
+ }),
219
+ SDUI.components.Select({
220
+ label: 'Status',
221
+ name: 'edit_status',
222
+ value: s.form.status.$bind,
223
+ options: [
224
+ { label: 'To Do', value: 'To Do' },
225
+ { label: 'In Progress', value: 'In Progress' },
226
+ { label: 'Done', value: 'Done' },
227
+ ],
228
+ }),
229
+ SDUI.components.Select({
230
+ label: 'Priority',
231
+ name: 'edit_priority',
232
+ value: s.form.priority.$bind,
233
+ options: [
234
+ { label: 'Low', value: 'Low' },
235
+ { label: 'Medium', value: 'Medium' },
236
+ { label: 'High', value: 'High' },
237
+ ],
238
+ }),
239
+ SDUI.components.Textarea({
240
+ label: 'Notes',
241
+ name: 'edit_notes',
242
+ value: s.form.notes.$bind,
243
+ }),
244
+ ],
245
+ }),
246
+ SDUI.components.HStack({
247
+ gap: 'space200',
248
+ justify: 'flex-end',
249
+ children: [
250
+ SDUI.components.Button({
251
+ label: 'Delete',
252
+ appearance: 'DESTRUCTIVE',
253
+ onPress: SDUI.actions.callFunction(functionId, 'delete', {
254
+ id: s.selectedRow['id'],
255
+ responsePath: '/todos',
256
+ onSuccess: { set: { '/showEditModal': false } },
257
+ }),
258
+ }),
259
+ SDUI.components.Button({
260
+ label: 'Cancel',
261
+ appearance: 'OUTLINE',
262
+ onPress: SDUI.actions.set(s.showEditModal, false),
263
+ }),
264
+ SDUI.components.Button({
265
+ label: 'Save',
266
+ appearance: 'PRIMARY',
267
+ onPress: SDUI.actions.callFunction(functionId, 'update', {
268
+ id: s.selectedRow['id'],
269
+ title: s.form.title,
270
+ status: s.form.status,
271
+ priority: s.form.priority,
272
+ notes: s.form.notes,
273
+ responsePath: '/todos',
274
+ onSuccess: { set: { '/showEditModal': false } },
275
+ }),
276
+ }),
277
+ ],
278
+ }),
279
+ ],
280
+ }),
281
+ ],
282
+ });
283
+
284
+ return SDUI.render(s, root);
285
+ }
286
+
287
+ export async function onRipplingEvent(
288
+ event: FunctionEvent,
289
+ context: FunctionContext,
290
+ ): Promise<FunctionResponse> {
291
+ const params = event['parameters'] as Record<string, string | undefined> | undefined;
292
+ const action = params?.['action'];
293
+ const functionId = context.function?.function_id ?? 'demo-fn';
294
+
295
+ if (!action || action === 'init') {
296
+ mutableTodos = INITIAL_TODOS.map((r) => ({ ...r }));
297
+ const spec = renderSpec(functionId);
298
+ return new FunctionResponse({
299
+ body: { spec: JSON.stringify(spec) },
300
+ statusCode: 200,
301
+ headers: {},
302
+ message: '',
303
+ });
304
+ }
305
+
306
+ if (action === 'create') {
307
+ const p = params ?? {};
308
+ const id = `t_${mutableTodos.length + 1}`;
309
+ mutableTodos = [
310
+ ...mutableTodos,
311
+ {
312
+ id,
313
+ _key: id,
314
+ title__c: (p['title'] as string) || 'Untitled',
315
+ status__c: (p['status'] as string) || 'To Do',
316
+ priority__c: (p['priority'] as string) || 'Medium',
317
+ notes__c: (p['notes'] as string) || '',
318
+ },
319
+ ];
320
+ return new FunctionResponse({
321
+ body: mutableTodos as unknown as Record<string, unknown>,
322
+ statusCode: 200,
323
+ headers: {},
324
+ message: '',
325
+ });
326
+ }
327
+
328
+ if (action === 'update') {
329
+ const p = params ?? {};
330
+ mutableTodos = mutableTodos.map((r) =>
331
+ r.id === p['id']
332
+ ? {
333
+ ...r,
334
+ title__c: (p['title'] as string) || r.title__c,
335
+ status__c: (p['status'] as string) || r.status__c,
336
+ priority__c: (p['priority'] as string) || r.priority__c,
337
+ notes__c: (p['notes'] as string) ?? r.notes__c,
338
+ }
339
+ : r,
340
+ );
341
+ return new FunctionResponse({
342
+ body: mutableTodos as unknown as Record<string, unknown>,
343
+ statusCode: 200,
344
+ headers: {},
345
+ message: '',
346
+ });
347
+ }
348
+
349
+ if (action === 'delete') {
350
+ const id = params?.['id'];
351
+ mutableTodos = mutableTodos.filter((r) => r.id !== id);
352
+ return new FunctionResponse({
353
+ body: mutableTodos as unknown as Record<string, unknown>,
354
+ statusCode: 200,
355
+ headers: {},
356
+ message: '',
357
+ });
358
+ }
359
+
360
+ return new FunctionResponse({
361
+ body: {},
362
+ statusCode: 400,
363
+ headers: {},
364
+ message: 'Unknown action',
365
+ });
366
+ }
367
+ */
@@ -0,0 +1,282 @@
1
+ /**
2
+ * SDUI CRUD (Todo list) — mock data only; no Custom Objects / objectApiName.
3
+ * Uses in-repo `@rippling/rippling-sdk/lib/sdui` (same pattern as manifest examples).
4
+ *
5
+ * Run:
6
+ * npx ts-node --transpile-only -r tsconfig-paths/register examples/sdui/sdui-crud-todo/sdui-crud-todo.ts
7
+ */
8
+
9
+ import SDUI from '@rippling/rippling-sdk/lib/sdui';
10
+
11
+ const MOCK_TODOS = [
12
+ {
13
+ id: 't1',
14
+ _key: 't1',
15
+ title__c: 'Ship SDK patch',
16
+ status__c: 'In Progress',
17
+ priority__c: 'High',
18
+ notes__c: 'Regression pass on SDUI examples',
19
+ },
20
+ {
21
+ id: 't2',
22
+ _key: 't2',
23
+ title__c: 'Document Function paste flow',
24
+ status__c: 'To Do',
25
+ priority__c: 'Medium',
26
+ notes__c: 'Caps comment on rippling-function.ts',
27
+ },
28
+ {
29
+ id: 't3',
30
+ _key: 't3',
31
+ title__c: 'Weekly sync',
32
+ status__c: 'Done',
33
+ priority__c: 'Low',
34
+ notes__c: '',
35
+ },
36
+ ];
37
+
38
+ function renderSpec(functionId: string) {
39
+ const s = SDUI.createState({
40
+ todos: MOCK_TODOS,
41
+ selectedRow: null as unknown,
42
+ showCreateModal: false,
43
+ showEditModal: false,
44
+ form: { title: '', status: '', priority: '', notes: '' },
45
+ });
46
+
47
+ const mainColumn = SDUI.components.VStack({
48
+ gap: 'space500',
49
+ children: [
50
+ SDUI.components.VStack({
51
+ gap: 'space300',
52
+ children: [
53
+ SDUI.components.HStack({
54
+ gap: 'space200',
55
+ align: 'center',
56
+ wrap: true,
57
+ children: [
58
+ SDUI.components.Heading({
59
+ level: '2',
60
+ text: 'Team todos',
61
+ }),
62
+ SDUI.components.Badge({
63
+ text: 'Demo data',
64
+ appearance: 'NEUTRAL',
65
+ size: 'S',
66
+ }),
67
+ ],
68
+ }),
69
+ SDUI.components.Text({
70
+ text: 'Create, edit, and delete call this Function; the grid below uses sample rows until you connect Custom Objects or your own API.',
71
+ typestyle: 'bodyMd',
72
+ color: 'secondary',
73
+ maxWidth: '720px',
74
+ }),
75
+ ],
76
+ }),
77
+ SDUI.components.Layout({
78
+ width: '100%',
79
+ children: [SDUI.components.Divider({})],
80
+ }),
81
+ SDUI.components.Grid({
82
+ data: s.todos,
83
+ columns: [
84
+ { id: 'title__c', header: 'Title', data: 'title__c' },
85
+ { id: 'status__c', header: 'Status', data: 'status__c', type: 'text' },
86
+ { id: 'priority__c', header: 'Priority', data: 'priority__c', type: 'text' },
87
+ { id: 'notes__c', header: 'Notes', data: 'notes__c' },
88
+ ],
89
+ selectedRow: s.selectedRow.$bind,
90
+ headerActions: [{ id: 'new', label: 'New Todo', icon: 'ADD', appearance: 'PRIMARY' }],
91
+ onHeaderAction: [
92
+ SDUI.actions.set(s.form, { title: '', status: '', priority: '', notes: '' }),
93
+ SDUI.actions.set(s.showCreateModal, true),
94
+ ],
95
+ rowActions: [
96
+ { id: 'edit', label: 'Edit', icon: 'EDIT_OUTLINE', placement: 'menu' },
97
+ { id: 'delete', label: 'Delete', icon: 'TRASH_OUTLINE', placement: 'menu' },
98
+ ],
99
+ onRowAction: [
100
+ SDUI.actions.set(s.form, {
101
+ title: s.selectedRow['title__c'],
102
+ status: s.selectedRow['status__c'],
103
+ priority: s.selectedRow['priority__c'],
104
+ notes: s.selectedRow['notes__c'],
105
+ }),
106
+ SDUI.actions.set(s.showEditModal, true),
107
+ ],
108
+ onRowClick: [
109
+ SDUI.actions.set(s.form, {
110
+ title: s.selectedRow['title__c'],
111
+ status: s.selectedRow['status__c'],
112
+ priority: s.selectedRow['priority__c'],
113
+ notes: s.selectedRow['notes__c'],
114
+ }),
115
+ SDUI.actions.set(s.showEditModal, true),
116
+ ],
117
+ }),
118
+ ],
119
+ });
120
+
121
+ const root = SDUI.components.VStack({
122
+ align: 'center',
123
+ gap: 'space0',
124
+ children: [
125
+ SDUI.components.Layout({
126
+ maxWidth: '1080px',
127
+ width: '100%',
128
+ margin: { left: 'auto', right: 'auto' },
129
+ padding: { top: 32, bottom: 40, left: 24, right: 24 },
130
+ children: [mainColumn],
131
+ }),
132
+
133
+ SDUI.components.Modal({
134
+ title: 'New Todo',
135
+ isOpen: s.showCreateModal.$bind,
136
+ onClose: SDUI.actions.set(s.showCreateModal, false),
137
+ children: [
138
+ SDUI.components.VStack({
139
+ gap: 'space300',
140
+ children: [
141
+ SDUI.components.TextInput({
142
+ label: 'Title',
143
+ name: 'title',
144
+ value: s.form.title.$bind,
145
+ isRequired: true,
146
+ }),
147
+ SDUI.components.Select({
148
+ label: 'Status',
149
+ name: 'status',
150
+ value: s.form.status.$bind,
151
+ options: [
152
+ { label: 'To Do', value: 'To Do' },
153
+ { label: 'In Progress', value: 'In Progress' },
154
+ { label: 'Done', value: 'Done' },
155
+ ],
156
+ }),
157
+ SDUI.components.Select({
158
+ label: 'Priority',
159
+ name: 'priority',
160
+ value: s.form.priority.$bind,
161
+ options: [
162
+ { label: 'Low', value: 'Low' },
163
+ { label: 'Medium', value: 'Medium' },
164
+ { label: 'High', value: 'High' },
165
+ ],
166
+ }),
167
+ SDUI.components.Textarea({
168
+ label: 'Notes',
169
+ name: 'notes',
170
+ value: s.form.notes.$bind,
171
+ }),
172
+ ],
173
+ }),
174
+ SDUI.components.HStack({
175
+ gap: 'space200',
176
+ justify: 'flex-end',
177
+ children: [
178
+ SDUI.components.Button({
179
+ label: 'Cancel',
180
+ appearance: 'OUTLINE',
181
+ onPress: SDUI.actions.set(s.showCreateModal, false),
182
+ }),
183
+ SDUI.components.Button({
184
+ label: 'Create',
185
+ appearance: 'PRIMARY',
186
+ onPress: SDUI.actions.callFunction(functionId, 'create', {
187
+ title: s.form.title,
188
+ status: s.form.status,
189
+ priority: s.form.priority,
190
+ notes: s.form.notes,
191
+ responsePath: '/todos',
192
+ onSuccess: { set: { '/showCreateModal': false } },
193
+ }),
194
+ }),
195
+ ],
196
+ }),
197
+ ],
198
+ }),
199
+
200
+ SDUI.components.Modal({
201
+ title: 'Edit Todo',
202
+ isOpen: s.showEditModal.$bind,
203
+ onClose: SDUI.actions.set(s.showEditModal, false),
204
+ children: [
205
+ SDUI.components.VStack({
206
+ gap: 'space300',
207
+ children: [
208
+ SDUI.components.TextInput({
209
+ label: 'Title',
210
+ name: 'edit_title',
211
+ value: s.form.title.$bind,
212
+ isRequired: true,
213
+ }),
214
+ SDUI.components.Select({
215
+ label: 'Status',
216
+ name: 'edit_status',
217
+ value: s.form.status.$bind,
218
+ options: [
219
+ { label: 'To Do', value: 'To Do' },
220
+ { label: 'In Progress', value: 'In Progress' },
221
+ { label: 'Done', value: 'Done' },
222
+ ],
223
+ }),
224
+ SDUI.components.Select({
225
+ label: 'Priority',
226
+ name: 'edit_priority',
227
+ value: s.form.priority.$bind,
228
+ options: [
229
+ { label: 'Low', value: 'Low' },
230
+ { label: 'Medium', value: 'Medium' },
231
+ { label: 'High', value: 'High' },
232
+ ],
233
+ }),
234
+ SDUI.components.Textarea({
235
+ label: 'Notes',
236
+ name: 'edit_notes',
237
+ value: s.form.notes.$bind,
238
+ }),
239
+ ],
240
+ }),
241
+ SDUI.components.HStack({
242
+ gap: 'space200',
243
+ justify: 'flex-end',
244
+ children: [
245
+ SDUI.components.Button({
246
+ label: 'Delete',
247
+ appearance: 'DESTRUCTIVE',
248
+ onPress: SDUI.actions.callFunction(functionId, 'delete', {
249
+ id: s.selectedRow['id'],
250
+ responsePath: '/todos',
251
+ onSuccess: { set: { '/showEditModal': false } },
252
+ }),
253
+ }),
254
+ SDUI.components.Button({
255
+ label: 'Cancel',
256
+ appearance: 'OUTLINE',
257
+ onPress: SDUI.actions.set(s.showEditModal, false),
258
+ }),
259
+ SDUI.components.Button({
260
+ label: 'Save',
261
+ appearance: 'PRIMARY',
262
+ onPress: SDUI.actions.callFunction(functionId, 'update', {
263
+ id: s.selectedRow['id'],
264
+ title: s.form.title,
265
+ status: s.form.status,
266
+ priority: s.form.priority,
267
+ notes: s.form.notes,
268
+ responsePath: '/todos',
269
+ onSuccess: { set: { '/showEditModal': false } },
270
+ }),
271
+ }),
272
+ ],
273
+ }),
274
+ ],
275
+ }),
276
+ ],
277
+ });
278
+
279
+ return SDUI.render(s, root);
280
+ }
281
+
282
+ console.log(JSON.stringify(renderSpec('demo-fn'), null, 2));