-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Integration][HiBob] add initial version of HiBob integration #1273
base: main
Are you sure you want to change the base?
[Integration][HiBob] add initial version of HiBob integration #1273
Conversation
9be84e2
to
06e9e8b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your contribution @thinkingabouther!!!
Left some comments, I would love to assist with going over the reviews and solutions.
selector: | ||
query: .name | startswith("work.column_1659977338244") | ||
port: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you please elaborate on work.column_1659977338244
is that something specific to your org?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
referenced it here: #1273 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currently _team
and _user
is not available by default to all organizations, I would suggest defining default of HiBobTeam
and HiBobUser
at the start and then once its fully available we will adjust the defaults to point to the _team
and _user
blueprints
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've moved the _team and _user blueprint to examples, the default resources will use different identifiers as advised. Thank you!
resources: | ||
- kind: list | ||
selector: | ||
query: .name | <your-team-list-name> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you elaborate on what you are trying achieve here? Ideally I would like this to be auto discoverable on setup either from the hibob api or configured by the user installing it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me know if you would like to schedule a call to brainstorm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to have auto-discovery bit as well, yet I'm not sure it is possible that it is going to work with lists
.
HiBob lists
essentially store any custom enums defined in the HR system, such as types of employment agreements, locations, etc. Unfortunately, there’s no clear way to distinguish a list containing team names from any other list without knowing its exact list name. Moreover, the list names are assigned automatically by HiBob, which is why you noticed a name like column_1659977338244
in the initial draft.
However, the default /profile response includes a department field for each employee. In our case, the department represents a higher-level organizational unit, which we don’t plan to use in Port at this time.
Based on this, I propose the following approach:
-
Auto-populate
HiBobTeam
by configuring the default blueprints inport-app-config.yml
to automatically populate theHiBobTeam
with values from thedepartment
field in employee profiles. This setup ensures that it works out-of-the-box for most users, as some organizations may even prefer to use thedepartment
field for ABAC in Port. -
Provide an example for custom mapping between
lists
andprofiles
by placing the current implementation (mapping a specific list to an employee field) in the_examples
folder. This will serve as a reference for future users who might need a solution for the use cases similar to our organization.
Let me know your thoughts on this approach! 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented the changes as mentioned, you are welcome to review again 😃
identifier: .email | ||
blueprint: '"_user"' | ||
relations: | ||
teams: <your-team-list-name> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
proposed a solution here: #1273 (comment)
def transform_to_array_of_lists(lists_object: dict[str, Any]) -> list[dict[str, Any]]: | ||
array_of_lists = [] | ||
for list_name, list_content in lists_object.items(): | ||
transformed_entry = { | ||
"name": list_name, | ||
"values": list_content.get("values", []), | ||
"items": list_content.get("items", []), | ||
} | ||
array_of_lists.append(transformed_entry) | ||
return array_of_lists |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what this is needed for? when implementing integrations we are thriving to not perform any data manipulation on raw and leaving it as is so it will be easy to reference to their api docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is tricky, indeed.
The thing is, HiBob API wraps the list of lists into a top-level JSON object instead of an array.
So, this is the example structure for the lists response:
{
"list_name_1": {
"name": "list_name_1"
"items": [{...}, {...}]
"values": [{...}, {...}]
},
"list_name_2": {
"name": "list_name_2"
"items": [{...}, {...}]
"values": [{...}, {...}]
}
}
To me, this structure seems less straightforward for future manipulation in Port. Therefore, I’ve opted to return the data in the following structure instead:
[
{
"name": "list_name_1"
"items": [{...}, {...}]
"values": [{...}, {...}]
},
{
"name": "list_name_2"
"items": [{...}, {...}]
"values": [{...}, {...}]
}
]
Rather than producing a single object of DictionaryOfLists
kind, I’m returning an array of individual objects of List
kind. From a usage perspective, I believe both implementations would work, but the latter is more concise and easier to manipulate.
Let me know your thoughts based on this input! I’m happy to adjust the logic if needed. 😃
P.S. Unfortunately, the easy to reference to their api docs
won't work regardless of the implementation, since there are no examples provided in the API spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the delayed answer @thinkingabouther !
I wonder if we will be able to pass the specific list which we want to query and only export it would it make this transformation redundant? I've commented above my suggestion
06e9e8b
to
52fc4a8
Compare
Co-authored-by: Tom Tankilevitch <[email protected]>
Co-authored-by: Tom Tankilevitch <[email protected]>
Co-authored-by: Tom Tankilevitch <[email protected]>
Co-authored-by: Tom Tankilevitch <[email protected]>
792fe44
to
97a1469
Compare
Thank you for your review @Tankilevitch! Please take a look at changes/comments when you have time. |
97a1469
to
7a4cad1
Compare
hey @thinkingabouther, currently we are not supporting viewing not port official integrations in the UI, we are planning to add that capability to improve the development experience. regarding the data model and api I wonder if something like the way fivetran had modeled the hibob integration with ERD can provide some guidance on the way the hibob api is structured. https://fivetran.com/docs/connectors/applications/hibob |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @thinkingabouther looks very detailed PR!!!
I've left a few comments and suggestions, let me know what you think.
Feels like we are very close, in the mean time I'll get a hibob environment to try the integration as well :)
lists_responses = await self.client.get( | ||
f"{self.api_url}/v1/company/named-lists" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you reference the api docs for this endpoint?
- kind: list | ||
selector: | ||
query: .name | startswith("work.column_1659977338244") # Name of the List storing your teams' names (see lists.response.json) | ||
port: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like what you actually trying to achieve is way to declare to the kind what list to query from the api.
we support ways to pass the api query params through the kind to the resync in order to perform more efficient queries.
see this pr for example on how we added support to pass query filters to integration that then are being applied to the api request.
def transform_to_array_of_lists(lists_object: dict[str, Any]) -> list[dict[str, Any]]: | ||
array_of_lists = [] | ||
for list_name, list_content in lists_object.items(): | ||
transformed_entry = { | ||
"name": list_name, | ||
"values": list_content.get("values", []), | ||
"items": list_content.get("items", []), | ||
} | ||
array_of_lists.append(transformed_entry) | ||
return array_of_lists |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the delayed answer @thinkingabouther !
I wonder if we will be able to pass the specific list which we want to query and only export it would it make this transformation redundant? I've commented above my suggestion
TODO:
Description
What: Integration to fetch data from HiBob API - HR system that stores organization data such as employees' personal data and organizational structure, and facilitates performance reviews
Why: In our organization, the HR team manages employees' relations with their development teams in HiBob. By ingesting this data into Port, we will be able to set up Attribute-based Access Control for our Service Catalog by populating
Port Teams
to controlwho sees what and who does what
. Generally, the new integration itself allows ingesting any HR-related data (e.g., office locations, performance metrics, even compensation-related information) into the development platform.How: By using the Read the public profile section of all active employees API endpoint, it is possible to fetch employees' personal data (e.g. name, email, relation to their manager). By using the Get all company lists API endpoint, we fetch all custom company-wide lists (kind of enums) such as office locations, development teams, employment agreement types, etc. By merging the responses from the 1st and 2nd endpoint, it is possible to fetch most of the employees' HR data.
Type of change
All tests should be run against the port production environment(using a testing org).
Integration testing checklist (Awaiting Code Review resolution)
examples
folder in the integration directory.Preflight checklist
Profiles
andLists
are fetched with a single request each.Profiles
allow 40 requests per minute by default,Lists
allow 50/minute)Screenshots
HiBobUsers
andHiBobTeams
graph with default resources:Employee
profiles after merging them withTeams
fromCompany Lists
(mapping, blueprints and raw responses are in theexamples
folder)API Documentation