Skip to content

Commit 4144899

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
refactor(integrations): use shared Oracle Fusion foundation
1 parent e7da78a commit 4144899

32 files changed

Lines changed: 1845 additions & 1157 deletions

apps/docs/components/ui/icon-mapping.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ import {
175175
OktaIcon,
176176
OnePasswordIcon,
177177
OpenAIIcon,
178+
OracleIcon,
178179
OutlookIcon,
179180
PackageSearchIcon,
180181
PagerDutyIcon,
@@ -480,7 +481,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
480481
onedrive: MicrosoftOneDriveIcon,
481482
onepassword: OnePasswordIcon,
482483
openai: OpenAIIcon,
483-
oracle_fusion_hcm: NetSuiteIcon,
484+
oracle_fusion_hcm: OracleIcon,
484485
outlook: OutlookIcon,
485486
pagerduty: PagerDutyIcon,
486487
parallel_ai: ParallelIcon,

apps/docs/content/docs/integrations/oracle_fusion_hcm.mdx

Lines changed: 40 additions & 61 deletions
Large diffs are not rendered by default.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import { describe, expect, it } from 'vitest'
5+
import { OracleIcon } from '@/components/icons'
6+
import { OracleFusionHcmBlock, OracleFusionHcmBlockMeta } from '@/blocks/blocks/oracle_fusion_hcm'
7+
import { AuthMode } from '@/blocks/types'
8+
9+
describe('OracleFusionHcmBlock', () => {
10+
const subBlock = (id: string) =>
11+
OracleFusionHcmBlock.subBlocks.find((candidate) => candidate.id === id)
12+
13+
it('uses one reusable service-account credential with a canonical manual fallback', () => {
14+
expect(OracleFusionHcmBlock.authMode).toBe(AuthMode.ApiKey)
15+
expect(OracleFusionHcmBlock.icon).toBe(OracleIcon)
16+
expect(subBlock('credential')).toMatchObject({
17+
type: 'oauth-input',
18+
serviceId: 'oracle_fusion_hcm',
19+
requiredScopes: [],
20+
credentialKind: 'service-account',
21+
canonicalParamId: 'oauthCredential',
22+
mode: 'basic',
23+
required: true,
24+
})
25+
expect(subBlock('manualCredential')).toMatchObject({
26+
type: 'short-input',
27+
canonicalParamId: 'oauthCredential',
28+
mode: 'advanced',
29+
required: true,
30+
})
31+
})
32+
33+
it('removes raw destination and username/password inputs', () => {
34+
const subBlockIds = OracleFusionHcmBlock.subBlocks.map((candidate) => candidate.id)
35+
expect(subBlockIds).not.toEqual(expect.arrayContaining(['tenantUrl', 'username', 'password']))
36+
expect(OracleFusionHcmBlock.inputs).toHaveProperty('oauthCredential')
37+
expect(OracleFusionHcmBlock.inputs).not.toHaveProperty('tenantUrl')
38+
expect(OracleFusionHcmBlock.inputs).not.toHaveProperty('username')
39+
expect(OracleFusionHcmBlock.inputs).not.toHaveProperty('password')
40+
})
41+
42+
it('keeps all 18 tools, four protected selectors, and shared cursor output wired', () => {
43+
expect(OracleFusionHcmBlock.tools.access).toHaveLength(18)
44+
expect(
45+
['personPicker', 'assignmentPicker', 'absencePicker', 'absenceTypePicker'].map((id) =>
46+
subBlock(id)
47+
)
48+
).toEqual([
49+
expect.objectContaining({ selectorKey: 'oracle_fusion_hcm.workers' }),
50+
expect.objectContaining({ selectorKey: 'oracle_fusion_hcm.assignments' }),
51+
expect.objectContaining({ selectorKey: 'oracle_fusion_hcm.absences' }),
52+
expect.objectContaining({ selectorKey: 'oracle_fusion_hcm.absenceTypes' }),
53+
])
54+
expect(OracleFusionHcmBlock.outputs).toHaveProperty('nextOffset')
55+
})
56+
57+
it('preserves all eight templates and seven skills with Oracle branding', () => {
58+
expect(OracleFusionHcmBlockMeta.templates).toHaveLength(8)
59+
expect(OracleFusionHcmBlockMeta.skills).toHaveLength(7)
60+
for (const template of OracleFusionHcmBlockMeta.templates) {
61+
expect(template.icon).toBe(OracleIcon)
62+
}
63+
})
64+
})

apps/sim/blocks/blocks/oracle_fusion_hcm.ts

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { NetSuiteIcon } from '@/components/icons'
1+
import { OracleIcon } from '@/components/icons'
2+
import { getScopesForService } from '@/lib/oauth/utils'
23
import type { BlockConfig, BlockMeta } from '@/blocks/types'
34
import { AuthMode, IntegrationType } from '@/blocks/types'
45

@@ -62,13 +63,13 @@ export const OracleFusionHcmBlock: BlockConfig = {
6263
name: 'Oracle Fusion Cloud HCM',
6364
description: 'Read workers, absences, reporting lines, and workforce structures',
6465
longDescription:
65-
'Connect to Oracle Fusion Cloud HCM with a least-privilege Basic-auth account. Read public worker profiles, assignments, reporting relationships, absences, absence types, and workforce structures without exposing write operations or sensitive HR fields.',
66+
'Connect to Oracle Fusion Cloud HCM with a reusable, least-privilege integration-user credential. Read public worker profiles, assignments, reporting relationships, absences, absence types, and workforce structures without exposing write operations, raw credentials, or sensitive HR fields.',
6667
docsLink: 'https://docs.sim.ai/integrations/oracle_fusion_hcm',
6768
category: 'tools',
6869
integrationType: IntegrationType.HR,
6970
authMode: AuthMode.ApiKey,
7071
bgColor: '#F80000',
71-
icon: NetSuiteIcon,
72+
icon: OracleIcon,
7273
canvasPresentation: {
7374
defaultTitle: 'Oracle Fusion Cloud HCM',
7475
sentences: {
@@ -128,26 +129,24 @@ export const OracleFusionHcmBlock: BlockConfig = {
128129
],
129130
},
130131
{
131-
id: 'tenantUrl',
132-
title: 'Tenant URL',
133-
type: 'short-input',
134-
placeholder: 'https://example.fa.ocs.oraclecloud.com',
135-
required: true,
136-
description: 'Canonical Oracle Fusion application origin',
137-
},
138-
{
139-
id: 'username',
140-
title: 'Username',
141-
type: 'short-input',
142-
placeholder: 'Integration username',
132+
id: 'credential',
133+
title: 'Oracle Fusion Account',
134+
type: 'oauth-input',
135+
serviceId: 'oracle_fusion_hcm',
136+
requiredScopes: getScopesForService('oracle_fusion_hcm'),
137+
credentialKind: 'service-account',
138+
canonicalParamId: 'oauthCredential',
139+
mode: 'basic',
140+
placeholder: 'Select Oracle Fusion credential',
143141
required: true,
144142
},
145143
{
146-
id: 'password',
147-
title: 'Password',
144+
id: 'manualCredential',
145+
title: 'Oracle Fusion Account',
148146
type: 'short-input',
149-
placeholder: 'Integration password',
150-
password: true,
147+
canonicalParamId: 'oauthCredential',
148+
mode: 'advanced',
149+
placeholder: 'Enter credential ID',
151150
required: true,
152151
},
153152
{
@@ -157,7 +156,7 @@ export const OracleFusionHcmBlock: BlockConfig = {
157156
canonicalParamId: 'personId',
158157
serviceId: 'oracle_fusion_hcm',
159158
selectorKey: 'oracle_fusion_hcm.workers',
160-
dependsOn: ['tenantUrl', 'username', 'password'],
159+
dependsOn: ['credential'],
161160
mode: 'basic',
162161
condition: { field: 'operation', value: [...PERSON_OPERATIONS, 'get_absence'] },
163162
required: { field: 'operation', value: PERSON_OPERATIONS },
@@ -180,7 +179,7 @@ export const OracleFusionHcmBlock: BlockConfig = {
180179
canonicalParamId: 'assignmentId',
181180
serviceId: 'oracle_fusion_hcm',
182181
selectorKey: 'oracle_fusion_hcm.assignments',
183-
dependsOn: ['tenantUrl', 'username', 'password', 'personPicker'],
182+
dependsOn: ['credential', 'personPicker'],
184183
mode: 'basic',
185184
condition: { field: 'operation', value: ASSIGNMENT_OPERATIONS },
186185
required: { field: 'operation', value: ASSIGNMENT_OPERATIONS },
@@ -203,7 +202,7 @@ export const OracleFusionHcmBlock: BlockConfig = {
203202
canonicalParamId: 'absenceId',
204203
serviceId: 'oracle_fusion_hcm',
205204
selectorKey: 'oracle_fusion_hcm.absences',
206-
dependsOn: ['tenantUrl', 'username', 'password', 'personPicker'],
205+
dependsOn: ['credential', 'personPicker'],
207206
mode: 'basic',
208207
condition: { field: 'operation', value: 'get_absence' },
209208
required: { field: 'operation', value: 'get_absence' },
@@ -226,7 +225,7 @@ export const OracleFusionHcmBlock: BlockConfig = {
226225
canonicalParamId: 'absenceTypeId',
227226
serviceId: 'oracle_fusion_hcm',
228227
selectorKey: 'oracle_fusion_hcm.absenceTypes',
229-
dependsOn: ['tenantUrl', 'username', 'password', 'personPicker'],
228+
dependsOn: ['credential', 'personPicker'],
230229
mode: 'basic',
231230
condition: { field: 'operation', value: 'list_absences' },
232231
placeholder: 'Optionally select an absence type',
@@ -339,9 +338,7 @@ export const OracleFusionHcmBlock: BlockConfig = {
339338
},
340339
inputs: {
341340
operation: { type: 'string', description: 'Read-only Oracle HCM operation' },
342-
tenantUrl: { type: 'string', description: 'Oracle Fusion tenant origin' },
343-
username: { type: 'string', description: 'Oracle username' },
344-
password: { type: 'string', description: 'Oracle password' },
341+
oauthCredential: { type: 'string', description: 'Oracle Fusion integration-user credential' },
345342
personId: { type: 'string', description: 'Person ID' },
346343
assignmentId: { type: 'string', description: 'Assignment ID' },
347344
absenceId: { type: 'string', description: 'Absence entry ID' },
@@ -486,6 +483,11 @@ export const OracleFusionHcmBlock: BlockConfig = {
486483
description: 'Estimated total when Oracle provides it',
487484
condition: { field: 'operation', value: LIST_OPERATIONS },
488485
},
486+
nextOffset: {
487+
type: 'number',
488+
description: 'Next Oracle page offset when another page exists',
489+
condition: { field: 'operation', value: LIST_OPERATIONS },
490+
},
489491
},
490492
}
491493

@@ -494,7 +496,7 @@ export const OracleFusionHcmBlockMeta = {
494496
url: 'https://www.oracle.com/human-capital-management/',
495497
templates: [
496498
{
497-
icon: NetSuiteIcon,
499+
icon: OracleIcon,
498500
title: 'Oracle worker lookup',
499501
prompt:
500502
'Build a workflow that safely searches Oracle Fusion Cloud HCM public workers, retrieves the selected worker and assignments, and returns only work identity and organizational details.',
@@ -503,7 +505,7 @@ export const OracleFusionHcmBlockMeta = {
503505
tags: ['hr', 'enterprise'],
504506
},
505507
{
506-
icon: NetSuiteIcon,
508+
icon: OracleIcon,
507509
title: 'Oracle reporting chain review',
508510
prompt:
509511
'Create a workflow that selects an Oracle HCM worker and assignment, lists that assignment’s managers, and formats a concise reporting-chain review.',
@@ -512,7 +514,7 @@ export const OracleFusionHcmBlockMeta = {
512514
tags: ['hr', 'reporting'],
513515
},
514516
{
515-
icon: NetSuiteIcon,
517+
icon: OracleIcon,
516518
title: 'Oracle direct reports roster',
517519
prompt:
518520
'Build a workflow that lists direct reports for a selected Oracle HCM assignment and writes the bounded roster page to a review table.',
@@ -521,7 +523,7 @@ export const OracleFusionHcmBlockMeta = {
521523
tags: ['hr', 'reporting'],
522524
},
523525
{
524-
icon: NetSuiteIcon,
526+
icon: OracleIcon,
525527
title: 'Oracle assignment audit',
526528
prompt:
527529
'Create a scheduled workflow that reads worker assignments from Oracle HCM, compares department, job, position, and location with a reference table, and flags mismatches without changing Oracle.',
@@ -530,7 +532,7 @@ export const OracleFusionHcmBlockMeta = {
530532
tags: ['hr', 'compliance'],
531533
},
532534
{
533-
icon: NetSuiteIcon,
535+
icon: OracleIcon,
534536
title: 'Oracle absence calendar',
535537
prompt:
536538
'Build a workflow that reads one worker’s Oracle HCM absences for a selected absence type and date range, then creates a review calendar without exposing reasons, comments, attachments, or medical data.',
@@ -539,7 +541,7 @@ export const OracleFusionHcmBlockMeta = {
539541
tags: ['hr', 'planning'],
540542
},
541543
{
542-
icon: NetSuiteIcon,
544+
icon: OracleIcon,
543545
title: 'Oracle absence approval review',
544546
prompt:
545547
'Create a workflow that lists a worker’s Oracle HCM absences, summarizes status, approval state, dates, and duration, and routes exceptions for human review.',
@@ -548,7 +550,7 @@ export const OracleFusionHcmBlockMeta = {
548550
tags: ['hr', 'review'],
549551
},
550552
{
551-
icon: NetSuiteIcon,
553+
icon: OracleIcon,
552554
title: 'Oracle workforce structure catalog',
553555
prompt:
554556
'Build a scheduled workflow that reads one page each of Oracle HCM jobs, job families, departments, locations, business units, legal employers, grades, and person types and stores a dated catalog snapshot.',
@@ -557,7 +559,7 @@ export const OracleFusionHcmBlockMeta = {
557559
tags: ['hr', 'reporting'],
558560
},
559561
{
560-
icon: NetSuiteIcon,
562+
icon: OracleIcon,
561563
title: 'Oracle job alignment report',
562564
prompt:
563565
'Create a workflow that compares Oracle HCM jobs, positions, and grades by code and effective date, then produces a bounded alignment report for HR review.',
@@ -607,7 +609,7 @@ export const OracleFusionHcmBlockMeta = {
607609
name: 'page-oracle-hcm-results',
608610
description: 'Continue an Oracle HCM collection safely.',
609611
content:
610-
'# Page Oracle HCM Results\n\n## Steps\n\n1. Read the returned limit, offset, and hasMore values.\n2. Continue at offset plus limit only when hasMore is true and another page is needed.\n3. Never auto-load an entire collection.\n\n## Output\n\nReturn the requested page and its updated pagination state.',
612+
'# Page Oracle HCM Results\n\n## Steps\n\n1. Read the returned nextOffset and hasMore values.\n2. Continue at nextOffset only when hasMore is true and another page is needed.\n3. Never auto-load an entire collection.\n\n## Output\n\nReturn the requested page and its updated pagination state.',
611613
},
612614
],
613615
} as const satisfies BlockMeta

apps/sim/lib/api/contracts/tools/oracle-fusion-hcm.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ const dateSchema = z
2929
const searchSchema = z.string().trim().min(1).max(200).optional()
3030

3131
const oracleFusionHcmBaseBodySchema = z.object({
32-
tenantUrl: z.string().trim().min(1).max(2048),
33-
username: z.string().trim().min(1).max(256),
34-
password: z.string().min(1).max(2048),
32+
instanceUrl: z.string().trim().min(1).max(2048),
33+
accessToken: z.string().min(1).max(4096),
3534
})
3635

3736
const paginationBodyShape = {
@@ -272,6 +271,7 @@ const paginationResponseShape = {
272271
limit: z.number().int().min(0),
273272
offset: z.number().int().min(0),
274273
totalResults: z.number().int().min(0).optional(),
274+
nextOffset: z.number().int().min(0).optional(),
275275
}
276276

277277
const successResponse = <T extends z.ZodType>(output: T) =>

apps/sim/lib/integrations/icon-mapping.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ import {
173173
ObsidianIcon,
174174
OktaIcon,
175175
OnePasswordIcon,
176+
OracleIcon,
176177
OutlookIcon,
177178
PackageSearchIcon,
178179
PagerDutyIcon,
@@ -462,7 +463,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
462463
okta: OktaIcon,
463464
onedrive: MicrosoftOneDriveIcon,
464465
onepassword: OnePasswordIcon,
465-
oracle_fusion_hcm: NetSuiteIcon,
466+
oracle_fusion_hcm: OracleIcon,
466467
outlook: OutlookIcon,
467468
pagerduty: PagerDutyIcon,
468469
parallel_ai: ParallelIcon,

0 commit comments

Comments
 (0)