@tellescope/sdk 1.255.7 → 1.255.8
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/lib/cjs/sdk.d.ts +2 -2
- package/lib/cjs/session.d.ts +1 -0
- package/lib/cjs/session.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/custom_dashboards.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/custom_dashboards.test.js +258 -32
- package/lib/cjs/tests/api_tests/custom_dashboards.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/gmail_sync_related_contact_emails.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/gmail_sync_related_contact_emails.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/gmail_sync_related_contact_emails.test.js +183 -0
- package/lib/cjs/tests/api_tests/gmail_sync_related_contact_emails.test.js.map +1 -0
- package/lib/cjs/tests/tests.js +54 -54
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/esm/tests/api_tests/gmail_sync_related_contact_emails.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/gmail_sync_related_contact_emails.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/gmail_sync_related_contact_emails.test.js +179 -0
- package/lib/esm/tests/api_tests/gmail_sync_related_contact_emails.test.js.map +1 -0
- package/lib/esm/tests/api_tests/medication_added_trigger.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/medication_added_trigger.test.js +136 -206
- package/lib/esm/tests/api_tests/medication_added_trigger.test.js.map +1 -1
- package/lib/esm/tests/api_tests/security/F-0005-ai-conversations-rbac.test.d.ts +0 -10
- package/lib/esm/tests/api_tests/security/F-0005-ai-conversations-rbac.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/security/F-0005-ai-conversations-rbac.test.js +41 -184
- package/lib/esm/tests/api_tests/security/F-0005-ai-conversations-rbac.test.js.map +1 -1
- package/lib/esm/tests/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +165 -177
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/tests/api_tests/custom_dashboards.test.ts +208 -0
- package/src/tests/tests.ts +1 -1
- package/test_generated.pdf +0 -0
|
@@ -4,6 +4,7 @@ import { Session } from "../../sdk"
|
|
|
4
4
|
import {
|
|
5
5
|
async_test,
|
|
6
6
|
log_header,
|
|
7
|
+
wait,
|
|
7
8
|
} from "@tellescope/testing"
|
|
8
9
|
import { setup_tests } from "../setup"
|
|
9
10
|
|
|
@@ -199,6 +200,56 @@ export const custom_dashboards_tests = async ({ sdk, sdkNonAdmin }: { sdk: Sessi
|
|
|
199
200
|
}
|
|
200
201
|
)
|
|
201
202
|
|
|
203
|
+
// Test 6b: Create dashboard with every built-in block type (legacy renderer set)
|
|
204
|
+
const dashboardWithBuiltInTypes = await sdk.api.custom_dashboards.createOne({
|
|
205
|
+
title: "Built-In Block Types Dashboard",
|
|
206
|
+
blocks: [
|
|
207
|
+
{ type: "Inbox" },
|
|
208
|
+
{ type: "Tickets" },
|
|
209
|
+
{ type: "Team Chats" },
|
|
210
|
+
{ type: "Upcoming Events" },
|
|
211
|
+
{ type: "To-Dos" },
|
|
212
|
+
{ type: "Database", info: { databaseId: "60398b0231a295e64f084fd9" } },
|
|
213
|
+
],
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
await async_test(
|
|
217
|
+
"Dashboard with all built-in block types created correctly",
|
|
218
|
+
async () => dashboardWithBuiltInTypes,
|
|
219
|
+
{
|
|
220
|
+
onResult: r => (
|
|
221
|
+
r.blocks.length === 6
|
|
222
|
+
&& r.blocks[0].type === "Inbox"
|
|
223
|
+
&& r.blocks[1].type === "Tickets"
|
|
224
|
+
&& r.blocks[2].type === "Team Chats"
|
|
225
|
+
&& r.blocks[3].type === "Upcoming Events"
|
|
226
|
+
&& r.blocks[4].type === "To-Dos"
|
|
227
|
+
&& r.blocks[5].type === "Database"
|
|
228
|
+
&& r.blocks[5].info !== undefined && r.blocks[5].info.databaseId === "60398b0231a295e64f084fd9"
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
// Test 6c: Unknown top-level block fields are stripped on save (params belong in info)
|
|
234
|
+
const dashboardWithUnknownBlockField = await sdk.api.custom_dashboards.createOne({
|
|
235
|
+
title: "Unknown Block Field Dashboard",
|
|
236
|
+
blocks: [
|
|
237
|
+
{ type: "Inbox", customTopLevel: "x", info: { kept: true } } as any,
|
|
238
|
+
],
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
await async_test(
|
|
242
|
+
"Unknown top-level block fields stripped, info preserved",
|
|
243
|
+
async () => dashboardWithUnknownBlockField,
|
|
244
|
+
{
|
|
245
|
+
onResult: r => (
|
|
246
|
+
r.blocks.length === 1
|
|
247
|
+
&& (r.blocks[0] as any).customTopLevel === undefined
|
|
248
|
+
&& r.blocks[0].info !== undefined && r.blocks[0].info.kept === true
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
)
|
|
252
|
+
|
|
202
253
|
// Test 7: Update gridConfig only
|
|
203
254
|
const updatedGridConfig = await sdk.api.custom_dashboards.updateOne(dashboardWithNewTypes.id, {
|
|
204
255
|
gridConfig: { columns: 24, gap: 8 },
|
|
@@ -215,6 +266,67 @@ export const custom_dashboards_tests = async ({ sdk, sdkNonAdmin }: { sdk: Sessi
|
|
|
215
266
|
}
|
|
216
267
|
)
|
|
217
268
|
|
|
269
|
+
// Test 7b: Create dashboard with top-level type field
|
|
270
|
+
const typedDashboard = await sdk.api.custom_dashboards.createOne({
|
|
271
|
+
title: "Typed Dashboard",
|
|
272
|
+
type: "home",
|
|
273
|
+
blocks: [{ type: "Inbox", colSpan: 12 }],
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
await async_test(
|
|
277
|
+
"Dashboard with top-level type created correctly",
|
|
278
|
+
async () => typedDashboard,
|
|
279
|
+
{ onResult: r => r.type === "home" }
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
// Test 7c: Dashboards without type still work (backwards compatibility)
|
|
283
|
+
await async_test(
|
|
284
|
+
"Dashboard without type has undefined type",
|
|
285
|
+
async () => sdk.api.custom_dashboards.getOne(basicDashboard.id),
|
|
286
|
+
{ onResult: r => r.type === undefined }
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
// Test 7d: Update top-level type
|
|
290
|
+
const updatedType = await sdk.api.custom_dashboards.updateOne(typedDashboard.id, {
|
|
291
|
+
type: "clinical",
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
await async_test(
|
|
295
|
+
"Dashboard type updated correctly",
|
|
296
|
+
async () => updatedType,
|
|
297
|
+
{ onResult: r => r.type === "clinical" }
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
// Test 7e: Filter dashboards by type
|
|
301
|
+
const secondTypedDashboard = await sdk.api.custom_dashboards.createOne({
|
|
302
|
+
title: "Second Typed Dashboard",
|
|
303
|
+
type: "clinical",
|
|
304
|
+
blocks: [{ type: "Tickets", colSpan: 12 }],
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
await async_test(
|
|
308
|
+
"Dashboards filtered by type via filter",
|
|
309
|
+
async () => sdk.api.custom_dashboards.getSome({ filter: { type: "clinical" } }),
|
|
310
|
+
{
|
|
311
|
+
onResult: r => (
|
|
312
|
+
r.length === 2
|
|
313
|
+
&& r.every(d => d.type === "clinical")
|
|
314
|
+
)
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
// Test 7f: Filter dashboards by type via mdbFilter
|
|
319
|
+
await async_test(
|
|
320
|
+
"Dashboards filtered by type via mdbFilter",
|
|
321
|
+
async () => sdk.api.custom_dashboards.getSome({ mdbFilter: { type: "clinical" } }),
|
|
322
|
+
{
|
|
323
|
+
onResult: r => (
|
|
324
|
+
r.length === 2
|
|
325
|
+
&& r.every(d => d.type === "clinical")
|
|
326
|
+
)
|
|
327
|
+
}
|
|
328
|
+
)
|
|
329
|
+
|
|
218
330
|
// Test 8: Non-admin can read all dashboards by default
|
|
219
331
|
const nonAdminList = await sdkNonAdmin.api.custom_dashboards.getSome({ filter: {} })
|
|
220
332
|
|
|
@@ -224,14 +336,110 @@ export const custom_dashboards_tests = async ({ sdk, sdkNonAdmin }: { sdk: Sessi
|
|
|
224
336
|
{ onResult: r => r.length >= 2 }
|
|
225
337
|
)
|
|
226
338
|
|
|
339
|
+
// Test 9: visibleToAllUsers grants org-wide access to users without full read access
|
|
340
|
+
const restrictedRole = await sdk.api.role_based_access_permissions.createOne({
|
|
341
|
+
role: 'Dashboard Default Access',
|
|
342
|
+
permissions: {
|
|
343
|
+
custom_dashboards: { read: 'Default', create: null, update: null, delete: null },
|
|
344
|
+
},
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
const restrictedUserEmail = 'dashboard.restricted.test@tellescope.com'
|
|
348
|
+
let restrictedUser = await sdk.api.users.getOne({ email: restrictedUserEmail }).catch(() => null) // throws error on none found
|
|
349
|
+
if (restrictedUser && !restrictedUser.verifiedEmail) { // verifiedEmail can only be set on create, so recreate stale users
|
|
350
|
+
await sdk.api.users.deleteOne(restrictedUser.id)
|
|
351
|
+
restrictedUser = null
|
|
352
|
+
}
|
|
353
|
+
if (!restrictedUser) {
|
|
354
|
+
restrictedUser = await sdk.api.users.createOne({ email: restrictedUserEmail, notificationEmailsDisabled: true, verifiedEmail: true })
|
|
355
|
+
}
|
|
356
|
+
// ensure role is set, in case GET returned a user without a role or with a different role
|
|
357
|
+
await sdk.api.users.updateOne(restrictedUser.id, { roles: [restrictedRole.role] }, { replaceObjectFields: true })
|
|
358
|
+
await wait(undefined, 2000) // role change triggers a logout
|
|
359
|
+
|
|
360
|
+
const sdkRestricted = new Session({
|
|
361
|
+
host,
|
|
362
|
+
authToken: (await sdk.api.users.generate_auth_token({ id: restrictedUser.id })).authToken,
|
|
363
|
+
})
|
|
364
|
+
await async_test('test_authenticated (restricted dashboard user)', sdkRestricted.test_authenticated, { expectedResult: 'Authenticated!' })
|
|
365
|
+
|
|
366
|
+
const hiddenDashboard = await sdk.api.custom_dashboards.createOne({
|
|
367
|
+
title: "Hidden From Restricted",
|
|
368
|
+
blocks: [{ type: "Inbox", colSpan: 12 }],
|
|
369
|
+
})
|
|
370
|
+
const orgWideDashboard = await sdk.api.custom_dashboards.createOne({
|
|
371
|
+
title: "Org-Wide Dashboard",
|
|
372
|
+
visibleToAllUsers: true,
|
|
373
|
+
blocks: [{ type: "Inbox", colSpan: 12 }],
|
|
374
|
+
})
|
|
375
|
+
const explicitFalseDashboard = await sdk.api.custom_dashboards.createOne({
|
|
376
|
+
title: "Explicit False Dashboard",
|
|
377
|
+
visibleToAllUsers: false,
|
|
378
|
+
blocks: [{ type: "Inbox", colSpan: 12 }],
|
|
379
|
+
})
|
|
380
|
+
const assignedDashboard = await sdk.api.custom_dashboards.createOne({
|
|
381
|
+
title: "Assigned To Restricted",
|
|
382
|
+
userIds: [restrictedUser.id],
|
|
383
|
+
blocks: [{ type: "Inbox", colSpan: 12 }],
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
await async_test(
|
|
387
|
+
"Restricted user sees org-wide and assigned dashboards only",
|
|
388
|
+
() => sdkRestricted.api.custom_dashboards.getSome({ filter: {} }),
|
|
389
|
+
{
|
|
390
|
+
onResult: r => (
|
|
391
|
+
!!r.find(d => d.id === orgWideDashboard.id)
|
|
392
|
+
&& !!r.find(d => d.id === assignedDashboard.id)
|
|
393
|
+
&& !r.find(d => d.id === hiddenDashboard.id)
|
|
394
|
+
&& !r.find(d => d.id === explicitFalseDashboard.id)
|
|
395
|
+
)
|
|
396
|
+
}
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
await async_test(
|
|
400
|
+
"Restricted user can read org-wide dashboard by id",
|
|
401
|
+
() => sdkRestricted.api.custom_dashboards.getOne(orgWideDashboard.id),
|
|
402
|
+
{ onResult: r => r.id === orgWideDashboard.id && r.visibleToAllUsers === true }
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
await async_test(
|
|
406
|
+
"Restricted user cannot read unshared dashboard by id",
|
|
407
|
+
() => sdkRestricted.api.custom_dashboards.getOne(hiddenDashboard.id),
|
|
408
|
+
{ shouldError: true, onError: () => true }
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
// Toggling the flag on takes effect for the restricted user
|
|
412
|
+
await sdk.api.custom_dashboards.updateOne(hiddenDashboard.id, { visibleToAllUsers: true })
|
|
413
|
+
|
|
414
|
+
await async_test(
|
|
415
|
+
"Restricted user can read dashboard after visibleToAllUsers enabled",
|
|
416
|
+
() => sdkRestricted.api.custom_dashboards.getOne(hiddenDashboard.id),
|
|
417
|
+
{ onResult: r => r.id === hiddenDashboard.id }
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
// Admin continues to see everything, including unshared dashboards
|
|
421
|
+
await async_test(
|
|
422
|
+
"Admin still sees explicit-false dashboard",
|
|
423
|
+
() => sdk.api.custom_dashboards.getOne(explicitFalseDashboard.id),
|
|
424
|
+
{ onResult: r => r.id === explicitFalseDashboard.id }
|
|
425
|
+
)
|
|
426
|
+
|
|
227
427
|
// Cleanup
|
|
228
428
|
await Promise.all([
|
|
429
|
+
sdk.api.custom_dashboards.deleteOne(hiddenDashboard.id),
|
|
430
|
+
sdk.api.custom_dashboards.deleteOne(orgWideDashboard.id),
|
|
431
|
+
sdk.api.custom_dashboards.deleteOne(explicitFalseDashboard.id),
|
|
432
|
+
sdk.api.custom_dashboards.deleteOne(assignedDashboard.id),
|
|
229
433
|
sdk.api.custom_dashboards.deleteOne(basicDashboard.id),
|
|
230
434
|
sdk.api.custom_dashboards.deleteOne(duplicateTitleDashboard.id),
|
|
231
435
|
sdk.api.custom_dashboards.deleteOne(fullDashboard.id),
|
|
232
436
|
sdk.api.custom_dashboards.deleteOne(dashboardWithUserIds.id),
|
|
233
437
|
sdk.api.custom_dashboards.deleteOne(dashboardWithNewTypes.id),
|
|
234
438
|
sdk.api.custom_dashboards.deleteOne(dashboardWithComplexBlocks.id),
|
|
439
|
+
sdk.api.custom_dashboards.deleteOne(dashboardWithBuiltInTypes.id),
|
|
440
|
+
sdk.api.custom_dashboards.deleteOne(dashboardWithUnknownBlockField.id),
|
|
441
|
+
sdk.api.custom_dashboards.deleteOne(typedDashboard.id),
|
|
442
|
+
sdk.api.custom_dashboards.deleteOne(secondTypedDashboard.id),
|
|
235
443
|
])
|
|
236
444
|
}
|
|
237
445
|
|
package/src/tests/tests.ts
CHANGED
|
@@ -15038,6 +15038,7 @@ const ip_address_form_tests = async () => {
|
|
|
15038
15038
|
await replace_form_field_template_values_tests()
|
|
15039
15039
|
await mfa_tests()
|
|
15040
15040
|
await setup_tests(sdk, sdkNonAdmin)
|
|
15041
|
+
await custom_dashboards_tests({ sdk, sdkNonAdmin })
|
|
15041
15042
|
await register_business_id_injection_tests({ sdk, sdkNonAdmin })
|
|
15042
15043
|
await automation_trigger_tests()
|
|
15043
15044
|
await resource_access_tags_tests({ sdk, sdkNonAdmin })
|
|
@@ -15091,7 +15092,6 @@ const ip_address_form_tests = async () => {
|
|
|
15091
15092
|
await calendar_event_limits_tests({ sdk, sdkNonAdmin })
|
|
15092
15093
|
await get_some_projection_tests({ sdk, sdkNonAdmin })
|
|
15093
15094
|
await elation_user_id_tests({ sdk, sdkNonAdmin })
|
|
15094
|
-
await custom_dashboards_tests({ sdk, sdkNonAdmin })
|
|
15095
15095
|
await concurrent_build_threads_tests({ sdk, sdkNonAdmin })
|
|
15096
15096
|
await custom_aggregation_tests({ sdk, sdkNonAdmin })
|
|
15097
15097
|
await no_access_permission_checks_tests({ sdk, sdkNonAdmin })
|
package/test_generated.pdf
CHANGED
|
Binary file
|