@objectstack/platform-objects 7.3.0 → 7.4.1
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.
- package/dist/apps/index.d.mts +45 -19
- package/dist/apps/index.d.ts +45 -19
- package/dist/apps/index.js +1434 -3406
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/index.mjs +1434 -3407
- package/dist/apps/index.mjs.map +1 -1
- package/dist/audit/index.d.mts +4595 -26176
- package/dist/audit/index.d.ts +4595 -26176
- package/dist/audit/index.js +63 -1063
- package/dist/audit/index.js.map +1 -1
- package/dist/audit/index.mjs +64 -1057
- package/dist/audit/index.mjs.map +1 -1
- package/dist/identity/index.d.mts +839 -1281
- package/dist/identity/index.d.ts +839 -1281
- package/dist/index.d.mts +3 -8
- package/dist/index.d.ts +3 -8
- package/dist/index.js +2344 -6782
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2343 -6767
- package/dist/index.mjs.map +1 -1
- package/dist/integration/index.d.mts +1 -2947
- package/dist/integration/index.d.ts +1 -2947
- package/dist/integration/index.js +0 -136
- package/dist/integration/index.js.map +1 -1
- package/dist/integration/index.mjs +0 -135
- package/dist/integration/index.mjs.map +1 -1
- package/dist/metadata/index.d.mts +3924 -261
- package/dist/metadata/index.d.ts +3924 -261
- package/dist/metadata/index.js +101 -0
- package/dist/metadata/index.js.map +1 -1
- package/dist/metadata/index.mjs +101 -1
- package/dist/metadata/index.mjs.map +1 -1
- package/dist/metadata-translations/index.js +597 -505
- package/dist/metadata-translations/index.js.map +1 -1
- package/dist/metadata-translations/index.mjs +597 -505
- package/dist/metadata-translations/index.mjs.map +1 -1
- package/dist/plugin.js +1790 -3614
- package/dist/plugin.js.map +1 -1
- package/dist/plugin.mjs +1790 -3614
- package/dist/plugin.mjs.map +1 -1
- package/dist/security/index.d.mts +1 -18850
- package/dist/security/index.d.ts +1 -18850
- package/dist/security/index.js +0 -1531
- package/dist/security/index.js.map +1 -1
- package/dist/security/index.mjs +0 -1523
- package/dist/security/index.mjs.map +1 -1
- package/dist/system/index.d.mts +144 -212
- package/dist/system/index.d.ts +144 -212
- package/package.json +2 -2
- package/dist/state-machine.zod-BNanU03M.d-Ek3_yo9P.d.mts +0 -41
- package/dist/state-machine.zod-BNanU03M.d-Ek3_yo9P.d.ts +0 -41
package/dist/audit/index.js
CHANGED
|
@@ -2,541 +2,115 @@
|
|
|
2
2
|
|
|
3
3
|
var data = require('@objectstack/spec/data');
|
|
4
4
|
|
|
5
|
-
// src/audit/sys-
|
|
6
|
-
var
|
|
7
|
-
name: "
|
|
8
|
-
label: "
|
|
9
|
-
pluralLabel: "
|
|
10
|
-
icon: "
|
|
5
|
+
// src/audit/sys-notification.object.ts
|
|
6
|
+
var SysNotification = data.ObjectSchema.create({
|
|
7
|
+
name: "sys_notification",
|
|
8
|
+
label: "Notification Event",
|
|
9
|
+
pluralLabel: "Notification Events",
|
|
10
|
+
icon: "bell",
|
|
11
11
|
isSystem: true,
|
|
12
|
-
managedBy: "
|
|
13
|
-
description: "
|
|
14
|
-
displayNameField: "
|
|
15
|
-
titleFormat: "{
|
|
16
|
-
compactLayout: ["
|
|
12
|
+
managedBy: "system",
|
|
13
|
+
description: "Notification events \u2014 one row per emit() (ADR-0030 Layer 2 ingress)",
|
|
14
|
+
displayNameField: "topic",
|
|
15
|
+
titleFormat: "{topic}",
|
|
16
|
+
compactLayout: ["topic", "severity", "source_object", "created_at"],
|
|
17
17
|
listViews: {
|
|
18
18
|
recent: {
|
|
19
19
|
type: "grid",
|
|
20
20
|
name: "recent",
|
|
21
21
|
label: "Recent",
|
|
22
|
-
data: { provider: "object", object: "
|
|
23
|
-
columns: ["
|
|
22
|
+
data: { provider: "object", object: "sys_notification" },
|
|
23
|
+
columns: ["topic", "severity", "actor_id", "source_object", "created_at"],
|
|
24
24
|
sort: [{ field: "created_at", order: "desc" }],
|
|
25
25
|
pagination: { pageSize: 50 },
|
|
26
|
-
emptyState: { title: "No
|
|
27
|
-
},
|
|
28
|
-
writes_only: {
|
|
29
|
-
type: "grid",
|
|
30
|
-
name: "writes_only",
|
|
31
|
-
label: "Writes",
|
|
32
|
-
data: { provider: "object", object: "sys_audit_log" },
|
|
33
|
-
columns: ["created_at", "action", "object_name", "record_id", "user_id"],
|
|
34
|
-
filter: [{ field: "action", operator: "in", value: ["create", "update", "delete", "restore"] }],
|
|
35
|
-
sort: [{ field: "created_at", order: "desc" }],
|
|
36
|
-
pagination: { pageSize: 50 }
|
|
37
|
-
},
|
|
38
|
-
auth_events: {
|
|
39
|
-
type: "grid",
|
|
40
|
-
name: "auth_events",
|
|
41
|
-
label: "Auth",
|
|
42
|
-
data: { provider: "object", object: "sys_audit_log" },
|
|
43
|
-
columns: ["created_at", "action", "user_id"],
|
|
44
|
-
filter: [{ field: "action", operator: "in", value: ["login", "logout", "permission_change"] }],
|
|
45
|
-
sort: [{ field: "created_at", order: "desc" }],
|
|
46
|
-
pagination: { pageSize: 50 }
|
|
26
|
+
emptyState: { title: "No events", message: "No notification events have been emitted." }
|
|
47
27
|
},
|
|
48
|
-
|
|
28
|
+
by_topic: {
|
|
49
29
|
type: "grid",
|
|
50
|
-
name: "
|
|
51
|
-
label: "
|
|
52
|
-
data: { provider: "object", object: "
|
|
53
|
-
columns: ["
|
|
54
|
-
filter: [{ field: "action", operator: "in", value: ["config_change", "export", "import"] }],
|
|
55
|
-
sort: [{ field: "created_at", order: "desc" }],
|
|
56
|
-
pagination: { pageSize: 50 }
|
|
57
|
-
},
|
|
58
|
-
all_events: {
|
|
59
|
-
type: "grid",
|
|
60
|
-
name: "all_events",
|
|
61
|
-
label: "All",
|
|
62
|
-
data: { provider: "object", object: "sys_audit_log" },
|
|
63
|
-
columns: ["created_at", "action", "object_name", "record_id", "user_id"],
|
|
30
|
+
name: "by_topic",
|
|
31
|
+
label: "By Topic",
|
|
32
|
+
data: { provider: "object", object: "sys_notification" },
|
|
33
|
+
columns: ["topic", "severity", "source_object", "source_id", "created_at"],
|
|
64
34
|
sort: [{ field: "created_at", order: "desc" }],
|
|
65
|
-
pagination: { pageSize: 100 }
|
|
35
|
+
pagination: { pageSize: 100 },
|
|
36
|
+
grouping: { fields: [{ field: "topic", order: "asc", collapsed: false }] }
|
|
66
37
|
}
|
|
67
38
|
},
|
|
68
39
|
fields: {
|
|
69
|
-
// ── Event ────────────────────────────────────────────────────
|
|
70
|
-
created_at: data.Field.datetime({
|
|
71
|
-
label: "Timestamp",
|
|
72
|
-
required: true,
|
|
73
|
-
defaultValue: "NOW()",
|
|
74
|
-
readonly: true,
|
|
75
|
-
group: "Event"
|
|
76
|
-
}),
|
|
77
|
-
action: data.Field.select(
|
|
78
|
-
["create", "update", "delete", "restore", "login", "logout", "permission_change", "config_change", "export", "import"],
|
|
79
|
-
{
|
|
80
|
-
label: "Action",
|
|
81
|
-
required: true,
|
|
82
|
-
readonly: true,
|
|
83
|
-
searchable: true,
|
|
84
|
-
description: "Action type (snake_case)",
|
|
85
|
-
group: "Event"
|
|
86
|
-
}
|
|
87
|
-
),
|
|
88
|
-
user_id: data.Field.lookup("sys_user", {
|
|
89
|
-
label: "Actor",
|
|
90
|
-
required: false,
|
|
91
|
-
readonly: true,
|
|
92
|
-
searchable: true,
|
|
93
|
-
description: "User who performed the action (null for system actions)",
|
|
94
|
-
group: "Event"
|
|
95
|
-
}),
|
|
96
|
-
// ── Target record ────────────────────────────────────────────
|
|
97
|
-
object_name: data.Field.text({
|
|
98
|
-
label: "Object",
|
|
99
|
-
required: false,
|
|
100
|
-
readonly: true,
|
|
101
|
-
searchable: true,
|
|
102
|
-
maxLength: 255,
|
|
103
|
-
description: "Target object (e.g. sys_user, project_task)",
|
|
104
|
-
group: "Target"
|
|
105
|
-
}),
|
|
106
|
-
record_id: data.Field.text({
|
|
107
|
-
label: "Record ID",
|
|
108
|
-
required: false,
|
|
109
|
-
readonly: true,
|
|
110
|
-
searchable: true,
|
|
111
|
-
description: "ID of the affected record",
|
|
112
|
-
group: "Target"
|
|
113
|
-
}),
|
|
114
|
-
// ── Change payload ───────────────────────────────────────────
|
|
115
|
-
old_value: data.Field.textarea({
|
|
116
|
-
label: "Old Value",
|
|
117
|
-
required: false,
|
|
118
|
-
readonly: true,
|
|
119
|
-
description: "JSON-serialized previous state",
|
|
120
|
-
group: "Changes"
|
|
121
|
-
}),
|
|
122
|
-
new_value: data.Field.textarea({
|
|
123
|
-
label: "New Value",
|
|
124
|
-
required: false,
|
|
125
|
-
readonly: true,
|
|
126
|
-
description: "JSON-serialized new state",
|
|
127
|
-
group: "Changes"
|
|
128
|
-
}),
|
|
129
|
-
// ── Client fingerprint ───────────────────────────────────────
|
|
130
|
-
ip_address: data.Field.text({
|
|
131
|
-
label: "IP Address",
|
|
132
|
-
required: false,
|
|
133
|
-
readonly: true,
|
|
134
|
-
maxLength: 45,
|
|
135
|
-
group: "Client"
|
|
136
|
-
}),
|
|
137
|
-
user_agent: data.Field.textarea({
|
|
138
|
-
label: "User Agent",
|
|
139
|
-
required: false,
|
|
140
|
-
readonly: true,
|
|
141
|
-
group: "Client"
|
|
142
|
-
}),
|
|
143
|
-
// ── Context ──────────────────────────────────────────────────
|
|
144
|
-
tenant_id: data.Field.lookup("sys_organization", {
|
|
145
|
-
label: "Tenant",
|
|
146
|
-
required: false,
|
|
147
|
-
readonly: true,
|
|
148
|
-
description: "Tenant context for multi-tenant isolation",
|
|
149
|
-
group: "Context"
|
|
150
|
-
}),
|
|
151
|
-
metadata: data.Field.textarea({
|
|
152
|
-
label: "Metadata",
|
|
153
|
-
required: false,
|
|
154
|
-
readonly: true,
|
|
155
|
-
description: "JSON-serialized additional context",
|
|
156
|
-
group: "Context"
|
|
157
|
-
}),
|
|
158
|
-
// ── System ───────────────────────────────────────────────────
|
|
159
40
|
id: data.Field.text({
|
|
160
|
-
label: "
|
|
161
|
-
required: true,
|
|
162
|
-
readonly: true,
|
|
163
|
-
group: "System"
|
|
164
|
-
})
|
|
165
|
-
},
|
|
166
|
-
indexes: [
|
|
167
|
-
{ fields: ["created_at"] },
|
|
168
|
-
{ fields: ["user_id"] },
|
|
169
|
-
{ fields: ["object_name", "record_id"] },
|
|
170
|
-
{ fields: ["action"] },
|
|
171
|
-
{ fields: ["tenant_id"] }
|
|
172
|
-
],
|
|
173
|
-
enable: {
|
|
174
|
-
trackHistory: false,
|
|
175
|
-
// Audit logs are themselves the audit trail
|
|
176
|
-
searchable: true,
|
|
177
|
-
apiEnabled: true,
|
|
178
|
-
apiMethods: ["get", "list"],
|
|
179
|
-
// Read-only — creation happens via internal system hooks only
|
|
180
|
-
trash: false,
|
|
181
|
-
// Never soft-delete audit logs
|
|
182
|
-
mru: false,
|
|
183
|
-
clone: false
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
var SysPresence = data.ObjectSchema.create({
|
|
187
|
-
name: "sys_presence",
|
|
188
|
-
label: "Presence",
|
|
189
|
-
pluralLabel: "Presences",
|
|
190
|
-
icon: "wifi",
|
|
191
|
-
isSystem: true,
|
|
192
|
-
managedBy: "append-only",
|
|
193
|
-
description: "Real-time user presence and activity tracking",
|
|
194
|
-
titleFormat: "{user_id} ({status})",
|
|
195
|
-
compactLayout: ["user_id", "status", "last_seen"],
|
|
196
|
-
fields: {
|
|
197
|
-
id: data.Field.text({
|
|
198
|
-
label: "Presence ID",
|
|
199
|
-
required: true,
|
|
200
|
-
readonly: true
|
|
201
|
-
}),
|
|
202
|
-
created_at: data.Field.datetime({
|
|
203
|
-
label: "Created At",
|
|
204
|
-
defaultValue: "NOW()",
|
|
205
|
-
readonly: true
|
|
206
|
-
}),
|
|
207
|
-
updated_at: data.Field.datetime({
|
|
208
|
-
label: "Updated At",
|
|
209
|
-
defaultValue: "NOW()",
|
|
210
|
-
readonly: true
|
|
211
|
-
}),
|
|
212
|
-
user_id: data.Field.lookup("sys_user", {
|
|
213
|
-
label: "User",
|
|
214
|
-
required: true,
|
|
215
|
-
searchable: true
|
|
216
|
-
}),
|
|
217
|
-
session_id: data.Field.lookup("sys_session", {
|
|
218
|
-
label: "Session",
|
|
219
|
-
required: true
|
|
220
|
-
}),
|
|
221
|
-
status: data.Field.select({
|
|
222
|
-
label: "Status",
|
|
223
|
-
required: true,
|
|
224
|
-
defaultValue: "online",
|
|
225
|
-
options: [
|
|
226
|
-
{ value: "online", label: "Online" },
|
|
227
|
-
{ value: "away", label: "Away" },
|
|
228
|
-
{ value: "busy", label: "Busy" },
|
|
229
|
-
{ value: "offline", label: "Offline" }
|
|
230
|
-
]
|
|
231
|
-
}),
|
|
232
|
-
last_seen: data.Field.datetime({
|
|
233
|
-
label: "Last Seen",
|
|
234
|
-
required: true,
|
|
235
|
-
defaultValue: "NOW()"
|
|
236
|
-
}),
|
|
237
|
-
current_location: data.Field.text({
|
|
238
|
-
label: "Current Location",
|
|
239
|
-
required: false,
|
|
240
|
-
maxLength: 500
|
|
241
|
-
}),
|
|
242
|
-
device: data.Field.select({
|
|
243
|
-
label: "Device",
|
|
244
|
-
required: false,
|
|
245
|
-
options: [
|
|
246
|
-
{ value: "desktop", label: "Desktop" },
|
|
247
|
-
{ value: "mobile", label: "Mobile" },
|
|
248
|
-
{ value: "tablet", label: "Tablet" },
|
|
249
|
-
{ value: "other", label: "Other" }
|
|
250
|
-
]
|
|
251
|
-
}),
|
|
252
|
-
custom_status: data.Field.text({
|
|
253
|
-
label: "Custom Status",
|
|
254
|
-
required: false,
|
|
255
|
-
maxLength: 255
|
|
256
|
-
}),
|
|
257
|
-
metadata: data.Field.json({
|
|
258
|
-
label: "Metadata",
|
|
259
|
-
required: false,
|
|
260
|
-
description: "Arbitrary JSON metadata associated with the presence state (matches PresenceStateSchema.metadata)."
|
|
261
|
-
})
|
|
262
|
-
},
|
|
263
|
-
indexes: [
|
|
264
|
-
{ fields: ["user_id"], unique: false },
|
|
265
|
-
{ fields: ["session_id"], unique: true },
|
|
266
|
-
{ fields: ["status"], unique: false }
|
|
267
|
-
],
|
|
268
|
-
enable: {
|
|
269
|
-
trackHistory: false,
|
|
270
|
-
searchable: false,
|
|
271
|
-
apiEnabled: true,
|
|
272
|
-
apiMethods: ["get", "list", "create", "update", "delete"],
|
|
273
|
-
trash: false,
|
|
274
|
-
mru: false
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
var SysActivity = data.ObjectSchema.create({
|
|
278
|
-
name: "sys_activity",
|
|
279
|
-
label: "Activity",
|
|
280
|
-
pluralLabel: "Activities",
|
|
281
|
-
icon: "activity",
|
|
282
|
-
isSystem: true,
|
|
283
|
-
managedBy: "append-only",
|
|
284
|
-
description: "Recent activity stream entries (lightweight, denormalized)",
|
|
285
|
-
displayNameField: "summary",
|
|
286
|
-
titleFormat: "{type} \xB7 {summary}",
|
|
287
|
-
compactLayout: ["timestamp", "type", "actor_name", "summary"],
|
|
288
|
-
fields: {
|
|
289
|
-
id: data.Field.text({
|
|
290
|
-
label: "Activity ID",
|
|
41
|
+
label: "Notification ID",
|
|
291
42
|
required: true,
|
|
292
43
|
readonly: true,
|
|
293
44
|
group: "System"
|
|
294
45
|
}),
|
|
295
|
-
|
|
296
|
-
|
|
46
|
+
// ── Event identity ───────────────────────────────────────────
|
|
47
|
+
topic: data.Field.text({
|
|
48
|
+
label: "Topic",
|
|
297
49
|
required: true,
|
|
298
|
-
|
|
299
|
-
readonly: true,
|
|
300
|
-
group: "Event"
|
|
301
|
-
}),
|
|
302
|
-
type: data.Field.select(
|
|
303
|
-
[
|
|
304
|
-
"created",
|
|
305
|
-
"updated",
|
|
306
|
-
"deleted",
|
|
307
|
-
"commented",
|
|
308
|
-
"mentioned",
|
|
309
|
-
"shared",
|
|
310
|
-
"assigned",
|
|
311
|
-
"completed",
|
|
312
|
-
"login",
|
|
313
|
-
"logout",
|
|
314
|
-
"system"
|
|
315
|
-
],
|
|
316
|
-
{
|
|
317
|
-
label: "Type",
|
|
318
|
-
required: true,
|
|
319
|
-
readonly: true,
|
|
320
|
-
searchable: true,
|
|
321
|
-
group: "Event"
|
|
322
|
-
}
|
|
323
|
-
),
|
|
324
|
-
summary: data.Field.text({
|
|
325
|
-
label: "Summary",
|
|
326
|
-
required: true,
|
|
327
|
-
readonly: true,
|
|
328
|
-
maxLength: 500,
|
|
50
|
+
maxLength: 200,
|
|
329
51
|
searchable: true,
|
|
330
|
-
description: "
|
|
52
|
+
description: "Notification topic, e.g. task.assigned, collab.mention",
|
|
331
53
|
group: "Event"
|
|
332
54
|
}),
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
label: "Actor",
|
|
336
|
-
required: false,
|
|
337
|
-
readonly: true,
|
|
338
|
-
searchable: true,
|
|
339
|
-
group: "Actor"
|
|
340
|
-
}),
|
|
341
|
-
actor_name: data.Field.text({
|
|
342
|
-
label: "Actor Name",
|
|
343
|
-
required: false,
|
|
344
|
-
readonly: true,
|
|
345
|
-
group: "Actor"
|
|
346
|
-
}),
|
|
347
|
-
actor_avatar_url: data.Field.url({
|
|
348
|
-
label: "Actor Avatar",
|
|
349
|
-
required: false,
|
|
350
|
-
readonly: true,
|
|
351
|
-
group: "Actor"
|
|
352
|
-
}),
|
|
353
|
-
// ── Target ───────────────────────────────────────────────────
|
|
354
|
-
object_name: data.Field.text({
|
|
355
|
-
label: "Object",
|
|
356
|
-
required: false,
|
|
357
|
-
readonly: true,
|
|
358
|
-
searchable: true,
|
|
359
|
-
maxLength: 255,
|
|
360
|
-
description: "Target object short name (e.g. account, sys_user)",
|
|
361
|
-
group: "Target"
|
|
362
|
-
}),
|
|
363
|
-
record_id: data.Field.text({
|
|
364
|
-
label: "Record ID",
|
|
365
|
-
required: false,
|
|
366
|
-
readonly: true,
|
|
367
|
-
searchable: true,
|
|
368
|
-
group: "Target"
|
|
369
|
-
}),
|
|
370
|
-
record_label: data.Field.text({
|
|
371
|
-
label: "Record Label",
|
|
55
|
+
payload: data.Field.json({
|
|
56
|
+
label: "Payload",
|
|
372
57
|
required: false,
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
description: "Display label of the target record at write time",
|
|
376
|
-
group: "Target"
|
|
377
|
-
}),
|
|
378
|
-
url: data.Field.url({
|
|
379
|
-
label: "URL",
|
|
380
|
-
required: false,
|
|
381
|
-
readonly: true,
|
|
382
|
-
description: "Optional deep-link to the activity target",
|
|
383
|
-
group: "Target"
|
|
58
|
+
description: "Template inputs carried to channels (title/body/url/actor/source/\u2026)",
|
|
59
|
+
group: "Event"
|
|
384
60
|
}),
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
label: "Environment",
|
|
61
|
+
severity: data.Field.select(["info", "warning", "critical"], {
|
|
62
|
+
label: "Severity",
|
|
388
63
|
required: false,
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
group: "Context"
|
|
64
|
+
defaultValue: "info",
|
|
65
|
+
description: "Severity hint for rendering / filtering",
|
|
66
|
+
group: "Event"
|
|
393
67
|
}),
|
|
394
|
-
|
|
395
|
-
label: "
|
|
68
|
+
dedup_key: data.Field.text({
|
|
69
|
+
label: "Dedup Key",
|
|
396
70
|
required: false,
|
|
397
|
-
readonly: true,
|
|
398
|
-
description: "JSON-serialized additional context",
|
|
399
|
-
group: "Context"
|
|
400
|
-
})
|
|
401
|
-
},
|
|
402
|
-
indexes: [
|
|
403
|
-
{ fields: ["timestamp"] },
|
|
404
|
-
{ fields: ["actor_id"] },
|
|
405
|
-
{ fields: ["object_name", "record_id"] },
|
|
406
|
-
{ fields: ["type"] },
|
|
407
|
-
{ fields: ["environment_id"] }
|
|
408
|
-
],
|
|
409
|
-
enable: {
|
|
410
|
-
trackHistory: false,
|
|
411
|
-
searchable: true,
|
|
412
|
-
apiEnabled: true,
|
|
413
|
-
apiMethods: ["get", "list"],
|
|
414
|
-
trash: false,
|
|
415
|
-
mru: false,
|
|
416
|
-
clone: false
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
var SysComment = data.ObjectSchema.create({
|
|
420
|
-
name: "sys_comment",
|
|
421
|
-
label: "Comment",
|
|
422
|
-
pluralLabel: "Comments",
|
|
423
|
-
icon: "message-square",
|
|
424
|
-
isSystem: true,
|
|
425
|
-
managedBy: "platform",
|
|
426
|
-
description: "Threaded comments attached to records via thread_id",
|
|
427
|
-
displayNameField: "body",
|
|
428
|
-
titleFormat: "{author_name}: {body}",
|
|
429
|
-
compactLayout: ["created_at", "author_name", "body"],
|
|
430
|
-
fields: {
|
|
431
|
-
id: data.Field.text({
|
|
432
|
-
label: "Comment ID",
|
|
433
|
-
required: true,
|
|
434
|
-
readonly: true,
|
|
435
|
-
group: "System"
|
|
436
|
-
}),
|
|
437
|
-
// ── Thread ───────────────────────────────────────────────────
|
|
438
|
-
thread_id: data.Field.text({
|
|
439
|
-
label: "Thread",
|
|
440
|
-
required: true,
|
|
441
|
-
searchable: true,
|
|
442
71
|
maxLength: 255,
|
|
443
|
-
description: "
|
|
444
|
-
group: "
|
|
445
|
-
}),
|
|
446
|
-
parent_id: data.Field.lookup("sys_comment", {
|
|
447
|
-
label: "Parent Comment",
|
|
448
|
-
required: false,
|
|
449
|
-
description: "Optional parent comment for nested replies",
|
|
450
|
-
group: "Thread"
|
|
451
|
-
}),
|
|
452
|
-
reply_count: data.Field.number({
|
|
453
|
-
label: "Reply Count",
|
|
454
|
-
defaultValue: 0,
|
|
455
|
-
readonly: true,
|
|
456
|
-
group: "Thread"
|
|
457
|
-
}),
|
|
458
|
-
// ── Author ───────────────────────────────────────────────────
|
|
459
|
-
author_id: data.Field.lookup("sys_user", {
|
|
460
|
-
label: "Author",
|
|
461
|
-
required: true,
|
|
462
|
-
searchable: true,
|
|
463
|
-
group: "Author"
|
|
464
|
-
}),
|
|
465
|
-
author_name: data.Field.text({
|
|
466
|
-
label: "Author Name",
|
|
467
|
-
required: false,
|
|
468
|
-
group: "Author"
|
|
72
|
+
description: "Idempotency key within a topic window; a repeat emit is a no-op",
|
|
73
|
+
group: "Event"
|
|
469
74
|
}),
|
|
470
|
-
|
|
471
|
-
|
|
75
|
+
// ── Source linkage ───────────────────────────────────────────
|
|
76
|
+
source_object: data.Field.text({
|
|
77
|
+
label: "Source Object",
|
|
472
78
|
required: false,
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
body: data.Field.textarea({
|
|
477
|
-
label: "Body",
|
|
478
|
-
required: true,
|
|
479
|
-
searchable: true,
|
|
480
|
-
description: "Comment text (Markdown supported)",
|
|
481
|
-
group: "Body"
|
|
79
|
+
maxLength: 100,
|
|
80
|
+
description: "Object name of the related record (e.g. lead, opportunity)",
|
|
81
|
+
group: "Source"
|
|
482
82
|
}),
|
|
483
|
-
|
|
484
|
-
label: "
|
|
83
|
+
source_id: data.Field.text({
|
|
84
|
+
label: "Source Record",
|
|
485
85
|
required: false,
|
|
486
|
-
|
|
487
|
-
|
|
86
|
+
maxLength: 100,
|
|
87
|
+
description: "Record id within source_object",
|
|
88
|
+
group: "Source"
|
|
488
89
|
}),
|
|
489
|
-
|
|
490
|
-
label: "
|
|
90
|
+
actor_id: data.Field.lookup("sys_user", {
|
|
91
|
+
label: "Actor",
|
|
491
92
|
required: false,
|
|
492
|
-
description: "
|
|
493
|
-
group: "
|
|
93
|
+
description: "User who caused the event (mentioner, assigner)",
|
|
94
|
+
group: "Source"
|
|
494
95
|
}),
|
|
495
96
|
// ── Lifecycle ────────────────────────────────────────────────
|
|
496
|
-
is_edited: data.Field.boolean({
|
|
497
|
-
label: "Edited",
|
|
498
|
-
defaultValue: false,
|
|
499
|
-
group: "Lifecycle"
|
|
500
|
-
}),
|
|
501
|
-
edited_at: data.Field.datetime({
|
|
502
|
-
label: "Edited At",
|
|
503
|
-
required: false,
|
|
504
|
-
group: "Lifecycle"
|
|
505
|
-
}),
|
|
506
|
-
visibility: data.Field.select(
|
|
507
|
-
["public", "internal", "private"],
|
|
508
|
-
{
|
|
509
|
-
label: "Visibility",
|
|
510
|
-
defaultValue: "public",
|
|
511
|
-
group: "Lifecycle"
|
|
512
|
-
}
|
|
513
|
-
),
|
|
514
97
|
created_at: data.Field.datetime({
|
|
515
98
|
label: "Created At",
|
|
516
99
|
required: true,
|
|
517
100
|
defaultValue: "NOW()",
|
|
518
101
|
readonly: true,
|
|
519
102
|
group: "System"
|
|
520
|
-
}),
|
|
521
|
-
updated_at: data.Field.datetime({
|
|
522
|
-
label: "Updated At",
|
|
523
|
-
required: false,
|
|
524
|
-
group: "System"
|
|
525
103
|
})
|
|
526
104
|
},
|
|
527
105
|
indexes: [
|
|
528
|
-
{ fields: ["
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
trash: true,
|
|
537
|
-
mru: false,
|
|
538
|
-
clone: false
|
|
539
|
-
}
|
|
106
|
+
{ fields: ["topic", "created_at"] },
|
|
107
|
+
// Idempotency spine (ADR-0030). UNIQUE so `emit()` dedup is race-safe: a
|
|
108
|
+
// concurrent emit with the same dedup_key loses the insert and converges to
|
|
109
|
+
// the winner (mirrors the delivery outbox). SQL treats NULLs as distinct, so
|
|
110
|
+
// the (common) events with no dedup_key are unconstrained.
|
|
111
|
+
{ fields: ["dedup_key"], unique: true },
|
|
112
|
+
{ fields: ["source_object", "source_id"] }
|
|
113
|
+
]
|
|
540
114
|
});
|
|
541
115
|
var SysAttachment = data.ObjectSchema.create({
|
|
542
116
|
name: "sys_attachment",
|
|
@@ -655,202 +229,6 @@ var SysAttachment = data.ObjectSchema.create({
|
|
|
655
229
|
clone: false
|
|
656
230
|
}
|
|
657
231
|
});
|
|
658
|
-
var SysNotification = data.ObjectSchema.create({
|
|
659
|
-
name: "sys_notification",
|
|
660
|
-
label: "Notification",
|
|
661
|
-
pluralLabel: "Notifications",
|
|
662
|
-
icon: "bell",
|
|
663
|
-
isSystem: true,
|
|
664
|
-
managedBy: "system",
|
|
665
|
-
description: "Per-user notification inbox entries",
|
|
666
|
-
displayNameField: "title",
|
|
667
|
-
titleFormat: "{title}",
|
|
668
|
-
compactLayout: ["title", "type", "is_read", "created_at"],
|
|
669
|
-
/**
|
|
670
|
-
* Row-level inbox actions. Use `visible` CEL expressions to ensure
|
|
671
|
-
* `mark_read` only shows on unread rows and vice-versa, mirroring the
|
|
672
|
-
* mark-as-read affordances in GitHub / Linear inboxes. The toolbar-level
|
|
673
|
-
* `mark_all_read` is intentionally omitted server-side: it requires a
|
|
674
|
-
* bulk update primitive that doesn't yet exist on the REST surface, and
|
|
675
|
-
* the popover already handles the multi-row case client-side via N
|
|
676
|
-
* single-row PATCHes (see `InboxPopover.tsx` -> AppHeader `markAllRead`).
|
|
677
|
-
*/
|
|
678
|
-
actions: [
|
|
679
|
-
{
|
|
680
|
-
name: "mark_read",
|
|
681
|
-
label: "Mark as Read",
|
|
682
|
-
icon: "check",
|
|
683
|
-
variant: "secondary",
|
|
684
|
-
mode: "custom",
|
|
685
|
-
locations: ["list_item"],
|
|
686
|
-
type: "api",
|
|
687
|
-
method: "PATCH",
|
|
688
|
-
target: "/api/v1/data/sys_notification/{id}",
|
|
689
|
-
bodyExtra: { is_read: true },
|
|
690
|
-
visible: "!record.is_read",
|
|
691
|
-
successMessage: "Notification marked as read",
|
|
692
|
-
refreshAfter: true
|
|
693
|
-
},
|
|
694
|
-
{
|
|
695
|
-
name: "mark_unread",
|
|
696
|
-
label: "Mark as Unread",
|
|
697
|
-
icon: "bell-dot",
|
|
698
|
-
variant: "secondary",
|
|
699
|
-
mode: "custom",
|
|
700
|
-
locations: ["list_item"],
|
|
701
|
-
type: "api",
|
|
702
|
-
method: "PATCH",
|
|
703
|
-
target: "/api/v1/data/sys_notification/{id}",
|
|
704
|
-
bodyExtra: { is_read: false, read_at: null },
|
|
705
|
-
visible: "record.is_read",
|
|
706
|
-
successMessage: "Notification marked as unread",
|
|
707
|
-
refreshAfter: true
|
|
708
|
-
}
|
|
709
|
-
],
|
|
710
|
-
listViews: {
|
|
711
|
-
unread: {
|
|
712
|
-
type: "grid",
|
|
713
|
-
name: "unread",
|
|
714
|
-
label: "Unread",
|
|
715
|
-
data: { provider: "object", object: "sys_notification" },
|
|
716
|
-
// Title + actor first (the "who/what" the user actually scans);
|
|
717
|
-
// type stays as a categorising chip; created_at right-aligned.
|
|
718
|
-
columns: ["title", "actor_name", "type", "created_at"],
|
|
719
|
-
filter: [
|
|
720
|
-
{ field: "recipient_id", operator: "equals", value: "{current_user_id}" },
|
|
721
|
-
{ field: "is_read", operator: "equals", value: false }
|
|
722
|
-
],
|
|
723
|
-
sort: [{ field: "created_at", order: "desc" }],
|
|
724
|
-
pagination: { pageSize: 50 },
|
|
725
|
-
emptyState: { title: "Inbox zero", message: "No unread notifications." }
|
|
726
|
-
},
|
|
727
|
-
mine: {
|
|
728
|
-
type: "grid",
|
|
729
|
-
name: "mine",
|
|
730
|
-
label: "Mine",
|
|
731
|
-
data: { provider: "object", object: "sys_notification" },
|
|
732
|
-
columns: ["title", "actor_name", "type", "is_read", "created_at"],
|
|
733
|
-
filter: [{ field: "recipient_id", operator: "equals", value: "{current_user_id}" }],
|
|
734
|
-
sort: [{ field: "created_at", order: "desc" }],
|
|
735
|
-
pagination: { pageSize: 50 },
|
|
736
|
-
// Group by notification category so mention/assignment storms don't
|
|
737
|
-
// hide system or task_due rows. Users still toggle to flat via the
|
|
738
|
-
// toolbar Group control if they prefer chronology only.
|
|
739
|
-
grouping: { fields: [{ field: "type", order: "asc", collapsed: false }] }
|
|
740
|
-
},
|
|
741
|
-
all_notifications: {
|
|
742
|
-
type: "grid",
|
|
743
|
-
name: "all_notifications",
|
|
744
|
-
label: "All",
|
|
745
|
-
data: { provider: "object", object: "sys_notification" },
|
|
746
|
-
columns: ["title", "recipient_id", "actor_name", "type", "is_read", "created_at"],
|
|
747
|
-
sort: [{ field: "created_at", order: "desc" }],
|
|
748
|
-
pagination: { pageSize: 100 }
|
|
749
|
-
}
|
|
750
|
-
},
|
|
751
|
-
fields: {
|
|
752
|
-
id: data.Field.text({
|
|
753
|
-
label: "Notification ID",
|
|
754
|
-
required: true,
|
|
755
|
-
readonly: true,
|
|
756
|
-
group: "System"
|
|
757
|
-
}),
|
|
758
|
-
// ── Routing ──────────────────────────────────────────────────
|
|
759
|
-
recipient_id: data.Field.lookup("sys_user", {
|
|
760
|
-
label: "Recipient",
|
|
761
|
-
required: true,
|
|
762
|
-
searchable: true,
|
|
763
|
-
description: "User the notification is delivered to",
|
|
764
|
-
group: "Routing"
|
|
765
|
-
}),
|
|
766
|
-
// ── Content ──────────────────────────────────────────────────
|
|
767
|
-
type: data.Field.select(
|
|
768
|
-
["mention", "assignment", "comment_reply", "lead_converted", "task_due", "system"],
|
|
769
|
-
{
|
|
770
|
-
label: "Type",
|
|
771
|
-
required: true,
|
|
772
|
-
defaultValue: "system",
|
|
773
|
-
description: "Notification category \u2014 drives icon + sort priority",
|
|
774
|
-
group: "Content"
|
|
775
|
-
}
|
|
776
|
-
),
|
|
777
|
-
title: data.Field.text({
|
|
778
|
-
label: "Title",
|
|
779
|
-
required: true,
|
|
780
|
-
maxLength: 255,
|
|
781
|
-
searchable: true,
|
|
782
|
-
group: "Content"
|
|
783
|
-
}),
|
|
784
|
-
body: data.Field.textarea({
|
|
785
|
-
label: "Body",
|
|
786
|
-
required: false,
|
|
787
|
-
description: "Optional secondary text (one-line summary)",
|
|
788
|
-
group: "Content"
|
|
789
|
-
}),
|
|
790
|
-
// ── Source linkage ───────────────────────────────────────────
|
|
791
|
-
source_object: data.Field.text({
|
|
792
|
-
label: "Source Object",
|
|
793
|
-
required: false,
|
|
794
|
-
maxLength: 100,
|
|
795
|
-
description: "Object name of the related record (e.g. lead, opportunity)",
|
|
796
|
-
group: "Source"
|
|
797
|
-
}),
|
|
798
|
-
source_id: data.Field.text({
|
|
799
|
-
label: "Source Record",
|
|
800
|
-
required: false,
|
|
801
|
-
maxLength: 100,
|
|
802
|
-
description: "Record id within source_object",
|
|
803
|
-
group: "Source"
|
|
804
|
-
}),
|
|
805
|
-
url: data.Field.url({
|
|
806
|
-
label: "Deep Link",
|
|
807
|
-
required: false,
|
|
808
|
-
description: "Optional URL to navigate to when clicked",
|
|
809
|
-
group: "Source"
|
|
810
|
-
}),
|
|
811
|
-
actor_id: data.Field.lookup("sys_user", {
|
|
812
|
-
label: "Actor",
|
|
813
|
-
required: false,
|
|
814
|
-
description: "User who caused the notification (mentioner, assigner)",
|
|
815
|
-
group: "Source"
|
|
816
|
-
}),
|
|
817
|
-
actor_name: data.Field.text({
|
|
818
|
-
label: "Actor Name",
|
|
819
|
-
required: false,
|
|
820
|
-
group: "Source"
|
|
821
|
-
}),
|
|
822
|
-
// ── Read state ───────────────────────────────────────────────
|
|
823
|
-
is_read: data.Field.boolean({
|
|
824
|
-
label: "Read",
|
|
825
|
-
defaultValue: false,
|
|
826
|
-
description: "True once recipient acknowledges",
|
|
827
|
-
group: "State"
|
|
828
|
-
}),
|
|
829
|
-
read_at: data.Field.datetime({
|
|
830
|
-
label: "Read At",
|
|
831
|
-
required: false,
|
|
832
|
-
group: "State"
|
|
833
|
-
}),
|
|
834
|
-
// ── Lifecycle ────────────────────────────────────────────────
|
|
835
|
-
created_at: data.Field.datetime({
|
|
836
|
-
label: "Created At",
|
|
837
|
-
required: true,
|
|
838
|
-
defaultValue: "NOW()",
|
|
839
|
-
readonly: true,
|
|
840
|
-
group: "System"
|
|
841
|
-
}),
|
|
842
|
-
updated_at: data.Field.datetime({
|
|
843
|
-
label: "Updated At",
|
|
844
|
-
required: false,
|
|
845
|
-
group: "System"
|
|
846
|
-
})
|
|
847
|
-
},
|
|
848
|
-
indexes: [
|
|
849
|
-
{ fields: ["recipient_id", "is_read", "created_at"] },
|
|
850
|
-
{ fields: ["recipient_id", "created_at"] },
|
|
851
|
-
{ fields: ["source_object", "source_id"] }
|
|
852
|
-
]
|
|
853
|
-
});
|
|
854
232
|
var SysEmail = data.ObjectSchema.create({
|
|
855
233
|
name: "sys_email",
|
|
856
234
|
label: "Email",
|
|
@@ -1353,377 +731,6 @@ var SysReportSchedule = data.ObjectSchema.create({
|
|
|
1353
731
|
{ fields: ["owner_id"] }
|
|
1354
732
|
]
|
|
1355
733
|
});
|
|
1356
|
-
var SysApprovalProcess = data.ObjectSchema.create({
|
|
1357
|
-
name: "sys_approval_process",
|
|
1358
|
-
label: "Approval Process",
|
|
1359
|
-
pluralLabel: "Approval Processes",
|
|
1360
|
-
icon: "check-square",
|
|
1361
|
-
isSystem: true,
|
|
1362
|
-
managedBy: "config",
|
|
1363
|
-
// Authoring an approval process requires a visual step designer that
|
|
1364
|
-
// doesn't yet exist — the embedded `definition_json` textarea would
|
|
1365
|
-
// force admins to hand-write a multi-page ApprovalProcess envelope.
|
|
1366
|
-
// Suppress generic CRUD until the designer lands. Real authoring path:
|
|
1367
|
-
// call `defineApprovalProcess({...})` in code and seed via the
|
|
1368
|
-
// approvals service (`POST /api/v1/approvals/processes`) or commit the
|
|
1369
|
-
// definition as a fixture. Editing existing rows (e.g. toggling
|
|
1370
|
-
// `active`) is also suppressed for now because the same textarea would
|
|
1371
|
-
// appear; use the service API or a future designer instead.
|
|
1372
|
-
userActions: { create: false, edit: false, delete: false, import: false },
|
|
1373
|
-
description: "Persisted approval process definition. Authored via defineApprovalProcess() in code; visual designer is on the roadmap.",
|
|
1374
|
-
displayNameField: "name",
|
|
1375
|
-
titleFormat: "{label}",
|
|
1376
|
-
compactLayout: ["name", "object_name", "active", "updated_at"],
|
|
1377
|
-
listViews: {
|
|
1378
|
-
active: {
|
|
1379
|
-
type: "grid",
|
|
1380
|
-
name: "active",
|
|
1381
|
-
label: "Active",
|
|
1382
|
-
data: { provider: "object", object: "sys_approval_process" },
|
|
1383
|
-
columns: ["label", "object_name", "active", "updated_at"],
|
|
1384
|
-
filter: [{ field: "active", operator: "equals", value: true }],
|
|
1385
|
-
sort: [{ field: "label", order: "asc" }],
|
|
1386
|
-
pagination: { pageSize: 50 }
|
|
1387
|
-
},
|
|
1388
|
-
inactive: {
|
|
1389
|
-
type: "grid",
|
|
1390
|
-
name: "inactive",
|
|
1391
|
-
label: "Inactive",
|
|
1392
|
-
data: { provider: "object", object: "sys_approval_process" },
|
|
1393
|
-
columns: ["label", "object_name", "active", "updated_at"],
|
|
1394
|
-
filter: [{ field: "active", operator: "equals", value: false }],
|
|
1395
|
-
sort: [{ field: "label", order: "asc" }],
|
|
1396
|
-
pagination: { pageSize: 50 }
|
|
1397
|
-
},
|
|
1398
|
-
by_object: {
|
|
1399
|
-
type: "grid",
|
|
1400
|
-
name: "by_object",
|
|
1401
|
-
label: "By Object",
|
|
1402
|
-
data: { provider: "object", object: "sys_approval_process" },
|
|
1403
|
-
columns: ["object_name", "label", "active", "updated_at"],
|
|
1404
|
-
sort: [{ field: "object_name", order: "asc" }, { field: "label", order: "asc" }],
|
|
1405
|
-
grouping: { fields: [{ field: "object_name", order: "asc", collapsed: false }] },
|
|
1406
|
-
pagination: { pageSize: 100 }
|
|
1407
|
-
},
|
|
1408
|
-
all_processes: {
|
|
1409
|
-
type: "grid",
|
|
1410
|
-
name: "all_processes",
|
|
1411
|
-
label: "All",
|
|
1412
|
-
data: { provider: "object", object: "sys_approval_process" },
|
|
1413
|
-
columns: ["label", "object_name", "active", "updated_at"],
|
|
1414
|
-
sort: [{ field: "label", order: "asc" }],
|
|
1415
|
-
pagination: { pageSize: 50 }
|
|
1416
|
-
}
|
|
1417
|
-
},
|
|
1418
|
-
fields: {
|
|
1419
|
-
id: data.Field.text({ label: "Process ID", required: true, readonly: true, group: "System" }),
|
|
1420
|
-
name: data.Field.text({
|
|
1421
|
-
label: "Name",
|
|
1422
|
-
required: true,
|
|
1423
|
-
maxLength: 100,
|
|
1424
|
-
description: "Unique snake_case name \u2014 referenced by submitters and audit rows",
|
|
1425
|
-
group: "Definition"
|
|
1426
|
-
}),
|
|
1427
|
-
label: data.Field.text({
|
|
1428
|
-
label: "Display Label",
|
|
1429
|
-
required: true,
|
|
1430
|
-
maxLength: 200,
|
|
1431
|
-
group: "Definition"
|
|
1432
|
-
}),
|
|
1433
|
-
object_name: data.Field.text({
|
|
1434
|
-
label: "Object",
|
|
1435
|
-
required: true,
|
|
1436
|
-
maxLength: 100,
|
|
1437
|
-
description: "Short object name this process governs",
|
|
1438
|
-
group: "Definition"
|
|
1439
|
-
}),
|
|
1440
|
-
description: data.Field.textarea({ label: "Description", required: false, group: "Definition" }),
|
|
1441
|
-
active: data.Field.boolean({
|
|
1442
|
-
label: "Active",
|
|
1443
|
-
required: true,
|
|
1444
|
-
defaultValue: false,
|
|
1445
|
-
description: "Only active processes are dispatched on submission",
|
|
1446
|
-
group: "Definition"
|
|
1447
|
-
}),
|
|
1448
|
-
definition_json: data.Field.textarea({
|
|
1449
|
-
label: "Definition",
|
|
1450
|
-
required: true,
|
|
1451
|
-
description: "Serialised ApprovalProcess JSON (see @objectstack/spec/automation/approval)",
|
|
1452
|
-
group: "Definition"
|
|
1453
|
-
}),
|
|
1454
|
-
created_at: data.Field.datetime({
|
|
1455
|
-
label: "Created At",
|
|
1456
|
-
required: true,
|
|
1457
|
-
defaultValue: "NOW()",
|
|
1458
|
-
readonly: true,
|
|
1459
|
-
group: "System"
|
|
1460
|
-
}),
|
|
1461
|
-
updated_at: data.Field.datetime({ label: "Updated At", required: false, group: "System" })
|
|
1462
|
-
},
|
|
1463
|
-
indexes: [
|
|
1464
|
-
{ fields: ["name"], unique: true },
|
|
1465
|
-
{ fields: ["object_name"] },
|
|
1466
|
-
{ fields: ["active", "object_name"] }
|
|
1467
|
-
]
|
|
1468
|
-
});
|
|
1469
|
-
var SysApprovalRequest = data.ObjectSchema.create({
|
|
1470
|
-
name: "sys_approval_request",
|
|
1471
|
-
label: "Approval Request",
|
|
1472
|
-
pluralLabel: "Approval Requests",
|
|
1473
|
-
icon: "inbox",
|
|
1474
|
-
isSystem: true,
|
|
1475
|
-
managedBy: "system",
|
|
1476
|
-
description: "Live approval instance tracked per submission",
|
|
1477
|
-
displayNameField: "id",
|
|
1478
|
-
titleFormat: "{process_name} \xB7 {record_id}",
|
|
1479
|
-
compactLayout: ["process_name", "object_name", "record_id", "status", "current_step", "submitter_id", "updated_at"],
|
|
1480
|
-
// Curated built-in list views — render as segmented tabs in the console.
|
|
1481
|
-
// Filters use {current_user_id} substitution wired by the console.
|
|
1482
|
-
listViews: {
|
|
1483
|
-
my_pending: {
|
|
1484
|
-
type: "grid",
|
|
1485
|
-
name: "my_pending",
|
|
1486
|
-
label: "My Pending",
|
|
1487
|
-
data: { provider: "object", object: "sys_approval_request" },
|
|
1488
|
-
columns: ["process_name", "object_name", "record_id", "current_step", "submitter_id", "updated_at"],
|
|
1489
|
-
filter: [
|
|
1490
|
-
{ field: "status", operator: "equals", value: "pending" },
|
|
1491
|
-
{ field: "pending_approvers", operator: "contains", value: "{current_user_id}" }
|
|
1492
|
-
],
|
|
1493
|
-
sort: [{ field: "updated_at", order: "desc" }],
|
|
1494
|
-
pagination: { pageSize: 25 },
|
|
1495
|
-
emptyState: { title: "No pending approvals", message: "You're all caught up." }
|
|
1496
|
-
},
|
|
1497
|
-
submitted_by_me: {
|
|
1498
|
-
type: "grid",
|
|
1499
|
-
name: "submitted_by_me",
|
|
1500
|
-
label: "I Submitted",
|
|
1501
|
-
data: { provider: "object", object: "sys_approval_request" },
|
|
1502
|
-
columns: ["process_name", "object_name", "record_id", "status", "current_step", "updated_at"],
|
|
1503
|
-
filter: [{ field: "submitter_id", operator: "equals", value: "{current_user_id}" }],
|
|
1504
|
-
sort: [{ field: "updated_at", order: "desc" }],
|
|
1505
|
-
pagination: { pageSize: 25 }
|
|
1506
|
-
},
|
|
1507
|
-
completed: {
|
|
1508
|
-
type: "grid",
|
|
1509
|
-
name: "completed",
|
|
1510
|
-
label: "Completed",
|
|
1511
|
-
data: { provider: "object", object: "sys_approval_request" },
|
|
1512
|
-
columns: ["process_name", "object_name", "record_id", "status", "submitter_id", "completed_at"],
|
|
1513
|
-
filter: [{ field: "status", operator: "in", value: ["approved", "rejected", "recalled"] }],
|
|
1514
|
-
sort: [{ field: "completed_at", order: "desc" }],
|
|
1515
|
-
pagination: { pageSize: 25 }
|
|
1516
|
-
},
|
|
1517
|
-
all_requests: {
|
|
1518
|
-
type: "grid",
|
|
1519
|
-
name: "all_requests",
|
|
1520
|
-
label: "All",
|
|
1521
|
-
data: { provider: "object", object: "sys_approval_request" },
|
|
1522
|
-
columns: ["process_name", "object_name", "record_id", "status", "current_step", "submitter_id", "updated_at"],
|
|
1523
|
-
sort: [{ field: "updated_at", order: "desc" }],
|
|
1524
|
-
pagination: { pageSize: 50 }
|
|
1525
|
-
}
|
|
1526
|
-
},
|
|
1527
|
-
fields: {
|
|
1528
|
-
id: data.Field.text({ label: "Request ID", required: true, readonly: true, group: "System" }),
|
|
1529
|
-
organization_id: data.Field.lookup("sys_organization", {
|
|
1530
|
-
label: "Organization",
|
|
1531
|
-
required: false,
|
|
1532
|
-
group: "System",
|
|
1533
|
-
description: "Tenant that owns this approval request (propagated from submitter context)"
|
|
1534
|
-
}),
|
|
1535
|
-
process_name: data.Field.text({
|
|
1536
|
-
label: "Process",
|
|
1537
|
-
required: true,
|
|
1538
|
-
maxLength: 100,
|
|
1539
|
-
description: "sys_approval_process.name this request was opened against",
|
|
1540
|
-
group: "Target"
|
|
1541
|
-
}),
|
|
1542
|
-
object_name: data.Field.text({
|
|
1543
|
-
label: "Object",
|
|
1544
|
-
required: true,
|
|
1545
|
-
maxLength: 100,
|
|
1546
|
-
group: "Target"
|
|
1547
|
-
}),
|
|
1548
|
-
record_id: data.Field.text({
|
|
1549
|
-
label: "Record ID",
|
|
1550
|
-
required: true,
|
|
1551
|
-
maxLength: 100,
|
|
1552
|
-
group: "Target"
|
|
1553
|
-
}),
|
|
1554
|
-
submitter_id: data.Field.lookup("sys_user", {
|
|
1555
|
-
label: "Submitter",
|
|
1556
|
-
required: false,
|
|
1557
|
-
group: "Target"
|
|
1558
|
-
}),
|
|
1559
|
-
submitter_comment: data.Field.textarea({
|
|
1560
|
-
label: "Submitter Comment",
|
|
1561
|
-
required: false,
|
|
1562
|
-
group: "Target"
|
|
1563
|
-
}),
|
|
1564
|
-
status: data.Field.select(
|
|
1565
|
-
["pending", "approved", "rejected", "recalled"],
|
|
1566
|
-
{
|
|
1567
|
-
label: "Status",
|
|
1568
|
-
required: true,
|
|
1569
|
-
defaultValue: "pending",
|
|
1570
|
-
description: "Lifecycle state of the request",
|
|
1571
|
-
group: "State"
|
|
1572
|
-
}
|
|
1573
|
-
),
|
|
1574
|
-
current_step: data.Field.text({
|
|
1575
|
-
label: "Current Step",
|
|
1576
|
-
required: false,
|
|
1577
|
-
maxLength: 100,
|
|
1578
|
-
description: "Machine name of the step awaiting approval",
|
|
1579
|
-
group: "State"
|
|
1580
|
-
}),
|
|
1581
|
-
current_step_index: data.Field.number({
|
|
1582
|
-
label: "Current Step Index",
|
|
1583
|
-
required: false,
|
|
1584
|
-
defaultValue: 0,
|
|
1585
|
-
group: "State"
|
|
1586
|
-
}),
|
|
1587
|
-
pending_approvers: data.Field.textarea({
|
|
1588
|
-
label: "Pending Approvers",
|
|
1589
|
-
required: false,
|
|
1590
|
-
description: "Comma-separated user ids who can act on the current step",
|
|
1591
|
-
group: "State"
|
|
1592
|
-
}),
|
|
1593
|
-
payload_json: data.Field.textarea({
|
|
1594
|
-
label: "Snapshot",
|
|
1595
|
-
required: false,
|
|
1596
|
-
description: "Record snapshot at submission time",
|
|
1597
|
-
group: "State"
|
|
1598
|
-
}),
|
|
1599
|
-
process_hash: data.Field.text({
|
|
1600
|
-
label: "Process Hash",
|
|
1601
|
-
required: false,
|
|
1602
|
-
maxLength: 80,
|
|
1603
|
-
readonly: true,
|
|
1604
|
-
description: "sha256 of the approval process body at submit time (ADR-0009 execution pinning). Resolved through sys_metadata_history so process upgrades do not affect in-flight requests.",
|
|
1605
|
-
group: "State"
|
|
1606
|
-
}),
|
|
1607
|
-
completed_at: data.Field.datetime({
|
|
1608
|
-
label: "Completed At",
|
|
1609
|
-
required: false,
|
|
1610
|
-
group: "State"
|
|
1611
|
-
}),
|
|
1612
|
-
created_at: data.Field.datetime({
|
|
1613
|
-
label: "Created At",
|
|
1614
|
-
required: true,
|
|
1615
|
-
defaultValue: "NOW()",
|
|
1616
|
-
readonly: true,
|
|
1617
|
-
group: "System"
|
|
1618
|
-
}),
|
|
1619
|
-
updated_at: data.Field.datetime({ label: "Updated At", required: false, group: "System" })
|
|
1620
|
-
},
|
|
1621
|
-
indexes: [
|
|
1622
|
-
// Look up "is there a pending request for this record?" — common
|
|
1623
|
-
// guard on submit and on edit-while-locked checks.
|
|
1624
|
-
{ fields: ["object_name", "record_id"] },
|
|
1625
|
-
{ fields: ["status", "object_name"] },
|
|
1626
|
-
// "My approvals" inbox — pending_approvers is a CSV string so this
|
|
1627
|
-
// index only helps with status pre-filtering; the engine does a
|
|
1628
|
-
// post-filter substring match per row.
|
|
1629
|
-
{ fields: ["status", "updated_at"] },
|
|
1630
|
-
{ fields: ["submitter_id", "status"] }
|
|
1631
|
-
]
|
|
1632
|
-
});
|
|
1633
|
-
var SysApprovalAction = data.ObjectSchema.create({
|
|
1634
|
-
name: "sys_approval_action",
|
|
1635
|
-
label: "Approval Action",
|
|
1636
|
-
pluralLabel: "Approval Actions",
|
|
1637
|
-
icon: "check-circle",
|
|
1638
|
-
isSystem: true,
|
|
1639
|
-
managedBy: "append-only",
|
|
1640
|
-
description: "Append-only audit trail for approval actions",
|
|
1641
|
-
displayNameField: "id",
|
|
1642
|
-
titleFormat: "{action} \xB7 {step_name}",
|
|
1643
|
-
compactLayout: ["request_id", "step_name", "action", "actor_id", "created_at"],
|
|
1644
|
-
listViews: {
|
|
1645
|
-
recent: {
|
|
1646
|
-
type: "grid",
|
|
1647
|
-
name: "recent",
|
|
1648
|
-
label: "Recent",
|
|
1649
|
-
data: { provider: "object", object: "sys_approval_action" },
|
|
1650
|
-
columns: ["created_at", "request_id", "step_name", "action", "actor_id", "comment"],
|
|
1651
|
-
sort: [{ field: "created_at", order: "desc" }],
|
|
1652
|
-
pagination: { pageSize: 50 },
|
|
1653
|
-
emptyState: { title: "No approval actions yet", message: "Actions are logged automatically when approvals progress." }
|
|
1654
|
-
},
|
|
1655
|
-
by_actor: {
|
|
1656
|
-
type: "grid",
|
|
1657
|
-
name: "by_actor",
|
|
1658
|
-
label: "By Actor",
|
|
1659
|
-
data: { provider: "object", object: "sys_approval_action" },
|
|
1660
|
-
columns: ["actor_id", "created_at", "request_id", "step_name", "action"],
|
|
1661
|
-
sort: [{ field: "actor_id", order: "asc" }, { field: "created_at", order: "desc" }],
|
|
1662
|
-
grouping: { fields: [{ field: "actor_id", order: "asc", collapsed: false }] },
|
|
1663
|
-
pagination: { pageSize: 100 }
|
|
1664
|
-
},
|
|
1665
|
-
all_actions: {
|
|
1666
|
-
type: "grid",
|
|
1667
|
-
name: "all_actions",
|
|
1668
|
-
label: "All",
|
|
1669
|
-
data: { provider: "object", object: "sys_approval_action" },
|
|
1670
|
-
columns: ["created_at", "request_id", "step_name", "action", "actor_id", "comment"],
|
|
1671
|
-
sort: [{ field: "created_at", order: "desc" }],
|
|
1672
|
-
pagination: { pageSize: 100 }
|
|
1673
|
-
}
|
|
1674
|
-
},
|
|
1675
|
-
fields: {
|
|
1676
|
-
id: data.Field.text({ label: "Action ID", required: true, readonly: true, group: "System" }),
|
|
1677
|
-
organization_id: data.Field.lookup("sys_organization", {
|
|
1678
|
-
label: "Organization",
|
|
1679
|
-
required: false,
|
|
1680
|
-
group: "System",
|
|
1681
|
-
description: "Tenant that owns this action (mirrors the parent request)"
|
|
1682
|
-
}),
|
|
1683
|
-
request_id: data.Field.lookup("sys_approval_request", {
|
|
1684
|
-
label: "Request",
|
|
1685
|
-
required: true,
|
|
1686
|
-
group: "Target"
|
|
1687
|
-
}),
|
|
1688
|
-
step_name: data.Field.text({
|
|
1689
|
-
label: "Step",
|
|
1690
|
-
required: false,
|
|
1691
|
-
maxLength: 100,
|
|
1692
|
-
description: "Machine name of the step at the time of the action",
|
|
1693
|
-
group: "Target"
|
|
1694
|
-
}),
|
|
1695
|
-
step_index: data.Field.number({
|
|
1696
|
-
label: "Step Index",
|
|
1697
|
-
required: false,
|
|
1698
|
-
group: "Target"
|
|
1699
|
-
}),
|
|
1700
|
-
action: data.Field.select(
|
|
1701
|
-
["submit", "approve", "reject", "recall", "escalate"],
|
|
1702
|
-
{
|
|
1703
|
-
label: "Action",
|
|
1704
|
-
required: true,
|
|
1705
|
-
group: "Action"
|
|
1706
|
-
}
|
|
1707
|
-
),
|
|
1708
|
-
actor_id: data.Field.lookup("sys_user", {
|
|
1709
|
-
label: "Actor",
|
|
1710
|
-
required: false,
|
|
1711
|
-
group: "Action"
|
|
1712
|
-
}),
|
|
1713
|
-
comment: data.Field.textarea({ label: "Comment", required: false, group: "Action" }),
|
|
1714
|
-
created_at: data.Field.datetime({
|
|
1715
|
-
label: "Created At",
|
|
1716
|
-
required: true,
|
|
1717
|
-
defaultValue: "NOW()",
|
|
1718
|
-
readonly: true,
|
|
1719
|
-
group: "System"
|
|
1720
|
-
})
|
|
1721
|
-
},
|
|
1722
|
-
indexes: [
|
|
1723
|
-
{ fields: ["request_id", "created_at"] },
|
|
1724
|
-
{ fields: ["request_id", "step_index", "action"] }
|
|
1725
|
-
]
|
|
1726
|
-
});
|
|
1727
734
|
var SysJob = data.ObjectSchema.create({
|
|
1728
735
|
name: "sys_job",
|
|
1729
736
|
label: "Background Job",
|
|
@@ -1955,20 +962,13 @@ var SysJobQueue = data.ObjectSchema.create({
|
|
|
1955
962
|
]
|
|
1956
963
|
});
|
|
1957
964
|
|
|
1958
|
-
exports.SysActivity = SysActivity;
|
|
1959
|
-
exports.SysApprovalAction = SysApprovalAction;
|
|
1960
|
-
exports.SysApprovalProcess = SysApprovalProcess;
|
|
1961
|
-
exports.SysApprovalRequest = SysApprovalRequest;
|
|
1962
965
|
exports.SysAttachment = SysAttachment;
|
|
1963
|
-
exports.SysAuditLog = SysAuditLog;
|
|
1964
|
-
exports.SysComment = SysComment;
|
|
1965
966
|
exports.SysEmail = SysEmail;
|
|
1966
967
|
exports.SysEmailTemplate = SysEmailTemplate;
|
|
1967
968
|
exports.SysJob = SysJob;
|
|
1968
969
|
exports.SysJobQueue = SysJobQueue;
|
|
1969
970
|
exports.SysJobRun = SysJobRun;
|
|
1970
971
|
exports.SysNotification = SysNotification;
|
|
1971
|
-
exports.SysPresence = SysPresence;
|
|
1972
972
|
exports.SysReportSchedule = SysReportSchedule;
|
|
1973
973
|
exports.SysSavedReport = SysSavedReport;
|
|
1974
974
|
//# sourceMappingURL=index.js.map
|