diff --git a/products/idn/docs/identity-now/saas-connectivity/connector-commands/account-list.md b/products/idn/docs/identity-now/saas-connectivity/connector-commands/account-list.md index 10252a923..2051d2c94 100644 --- a/products/idn/docs/identity-now/saas-connectivity/connector-commands/account-list.md +++ b/products/idn/docs/identity-now/saas-connectivity/connector-commands/account-list.md @@ -77,6 +77,12 @@ IDN will throw a connection timeout error if your connector doesn't respond with ::: +:::caution Important + +IDN supports [delta aggregation](#delta-aggregation-state). If your source has a large number of accounts that will be syncronized with IDN, then it is highly recommended to utilize [delta aggregation](#delta-aggregation-state) for the source. + +::: + The following code snippet from [index.ts](https://github.com/sailpoint-oss/airtable-example-connector/blob/main/src/index.ts) shows how to register the account list command on the connector object: ```javascript @@ -174,9 +180,11 @@ The result of the account list command is not an array of objects but several in If your source can keep track of changes to the data in some way, then delta aggregation can be performed on a source. In order to implement, there are a few things that need to be configured -1. In your connector-spec.json file, in the sourceConfig section, a checkbox needs to be added to enable state with the key ```spConnEnableStatefulCommands```: +1. In your connector-spec.json file, the feature needs to be enabled by adding the following key: ```"supportsStatefulCommands": true,``` and in the sourceConfig section, a checkbox needs to be added to enable state with the key ```spConnEnableStatefulCommands```: -``` +```javascript +"supportsStatefulCommands": true, +... { "key": "spConnEnableStatefulCommands", "label": "Stateful", @@ -185,9 +193,9 @@ If your source can keep track of changes to the data in some way, then delta agg } ``` -2. In the ```stdAccountList``` command, when you are done sending commands, you need to also send the state to IDN so it knows where to start the next time it sends a list request: +2. In the ```stdAccountList``` command, when you are done sending accounts, you need to also send the state to IDN so it knows where to start the next time it sends a list request: -``` +```javascript const state = {"data": Date.now().toString()} ... res.saveState(state) @@ -203,7 +211,7 @@ The state that you send using the ```saveState``` command MUST be a json object, 3. In the ```stdAccountList``` command, you need to properly handle the state object. Something like below checks the stateful boolean as well as the state object and fetches accounts accordingly: -``` +```javascript .stdAccountList(async (context: Context, input: StdAccountListInput, res: Response) => { let accounts = [] const state = {"data": Date.now().toString()} diff --git a/products/idn/docs/identity-now/saas-connectivity/connector-commands/entitlement-list.md b/products/idn/docs/identity-now/saas-connectivity/connector-commands/entitlement-list.md index a8b564449..cd1fbf5d2 100644 --- a/products/idn/docs/identity-now/saas-connectivity/connector-commands/entitlement-list.md +++ b/products/idn/docs/identity-now/saas-connectivity/connector-commands/entitlement-list.md @@ -108,4 +108,67 @@ private buildStandardObject(): StdEntitlementReadOutput | StdEntitlementListOutp IDN will throw a connection timeout error if your connector doesn't respond within 3 minutes, and there are memory limitations involved with aggregating data. To prevent large memory utilization or timeout errors, you should set up your connectors to send data to IDN as it's retrieved from your source system. For more details and an example, refer to [Connector Timeouts](../in-depth/connector-timeouts.md). -::: \ No newline at end of file +::: + +:::caution Important + +IDN supports [delta aggregation](#delta-aggregation-state). If your source has a large number of entitlements that will be syncronized with IDN, then it is highly recommended to utilize [delta aggregation](#delta-aggregation-state) for the source. + +::: + +## Delta Aggregation (State) + +If your source can keep track of changes to the data in some way, then delta aggregation can be performed on a source. In order to implement, there are a few things that need to be configured + +1. In your connector-spec.json file, the feature needs to be enabled by adding the following key: ```"supportsStatefulCommands": true,``` and in the sourceConfig section, a checkbox needs to be added to enable state with the key ```spConnEnableStatefulCommands```: + +```javascript +"supportsStatefulCommands": true, +... +{ + "key": "spConnEnableStatefulCommands", + "label": "Stateful", + "required": true, + "type": "checkbox" +} +``` + +2. In the ```stdEntitlementList``` command, when you are done sending entitlments, you need to also send the state to IDN so it knows where to start the next time it sends a list request: + +```javascript +const state = {"data": Date.now().toString()} +... +res.saveState(state) +``` + +In the above example, I am capturing the date, but you can use any value you want to store the state + +:::caution Important + +The state that you send using the ```saveState``` command MUST be a json object, and it is recommend to only save strings to ensure proper serialization/deserialization of the data. You cannot send a simple string or number or it will not properly save the state. + +::: + +3. In the ```stdEntitlementList``` command, you need to properly handle the state object. Something like below checks the stateful boolean as well as the state object and fetches accounts accordingly: + +```javascript +.stdEntitlementList(async (context: Context, input: StdEntitlementListInput, res: Response) => { + let groups = [] + const state = {"data": Date.now().toString()} + if (!input.state && input.stateful) { + logger.info(input, "No state provided, fetching all entitlements") + const groups = await airtable.getAllEntitlements() + } else if (input.state && input.stateful) { + logger.info(input ,"Current state provided, only fetching entitlements after that state") + const groups = await airtable.getAllStatefulEntitlements(new Date(Number(input.state?.data))) + } else { + logger.info(input.state ,"Source is not stateful, getting all entitlements") + const groups = await airtable.getAllEntitlements() + } + logger.info(groups, "fetched the following entitlements in Airtable") + for (const group of groups) { + res.send(group.toStdEntitlementListOutput()) + } + res.saveState(state) +}) +``` \ No newline at end of file diff --git a/src/components/blog/BlogBanner/index.js b/src/components/blog/BlogBanner/index.js index 5f9e5878f..e1ae1b386 100644 --- a/src/components/blog/BlogBanner/index.js +++ b/src/components/blog/BlogBanner/index.js @@ -9,13 +9,11 @@ export default function BlogBanner() {
+
- SailPoint Developer Blog + Blog
- - -
); } diff --git a/src/components/blog/BlogBanner/styles.module.css b/src/components/blog/BlogBanner/styles.module.css index fa4843401..6382c3e3b 100644 --- a/src/components/blog/BlogBanner/styles.module.css +++ b/src/components/blog/BlogBanner/styles.module.css @@ -6,8 +6,8 @@ max-width: 396px; font-weight: bold; line-height: 133%; - top: 21px; - left: 74px; + top: -84px; + left: 59px; } .background { @@ -18,7 +18,11 @@ .imageContainer { width: 100%; - height: 180px; - background-image: url('../../../../static/blog/blog_banner_template.png'); - background-repeat: repeat; + height: 90px; + background: rgb(0,51,161); + background: linear-gradient(90deg, rgba(0,51,161,1) 0%, rgba(84,192,232,1) 100%); +} + +.headerImage { + height: 90px; } \ No newline at end of file diff --git a/src/components/marketplace/MarketplaceBanner/index.js b/src/components/marketplace/MarketplaceBanner/index.js index 8c9e2cacd..8a3a49cb4 100644 --- a/src/components/marketplace/MarketplaceBanner/index.js +++ b/src/components/marketplace/MarketplaceBanner/index.js @@ -9,8 +9,9 @@ export default function MarketplaceBanner() {
+
- SailPoint Developer Marketplace + Marketplace
diff --git a/src/components/marketplace/MarketplaceBanner/styles.module.css b/src/components/marketplace/MarketplaceBanner/styles.module.css index 447c3ecb9..b4570f741 100644 --- a/src/components/marketplace/MarketplaceBanner/styles.module.css +++ b/src/components/marketplace/MarketplaceBanner/styles.module.css @@ -6,8 +6,8 @@ max-width: 459px; font-weight: bold; line-height: 130%; - top: 29px; - left: 228px; + top: -84px; + left: 101px; } .background { @@ -18,8 +18,11 @@ .imageContainer { width: 100%; - height: 180px; - background-size: 1920px 180px; - background-image: url('../../../../static/blog/marketplace_banner_template.png'); - background-repeat: repeat; + height: 90px; + background: rgb(0,51,161); + background: linear-gradient(90deg, rgba(0,51,161,1) 0%, rgba(84,192,232,1) 100%); +} + +.headerImage { + height: 90px; } \ No newline at end of file diff --git a/static/blog/blog_banner_template.png b/static/blog/blog_banner_template.png index 9859513c0..ed25e8070 100644 Binary files a/static/blog/blog_banner_template.png and b/static/blog/blog_banner_template.png differ diff --git a/static/blog/marketplace_banner_template.png b/static/blog/marketplace_banner_template.png index d85daa14a..230b4f32c 100644 Binary files a/static/blog/marketplace_banner_template.png and b/static/blog/marketplace_banner_template.png differ