mirror of
https://github.com/LukeHagar/developer.sailpoint.com.git
synced 2025-12-10 04:19:42 +00:00
Merge branch 'main' into feature/pythonSDKDocs
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,6 +16,7 @@
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env
|
||||
.npmrc
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
|
||||
@@ -59,9 +59,9 @@ Scopes are granular permissions you can add to personal access tokens (PATs) to
|
||||
|
||||
Scopes contain one or more rights, which are low level permissions that grant access to individual endpoints. This means that a single scope, like `idn:access-request:manage`, can grant access to multiple API endpoints. To determine which scopes a PAT needs, you must first identify which endpoints the PAT needs to invoke. Each endpoint's API specification indicates which scope is necessary to call the endpoint. You can use this approach to curate a list of scopes that must be applied to the credential to call the necessary endpoints. [Learn more about how to find an API's required scopes here](#identifying-necessary-authorization-for-an-endpoint).
|
||||
|
||||
By default, each PAT has the scope, `sp:scopes:all`, which grants access to all the rights appropriate for the [user level](https://documentation.sailpoint.com/saas/help/common/users/user_level_matrix.html). For example, a user with the **Admin** user level has access to all APIs, so `sp:scopes:all` grants **Admin** users access to all APIs. A user with the **Cert Admin** user level, however, has access to only a subset of APIs necessary to perform their role, most notably the certification APIs, so `sp:scopes:all` grants **Cert Admin** users access to only that subset of APIs.
|
||||
By default, each PAT has the scope `sp:scopes:default`, which is the least privileged scope. It only grants access to endpoints that require no authorization at all, such as [List Public Identities](https://developer.sailpoint.com/idn/api/v3/get-public-identities). Access to the endpoint may still be determined by the user's [user level](https://documentation.sailpoint.com/saas/help/common/users/user_level_matrix.html).
|
||||
|
||||
Alternatively, `sp:scopes:default` is the least privileged scope that only grants access to endpoints that require no authorization at all, such as [list public identities](https://developer.sailpoint.com/docs/api/v3/get-public-identities).
|
||||
Alternatively, `sp:scopes:all` grants access to all the rights appropriate for the [user level](https://documentation.sailpoint.com/saas/help/common/users/user_level_matrix.html). For example, a user with the **Admin** user level has access to all APIs, so `sp:scopes:all` grants **Admin** users access to all APIs. A user with the **Cert Admin** user level, however, has access to only a subset of APIs necessary to perform their role, most notably the certification APIs, so `sp:scopes:all` grants **Cert Admin** users access to only that subset of APIs.
|
||||
|
||||
Scopes are additive, which means the final right set is the intersection of all the rights granted by the scopes assigned to a PAT, excluding any rights that fall outside of the user level. Each scope added to an PAT builds up the credential's permission set, incrementally increasing access to the API. If a PAT has `sp:scopes:all` granted, then any additional scope is ignored because `sp:scopes:all` already contains the complete set of rights available to the user level.
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ You can use the Identity Security Cloud APIs to update existing resources. Many
|
||||
|
||||
- You can send a **PUT** request to replace the existing resource with a new one. For example, if you wanted to update one of John Doe's source accounts, you could use the [Put Account](https://developer.sailpoint.com/docs/api/v3/put-account) endpoint to replace John Doe's existing source account with a new one. This is a viable way to update a resource, but it requires you to update the entire resource each time.
|
||||
|
||||
- You can send a **PATCH** request to make a specific change to the resource. For example, if you wanted to update John Doe's account's associated "city" attribute, you could use the [Patch Account](https://developer.sailpoint.com/docs/api/v3/update-account) endpoint to replace his existing "city" with a new one, all without affecting any of the other source account details. This can be very helpful when you want to make specific updates to resources, but it requires some knowledge of the types of changes, or "operations", that are possible, the specific paths of the fields you want to update, and some understanding of the basic data types.
|
||||
- You can send a **PATCH** request to make a specific change to the resource. For example, if you wanted to update John Doe's account's associated `identityId` attribute, you could use the [Patch Account](https://developer.sailpoint.com/docs/api/v3/update-account) endpoint to replace his existing `identityId` with a new one, all without affecting any of the other source account details. This can be very helpful when you want to make specific updates to resources, but it requires some knowledge of the types of changes, or "operations", that are possible, the specific paths of the fields you want to update, and some understanding of the basic data types.
|
||||
|
||||
This guide will focus on the partial update method, PATCH requests. Read this guide to learn how to start sending PATCH requests.
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
id: connectivity-customizers-config
|
||||
title: Customizer Config Object
|
||||
pagination_label: Config Object
|
||||
sidebar_label: Config Object
|
||||
sidebar_position: 6.5
|
||||
sidebar_class_name: saasConnectivity
|
||||
keywords: ['connectivity', 'connectors', customizers]
|
||||
description: The config object in a customizer
|
||||
slug: /connectivity/saas-connectivity/customizers/config
|
||||
tags: ['Connectivity']
|
||||
---
|
||||
|
||||
# Customizer Config Object
|
||||
|
||||
The connector config object holds all the config values that are set in the SaaS connector. These can be used to fetch custom settings added by the user, as well as inspect values from the connector instance itself.
|
||||
|
||||
The config object is fetched during initialization of the connector
|
||||
|
||||
```typescript
|
||||
const config: Config = await readConfig()
|
||||
```
|
||||
|
||||
### Example Config Object
|
||||
|
||||
Below is an example object model that can be used to type your config. Any values set by the connector itself are added at the top level json.
|
||||
|
||||
```typescript
|
||||
export interface Config {
|
||||
beforeProvisioningRule: any
|
||||
cloudCacheUpdate: number
|
||||
cloudDisplayName: string
|
||||
cloudExternalId: string
|
||||
connectionType: string
|
||||
connectorName: string
|
||||
deleteThresholdPercentage: number
|
||||
deltaAggregation: DeltaAggregation
|
||||
deltaAggregationEnabled: boolean
|
||||
formPath: any
|
||||
hasFullAggregationCompleted: boolean
|
||||
healthCheckTimeout: number
|
||||
healthy: boolean
|
||||
idnProxyType: string
|
||||
managementWorkgroup: any
|
||||
managerCorrelationFilter: any
|
||||
since: string
|
||||
"slpt-source-diagnostics": string
|
||||
sourceConnected: boolean
|
||||
sourceDescription: string
|
||||
spConnEnableStatefulCommands: boolean
|
||||
spConnectorInstanceId: string
|
||||
spConnectorSpecId: string
|
||||
status: string
|
||||
supportsDeltaAgg: boolean
|
||||
templateApplication: string
|
||||
}
|
||||
|
||||
export interface DeltaAggregation {
|
||||
"std:account:list": any
|
||||
"std:entitlement:list": any
|
||||
}
|
||||
```
|
||||
@@ -17,6 +17,6 @@ Below is a list of limits set in SaaS Connectivity:
|
||||
- The actual run time of a connector is not limited at this time, however a response in the form of `res.send()` must be recieved from a command at least every 3 minutes
|
||||
- If you have a long running call, you can use `res.keepAlive()` to send a heartbeat to Identity Security Cloud in between `res.send()` calls to let it know the connector is still running
|
||||
- **Response Size**
|
||||
- The maximum size of a single `res.send()` call is 256 KiB. Not that some metadata is sent along with the call, so the max size of the payload sent will be slightly less than 256 KiB
|
||||
- The maximum size of a single `res.send()` call is 256 KiB. Note that some metadata is sent along with the call, so the max size of the payload sent will be slightly less than 256 KiB
|
||||
- **Memory Limits**
|
||||
- Each instance of a running SaaS connector is limited to 512 MB
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
id: configuration-hub
|
||||
title: Configuration Hub
|
||||
pagination_label: Configuration Hub
|
||||
sidebar_position: 3
|
||||
sidebar_class_name: configurationHub
|
||||
keywords: ['configuration']
|
||||
description: Manage tenant configurations with the ISC UI.
|
||||
slug: /extensibility/configuration-management/configuration-hub
|
||||
tags: ['Configuration', 'Hub']
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The SailPoint Configuration Hub supports management of configuration objects in your Identity Security Cloud (ISC) tenant through backup and deploy operations from the ISC UI. For example, you can back up configurations like sources and identity profiles defined for your business, restore them in the event of configuration errors or loss, or migrate and deploy them to your other tenants.
|
||||
|
||||
To learn more about Configuration Hub, refer to the [Configuration Hub documentation](https://documentation.sailpoint.com/saas/help/confighub/config_hub.html).
|
||||
|
||||
## Discuss
|
||||
|
||||
The most valuable resource for ISC developers is the SailPoint Developer Community itself, where ISC users and experts all over the world come together to ask questions and provide solutions.
|
||||
|
||||
To learn more about the SaiLPoint Configuration Hub and discuss it with SailPoint Developer Community members, go to the [SailPoint Developer Community Forum](https://developer.sailpoint.com/discuss/c/isc/6).
|
||||
@@ -19,9 +19,9 @@ tags: ['Introduction', 'Getting Started']
|
||||
|
||||
## Overview
|
||||
Configuration Management provides you with a form of version control for your tenant configurations.
|
||||
With Configuration Management, you can export snapshots of your current tenant configurations, downloading them in a JSON.
|
||||
With Configuration Management, you can export (backup in Configuration Hub) and import (deploy in Configuration Hub) snapshots of your current tenant configurations, downloading them in a JSON.
|
||||
These configurations can serve as different versions of your tenant configuration.
|
||||
You can then import those configurations into tenants to update, resore, or migrate tenant configurations.
|
||||
You can then import those configurations into tenants to update, restore, or migrate tenant configurations.
|
||||
|
||||
```mdx-code-block
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
id: saas-configuration
|
||||
title: SaaS Configuration
|
||||
pagination_label: SaaS Configuration
|
||||
sidebar_position: 3
|
||||
sidebar_position: 4
|
||||
sidebar_class_name: saasConfiguration
|
||||
keywords: ['configuration']
|
||||
description: Use SaaS Configuration APIs to import and export configurations.
|
||||
description: Manage tenant configurations with the SaaS Configuration APIs.
|
||||
slug: /extensibility/configuration-management/saas-configuration
|
||||
tags: ['SaaS Configuration']
|
||||
---
|
||||
|
||||
@@ -428,7 +428,7 @@ return generateUsername( identity.getFirstname(), identity.getLastname() );
|
||||
|
||||
Before you send the rule to the professional services team to upload your rule to your tenant for use, you can send it through the rule validator to check for any errors.
|
||||
|
||||
Refer to [Rule Validator](https://community.sailpoint.com/t5/Professional-Services/Identity Security Cloud-Rule-Validator/ta-p/166116) for installation.
|
||||
Refer to [Rule Validator](https://community.sailpoint.com/t5/Professional-Services/IdentityNow-Rule-Validator/ta-p/166116) for installation.
|
||||
|
||||
Run the rule validator against your newly written rule.
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ sailpoint.object.Identity identity = plan.getIdentity();
|
||||
String sAMAccountName = identity.getAttribute("adUsername");
|
||||
|
||||
sailpoint.rule.Identity foundIdentity = idn.getIdentityById("uid");
|
||||
String email = foundIdentity.getAttribute("email");
|
||||
String email = foundIdentity.getEmail();
|
||||
```
|
||||
|
||||
The below section provides a full accounting of the methods available to rule writers using the IdnRuleUtil class:
|
||||
|
||||
@@ -90,7 +90,7 @@ Some examples of expressions are:
|
||||
|
||||
- `true` indicates the transform rounds up (i.e., truncate the fractional date/time component indicated and then add one unit of that component).
|
||||
- `false` indicates the transform rounds down (i.e., truncate the fractional date/time component indicated).
|
||||
- `input` - This is an optional attribute that can explicitly define the input data passed into the transform logic. If no input is provided, the transform takes its input from the source and attribute combination configured with the UI.
|
||||
- **input** - This is an optional attribute that can explicitly define the input data passed into the transform logic. If no input is provided, the transform takes its input from the source and attribute combination configured with the UI.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -14,7 +14,23 @@ hide_table_of_contents: true
|
||||
|
||||
import MermaidViewer from '@site/src/components/MermaidViewer';
|
||||
|
||||
Secure Data Share (SDS) makes your SailPoint identity data available directly in your own AWS Snowflake account. The provided dataset is comprised of structured tables that include identity, audit events, entitlements, roles, access profiles, accounts, and application data. SDS is an alternative to [search](https://documentation.sailpoint.com/saas/help/search/index.html) that gives you direct access to your tenant data, allowing you to connect your favorite data analytics tools, like PowerBI and Tableau. For information on how to use SDS in your environment, see the documentation [here](https://documentation.sailpoint.com/saas/help/secure_data_share/secure_data_share.html). For the entity relationship (ER) diagrams that represent the data model, please see the following pages.
|
||||
# Secure Data Share
|
||||
|
||||
Secure Data Share (SDS) makes your SailPoint identity data available directly in your own [AWS Snowflake](https://aws.amazon.com/financial-services/partner-solutions/snowflake/) account. The provided dataset comprises structured tables that include identity, audit event, entitlement, role, access profile, account, and application data. Secure Data Share is an alternative to SailPoint's [Search](https://documentation.sailpoint.com/saas/help/search/index.html). SDS uses SQL as the query language, whereas Search uses the [Elasticsearch Query Language](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html). SQL provides certain advantages over Elasticsearch: joining and aggregating data is easier in SQL, and the Snowflake interface has a built-in SQL explorer and allows you to download your search results in CSV format. SDS also allows you to connect your SailPoint data to your favorite data analytics tools, like [PowerBI](https://learn.microsoft.com/en-us/power-bi/connect-data/service-connect-snowflake) and [Tableau](https://help.tableau.com/current/pro/desktop/en-us/examples_snowflake.htm), further enhancing the reporting capabilities for your SailPoint data.
|
||||
|
||||
If you would like to speak to a SailPoint representative about Secure Data Share, please [schedule a meeting here](https://calendly.com/jordan-mandernach/secure_data_share).
|
||||
|
||||
## Requirements
|
||||
|
||||
Secure Data Share is an add-on for Identity Security Cloud. Please contact your sales representative to discuss your SDS options. You must also have an AWS Snowflake account so that SailPoint can synchronize your tenant data with your Snowflake instance.
|
||||
|
||||
## Data Synchronization SLA
|
||||
|
||||
Similar to Search, SDS has a synchronization service-level agreement (SLA) of 24 hours. This means it can take up to 24 hours for operational data in your tenant to be synchronized with your Snowflake database. SailPoint Search and SDS are two separate systems, and there is no guarantee on which service will receive updated data first. In some cases, operational data may appear in Search before SDS, and in other cases SDS may receive the data first.
|
||||
|
||||
## How to use SDS
|
||||
|
||||
For information on how to install and use SDS in your environment, see the documentation [here](https://documentation.sailpoint.com/saas/help/secure_data_share/secure_data_share.html). Because SDS uses SQL as the query language, your tenant data is formatted into relational tables. To view the relationships between these tables, please see the following pages for the entity relationship (ER) diagrams that represent the data model.
|
||||
|
||||
```mdx-code-block
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
@@ -22,3 +38,8 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
<DocCardList items={useCurrentSidebarCategory().items}/>
|
||||
```
|
||||
|
||||
## Discuss
|
||||
The most valuable resource for ISC developers is the SailPoint Developer Community itself, where ISC users and experts all over the world come together to ask questions and provide solutions.
|
||||
|
||||
To learn more about SDS and discuss it with SailPoint Developer Community members, go to the [SailPoint Developer Community Forum](https://developer.sailpoint.com/discuss/c/identity-security-cloud/6).
|
||||
57
navbar.js
57
navbar.js
@@ -7,34 +7,43 @@ module.exports = {
|
||||
},
|
||||
items: [
|
||||
{
|
||||
type: 'dropdown',
|
||||
label: 'Documentation',
|
||||
position: 'left',
|
||||
label: 'Identity Security Cloud',
|
||||
to: '/docs',
|
||||
items: [
|
||||
{label: 'Identity Security Cloud', to: '/docs'},
|
||||
{label: 'IdentityIQ', to: '/docs/iiq'},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
type: 'dropdown',
|
||||
label: 'Community',
|
||||
position: 'left',
|
||||
items: [
|
||||
{
|
||||
label: 'Developer Forum',
|
||||
to: 'https://developer.sailpoint.com/discuss/',
|
||||
},
|
||||
{
|
||||
label: 'CoLab Marketplace',
|
||||
to: '/colab',
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Developer Blog',
|
||||
to: '/blog',
|
||||
},
|
||||
{
|
||||
label: 'Ambassador Program',
|
||||
to: '/ambassadors',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
position: 'left',
|
||||
label: 'IdentityIQ',
|
||||
to: '/docs/iiq',
|
||||
},
|
||||
{
|
||||
position: 'left',
|
||||
label: 'CoLab',
|
||||
to: '/colab',
|
||||
},
|
||||
{
|
||||
position: 'left',
|
||||
label: 'Blog',
|
||||
to: '/blog',
|
||||
},
|
||||
{
|
||||
position: 'left',
|
||||
label: 'Ideas',
|
||||
to: 'https://ideas.sailpoint.com',
|
||||
},
|
||||
{
|
||||
position: 'left',
|
||||
label: 'Discuss',
|
||||
to: 'https://developer.sailpoint.com/discuss/',
|
||||
label: 'Video Library',
|
||||
to: '/videos',
|
||||
},
|
||||
{
|
||||
type: 'dropdown',
|
||||
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -14,6 +14,7 @@
|
||||
"@docusaurus/theme-mermaid": "2.4.3",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||
"@fortawesome/pro-duotone-svg-icons": "^6.5.1",
|
||||
"@fortawesome/pro-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"@typeform/embed-react": "^1.21.0",
|
||||
@@ -23,6 +24,7 @@
|
||||
"docusaurus-plugin-openapi-docs": "^2.0.2",
|
||||
"docusaurus-theme-openapi-docs": "^2.0.2",
|
||||
"docusaurus2-dotenv": "^1.4.0",
|
||||
"ldrs": "^1.0.1",
|
||||
"prism-react-renderer": "^1.3.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@@ -3263,6 +3265,17 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/pro-solid-svg-icons": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://npm.fontawesome.com/@fortawesome/pro-solid-svg-icons/-/6.5.1/pro-solid-svg-icons-6.5.1.tgz",
|
||||
"integrity": "sha512-UnJzqw7w+RVtEnQ2Bqg09bGYkJEZRkTnbgweZDTznHjtxsJzQdJkD3hJPL6N00c8GbWpRYslNDnTNDGVSd94cQ==",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/react-fontawesome": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
|
||||
@@ -10614,6 +10627,11 @@
|
||||
"shell-quote": "^1.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ldrs": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ldrs/-/ldrs-1.0.1.tgz",
|
||||
"integrity": "sha512-eeCP1XEG72Yz6JX50zlYWRJcEfNBrpp8QSzyjD3HHhxrnt4steLX4iDHF3Dezjbnnj5qtuJn7lr1nln+/kpUIQ=="
|
||||
},
|
||||
"node_modules/leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"@docusaurus/theme-mermaid": "2.4.3",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||
"@fortawesome/pro-duotone-svg-icons": "^6.5.1",
|
||||
"@fortawesome/pro-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"@typeform/embed-react": "^1.21.0",
|
||||
@@ -36,6 +37,7 @@
|
||||
"docusaurus-plugin-openapi-docs": "^2.0.2",
|
||||
"docusaurus-theme-openapi-docs": "^2.0.2",
|
||||
"docusaurus2-dotenv": "^1.4.0",
|
||||
"ldrs": "^1.0.1",
|
||||
"prism-react-renderer": "^1.3.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
19
plugin-dynamic-routes/index.js
Normal file
19
plugin-dynamic-routes/index.js
Normal file
@@ -0,0 +1,19 @@
|
||||
module.exports = function (context, options) {
|
||||
return {
|
||||
name: 'plugin-dynamic-routes',
|
||||
|
||||
async contentLoaded({content, actions}) {
|
||||
const {routes} = options;
|
||||
const {addRoute} = actions;
|
||||
|
||||
routes.forEach((route) => {
|
||||
addRoute({
|
||||
path: route.path,
|
||||
exact: route.exact || false,
|
||||
component: route.component,
|
||||
customProps: route.customProps || {},
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -23,7 +23,7 @@ module.exports = [
|
||||
to: '/ambassadors',
|
||||
from: ['/ambassador-program', '/ambassador'],
|
||||
},
|
||||
{
|
||||
{
|
||||
from: ['/idn/docs/saas-configuration'],
|
||||
to: '/docs/extensibility/configuration-management/saas-configuration',
|
||||
},
|
||||
|
||||
13
sidebars.js
13
sidebars.js
@@ -12,7 +12,7 @@ const sidebars = {
|
||||
{
|
||||
type: 'category',
|
||||
label: 'API Specifications',
|
||||
collapsible: true,
|
||||
collapsible: false,
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'api/api-specifications',
|
||||
@@ -202,11 +202,6 @@ const sidebars = {
|
||||
label: 'Product Documentation',
|
||||
href: 'https://documentation.sailpoint.com',
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
label: 'Certifications',
|
||||
href: 'https://university.sailpoint.com/Saba/Web_spf/NA10P1PRD075/guest/categorydetail/categ000000000003041/true/xxemptyxx/',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -223,6 +218,7 @@ const sidebars = {
|
||||
{
|
||||
type: 'category',
|
||||
label: 'API Specifications',
|
||||
collapsible: false,
|
||||
link: {
|
||||
type: 'generated-index',
|
||||
title: 'API Specifications',
|
||||
@@ -252,11 +248,6 @@ const sidebars = {
|
||||
label: 'Product Documentation',
|
||||
href: 'https://documentation.sailpoint.com/#identityiq',
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
label: 'Certifications',
|
||||
href: 'https://university.sailpoint.com/Saba/Web_spf/NA10P1PRD075/guest/categorydetail/categ000000000003042/true/xxemptyxx/',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -4,35 +4,49 @@ import Link from '@docusaurus/Link';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
import {addDarkToFileName} from '../../../util/util';
|
||||
export default function AmbassadorCard({
|
||||
data
|
||||
}) {
|
||||
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
faSquareCheck,
|
||||
faCalendarClock,
|
||||
} from '@fortawesome/pro-duotone-svg-icons';
|
||||
export default function AmbassadorCard({data}) {
|
||||
return (
|
||||
<Link to={data.link} className={styles.link}>
|
||||
|
||||
|
||||
<div className={styles.card}>
|
||||
<div className={styles.cardFaceContainer}>
|
||||
<img className={styles.cardFace} src={useBaseUrl(data.creatorImage)}></img>
|
||||
<img
|
||||
className={styles.cardFace}
|
||||
src={useBaseUrl(data.creatorImage)}></img>
|
||||
<div className={styles.cardNameContainer}>
|
||||
<div className={styles.name}>{data.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.bio} dangerouslySetInnerHTML={{__html: data.bio}}></div>
|
||||
<div
|
||||
className={styles.bio}
|
||||
dangerouslySetInnerHTML={{__html: data.bio}}></div>
|
||||
|
||||
<div className={styles.cardData}>
|
||||
<img className={styles.cardEye} src={useBaseUrl('/icons/square-check-regular.svg')}></img>
|
||||
<div className={styles.cardCommentText}>{data.answers} solutions</div>
|
||||
<FontAwesomeIcon
|
||||
icon={faSquareCheck}
|
||||
className={styles.docCardIcon}
|
||||
size="lg"
|
||||
/>
|
||||
<div className={styles.cardCommentTextUpper}>
|
||||
{data.answers} solutions
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.cardDataLower}>
|
||||
<img className={styles.cardEye} src={useBaseUrl('/icons/calendar-clock-light.svg')}></img>
|
||||
<div className={styles.cardCommentText}>member since {data.member_since}</div>
|
||||
<FontAwesomeIcon
|
||||
icon={faCalendarClock}
|
||||
className={styles.docCardIcon}
|
||||
size="lg"
|
||||
/>
|
||||
<div className={styles.cardCommentText}>
|
||||
member since {data.member_since}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,16 +10,23 @@
|
||||
.card {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
min-height: 500px;
|
||||
|
||||
width: 365px;
|
||||
min-height: 545px;
|
||||
|
||||
/* UI Properties */
|
||||
background: var(--dev-card-background);
|
||||
box-shadow: var(--dev-card-shadow);
|
||||
border: 1px solid var(--dev-card-background);
|
||||
border-radius: 40px;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
background: var(--dev-new-car-background);
|
||||
border-radius: 0.5rem;
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
border: 1px solid var(--dev-card-border);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
@@ -28,10 +35,6 @@
|
||||
box-shadow: var(--dev-card-selected);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cardFaceContainer {
|
||||
display: flex;
|
||||
margin: 30px;
|
||||
@@ -41,8 +44,8 @@
|
||||
border-radius: 99px;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.cardNameContainer {
|
||||
@@ -53,7 +56,7 @@
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 25px;
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
width: 100%;
|
||||
top: 124px;
|
||||
@@ -89,19 +92,16 @@
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.bio {
|
||||
margin: 30px auto;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
width: 100%;
|
||||
color: var(--ifm-color-primary);
|
||||
padding: 30px;
|
||||
padding: 0px 30px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
|
||||
.cardData {
|
||||
position: absolute;
|
||||
bottom: 50px;
|
||||
@@ -113,7 +113,8 @@
|
||||
.cardEye {
|
||||
fill: #96a9bb;
|
||||
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||
filter: invert(79%) sepia(12%) saturate(484%) hue-rotate(168deg) brightness(84%) contrast(84%);
|
||||
filter: invert(79%) sepia(12%) saturate(484%) hue-rotate(168deg)
|
||||
brightness(84%) contrast(84%);
|
||||
margin-left: 5px;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
@@ -128,10 +129,23 @@
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.cardCommentTextUpper {
|
||||
color: #96a9ba;
|
||||
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||
margin-left: 10px;
|
||||
margin-bottom: 5px;
|
||||
height: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.cardDataLower {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 22px;
|
||||
left: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.docCardIcon {
|
||||
color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
@@ -1,50 +1,56 @@
|
||||
import React from 'react';
|
||||
import styles from './styles.module.css';
|
||||
import AmbassadorCard from '../AmbassadorCard';
|
||||
import BounceLoader from 'react-spinners/BounceLoader';
|
||||
import NewtonsCradle from '../../newtonsCradle';
|
||||
import {discourseBaseURL, developerWebsiteDomain} from '../../../util/util';
|
||||
|
||||
import {getAmbassadors, getAmbassadorDetails} from '../../../services/DiscourseService';
|
||||
export default function AmbassadorCards({
|
||||
expert
|
||||
}) {
|
||||
import {
|
||||
getAmbassadors,
|
||||
getAmbassadorDetails,
|
||||
} from '../../../services/DiscourseService';
|
||||
export default function AmbassadorCards({expert}) {
|
||||
const [cardData, setCardData] = React.useState();
|
||||
const [loadingCards, setLoadingCards] = React.useState(true);
|
||||
|
||||
const getPosts = async () => {
|
||||
let data = await getAmbassadors(expert, 1, 0);
|
||||
const resultset = []
|
||||
const resultset = [];
|
||||
|
||||
if (data.meta) {
|
||||
let count = 0
|
||||
let count = 0;
|
||||
while (count < data.meta.total) {
|
||||
data = await getAmbassadors(expert, 50, count);
|
||||
count += 50
|
||||
count += 50;
|
||||
if (data.members) {
|
||||
const memberDetails = await getAmbassadorDetails(data.members.map(item => item.id))
|
||||
const memberDetails = await getAmbassadorDetails(
|
||||
data.members.map((item) => item.id),
|
||||
);
|
||||
for (const member of data.members) {
|
||||
const memberDetail = memberDetails.users.filter(item => item.id === member.id)[0]
|
||||
if (member.avatar_template.includes("developer.sailpoint.com") && memberDetail.bio_excerpt && memberDetail.bio_excerpt.length > 150) {
|
||||
resultset.push(await getMemberList(member, memberDetail))
|
||||
}
|
||||
const memberDetail = memberDetails.users.filter(
|
||||
(item) => item.id === member.id,
|
||||
)[0];
|
||||
if (
|
||||
member.avatar_template.includes('developer.sailpoint.com') &&
|
||||
memberDetail.bio_excerpt &&
|
||||
memberDetail.bio_excerpt.length > 150
|
||||
) {
|
||||
resultset.push(await getMemberList(member, memberDetail));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setCardData(undefined);
|
||||
setLoadingCards(false);
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
resultset.sort((a, b) => a.date - b.date)
|
||||
resultset.sort((a, b) => a.date - b.date);
|
||||
setCardData(resultset);
|
||||
|
||||
setLoadingCards(false);
|
||||
};
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
getPosts();
|
||||
setCardData(undefined);
|
||||
@@ -55,25 +61,17 @@ export default function AmbassadorCards({
|
||||
return (
|
||||
<div className={styles.center}>
|
||||
<div className={styles.gridContainer}>
|
||||
{cardData.map(function(a, index){
|
||||
return <AmbassadorCard
|
||||
key={a.link}
|
||||
data={a}
|
||||
></AmbassadorCard>
|
||||
{cardData.map(function (a, index) {
|
||||
return <AmbassadorCard key={a.link} data={a}></AmbassadorCard>;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (loadingCards) {
|
||||
return (
|
||||
<BounceLoader
|
||||
className={styles.spinnerCenter}
|
||||
color={'#0033a1'}
|
||||
loading={true}
|
||||
size={150}
|
||||
aria-label="Loading Spinner"
|
||||
data-testid="loader"
|
||||
/>
|
||||
<div className={styles.spinnerCenter}>
|
||||
<NewtonsCradle />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
@@ -86,38 +84,37 @@ export default function AmbassadorCards({
|
||||
}
|
||||
|
||||
async function getMemberList(member, details) {
|
||||
|
||||
return {
|
||||
name: member.name,
|
||||
creatorImage: getavatarURL(member.avatar_template),
|
||||
title: member.title,
|
||||
bio: details.bio_excerpt,
|
||||
member_since: new Date(member.added_at).toLocaleString('default', {month: 'long'}) + ' ' + new Date(member.added_at).toISOString().slice(0, 4),
|
||||
member_since:
|
||||
new Date(member.added_at).toLocaleString('default', {month: 'long'}) +
|
||||
' ' +
|
||||
new Date(member.added_at).toISOString().slice(0, 4),
|
||||
badge_count: details.badge_count,
|
||||
answers: details.accepted_answers,
|
||||
location: details.location,
|
||||
website: details.website_name,
|
||||
link:
|
||||
discourseBaseURL() + 'u/' +
|
||||
member.username +
|
||||
'/summary',
|
||||
link: discourseBaseURL() + 'u/' + member.username + '/summary',
|
||||
};
|
||||
}
|
||||
|
||||
function getavatarURL(avatar) {
|
||||
if (avatar.includes(developerWebsiteDomain())) {
|
||||
return "https://" + developerWebsiteDomain() + avatar.replace("{size}", "120")
|
||||
return (
|
||||
'https://' + developerWebsiteDomain() + avatar.replace('{size}', '120')
|
||||
);
|
||||
} else {
|
||||
return avatar.replace("{size}", "120")
|
||||
return avatar.replace('{size}', '120');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function styleExcerpt(excerpt) {
|
||||
if (excerpt.length > 150) {
|
||||
return excerpt.slice(0, 150) + "..."
|
||||
return excerpt.slice(0, 150) + '...';
|
||||
} else {
|
||||
return excerpt.replace("…", "")
|
||||
return excerpt.replace('…', '');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
/* Getting Started Card container */
|
||||
.gridContainer {
|
||||
display: grid;
|
||||
place-content: center;
|
||||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
grid-gap: 40px;
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
width: 1620px;
|
||||
}
|
||||
|
||||
.center {
|
||||
margin: 0px auto;
|
||||
max-width: 1300px;
|
||||
margin-bottom: 50px;
|
||||
width: 1620px;
|
||||
}
|
||||
|
||||
.space {
|
||||
@@ -26,10 +25,38 @@
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.spinnerCenter {
|
||||
margin: 100px auto;
|
||||
max-width: 1300px;
|
||||
margin: auto;
|
||||
width: 4%;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1950px) {
|
||||
.gridContainer {
|
||||
width: 1215px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 1215px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1315px) {
|
||||
.gridContainer {
|
||||
width: 810px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 810px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 910px) {
|
||||
.gridContainer {
|
||||
width: 365px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 365px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,8 @@ import Link from '@docusaurus/Link';
|
||||
|
||||
export default function BlogBanner() {
|
||||
return (
|
||||
<div>
|
||||
|
||||
<div className={styles.imageContainer}>
|
||||
<img className={styles.headerImage} src={useBaseUrl('/blog/blog_banner_template.png')}></img>
|
||||
<div className={styles.blogHeaderText}>
|
||||
Blog
|
||||
</div>
|
||||
</div >
|
||||
<div className={styles.titleContainer}>
|
||||
{/* <h1 className={styles.blogTitle}>Blog</h1> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
|
||||
.blogHeaderText {
|
||||
position: relative;
|
||||
.blogTitle {
|
||||
text-align: center;
|
||||
margin-bottom: 2%;
|
||||
color: #ffffff;
|
||||
font-size: 48px;
|
||||
max-width: 396px;
|
||||
font-weight: bold;
|
||||
line-height: 133%;
|
||||
top: -84px;
|
||||
left: 59px;
|
||||
position: relative;
|
||||
top: 25px;
|
||||
}
|
||||
|
||||
.background {
|
||||
.titleContainer {
|
||||
width: 100%;
|
||||
object-fit: repeat;
|
||||
height: 100%;
|
||||
height: 45px;
|
||||
background: rgb(0, 51, 161);
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 51, 161, 1) 0%,
|
||||
rgba(84, 192, 232, 1) 100%
|
||||
);
|
||||
align-content: center;
|
||||
margin-bottom: 2%;
|
||||
}
|
||||
|
||||
.imageContainer {
|
||||
width: 100%;
|
||||
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;
|
||||
}
|
||||
@@ -2,55 +2,45 @@ import React from 'react';
|
||||
import styles from './styles.module.css';
|
||||
import Link from '@docusaurus/Link';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
import {addDarkToFileName} from '../../../util/util';
|
||||
export default function BlogCard({
|
||||
featured,
|
||||
link,
|
||||
title,
|
||||
tags,
|
||||
creatorImage,
|
||||
creatorTitle,
|
||||
image,
|
||||
excerpt,
|
||||
name,
|
||||
views,
|
||||
replies,
|
||||
readTime
|
||||
readTime,
|
||||
}) {
|
||||
|
||||
return (
|
||||
<Link to={link}>
|
||||
<div className={styles.card} >
|
||||
|
||||
<div className={styles.cardData}>
|
||||
<img className={styles.cardEye} src={useBaseUrl('/blog/eye-regular.svg')}></img>
|
||||
<div className={styles.cardCommentText}>{views}</div>
|
||||
<img className={styles.cardComment} src={useBaseUrl('/blog/comment-light.svg')}></img>
|
||||
<div className={styles.cardCommentText}>{replies}</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.cardUser}>
|
||||
<img className={styles.cardFace} src={useBaseUrl(creatorImage)}></img>
|
||||
<div className={styles.cardName}>{name}</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={featured ? styles.featuredCard : styles.card}>
|
||||
<div className={styles.cardText}>
|
||||
<img className={styles.cardImage} src={useBaseUrl(image)}></img>
|
||||
<div className={styles.cardTitle}>{title}</div>
|
||||
<div className={styles.tags}>
|
||||
{tags?.map((tag, index) => {
|
||||
if (index > 2) {
|
||||
return '';
|
||||
}
|
||||
return <div key={tag} className={styles.tag}>{tag}</div>;
|
||||
})}
|
||||
<img
|
||||
className={featured ? styles.featuredCardImage : styles.cardImage}
|
||||
src={useBaseUrl(image)}></img>
|
||||
<div className={styles.split}></div>
|
||||
|
||||
<div
|
||||
className={featured ? styles.featuredCardTitle : styles.cardTitle}>
|
||||
{title}
|
||||
</div>
|
||||
|
||||
<div className={styles.cardUser}>
|
||||
<img
|
||||
className={featured ? styles.featuredCardFace : styles.cardFace}
|
||||
src={useBaseUrl(creatorImage)}></img>
|
||||
|
||||
<div className={styles.cardName}>{name}</div>
|
||||
<div className={styles.cardCreatorTitle}>{creatorTitle}</div>
|
||||
|
||||
<div></div>
|
||||
</div>
|
||||
<div className={styles.cardBody}>{excerpt}</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
|
||||
@@ -1,127 +1,197 @@
|
||||
/* Getting Started Card */
|
||||
.card {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
height: 650px;
|
||||
/* UI Properties */
|
||||
background: var(--dev-card-background);
|
||||
box-shadow: var(--dev-card-shadow);
|
||||
border: 1px solid var(--dev-card-background);
|
||||
border-radius: 40px;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
max-width: 600px;
|
||||
transition: all 0.3s;
|
||||
width: 275px;
|
||||
max-width: 275px;
|
||||
background: var(--dev-new-car-background);
|
||||
border-radius: 0.5rem;
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
border: 1px solid var(--dev-card-border);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
.featuredCard {
|
||||
position: relative;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
width: 400px;
|
||||
height: 475px;
|
||||
background: var(--dev-new-car-background);
|
||||
border-radius: 0.5rem;
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
border: 1px solid var(--dev-card-border);
|
||||
}
|
||||
|
||||
.featuredCardImage {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 400px;
|
||||
height: 225px;
|
||||
border-top-left-radius: 0.5rem;
|
||||
border-top-right-radius: 0.5rem;
|
||||
}
|
||||
|
||||
a:link {
|
||||
text-decoration: none;
|
||||
}
|
||||
a:visited {
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
a:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.card:hover,
|
||||
.featuredCard:hover {
|
||||
cursor: pointer;
|
||||
transform: translate(0px, -5px);
|
||||
box-shadow: var(--dev-card-selected);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cardText {
|
||||
position: absolute;
|
||||
margin: 22px;
|
||||
min-width: 170px;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.cardImage {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 300px;
|
||||
height: 144px;
|
||||
border-top-left-radius: 0.5rem;
|
||||
border-top-right-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.featuredCardTitle {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
padding-right: 1rem;
|
||||
padding-left: 1rem;
|
||||
text-align: left;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.cardTitle {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cardBody {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.tag {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--dev-secondary-text);
|
||||
background-color: var(--dev-tag-highlight);
|
||||
padding: 0px 8px;
|
||||
margin-left: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
padding-right: 0.5rem;
|
||||
padding-left: 0.5rem;
|
||||
text-align: left;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cardUser {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 25px;
|
||||
display: flex;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 5%;
|
||||
}
|
||||
|
||||
.cardFace {
|
||||
border-radius: 9999px;
|
||||
margin: auto;
|
||||
margin-left: 2%;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.featuredCardFace {
|
||||
border-radius: 9999px;
|
||||
margin-left: 2%;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.cardName {
|
||||
min-width: 170px;
|
||||
font-weight: 800;
|
||||
margin-top: 7px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cardData {
|
||||
position: absolute;
|
||||
bottom: 50px;
|
||||
left: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.cardEye {
|
||||
fill: #96a9bb;
|
||||
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||
filter: invert(79%) sepia(12%) saturate(484%) hue-rotate(168deg) brightness(84%) contrast(84%);
|
||||
margin-left: 5px;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.cardComment {
|
||||
.cardCreatorTitle {
|
||||
min-width: 170px;
|
||||
margin-left: 10px;
|
||||
fill: #96a9bb;
|
||||
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||
filter: invert(79%) sepia(12%) saturate(484%) hue-rotate(168deg) brightness(84%) contrast(84%);
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
margin-bottom: 4px;
|
||||
display: flex;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.cardCommentText {
|
||||
color: #96a9ba;
|
||||
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||
margin-left: 5px;
|
||||
margin-bottom: 5px;
|
||||
height: 20px;
|
||||
font-size: 16px;
|
||||
.featuredCardName {
|
||||
min-width: 170px;
|
||||
font-weight: 800;
|
||||
margin-top: 7px;
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.featuredCardCreatorTitle {
|
||||
min-width: 170px;
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.split {
|
||||
background: linear-gradient(
|
||||
145deg,
|
||||
rgba(0, 51, 161, 1) 40%,
|
||||
rgba(0, 79, 181, 1) 65%,
|
||||
rgba(0, 113, 206, 1) 100%
|
||||
);
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 550px) {
|
||||
.cardText {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.featuredCard {
|
||||
width: 275px;
|
||||
max-width: 275px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.featuredCardImage {
|
||||
width: 275px;
|
||||
height: 144px;
|
||||
}
|
||||
|
||||
.featuredCardTitle {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.featuredCardFace {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
import React from 'react';
|
||||
import styles from './styles.module.css';
|
||||
import BlogCard from '../BlogCard';
|
||||
import BounceLoader from 'react-spinners/BounceLoader';
|
||||
import NewtonsCradle from '../../newtonsCradle';
|
||||
import {discourseBaseURL, developerWebsiteDomain} from '../../../util/util';
|
||||
import {getBlogPosts, getUserTitle} from '../../../services/DiscourseService';
|
||||
|
||||
import {getBlogPosts, getTopic} from '../../../services/DiscourseService';
|
||||
export default function BlogCards({filterCallback}) {
|
||||
export default function BlogCards({filterCallback, limit, featured}) {
|
||||
const [cardData, setCardData] = React.useState();
|
||||
const [loadingCards, setLoadingCards] = React.useState(true);
|
||||
|
||||
const getPosts = async () => {
|
||||
const data = await getBlogPosts(filterCallback.join('+'));
|
||||
if (!filterCallback) {
|
||||
filterCallback = ['identity-security-cloud'];
|
||||
}
|
||||
|
||||
if (featured) {
|
||||
filterCallback = ['featured'];
|
||||
}
|
||||
const data = await getBlogPosts(filterCallback.join('+'));
|
||||
const resultset = [];
|
||||
const titleList = [];
|
||||
if (data.topic_list.topics) {
|
||||
for (const topic of data.topic_list.topics) {
|
||||
if (topic.tags.length > 0) {
|
||||
@@ -21,80 +28,106 @@ export default function BlogCards({filterCallback}) {
|
||||
if (topicUser.description.includes('Original Poster')) {
|
||||
for (let user of data.users) {
|
||||
if (user.id === topicUser.user_id) {
|
||||
if (
|
||||
!titleList.find((x) => x.group === user.primary_group_name)
|
||||
) {
|
||||
let usertitle = await getUserTitle(user.primary_group_name);
|
||||
titleList.push({
|
||||
group: user.primary_group_name,
|
||||
title: usertitle.group.title,
|
||||
});
|
||||
user.title = usertitle.group.title;
|
||||
} else {
|
||||
user.title = titleList.find(
|
||||
(x) => x.group === user.primary_group_name,
|
||||
).title;
|
||||
}
|
||||
poster = user;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (topic.category_id !== 57) {
|
||||
resultset.push(await getPostList(topic, poster));
|
||||
if (featured || (!featured && !topic.tags.includes('featured'))) {
|
||||
resultset.push(await getPostList(topic, poster));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setCardData(resultset);
|
||||
if (limit) {
|
||||
setCardData(resultset.slice(0, limit));
|
||||
} else {
|
||||
setCardData(resultset);
|
||||
}
|
||||
} else {
|
||||
setCardData(undefined);
|
||||
}
|
||||
setLoadingCards(false);
|
||||
};
|
||||
|
||||
function shortenTitle(title) {
|
||||
if (title.length > 63) {
|
||||
return title.substring(0, 62) + '...';
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
getPosts();
|
||||
setCardData(undefined);
|
||||
setLoadingCards(true);
|
||||
}, [filterCallback]);
|
||||
|
||||
if (cardData && cardData.length > 0) {
|
||||
return (
|
||||
<div className={styles.center}>
|
||||
<div className={styles.gridContainer}>
|
||||
{cardData.map(function (a, index) {
|
||||
return (
|
||||
<BlogCard
|
||||
key={a.link}
|
||||
id={index + a.link}
|
||||
excerpt={a.excerpt}
|
||||
name={a.name}
|
||||
tags={a.tags}
|
||||
link={a.link}
|
||||
image={a.image}
|
||||
title={a.title}
|
||||
views={a.views}
|
||||
replies={a.replies}
|
||||
readTime={a.readTime}
|
||||
creatorImage={a.creatorImage}></BlogCard>
|
||||
);
|
||||
})}
|
||||
return (
|
||||
<div className={featured ? styles.featuredCenter : styles.center}>
|
||||
{loadingCards ? (
|
||||
// Show loading icon when data is still loading
|
||||
<div
|
||||
className={
|
||||
featured ? styles.featuredSpinnerCenter : styles.spinnerCenter
|
||||
}>
|
||||
<NewtonsCradle />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (loadingCards) {
|
||||
return (
|
||||
<BounceLoader
|
||||
className={styles.spinnerCenter}
|
||||
color={'#0033a1'}
|
||||
loading={true}
|
||||
size={150}
|
||||
aria-label="Loading Spinner"
|
||||
data-testid="loader"
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className={styles.noFound}>
|
||||
{' '}
|
||||
No Blogposts Found with the Given Search Criteria
|
||||
</div>
|
||||
);
|
||||
}
|
||||
) : cardData && cardData.length > 0 ? (
|
||||
// Show cards if not loading and cardData is available
|
||||
<div
|
||||
className={
|
||||
featured ? styles.featuredGridContainer : styles.gridContainer
|
||||
}>
|
||||
{cardData.map((a, index) => (
|
||||
<BlogCard
|
||||
featured={featured}
|
||||
key={a.link}
|
||||
id={index + a.link}
|
||||
excerpt={a.excerpt}
|
||||
name={a.name}
|
||||
tags={a.tags}
|
||||
link={a.link}
|
||||
image={a.image}
|
||||
title={shortenTitle(a.title)}
|
||||
views={a.views}
|
||||
replies={a.replies}
|
||||
readTime={a.readTime}
|
||||
creatorImage={a.creatorImage}
|
||||
creatorTitle={a.creatorTitle}></BlogCard>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
// Show no content message if not loading and no cardData
|
||||
<div className={styles.noFound}>
|
||||
No Blogposts Found with the Given Search Criteria
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
async function getPostList(topic, user) {
|
||||
console.log(topic);
|
||||
return {
|
||||
name: user.name,
|
||||
excerpt: styleExcerpt(topic.excerpt),
|
||||
creatorImage: getavatarURL(user.avatar_template),
|
||||
creatorTitle: user.title,
|
||||
tags: topic.tags,
|
||||
image: topic.image_url,
|
||||
link: discourseBaseURL() + 't/' + topic.slug + '/' + topic.id,
|
||||
@@ -103,7 +136,7 @@ async function getPostList(topic, user) {
|
||||
liked: topic.like_count,
|
||||
replies: topic.posts_count,
|
||||
solution: topic.has_accepted_answer,
|
||||
readTime: parseInt(500 / 100),
|
||||
readTime: parseInt(500 / 200),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
/* Getting Started Card container */
|
||||
.featuredGridContainer {
|
||||
display: flex;
|
||||
margin-left: 9%;
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.gridContainer {
|
||||
display: grid;
|
||||
place-content: center;
|
||||
grid-template-columns: repeat(auto-fit, minmax(345px, 1fr));
|
||||
grid-gap: 40px;
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
display: flex;
|
||||
/* place-content: center; */
|
||||
flex-wrap: wrap;
|
||||
gap: 23px;
|
||||
margin-left: 20px;
|
||||
justify-content: left;
|
||||
min-height: 600px;
|
||||
width: 1500px;
|
||||
}
|
||||
|
||||
.center {
|
||||
margin: 0px auto;
|
||||
max-width: 1300px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.space {
|
||||
height: 200px;
|
||||
width: 50%;
|
||||
width: 1500px;
|
||||
}
|
||||
|
||||
.noFound {
|
||||
@@ -26,10 +31,90 @@
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
|
||||
.featuredSpinnerCenter {
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
margin-top: 45%;
|
||||
}
|
||||
|
||||
.spinnerCenter {
|
||||
margin: 100px auto;
|
||||
max-width: 1300px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
position: absolute;
|
||||
left: 48%;
|
||||
top: 1025px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1950px) {
|
||||
.gridContainer {
|
||||
width: 1225px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 1225px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1350px) {
|
||||
.gridContainer {
|
||||
width: 950px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 950px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1050px) {
|
||||
.gridContainer {
|
||||
width: 675px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 675px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 700px) {
|
||||
.gridContainer {
|
||||
width: 275px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 275px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 550px) {
|
||||
.featuredGridContainer {
|
||||
margin-left: 0%;
|
||||
min-height: 350px;
|
||||
width: 275px;
|
||||
margin: auto;
|
||||
}
|
||||
.featuredCenter {
|
||||
width: 275px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.gridContainer,
|
||||
.featuredGridContainer {
|
||||
justify-content: center;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.spinnerCenter {
|
||||
left: 43%;
|
||||
top: 1225px;
|
||||
}
|
||||
|
||||
.featuredSpinnerCenter {
|
||||
width: 20%;
|
||||
margin: auto;
|
||||
margin-top: 35%;
|
||||
}
|
||||
|
||||
.noFound {
|
||||
width: 350px;
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +1,56 @@
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import styles from './styles.module.css';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import Link from '@docusaurus/Link';
|
||||
import { getTags } from '../../../services/DiscourseService';
|
||||
import BlogSidebarButton from './BlogSidebarButton';
|
||||
import {getTags} from '../../../services/DiscourseService';
|
||||
|
||||
export default function BlogSidebar({
|
||||
filterCallback
|
||||
}) {
|
||||
export default function BlogSidebar({filterCallback, defaultValue}) {
|
||||
const [tagProductData, setTagProductData] = React.useState();
|
||||
const [tagTechnologyData, setTagTechnologyData] = React.useState();
|
||||
const [filterTags, setFilterTags] = React.useState(true);
|
||||
let initialCheckState = defaultValue === 'Identityiq' ? true : false;
|
||||
const [isChecked, setIsChecked] = React.useState(initialCheckState);
|
||||
|
||||
const handleChange = () => {
|
||||
setIsChecked(!isChecked);
|
||||
let value = isChecked ? 'Identity-Security-Cloud' : 'Identityiq';
|
||||
filterCallback(value);
|
||||
};
|
||||
|
||||
const getTagData = async () => {
|
||||
const data = await getTags();
|
||||
const tagTechnologyResultset = []
|
||||
const tagProductResultset = []
|
||||
const tagTechnologyResultset = [];
|
||||
const tagProductResultset = [];
|
||||
for (const tagGroup of data.extras.tag_groups) {
|
||||
if (tagGroup.id === 45) {
|
||||
for (const tag of tagGroup.tags) {
|
||||
tagProductResultset.push(tag.text)
|
||||
}
|
||||
}
|
||||
if (tagGroup.id === 17) {
|
||||
for (const tag of tagGroup.tags) {
|
||||
tagTechnologyResultset.push(tag.text)
|
||||
tagProductResultset.push(tag.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
setTagProductData(tagProductResultset)
|
||||
setTagTechnologyData(tagTechnologyResultset)
|
||||
setTagProductData(tagProductResultset);
|
||||
};
|
||||
|
||||
function toggleSeeAll() {
|
||||
filterTags ? setFilterTags(false) : setFilterTags(true)
|
||||
}
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
getTagData();
|
||||
}, []);
|
||||
},[]);
|
||||
|
||||
const filterText = filterTags ? 'See All Tags' : 'See Less Tags'
|
||||
|
||||
if (tagProductData && tagTechnologyData) {
|
||||
if (tagProductData) {
|
||||
return (
|
||||
<div className={styles.sidebar}>
|
||||
<div className={styles.tagHeader}>Blogs by Product</div>
|
||||
<div className={styles.tagContainer}>
|
||||
{tagProductData.map(function(a, index){
|
||||
return <BlogSidebarButton key={a} text={a} filterCallback={filterCallback}></BlogSidebarButton>
|
||||
})}
|
||||
</div>
|
||||
<div className={styles.tagHeader}>Blogs by Identity Governance</div>
|
||||
<div className={styles.tagContainer}>
|
||||
{tagTechnologyData.map(function(a, index){
|
||||
return <div key={'div' + a} className={index > 10 && filterTags ? styles.hidden : ''} > <BlogSidebarButton key={a} text={a} filterCallback={filterCallback}></BlogSidebarButton></div>
|
||||
})}
|
||||
</div>
|
||||
<div className={styles.seeAll} onClick={(e) => toggleSeeAll()}>
|
||||
{filterText}
|
||||
{/* <img className={styles.caretDown} src={useBaseUrl('/blog/caret-down-thin.svg')}></img> */}
|
||||
<div className={styles.toggleContainer}>
|
||||
<div className={styles.toggleWrapper}>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="product-toggle"
|
||||
className={styles.toggleCheckbox}
|
||||
checked={isChecked}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<label htmlFor="product-toggle" className={styles.toggleLabel}>
|
||||
<div className={styles.toggleBackground}></div>
|
||||
<span className={styles.toggleTextLeft}>
|
||||
Identity Security Cloud
|
||||
</span>
|
||||
<span className={styles.toggleTextRight}>IdentityIQ</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
} else {
|
||||
return <div></div>;
|
||||
|
||||
@@ -1,8 +1,31 @@
|
||||
|
||||
.sidebar {
|
||||
width: 400px;
|
||||
height: 100%;
|
||||
margin-top: 50px;
|
||||
margin-left: 50px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.toggleContainer {
|
||||
margin: auto;
|
||||
/* width: 31%; */
|
||||
margin-bottom: 3%;
|
||||
}
|
||||
|
||||
/* @media screen and (max-width: 2100px) {
|
||||
.toggleContainer {
|
||||
width: 43%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
.toggleContainer {
|
||||
width: 82%;
|
||||
}
|
||||
} */
|
||||
|
||||
.title {
|
||||
margin-left: 2%;
|
||||
margin-bottom: 2%;
|
||||
margin-top: 2%;
|
||||
}
|
||||
|
||||
.tagHeader {
|
||||
@@ -16,7 +39,6 @@
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
@@ -30,7 +52,6 @@
|
||||
width: 100%;
|
||||
transition: background-color 500ms;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
.seeAll:hover {
|
||||
@@ -38,3 +59,181 @@
|
||||
background-color: var(--dev-text-color-normal);
|
||||
color: var(--dev-card-background);
|
||||
}
|
||||
|
||||
.dropdownContainer {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-left: 2%;
|
||||
}
|
||||
|
||||
.buttonText {
|
||||
float: left;
|
||||
margin-left: 5%;
|
||||
font-size: 16px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.dropdownButton {
|
||||
background-color: var(
|
||||
--dropdown-background
|
||||
); /* Dropdown background color */ /* Text color */
|
||||
padding: 14px 45px; /* Padding inside the dropdown button */
|
||||
border: 2px solid #cccccc; /* Border around the dropdown */
|
||||
border-radius: 5px; /* Rounded corners */
|
||||
cursor: pointer; /* Change mouse cursor to indicate it's clickable */
|
||||
position: relative; /* To position the arrow icon correctly */
|
||||
display: inline-block; /* To keep the button's block behavior */
|
||||
margin-bottom: 10%;
|
||||
padding-left: 1%;
|
||||
width: 220px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.dropdownButton:after {
|
||||
content: '▼'; /* Adds a dropdown arrow after the button text */
|
||||
position: absolute;
|
||||
right: 10px; /* Position the arrow to the right */
|
||||
top: 50%; /* Align vertically */
|
||||
transform: translateY(-50%); /* Center the arrow vertically */
|
||||
pointer-events: none; /* Prevent the arrow from being clickable */
|
||||
}
|
||||
|
||||
.dropdownButton:hover {
|
||||
background-color: var(
|
||||
--dev-card-background
|
||||
); /* Lighter background on hover */
|
||||
}
|
||||
|
||||
.dropdownButton:focus {
|
||||
outline: none; /* Remove default focus outline */
|
||||
border-color: #666666; /* Darker border color when focused */
|
||||
}
|
||||
|
||||
.dropdownContent {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: var(--dropdown-background);
|
||||
min-width: 300px;
|
||||
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
|
||||
z-index: 1;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
overflow-y: scroll;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
.dropdownContainer .dropdownContent label {
|
||||
display: flex;
|
||||
margin: 5px 5px;
|
||||
}
|
||||
|
||||
.dropdownContainer:hover .dropdownContent {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdownItem {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.dropdownItem:hover {
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
background-color: var(--dev-tag-highlight);
|
||||
}
|
||||
|
||||
.toggleWrapper {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
height: 50px;
|
||||
border-radius: 25px;
|
||||
background-color: #ddd;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.toggleCheckbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggleCheckbox:checked + .toggleLabel .toggleBackground {
|
||||
transform: translateX(100%);
|
||||
background-color: #93d500; /* IIQ color */
|
||||
}
|
||||
|
||||
.toggleCheckbox:not(:checked) + .toggleLabel .toggleBackground {
|
||||
background-color: #cc27b0;
|
||||
}
|
||||
|
||||
.toggleLabel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.toggleBackground {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 50%;
|
||||
background-color: #cc27b0; /* Default color for "Identity Security Cloud" */
|
||||
border-radius: 25px;
|
||||
transition: transform 0.25s ease, background-color 0.25s ease;
|
||||
}
|
||||
|
||||
.toggleText {
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.toggleCheckbox:not(:checked) + .toggleLabel .toggleTextLeft {
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
transition: color 0.25s;
|
||||
color: white; /* "Identity Security Cloud" highlighted */
|
||||
}
|
||||
|
||||
.toggleCheckbox:not(:checked) + .toggleLabel .toggleTextRight {
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
transition: color 0.25s;
|
||||
color: #415364; /* "IdentityIQ" not highlighted */
|
||||
}
|
||||
|
||||
.toggleCheckbox:checked + .toggleLabel .toggleTextRight {
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
transition: color 0.25s;
|
||||
color: white; /* "IdentityIQ" highlighted */
|
||||
}
|
||||
|
||||
.toggleCheckbox:checked + .toggleLabel .toggleTextLeft {
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
transition: color 0.25s;
|
||||
color: #415364; /* "Identity Security Cloud" not highlighted */
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 550px) {
|
||||
.toggleTextLeft {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.toggleWrapper {
|
||||
width: 325px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import Link from '@docusaurus/Link';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
import {addDarkToFileName} from '../../../util/util';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {faSquareCheck, faEye} from '@fortawesome/pro-duotone-svg-icons';
|
||||
export default function DiscussCard({
|
||||
link,
|
||||
title,
|
||||
@@ -20,12 +22,11 @@ export default function DiscussCard({
|
||||
let linkText = <div className={styles.linkText}>Join the Discussion</div>;
|
||||
if (solution) {
|
||||
solved = (
|
||||
<ThemedImage
|
||||
<FontAwesomeIcon
|
||||
icon={faSquareCheck}
|
||||
className={styles.cardSolved}
|
||||
sources={{
|
||||
light: useBaseUrl('/homepage/solved.png'),
|
||||
dark: useBaseUrl(addDarkToFileName('/homepage/solved.png')),
|
||||
}}></ThemedImage>
|
||||
size="lg"
|
||||
/>
|
||||
);
|
||||
linkText = <div className={styles.linkSolvedText}>View the Solution</div>;
|
||||
}
|
||||
@@ -44,12 +45,7 @@ export default function DiscussCard({
|
||||
light: useBaseUrl('/homepage/arrow-right.png'),
|
||||
dark: useBaseUrl('/homepage/arrow-right-dark.png'),
|
||||
}}></ThemedImage>
|
||||
<ThemedImage
|
||||
className={styles.cardEye}
|
||||
sources={{
|
||||
light: useBaseUrl('/homepage/eyeball.png'),
|
||||
dark: useBaseUrl(addDarkToFileName('/homepage/eyeball.png')),
|
||||
}}></ThemedImage>
|
||||
<FontAwesomeIcon icon={faEye} className={styles.cardEye} size="lg" />
|
||||
<img
|
||||
className={styles.cardLiked}
|
||||
src={useBaseUrl('/homepage/liked.png')}></img>
|
||||
@@ -64,7 +60,11 @@ export default function DiscussCard({
|
||||
if (index > 2) {
|
||||
return '';
|
||||
}
|
||||
return <div key={tag} className={styles.tag}>{tag}</div>;
|
||||
return (
|
||||
<div key={tag} className={styles.tag}>
|
||||
{tag}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,11 +4,19 @@
|
||||
margin-top: 20px;
|
||||
height: 300px;
|
||||
/* UI Properties */
|
||||
background: var(--dev-card-background);
|
||||
box-shadow: var(--dev-card-shadow);
|
||||
border: 1px solid var(--dev-card-background);
|
||||
border-radius: 40px;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
background: var(--dev-new-car-background);
|
||||
border-radius: 0.5rem;
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
border: 1px solid var(--dev-card-border);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
@@ -85,6 +93,7 @@
|
||||
right: 132px;
|
||||
top: 18px;
|
||||
width: 20px;
|
||||
color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
.cardDiscuss {
|
||||
@@ -99,8 +108,8 @@
|
||||
.cardEye {
|
||||
position: absolute;
|
||||
margin: 20px;
|
||||
right: 25px;
|
||||
top: 0;
|
||||
right: 28px;
|
||||
top: -3px;
|
||||
width: 22px;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,12 @@ import Link from '@docusaurus/Link';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import {addDarkToFileName} from '../../../util/util';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
faComments,
|
||||
faPeopleGroup,
|
||||
faUser,
|
||||
} from '@fortawesome/pro-duotone-svg-icons';
|
||||
export default function HomepageBasics({
|
||||
link,
|
||||
title,
|
||||
@@ -21,14 +27,47 @@ export default function HomepageBasics({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
let icon = '';
|
||||
if (image) {
|
||||
switch (image) {
|
||||
case 'discuss': {
|
||||
icon = (
|
||||
<FontAwesomeIcon
|
||||
icon={faComments}
|
||||
className={styles.docCardIcon}
|
||||
size="3x"
|
||||
/>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'team': {
|
||||
icon = (
|
||||
<FontAwesomeIcon
|
||||
icon={faPeopleGroup}
|
||||
className={styles.docCardIcon}
|
||||
size="3x"
|
||||
/>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'user': {
|
||||
icon = (
|
||||
<FontAwesomeIcon
|
||||
icon={faUser}
|
||||
className={styles.docCardIcon}
|
||||
size="3x"
|
||||
/>
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
icon = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className={styles.gettingStartedText}>
|
||||
<ThemedImage
|
||||
className={styles.gettingStartedCardIcon}
|
||||
sources={{
|
||||
light: useBaseUrl(image),
|
||||
dark: useBaseUrl(addDarkToFileName(image)),
|
||||
}}></ThemedImage>
|
||||
{icon}
|
||||
<div className={styles.gettingStartedOne}>{title}</div>
|
||||
<div
|
||||
className={styles.gettingStartedThree}
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
box-shadow: 0px 20px 60px #00000015;
|
||||
border: 2px solid #df61ca;
|
||||
border-radius: 5px;
|
||||
transition: all 0.3s;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.link {
|
||||
@@ -67,3 +67,7 @@
|
||||
color: #df61ca;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.docCardIcon {
|
||||
color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
@@ -11,18 +11,25 @@ export default function HomepageCard({link, title, image, product}) {
|
||||
return (
|
||||
<Link to={link}>
|
||||
<div className={styles.card}>
|
||||
<ThemedImage
|
||||
className={styles.cardIcon}
|
||||
sources={{
|
||||
light: useBaseUrl(image),
|
||||
dark: useBaseUrl(addDarkToFileName(image)),
|
||||
}}></ThemedImage>
|
||||
<ThemedImage
|
||||
className={styles.cardArrow}
|
||||
sources={{
|
||||
light: useBaseUrl('/homepage/arrow-right.png'),
|
||||
dark: useBaseUrl('/homepage/arrow-right-dark.png'),
|
||||
}}></ThemedImage>
|
||||
{image && (
|
||||
<>
|
||||
<ThemedImage
|
||||
className={styles.cardIcon}
|
||||
sources={{
|
||||
light: useBaseUrl(image),
|
||||
dark: useBaseUrl(addDarkToFileName(image)),
|
||||
}}
|
||||
/>
|
||||
|
||||
<ThemedImage
|
||||
className={styles.cardArrow}
|
||||
sources={{
|
||||
light: useBaseUrl('/homepage/arrow-right.png'),
|
||||
dark: useBaseUrl('/homepage/arrow-right-dark.png'),
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div className={styles.cardText}>{title}</div>
|
||||
<div className={`${styles.product} ${productStyles}`}>{product}</div>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
/* Getting Started Card */
|
||||
.card {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
height: 200px;
|
||||
/* UI Properties */
|
||||
background: var(--dev-card-background);
|
||||
box-shadow: var(--dev-card-shadow);
|
||||
border: 1px solid var(--dev-card-background);
|
||||
border-radius: 40px;
|
||||
position: relative;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
background: var(--dev-new-car-background);
|
||||
border-radius: 0.5rem;
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
border: 1px solid var(--dev-card-border);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
@@ -32,7 +40,7 @@
|
||||
margin: 20px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 38px;
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.cardArrow {
|
||||
@@ -60,3 +68,9 @@
|
||||
.iiq {
|
||||
color: #60b359;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 570px) {
|
||||
.cardIcon {
|
||||
width: 15%;
|
||||
}
|
||||
}
|
||||
|
||||
50
src/components/homepage/HomepageDeveloperDays/index.js
Normal file
50
src/components/homepage/HomepageDeveloperDays/index.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import styles from './styles.module.css';
|
||||
import Link from '@docusaurus/Link';
|
||||
import HomepageCard from '../HomepageCard';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
export default function HomepageGettingStarted() {
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.mainCard}>
|
||||
<div className={styles.contentContainer}>
|
||||
<div className={styles.gettingStartedText}>
|
||||
<div className={styles.gettingStartedOne}>
|
||||
SailPoint Developer Days
|
||||
</div>
|
||||
<div className={styles.gettingStartedTwo}>
|
||||
Join us for our annual conference for developers in April!
|
||||
</div>
|
||||
<div className={styles.gettingStartedThree}>
|
||||
Our largest conference for developers, architects, administrators,
|
||||
and more is finally here! Explore
|
||||
<span className={styles.bold}> cutting-edge technologies</span>,
|
||||
gain insights from industry leaders, and connect with fellow
|
||||
developers.
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.gridContainer}>
|
||||
<div>
|
||||
<a
|
||||
href="https://developer.sailpoint.com/discuss/developerdays"
|
||||
className={styles.registerButtonPink}>
|
||||
Register now
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.devDaysImageContainer}>
|
||||
<ThemedImage
|
||||
className={styles.cardIcon}
|
||||
sources={{
|
||||
light: useBaseUrl('/homepage/devdays2024-sm.png'),
|
||||
dark: useBaseUrl('/homepage/devdays2024-dark-sm.png'),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
144
src/components/homepage/HomepageDeveloperDays/styles.module.css
Normal file
144
src/components/homepage/HomepageDeveloperDays/styles.module.css
Normal file
@@ -0,0 +1,144 @@
|
||||
.mainCard {
|
||||
display: grid;
|
||||
grid-gap: 20px;
|
||||
max-width: 1180px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.gettingStartedText {
|
||||
margin-top: 50px;
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.gettingStartedOne {
|
||||
color: var(--ifm-color-primary);
|
||||
font-size: 30px;
|
||||
max-width: 396px;
|
||||
font-weight: bold;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
.gettingStartedTwo {
|
||||
margin-top: 20px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.gettingStartedThree {
|
||||
margin-top: 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Getting Started Card container */
|
||||
.gridContainer {
|
||||
display: grid;
|
||||
margin-left: 50px;
|
||||
margin-bottom: 50px;
|
||||
grid-gap: 20px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
|
||||
place-content: center;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
.video {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.cardIcon {
|
||||
width: 90%;
|
||||
margin-top: 100px;
|
||||
}
|
||||
.registerButton {
|
||||
align-items: center;
|
||||
background: var(--ifm-color-primary);
|
||||
border-radius: 0.5rem;
|
||||
border: none;
|
||||
color: #eee;
|
||||
display: inline-flex;
|
||||
padding: 10px 15px;
|
||||
margin-right: 45px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.registerButtonPink {
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
margin: 10px auto;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
line-height: 100%;
|
||||
width: 259px;
|
||||
height: 61px;
|
||||
line-height: 61px;
|
||||
background: transparent 0% 0% no-repeat padding-box;
|
||||
opacity: 1;
|
||||
box-shadow: 0px 20px 60px #00000015;
|
||||
border: 2px solid #df61ca;
|
||||
border-radius: 0.5rem;
|
||||
color: #df61ca;
|
||||
padding: 10px 15px;
|
||||
margin-right: 45px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.registerButtonPink:hover {
|
||||
cursor: pointer;
|
||||
top: -2px;
|
||||
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.2);
|
||||
background-color: var(--dev-button-hover);
|
||||
color: #cc27b0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1178px) {
|
||||
.carousel {
|
||||
margin-top: 0px;
|
||||
margin-left: 50px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
.contentContainer {
|
||||
width: 600px;
|
||||
}
|
||||
}
|
||||
@media only screen and (min-width: 1179px) {
|
||||
.carousel {
|
||||
margin-top: 100px;
|
||||
}
|
||||
.mainCard {
|
||||
grid-template-columns: repeat(auto-fit, minmax(520px, 1fr));
|
||||
/* UI Properties */
|
||||
background: var(--main-hero-card-background);
|
||||
box-shadow: var(--dev-main-card-shadow);
|
||||
border: 1px solid var(--dev-card-background);
|
||||
border-radius: 40px;
|
||||
opacity: 1;
|
||||
margin: 50px auto;
|
||||
width: calc(100% - 100px);
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 1200px) {
|
||||
.devDaysImageContainer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 570px) {
|
||||
.video {
|
||||
display: none;
|
||||
}
|
||||
.contentContainer {
|
||||
width: auto;
|
||||
}
|
||||
.carousel {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
@@ -25,13 +25,13 @@ export default function HomepageGettingStarted() {
|
||||
<HomepageCard
|
||||
link={'/docs'}
|
||||
title={'Get Started with Identity Security Cloud'}
|
||||
image={'/homepage/cloud.png'}></HomepageCard>
|
||||
image={'/homepage/SailPointIdentitySecurityCloud.svg'}></HomepageCard>
|
||||
<HomepageCard
|
||||
link={
|
||||
'https://documentation.sailpoint.com/identityiq/help/iiqlandingpage.html'
|
||||
}
|
||||
title={'Get Started with IdentityIQ'}
|
||||
image={'/homepage/cloud.png'}></HomepageCard>
|
||||
image={'/homepage/IdentityIQ.svg'}></HomepageCard>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.carousel}>
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function HomepageTeam() {
|
||||
expertise={'Identity Security Cloud'.toUpperCase()}
|
||||
image={'/homepage/tyler-mairose.png'}
|
||||
/>
|
||||
<TeamCard
|
||||
<TeamCard
|
||||
link={'https://developer.sailpoint.com/discuss/u/jthaytko/summary'}
|
||||
name={'James Haytko'}
|
||||
title={'Technical Writer'.toUpperCase()}
|
||||
@@ -41,9 +41,6 @@ export default function HomepageTeam() {
|
||||
expertise={'DEVELOPER TOOLS'}
|
||||
image={'/homepage/phil-ellis.png'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.bottomGridContainer}>
|
||||
<TeamCard
|
||||
link={'https://developer.sailpoint.com/discuss/u/Darrell/summary'}
|
||||
name={'Darrell Thobe'}
|
||||
@@ -51,14 +48,14 @@ export default function HomepageTeam() {
|
||||
expertise={'DEVELOPER TOOLS'}
|
||||
image={'/homepage/darrell-thobe.png'}
|
||||
/>
|
||||
<TeamCard
|
||||
link={'https://developer.sailpoint.com/discuss/u/lukehagar/summary'}
|
||||
name={'Luke Hagar'}
|
||||
title={'Software Engineer'.toUpperCase()}
|
||||
expertise={'DEVELOPER TOOLS'}
|
||||
image={'/homepage/lukehagar.png'}
|
||||
<TeamCard
|
||||
link={'https://developer.sailpoint.com/discuss/u/putty/summary'}
|
||||
name={'Derek Putnam'}
|
||||
title={'Community Manager'.toUpperCase()}
|
||||
expertise={'DEVELOPER COMMUNITY'}
|
||||
image={'/homepage/derek-putnam.png'}
|
||||
/>
|
||||
<TeamCard
|
||||
<TeamCard
|
||||
link={
|
||||
'https://developer.sailpoint.com/discuss/u/jordan_violet/summary'
|
||||
}
|
||||
|
||||
@@ -1,24 +1,45 @@
|
||||
/* Getting Started Card container */
|
||||
.bottomGridContainer {
|
||||
display: grid;
|
||||
place-content: center;
|
||||
grid-template-columns: repeat(auto-fit, minmax(195px, 1fr));
|
||||
grid-gap: 30px;
|
||||
margin-right: 170px;
|
||||
margin-left: 190px;
|
||||
}
|
||||
|
||||
.gridContainer {
|
||||
display: grid;
|
||||
place-content: center;
|
||||
grid-template-columns: repeat(auto-fit, minmax(195px, 1fr));
|
||||
display: flex;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
flex-wrap: wrap;
|
||||
grid-gap: 40px;
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
width: 1100px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.center {
|
||||
margin: 0px auto;
|
||||
max-width: 1300px;
|
||||
margin-bottom: 50px;
|
||||
width: 1100px;
|
||||
margin: auto;
|
||||
padding-bottom: 5%;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1150px) {
|
||||
.gridContainer {
|
||||
width: 820px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 820px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 920px) {
|
||||
.gridContainer {
|
||||
width: 560px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 560px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 660px) {
|
||||
.gridContainer {
|
||||
width: 220px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 220px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,24 +11,25 @@ export default function HomepageTrainingGuides() {
|
||||
product={'isc'}
|
||||
link={'/docs/api/getting-started'}
|
||||
title={'Make Your First API Call'}
|
||||
image={'/homepage/cloud.png'}></HomepageCard>
|
||||
image={'/homepage/cloud-data.svg'}></HomepageCard>
|
||||
<HomepageCard
|
||||
product={'isc'}
|
||||
link={'/docs/extensibility/transforms/guides/your-first-transform'}
|
||||
title={'Build a Transform'}
|
||||
image={'/homepage/cloud.png'}></HomepageCard>
|
||||
image={'/homepage/process.svg'}></HomepageCard>
|
||||
<HomepageCard
|
||||
product={'isc'}
|
||||
link={'/docs/connectivity/saas-connectivity'}
|
||||
title={'Build a SaaS Connector'}
|
||||
image={'/homepage/cloud.png'}></HomepageCard>
|
||||
image={'/homepage/connectivity.svg'}></HomepageCard>
|
||||
<HomepageCard
|
||||
product={'iiq'}
|
||||
link={
|
||||
'https://documentation.sailpoint.com/identityiq/help/plugins/identityiq_plugins.html'
|
||||
}
|
||||
title={'Build an IIQ Plugin'}
|
||||
image={'/homepage/cloud.png'}></HomepageCard>
|
||||
image={'/homepage/puzzle.svg'}
|
||||
isThemedImage={true}></HomepageCard>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -5,11 +5,19 @@
|
||||
height: 300px;
|
||||
width: 220px;
|
||||
/* UI Properties */
|
||||
background: var(--dev-card-background);
|
||||
box-shadow: var(--dev-card-shadow);
|
||||
border: 1px solid var(--dev-card-background);
|
||||
border-radius: 40px;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
background: var(--dev-new-car-background);
|
||||
border-radius: 0.5rem;
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
border: 1px solid var(--dev-card-border);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import styles from './styles.module.css';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
export default function MarketplaceBanner() {
|
||||
return (
|
||||
<div>
|
||||
|
||||
<div className={styles.imageContainer}>
|
||||
<img className={styles.headerImage} src={useBaseUrl('/blog/marketplace_banner_template.png')}></img>
|
||||
<div className={styles.blogHeaderText}>
|
||||
CoLab
|
||||
</div>
|
||||
</div >
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<Link to={'/colab'}>
|
||||
<div className={styles.titleContainer}>
|
||||
{/* <h1 className={styles.colabTitle}>CoLab</h1> */}
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
|
||||
.blogHeaderText {
|
||||
position: relative;
|
||||
.colabTitle {
|
||||
text-align: center;
|
||||
margin-bottom: 2%;
|
||||
color: #ffffff;
|
||||
font-size: 48px;
|
||||
max-width: 459px;
|
||||
font-weight: bold;
|
||||
line-height: 130%;
|
||||
top: -84px;
|
||||
left: 101px;
|
||||
position: relative;
|
||||
top: 25px;
|
||||
}
|
||||
|
||||
.background {
|
||||
.titleContainer {
|
||||
width: 100%;
|
||||
object-fit: repeat;
|
||||
height: 100%;
|
||||
height: 45px;
|
||||
background: rgb(0, 51, 161);
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 51, 161, 1) 0%,
|
||||
rgba(84, 192, 232, 1) 100%
|
||||
);
|
||||
align-content: center;
|
||||
margin-bottom: 2%;
|
||||
}
|
||||
|
||||
.imageContainer {
|
||||
width: 100%;
|
||||
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;
|
||||
}
|
||||
@@ -1,84 +1,64 @@
|
||||
import React from 'react';
|
||||
import styles from './styles.module.css';
|
||||
import Link from '@docusaurus/Link';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
import {addDarkToFileName} from '../../../util/util';
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
export default function MarketplaceCard({
|
||||
post,
|
||||
openDialogFunc,
|
||||
}) {
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {faShieldCheck, faAward} from '@fortawesome/pro-solid-svg-icons';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
function setFilters(e) {
|
||||
openDialogFunc({"title": post.title, "image": post.image, "link": post.link, "id": post.id});
|
||||
}
|
||||
|
||||
let badge = (
|
||||
<div></div>
|
||||
);
|
||||
if (post.tags.includes("sailpoint-developed")) {
|
||||
export default function MarketplaceCard({post, featured}) {
|
||||
let badge = <div></div>;
|
||||
if (post.tags.includes('sailpoint-developed')) {
|
||||
badge = (
|
||||
<div className={styles.cardBadge}>
|
||||
<img
|
||||
className={styles.cardBadgeImage}
|
||||
src={useBaseUrl('/icons/SailPoint-LogoIcon-RGB-Color.svg')}></img>
|
||||
<img
|
||||
className={styles.cardBadgeImage}
|
||||
src={useBaseUrl('/icons/SailPoint-LogoIcon-RGB-Color.svg')}></img>
|
||||
<span className={styles.cardBadgeText}>SailPoint Developed</span>
|
||||
</div>
|
||||
|
||||
);
|
||||
} else if (post.tags.includes("sailpoint-certified")) {
|
||||
} else if (post.tags.includes('sailpoint-certified')) {
|
||||
badge = (
|
||||
<div className={styles.cardBadgeCertified}>
|
||||
<img
|
||||
className={styles.cardBadgeCertifiedImage}
|
||||
src={useBaseUrl('/marketplace/award-simple-sharp-solid.svg')}></img>
|
||||
<span>SailPoint Certified</span>
|
||||
<div className={styles.badgeContainer}>
|
||||
<div title="SailPoint Certified" className={styles.cardBadgeCertified}>
|
||||
<FontAwesomeIcon
|
||||
icon={faShieldCheck}
|
||||
className={styles.docCardIcon}
|
||||
size="2x"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div onClick={(e) => setFilters(e)}>
|
||||
<div className={styles.card} >
|
||||
|
||||
<Link to={post.link}>
|
||||
{/* <div onClick={(e) => setFilters(e)}> */}
|
||||
<div className={featured ? styles.featuredCard : styles.card}>
|
||||
<div className={styles.cardText}>
|
||||
<img className={styles.cardImage} src={useBaseUrl(post.image)}></img>
|
||||
<div className={styles.cardTitle}>{post.title}</div>
|
||||
<div className={styles.tags}>
|
||||
{post.tags?.map((tag, index) => {
|
||||
|
||||
if (index > 2 || tag == 'sailpoint-certified' || tag == 'sailpoint-authored') {
|
||||
return '';
|
||||
}
|
||||
return <div key={tag} className={styles.tag}>{tag}</div>;
|
||||
})}
|
||||
<img
|
||||
className={featured ? styles.featuredCardImage : styles.cardImage}
|
||||
src={useBaseUrl(post.image)}></img>
|
||||
<div className={styles.split}></div>
|
||||
<div
|
||||
className={featured ? styles.featuredCardTitle : styles.cardTitle}>
|
||||
{post.title}
|
||||
</div>
|
||||
|
||||
<div className={styles.cardUser}>
|
||||
<img
|
||||
className={featured ? styles.featuredCardFace : styles.cardFace}
|
||||
src={useBaseUrl(post.creatorImage)}></img>
|
||||
|
||||
<div className={styles.cardName}>{post.creatorName}</div>
|
||||
<div className={styles.cardCreatorTitle}>{post.creatorTitle}</div>
|
||||
|
||||
<div></div>
|
||||
</div>
|
||||
<div className={styles.cardBody}>{post.excerpt}</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.cardData}>
|
||||
<img className={styles.cardEye} src={useBaseUrl('/blog/eye-regular.svg')}></img>
|
||||
<div className={styles.cardCommentText}>{post.views}</div>
|
||||
<img className={styles.cardComment} src={useBaseUrl('/blog/comment-light.svg')}></img>
|
||||
<div className={styles.cardCommentText}>{post.replies}</div>
|
||||
</div>
|
||||
|
||||
{/* <div className={styles.cardUser}>
|
||||
<img className={styles.cardFace} src={useBaseUrl(post.creatorImage)}></img>
|
||||
<div className={styles.cardName}>{post.name}</div>
|
||||
</div> */}
|
||||
|
||||
|
||||
{badge}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{/* </div> */}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,53 @@
|
||||
/* Getting Started Card */
|
||||
.card {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
height: 500px;
|
||||
/* UI Properties */
|
||||
background: var(--dev-card-background);
|
||||
box-shadow: var(--dev-card-shadow);
|
||||
border: 1px solid var(--dev-card-background);
|
||||
border-radius: 40px;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
max-width: 400px;
|
||||
transition: all 0.3s;
|
||||
width: 275px;
|
||||
height: 393.17px;
|
||||
background: var(--dev-new-car-background);
|
||||
border-radius: 0.5rem;
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
border: 1px solid var(--dev-card-border);
|
||||
}
|
||||
|
||||
.featuredCard {
|
||||
position: relative;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
width: 400px;
|
||||
height: 475px;
|
||||
background: var(--dev-new-car-background);
|
||||
border-radius: 0.5rem;
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
border: 1px solid var(--dev-card-border);
|
||||
}
|
||||
|
||||
.featuredCardImage {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 400px;
|
||||
height: 225px;
|
||||
border-top-left-radius: 0.5rem;
|
||||
border-top-right-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
@@ -19,131 +56,98 @@
|
||||
box-shadow: var(--dev-card-selected);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cardText {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 22px;
|
||||
min-width: 170px;
|
||||
margin-bottom: 75px;
|
||||
}
|
||||
|
||||
.cardImage {
|
||||
border-radius: 4px;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 144px;
|
||||
border-top-left-radius: 0.5rem;
|
||||
border-top-right-radius: 0.5rem;
|
||||
aspect-ratio: 16/9;
|
||||
}
|
||||
.split {
|
||||
background: linear-gradient(
|
||||
145deg,
|
||||
rgba(0, 51, 161, 1) 40%,
|
||||
rgba(0, 79, 181, 1) 65%,
|
||||
rgba(0, 113, 206, 1) 100%
|
||||
);
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.featuredCardTitle {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
padding-right: 1rem;
|
||||
padding-left: 1rem;
|
||||
text-align: left;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.cardTitle {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
padding-right: 0.5rem;
|
||||
padding-left: 0.5rem;
|
||||
text-align: left;
|
||||
height: 80px;
|
||||
color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
.cardBody {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
height: 80px;
|
||||
margin-top: 1rem;
|
||||
padding-right: 0.5rem;
|
||||
padding-left: 0.5rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tag {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--dev-secondary-text);
|
||||
background-color: var(--dev-tag-highlight);
|
||||
padding: 0px 8px;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cardUser {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 25px;
|
||||
display: flex;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 5%;
|
||||
}
|
||||
|
||||
.featuredCardFace {
|
||||
border-radius: 9999px;
|
||||
margin-left: 2%;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.cardFace {
|
||||
border-radius: 9999px;
|
||||
margin: auto;
|
||||
margin-left: 2%;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.cardName {
|
||||
min-width: 170px;
|
||||
font-weight: 800;
|
||||
margin-top: 7px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cardData {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.cardEye {
|
||||
fill: #96a9bb;
|
||||
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||
filter: invert(79%) sepia(12%) saturate(484%) hue-rotate(168deg) brightness(84%) contrast(84%);
|
||||
margin-left: 5px;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.cardComment {
|
||||
.cardCreatorTitle {
|
||||
min-width: 170px;
|
||||
margin-left: 10px;
|
||||
fill: #96a9bb;
|
||||
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||
filter: invert(79%) sepia(12%) saturate(484%) hue-rotate(168deg) brightness(84%) contrast(84%);
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
margin-bottom: 4px;
|
||||
display: flex;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.cardCommentText {
|
||||
color: #96a9ba;
|
||||
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||
margin-left: 5px;
|
||||
margin-bottom: 5px;
|
||||
height: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* .cardBadge {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
bottom: 0px;
|
||||
margin-left: 5px;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
} */
|
||||
|
||||
.cardBadge {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
@@ -161,20 +165,24 @@
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.cardBadgeText {
|
||||
margin-left: -19px;
|
||||
margin-top: 15px;
|
||||
.certifiedText {
|
||||
position: absolute;
|
||||
top: 107px;
|
||||
left: 95px;
|
||||
color: var(--dev-text-color-secondary);
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.cardBadgeText {
|
||||
margin-top: 15px;
|
||||
color: var(--dev-text-color-secondary);
|
||||
}
|
||||
|
||||
.cardBadgeCertified {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
right: 85px;
|
||||
bottom: 15px;
|
||||
margin-left: 5px;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
width: 250px;
|
||||
left: 225px;
|
||||
bottom: 10px;
|
||||
color: var(--dev-text-color-secondary);
|
||||
}
|
||||
|
||||
@@ -183,4 +191,45 @@
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
filter: var(--dev-icon-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.docCardIcon {
|
||||
margin-right: 0.5em;
|
||||
color: var(--ifm-color-primary);
|
||||
padding-top: 4%;
|
||||
padding-left: 4%;
|
||||
}
|
||||
|
||||
.badgeText {
|
||||
margin-top: 6%;
|
||||
}
|
||||
|
||||
.badgeContainer:hover .certifiedText {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 550px) {
|
||||
.cardText {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.featuredCard {
|
||||
width: 275px;
|
||||
max-width: 275px;
|
||||
height: 393.17px;
|
||||
}
|
||||
|
||||
.featuredCardImage {
|
||||
width: 275px;
|
||||
height: 144px;
|
||||
}
|
||||
|
||||
.featuredCardTitle {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.featuredCardFace {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,39 +3,71 @@ import styles from './styles.module.css';
|
||||
import MarketplaceCard from '../MarketplaceCard';
|
||||
import Modal from 'react-modal';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import BounceLoader from 'react-spinners/BounceLoader';
|
||||
import NewtonsCradle from '../../newtonsCradle';
|
||||
import {discourseBaseURL, developerWebsiteDomain} from '../../../util/util';
|
||||
|
||||
import {
|
||||
getMarketplacePosts,
|
||||
getMarketplaceTopic,
|
||||
getMarketplaceTopicRaw,
|
||||
getUserTitle,
|
||||
} from '../../../services/DiscourseService';
|
||||
import MarketplaceCardDetail from '../MarketplaceCardDetail';
|
||||
export default function MarketplaceCards({filterCallback}) {
|
||||
export default function MarketplaceCards({
|
||||
filterCallback,
|
||||
featured,
|
||||
limit,
|
||||
multiple,
|
||||
}) {
|
||||
const [cardData, setCardData] = React.useState();
|
||||
const [detailsOpen, setDetailsOpen] = React.useState(false);
|
||||
const [details, setDetails] = React.useState('');
|
||||
const [loadingCards, setLoadingCards] = React.useState(true);
|
||||
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setDetailsOpen(false);
|
||||
}
|
||||
const xImage = useBaseUrl('/icons/circle-xmark-regular.svg');
|
||||
|
||||
const getPosts = async () => {
|
||||
const data = await getMarketplacePosts(filterCallback.tags.join('+'), filterCallback.category);
|
||||
|
||||
let tags = filterCallback.tags;
|
||||
if (featured) {
|
||||
tags = ['featured'];
|
||||
}
|
||||
const data = await getMarketplacePosts(
|
||||
tags ? tags.join('+') : '',
|
||||
filterCallback.category,
|
||||
);
|
||||
|
||||
const resultset = [];
|
||||
const titleList = [];
|
||||
if (data.topic_list) {
|
||||
for (const topic of data.topic_list.topics) {
|
||||
if (topic.tags.length > 0) {
|
||||
let poster = {}
|
||||
let poster = {};
|
||||
for (let topicUser of topic.posters) {
|
||||
if (topicUser.description.includes("Original Poster")) {
|
||||
if (topicUser.description.includes('Original Poster')) {
|
||||
for (let user of data.users) {
|
||||
if (user.id === topicUser.user_id) {
|
||||
poster = user
|
||||
if (
|
||||
!titleList.find((x) => x.group === user.primary_group_name)
|
||||
) {
|
||||
let usertitle = await getUserTitle(user.primary_group_name);
|
||||
|
||||
if (usertitle.group === undefined) {
|
||||
titleList.push({
|
||||
group: user.primary_group_name,
|
||||
title: '',
|
||||
});
|
||||
} else {
|
||||
titleList.push({
|
||||
group: user.primary_group_name,
|
||||
title: usertitle.group.title || '',
|
||||
});
|
||||
user.title = usertitle.group.title;
|
||||
}
|
||||
} else {
|
||||
user.title = titleList.find(
|
||||
(x) => x.group === user.primary_group_name,
|
||||
).title;
|
||||
}
|
||||
poster = user;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +76,11 @@ export default function MarketplaceCards({filterCallback}) {
|
||||
resultset.push(await getPostList(topic, poster));
|
||||
}
|
||||
}
|
||||
setCardData(resultset);
|
||||
if (limit) {
|
||||
setCardData(resultset.slice(0, limit));
|
||||
} else {
|
||||
setCardData(resultset);
|
||||
}
|
||||
} else {
|
||||
setCardData(undefined);
|
||||
}
|
||||
@@ -68,82 +104,104 @@ export default function MarketplaceCards({filterCallback}) {
|
||||
Modal.setAppElement('#__docusaurus');
|
||||
React.useEffect(() => {
|
||||
getPosts();
|
||||
|
||||
setCardData(undefined);
|
||||
setLoadingCards(true);
|
||||
}, [filterCallback]);
|
||||
|
||||
|
||||
const xImage = useBaseUrl('/icons/circle-xmark-regular.svg')
|
||||
|
||||
if (cardData && cardData.length > 0) {
|
||||
return (
|
||||
<div className={styles.center}>
|
||||
<div className={styles.gridContainer}>
|
||||
{cardData.map(function (a, index) {
|
||||
return (
|
||||
<MarketplaceCard
|
||||
post={a}
|
||||
key={index + a.link}
|
||||
openDialogFunc={openDialog}></MarketplaceCard>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<Modal
|
||||
isOpen={detailsOpen}
|
||||
className={styles.modal}
|
||||
onRequestClose={handleCloseModal}
|
||||
contentLabel="Details">
|
||||
<div>
|
||||
<div>
|
||||
<MarketplaceCardDetail
|
||||
details={details.data}
|
||||
rawPost={details.raw}></MarketplaceCardDetail>
|
||||
return (
|
||||
<div className={featured ? styles.featuredCenter : styles.center}>
|
||||
{loadingCards ? (
|
||||
// Show loading icon when data is still loading
|
||||
<div>
|
||||
{featured ? (
|
||||
<div className={styles.featuredSpinnerCenter}>
|
||||
<NewtonsCradle />
|
||||
</div>
|
||||
<img
|
||||
className={styles.cardExit}
|
||||
src={xImage}
|
||||
onClick={async () => {
|
||||
setDetailsOpen(false);
|
||||
}}></img>
|
||||
) : (
|
||||
<div
|
||||
className={
|
||||
multiple
|
||||
? styles.spinnerCenterMultiple
|
||||
: styles.spinnerCenterSingle
|
||||
}>
|
||||
<NewtonsCradle />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : cardData && cardData.length > 0 ? (
|
||||
<>
|
||||
{multiple ? (
|
||||
<div className={styles.multipleGridContainer}>
|
||||
{cardData.map(function (a, index) {
|
||||
return (
|
||||
<MarketplaceCard
|
||||
featured={featured}
|
||||
post={a}
|
||||
key={index + a.link}
|
||||
openDialogFunc={openDialog}></MarketplaceCard>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={
|
||||
featured ? styles.featuredGridContainer : styles.gridContainer
|
||||
}>
|
||||
{cardData.map(function (a, index) {
|
||||
return (
|
||||
<MarketplaceCard
|
||||
featured={featured}
|
||||
post={a}
|
||||
key={index + a.link}
|
||||
openDialogFunc={openDialog}></MarketplaceCard>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div>
|
||||
<div className={styles.noFound}>
|
||||
{' '}
|
||||
Hey there, looks like no integrations match your search criteria.
|
||||
Check out our{' '}
|
||||
<a href="https://developer.sailpoint.com/discuss/t/about-the-sailpoint-developer-community-colab/11230">
|
||||
getting started guide
|
||||
</a>
|
||||
, and consider being the first to contribute this integration!
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
} else if (loadingCards) {
|
||||
return (
|
||||
<BounceLoader
|
||||
className={styles.spinnerCenter}
|
||||
color={'#0033a1'}
|
||||
loading={true}
|
||||
size={150}
|
||||
aria-label="Loading Spinner"
|
||||
data-testid="loader"
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className={styles.noFound}>
|
||||
{' '}
|
||||
Hey there, looks like no integrations match your search criteria. Check out our <a href='https://developer.sailpoint.com/discuss/t/about-the-sailpoint-developer-community-colab/11230'>getting started guide</a>, and consider being the first to contribute this integration!
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function shortenTitle(title) {
|
||||
if (title.length > 63) {
|
||||
return title.substring(0, 62) + '...';
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
function shortenDesc(desc) {
|
||||
if (desc.length > 93) {
|
||||
return desc.substring(0, 93) + '...';
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
async function getPostList(topic, user) {
|
||||
return {
|
||||
id: topic.id,
|
||||
name: user.name,
|
||||
excerpt: styleExcerpt(topic.excerpt),
|
||||
creatorName: user.name,
|
||||
excerpt: shortenDesc(styleExcerpt(topic.excerpt)),
|
||||
creatorImage: getavatarURL(user.avatar_template),
|
||||
creatorTitle: user.title,
|
||||
tags: topic.tags,
|
||||
image: topic.image_url,
|
||||
link:
|
||||
discourseBaseURL() + 't/' +
|
||||
topic.slug +
|
||||
'/' +
|
||||
topic.id,
|
||||
title: topic.title,
|
||||
link: discourseBaseURL() + 't/' + topic.slug + '/' + topic.id,
|
||||
title: shortenTitle(topic.title),
|
||||
views: topic.views,
|
||||
liked: topic.like_count,
|
||||
replies: topic.posts_count,
|
||||
@@ -154,9 +212,11 @@ async function getPostList(topic, user) {
|
||||
|
||||
function getavatarURL(avatar) {
|
||||
if (avatar.includes(developerWebsiteDomain())) {
|
||||
return "https://" + developerWebsiteDomain() + avatar.replace("{size}", "120")
|
||||
return (
|
||||
'https://' + developerWebsiteDomain() + avatar.replace('{size}', '120')
|
||||
);
|
||||
} else {
|
||||
return avatar.replace("{size}", "120")
|
||||
return avatar.replace('{size}', '120');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,9 +225,9 @@ function styleExcerpt(excerpt) {
|
||||
// remove any strings that have colons between them
|
||||
excerpt = excerpt.replace(/:[^:]*:/g, '');
|
||||
// get text between "Description" and "Legal Agreement"
|
||||
const match = excerpt.match(/Description([\s\S]*?)Legal Agreement/)
|
||||
const match = excerpt.match(/Description([\s\S]*?)Legal Agreement/);
|
||||
if (match) {
|
||||
excerpt = match[1].trim()
|
||||
excerpt = match[1].trim();
|
||||
}
|
||||
if (excerpt.length > 150) {
|
||||
return excerpt.slice(0, 100) + '...';
|
||||
|
||||
@@ -1,31 +1,35 @@
|
||||
/* Getting Started Card container */
|
||||
.featuredGridContainer {
|
||||
display: flex;
|
||||
/* place-content: center; */
|
||||
grid-template-columns: 1fr;
|
||||
flex-wrap: wrap;
|
||||
min-height: 500px;
|
||||
margin-left: 9%;
|
||||
}
|
||||
.multipleGridContainer {
|
||||
display: flex;
|
||||
/* place-content: center; */
|
||||
flex-wrap: wrap;
|
||||
gap: 23px;
|
||||
width: 1500px;
|
||||
}
|
||||
.gridContainer {
|
||||
display: flex;
|
||||
/* place-content: center; */
|
||||
flex-wrap: wrap;
|
||||
gap: 40px;
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
gap: 23px;
|
||||
width: 1500px;
|
||||
}
|
||||
.gridContainer::after {
|
||||
content: "";
|
||||
/* .gridContainer::after {
|
||||
content: '';
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 870px) {
|
||||
.gridContainer {
|
||||
place-content: center;
|
||||
}
|
||||
.gridContainer::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} */
|
||||
|
||||
.center {
|
||||
margin: 0px auto;
|
||||
margin-bottom: 50px;
|
||||
width: 1500px;
|
||||
}
|
||||
|
||||
.space {
|
||||
@@ -40,41 +44,18 @@
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.modal {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
margin-right: -50%;
|
||||
transform: translate(-50%, -50%);
|
||||
box-shadow: 2px 3px 10px rgba(0, 0, 0, 0.25);
|
||||
border-radius: 20px;
|
||||
background-color: var(--dev-popup-background);
|
||||
max-height: 80%;
|
||||
max-width: 90%;
|
||||
min-height: 80%;
|
||||
scroll-behavior: auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.cardExit {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
fill: #96a9bb;
|
||||
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||
filter: invert(79%) sepia(12%) saturate(484%) hue-rotate(168deg) brightness(84%) contrast(84%);
|
||||
filter: invert(79%) sepia(12%) saturate(484%) hue-rotate(168deg)
|
||||
brightness(84%) contrast(84%);
|
||||
margin-left: 5px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
transition: all 0.2s;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.cardExit:hover {
|
||||
@@ -84,9 +65,128 @@
|
||||
width: 23px;
|
||||
}
|
||||
|
||||
.featuredSpinnerCenter {
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
margin-top: 45%;
|
||||
}
|
||||
|
||||
.spinnerCenter {
|
||||
margin: 100px auto;
|
||||
max-width: 1300px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
.spinnerCenterMultiple {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.spinnerCenterSingle {
|
||||
position: absolute;
|
||||
top: 300px;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1950px) {
|
||||
.multipleGridContainer {
|
||||
width: 1225px;
|
||||
}
|
||||
|
||||
.gridContainer {
|
||||
width: 1225px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 1225px;
|
||||
}
|
||||
|
||||
.multipleGridContainer > a:nth-child(5) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1350px) {
|
||||
.multipleGridContainer {
|
||||
width: 950px;
|
||||
}
|
||||
.multipleGridContainer > a:nth-child(4),
|
||||
.multipleGridContainer > a:nth-child(5) {
|
||||
display: none;
|
||||
}
|
||||
.gridContainer {
|
||||
width: 950px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 950px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1050px) {
|
||||
.multipleGridContainer {
|
||||
width: 675px;
|
||||
}
|
||||
.multipleGridContainer > a:nth-child(3),
|
||||
.multipleGridContainer > a:nth-child(4),
|
||||
.multipleGridContainer > a:nth-child(5) {
|
||||
display: none;
|
||||
}
|
||||
.multipleGridContainer {
|
||||
place-content: center;
|
||||
}
|
||||
.gridContainer::after {
|
||||
display: none;
|
||||
}
|
||||
.gridContainer {
|
||||
width: 675px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 675px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 700px) {
|
||||
.multipleGridContainer {
|
||||
width: 275px;
|
||||
}
|
||||
|
||||
.multipleGridContainer > a:nth-child(2),
|
||||
.multipleGridContainer > a:nth-child(3),
|
||||
.multipleGridContainer > a:nth-child(4),
|
||||
.multipleGridContainer > a:nth-child(5) {
|
||||
display: none;
|
||||
}
|
||||
.multipleGridContainer {
|
||||
place-content: center;
|
||||
}
|
||||
.gridContainer::after {
|
||||
display: none;
|
||||
}
|
||||
.gridContainer {
|
||||
width: 275px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 275px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 550px) {
|
||||
.featuredGridContainer {
|
||||
min-height: 350px;
|
||||
width: 275px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.featuredSpinnerCenter {
|
||||
width: 20%;
|
||||
margin: auto;
|
||||
margin-top: 35%;
|
||||
}
|
||||
|
||||
.spinnerCenterMultiple,
|
||||
.spinnerCenterSingle {
|
||||
left: 43%;
|
||||
}
|
||||
.noFound {
|
||||
width: 350px;
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
23
src/components/newtonsCradle/index.js
Normal file
23
src/components/newtonsCradle/index.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import Styles from './styles.module.css';
|
||||
|
||||
export default function NewtonsCradle() {
|
||||
return (
|
||||
<>
|
||||
<div className={Styles.container}>
|
||||
<div className={Styles.line}></div>
|
||||
<div className={Styles.line}></div>
|
||||
<div className={Styles.line}></div>
|
||||
<div className={Styles.line}></div>
|
||||
<div className={Styles.line}></div>
|
||||
<div className={Styles.line}></div>
|
||||
<div className={Styles.line}></div>
|
||||
<div className={Styles.line}></div>
|
||||
<div className={Styles.line}></div>
|
||||
<div className={Styles.line}></div>
|
||||
<div className={Styles.line}></div>
|
||||
<div className={Styles.line}></div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
124
src/components/newtonsCradle/styles.module.css
Normal file
124
src/components/newtonsCradle/styles.module.css
Normal file
@@ -0,0 +1,124 @@
|
||||
.container {
|
||||
--uib-size: 100px;
|
||||
--uib-color: var(--ifm-color-primary);
|
||||
--uib-speed: 1s;
|
||||
--uib-stroke: 3px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
height: var(--uib-size);
|
||||
width: var(--uib-size);
|
||||
}
|
||||
|
||||
.line {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(50% - var(--uib-stroke) / 2);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
height: 100%;
|
||||
width: var(--uib-stroke);
|
||||
}
|
||||
|
||||
.line::before {
|
||||
content: '';
|
||||
height: 22%;
|
||||
width: 100%;
|
||||
border-radius: calc(var(--uib-stroke) / 2);
|
||||
background-color: var(--uib-color);
|
||||
animation: pulse calc(var(--uib-speed)) ease-in-out infinite;
|
||||
transition: background-color 0.3s ease;
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
|
||||
.line:nth-child(1) {
|
||||
transform: rotate(calc(360deg / -12 * 1));
|
||||
|
||||
&::before {
|
||||
animation-delay: calc(var(--uib-speed) / -12 * 1);
|
||||
}
|
||||
}
|
||||
.line:nth-child(2) {
|
||||
transform: rotate(calc(360deg / -12 * 2));
|
||||
|
||||
&::before {
|
||||
animation-delay: calc(var(--uib-speed) / -12 * 2);
|
||||
}
|
||||
}
|
||||
.line:nth-child(3) {
|
||||
transform: rotate(calc(360deg / -12 * 3));
|
||||
|
||||
&::before {
|
||||
animation-delay: calc(var(--uib-speed) / -12 * 3);
|
||||
}
|
||||
}
|
||||
.line:nth-child(4) {
|
||||
transform: rotate(calc(360deg / -12 * 4));
|
||||
|
||||
&::before {
|
||||
animation-delay: calc(var(--uib-speed) / -12 * 4);
|
||||
}
|
||||
}
|
||||
.line:nth-child(5) {
|
||||
transform: rotate(calc(360deg / -12 * 5));
|
||||
|
||||
&::before {
|
||||
animation-delay: calc(var(--uib-speed) / -12 * 5);
|
||||
}
|
||||
}
|
||||
.line:nth-child(6) {
|
||||
transform: rotate(calc(360deg / -12 * 6));
|
||||
|
||||
&::before {
|
||||
animation-delay: calc(var(--uib-speed) / -12 * 6);
|
||||
}
|
||||
}
|
||||
.line:nth-child(7) {
|
||||
transform: rotate(calc(360deg / -12 * 7));
|
||||
|
||||
&::before {
|
||||
animation-delay: calc(var(--uib-speed) / -12 * 7);
|
||||
}
|
||||
}
|
||||
.line:nth-child(8) {
|
||||
transform: rotate(calc(360deg / -12 * 8));
|
||||
|
||||
&::before {
|
||||
animation-delay: calc(var(--uib-speed) / -12 * 8);
|
||||
}
|
||||
}
|
||||
.line:nth-child(9) {
|
||||
transform: rotate(calc(360deg / -12 * 9));
|
||||
|
||||
&::before {
|
||||
animation-delay: calc(var(--uib-speed) / -12 * 9);
|
||||
}
|
||||
}
|
||||
.line:nth-child(10) {
|
||||
transform: rotate(calc(360deg / -12 * 10));
|
||||
|
||||
&::before {
|
||||
animation-delay: calc(var(--uib-speed) / -12 * 10);
|
||||
}
|
||||
}
|
||||
.line:nth-child(11) {
|
||||
transform: rotate(calc(360deg / -12 * 11));
|
||||
|
||||
&::before {
|
||||
animation-delay: calc(var(--uib-speed) / -12 * 11);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
transform: scaleY(0.75);
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
transform: scaleY(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
60
src/components/video-library/VideoCard/index.js
Normal file
60
src/components/video-library/VideoCard/index.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import React from 'react';
|
||||
import styles from './styles.module.css';
|
||||
import Link from '@docusaurus/Link';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
export default function VideoCard({
|
||||
featured,
|
||||
videoURL,
|
||||
thumbnail,
|
||||
title,
|
||||
body,
|
||||
avatar,
|
||||
username,
|
||||
tags,
|
||||
}) {
|
||||
return (
|
||||
<Link to={videoURL}>
|
||||
<div
|
||||
title={username}
|
||||
className={featured ? styles.featuredCard : styles.card}>
|
||||
<div className={styles.cardText}>
|
||||
<div
|
||||
className={
|
||||
featured ? styles.featuredThumbContainer : styles.thumbContainer
|
||||
}>
|
||||
<img
|
||||
className={featured ? styles.featuredCardImage : styles.cardImage}
|
||||
src={thumbnail}></img>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={featured ? styles.featuredCardTitle : styles.cardTitle}>
|
||||
<div className={styles.avatarContainer}>
|
||||
<img
|
||||
title={username}
|
||||
className={styles.avatar}
|
||||
src={useBaseUrl(avatar)}></img>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={
|
||||
featured ? styles.featuredTitleContainer : styles.titleContainer
|
||||
}>
|
||||
{title}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.tags}>
|
||||
{tags?.map((tag, index) => {
|
||||
return (
|
||||
<div key={tag} className={styles.tag}>
|
||||
{tag}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
165
src/components/video-library/VideoCard/styles.module.css
Normal file
165
src/components/video-library/VideoCard/styles.module.css
Normal file
@@ -0,0 +1,165 @@
|
||||
/* Getting Started Card */
|
||||
.card {
|
||||
position: relative;
|
||||
margin-top: 30px;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.featuredCard {
|
||||
position: relative;
|
||||
margin-top: 30px;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
width: 400px;
|
||||
height: 225px;
|
||||
}
|
||||
|
||||
.card:hover .thumbContainer {
|
||||
cursor: pointer;
|
||||
transform: translate(0px, -5px);
|
||||
box-shadow: var(--dev-card-selected);
|
||||
}
|
||||
|
||||
.cardText {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 22px;
|
||||
min-width: 170px;
|
||||
margin-bottom: 75px;
|
||||
}
|
||||
|
||||
.featuredThumbContainer {
|
||||
border: 1px solid var(--dev-card-border);
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 225px;
|
||||
}
|
||||
|
||||
.thumbContainer {
|
||||
border: 1px solid var(--dev-card-border);
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 144px;
|
||||
}
|
||||
|
||||
.featuredCardImage {
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
width: 400px;
|
||||
height: 225px;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.cardImage {
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
width: 256px;
|
||||
height: 144px;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.avatarContainer {
|
||||
padding-left: 2rem;
|
||||
position: relative;
|
||||
width: 2.125rem;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
--tw-border-opacity: 1;
|
||||
--w: 2.125rem;
|
||||
border-color: #f1f1e7;
|
||||
border-color: rgb(241 241 231 / var(--tw-border-opacity));
|
||||
border-radius: 9999px;
|
||||
border-width: 2px;
|
||||
left: 0;
|
||||
max-width: 2.125rem;
|
||||
max-width: var(--w);
|
||||
min-width: 2.125rem;
|
||||
min-width: var(--w);
|
||||
position: absolute;
|
||||
width: var(--w);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.featuredTitleContainer {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.titleContainer {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.featuredCardTitle {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
padding-right: 0.5rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.cardTitle {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
padding-right: 0.5rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.cardBody {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
left: 0;
|
||||
margin-top: 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.tag {
|
||||
font-size: 10px;
|
||||
font-weight: 300;
|
||||
color: var(--dev-secondary-text);
|
||||
background-color: var(--dev-tag-highlight);
|
||||
padding: 0px 8px;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 550px) {
|
||||
.cardText {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
50
src/components/video-library/VideoCardDetails/index.js
Normal file
50
src/components/video-library/VideoCardDetails/index.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import React, {useEffect} from 'react';
|
||||
import Video from '../../Video.js';
|
||||
import styles from './styles.module.css';
|
||||
import Layout from '@theme/Layout';
|
||||
import DiscourseEmbed from '../VideoComments/index.js';
|
||||
|
||||
const VideoCardDetail = (props) => {
|
||||
const base = 'https://play.vidyard.com/';
|
||||
|
||||
useEffect(() => {
|
||||
// This code would be part of your iframe's JavaScript
|
||||
window.addEventListener('message', (event) => {
|
||||
// console.log(event);
|
||||
if (event.origin === 'https://developer.identitysoon.com') {
|
||||
// The data that was sent from the iframe
|
||||
// console.log(event.data);
|
||||
// setIframeStyle();
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||
<main>
|
||||
<div className={styles.videoPlayer}>
|
||||
<Video
|
||||
source={base + props.route.customProps.uuid}
|
||||
container="vidyard"></Video>
|
||||
<div>
|
||||
<h1 className={styles.videoTitle}>
|
||||
{props.route.customProps.title}
|
||||
</h1>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
{props.route.customProps.body}
|
||||
</p>
|
||||
</div>
|
||||
<div id="discourseContainer" className={styles.discourseContainer}>
|
||||
<DiscourseEmbed
|
||||
discourseEmbedUrl={props.route.customProps.uuid}
|
||||
topicId={props.route.customProps.topicid}></DiscourseEmbed>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default VideoCardDetail;
|
||||
@@ -0,0 +1,11 @@
|
||||
.videoPlayer {
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
align-content: center;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.discourseContainer {
|
||||
border-radius: 0.5em;
|
||||
height: 400px;
|
||||
}
|
||||
158
src/components/video-library/VideoCards/index.js
Normal file
158
src/components/video-library/VideoCards/index.js
Normal file
@@ -0,0 +1,158 @@
|
||||
import React from 'react';
|
||||
import styles from './styles.module.css';
|
||||
import VideoCard from '../VideoCard';
|
||||
import {
|
||||
videoBaseURL,
|
||||
discourseBaseURL,
|
||||
developerWebsiteDomain,
|
||||
} from '../../../util/util';
|
||||
import NewtonsCradle from '../../newtonsCradle';
|
||||
import {getVideoPosts} from '../../../services/DiscourseService';
|
||||
|
||||
export default function VideoCards({filterCallback, limit, featured}) {
|
||||
const [cardData, setCardData] = React.useState();
|
||||
const [loadingCards, setLoadingCards] = React.useState(true);
|
||||
|
||||
function buildTopicUrl(slug, id) {
|
||||
return discourseBaseURL() + `t/${slug}/${id}`;
|
||||
}
|
||||
|
||||
function parseVideoDetails(inputStr) {
|
||||
// Split the string by the known separator for the description
|
||||
const parts = inputStr.split('\n\nDescription\n');
|
||||
const videoUrl = parts[0].trim(); // Get the video URL, trimming any whitespace(
|
||||
const lastSegment = videoUrl.split('/').pop();
|
||||
const page = lastSegment.replace('.html', '');
|
||||
const description = parts.length > 1 ? parts[1].trim() : ''; // Get the description if it exists
|
||||
return {
|
||||
videoUrl,
|
||||
description,
|
||||
page,
|
||||
};
|
||||
}
|
||||
|
||||
function shortenTitle(title) {
|
||||
if (title.length > 63) {
|
||||
return title.substring(0, 62) + '...';
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
const getVideoTopics = async () => {
|
||||
let tags = featured ? ['featured'] : filterCallback.tags;
|
||||
|
||||
const data = await getVideoPosts(tags ? tags : '');
|
||||
const resultset = [];
|
||||
if (data.topic_list) {
|
||||
for (const topic of data.topic_list.topics) {
|
||||
if (topic.tags.length > 0) {
|
||||
let {videoUrl, description} = parseVideoDetails(topic.excerpt);
|
||||
let thumbnail = videoUrl.replace('.html', '.jpg');
|
||||
let avatar = '';
|
||||
let username = '';
|
||||
let ogPoster = '';
|
||||
for (const poster of topic.posters) {
|
||||
if (poster.description.includes('Original Poster')) {
|
||||
ogPoster = poster;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const user of data.users) {
|
||||
if (user.id === ogPoster.user_id) {
|
||||
username = user.name;
|
||||
avatar = getavatarURL(user.avatar_template);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!description) {
|
||||
thumbnail = topic.image_url;
|
||||
}
|
||||
|
||||
if (featured || (!featured && !topic.tags.includes('featured'))) {
|
||||
resultset.push({
|
||||
key: topic.id,
|
||||
title: shortenTitle(topic.title),
|
||||
tags: topic.tags,
|
||||
body: description | topic.excerpt,
|
||||
thumbnail: thumbnail,
|
||||
avatar: avatar,
|
||||
username: username,
|
||||
url: buildTopicUrl(topic.slug, topic.id),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setCardData(undefined);
|
||||
}
|
||||
if (limit) {
|
||||
setCardData(resultset.slice(0, limit));
|
||||
} else {
|
||||
setCardData(resultset);
|
||||
}
|
||||
setLoadingCards(false);
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
getVideoTopics();
|
||||
setCardData(undefined);
|
||||
setLoadingCards(true);
|
||||
}, [filterCallback]);
|
||||
|
||||
return (
|
||||
<div className={featured ? null : styles.center}>
|
||||
{loadingCards ? (
|
||||
// Show loading icon when data is still loading
|
||||
<div
|
||||
className={
|
||||
featured ? styles.featuredSpinnerCenter : styles.spinnerCenter
|
||||
}>
|
||||
<NewtonsCradle />
|
||||
</div>
|
||||
) : cardData && cardData.length > 0 ? (
|
||||
<div
|
||||
className={
|
||||
featured ? styles.featuredGridContainer : styles.gridContainer
|
||||
}>
|
||||
{cardData.map(function (a, index) {
|
||||
return (
|
||||
<VideoCard
|
||||
featured={featured}
|
||||
key={a.key}
|
||||
videoURL={a.url}
|
||||
thumbnail={a.thumbnail}
|
||||
title={a.title}
|
||||
body={a.body}
|
||||
avatar={a.avatar}
|
||||
tags={a.tags}></VideoCard>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<div className={styles.noFound}>
|
||||
{' '}
|
||||
Hey there, looks like no integrations match your search criteria.
|
||||
Check out our{' '}
|
||||
<a href="https://developer.sailpoint.com/discuss/t/about-the-sailpoint-developer-community-colab/11230">
|
||||
getting started guide
|
||||
</a>
|
||||
, and consider being the first to contribute this integration!
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getavatarURL(avatar) {
|
||||
if (avatar.includes(developerWebsiteDomain())) {
|
||||
return (
|
||||
'https://' + developerWebsiteDomain() + avatar.replace('{size}', '120')
|
||||
);
|
||||
} else {
|
||||
return avatar.replace('{size}', '120');
|
||||
}
|
||||
}
|
||||
155
src/components/video-library/VideoCards/styles.module.css
Normal file
155
src/components/video-library/VideoCards/styles.module.css
Normal file
@@ -0,0 +1,155 @@
|
||||
/* Getting Started Card container */
|
||||
.featuredGridContainer {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.gridContainer {
|
||||
display: flex;
|
||||
/* place-content: center; */
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
margin-left: 20px;
|
||||
justify-content: left;
|
||||
width: 1525px;
|
||||
}
|
||||
/* .gridContainer::after {
|
||||
content: '';
|
||||
flex: auto;
|
||||
}
|
||||
.gridContainer::before {
|
||||
content: '';
|
||||
flex: auto;
|
||||
} */
|
||||
|
||||
.center {
|
||||
margin: 0px auto;
|
||||
margin-bottom: 50px;
|
||||
width: 50%;
|
||||
width: 1525px;
|
||||
}
|
||||
|
||||
.space {
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.noFound {
|
||||
font-size: 28px;
|
||||
font-weight: 500;
|
||||
color: var(--dev-secondary-text);
|
||||
padding: 8px;
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
.modal {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
margin-right: -50%;
|
||||
transform: translate(-50%, -50%);
|
||||
box-shadow: 2px 3px 10px rgba(0, 0, 0, 0.25);
|
||||
border-radius: 20px;
|
||||
background-color: var(--dev-popup-background);
|
||||
max-height: 80%;
|
||||
max-width: 90%;
|
||||
min-height: 80%;
|
||||
scroll-behavior: auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.cardExit {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
fill: #96a9bb;
|
||||
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||
filter: invert(79%) sepia(12%) saturate(484%) hue-rotate(168deg)
|
||||
brightness(84%) contrast(84%);
|
||||
margin-left: 5px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.cardExit:hover {
|
||||
top: 8px;
|
||||
cursor: pointer;
|
||||
height: 23px;
|
||||
width: 23px;
|
||||
}
|
||||
|
||||
.featuredSpinnerCenter {
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
margin-top: 25%;
|
||||
}
|
||||
|
||||
.spinnerCenter {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 725px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1950px) {
|
||||
.gridContainer {
|
||||
width: 1225px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 1225px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1350px) {
|
||||
.gridContainer {
|
||||
width: 925px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 925px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1050px) {
|
||||
.gridContainer {
|
||||
width: 650px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 650px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 775px) {
|
||||
.gridContainer {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 958px) {
|
||||
.spinnerCenter {
|
||||
left: 47%;
|
||||
top: 855px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 550px) {
|
||||
.gridContainer {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.featuredSpinnerCenter {
|
||||
width: 100%;
|
||||
margin-top: 30%;
|
||||
}
|
||||
|
||||
.spinnerCenter {
|
||||
left: 40%;
|
||||
top: 825px;
|
||||
}
|
||||
}
|
||||
54
src/components/video-library/VideoComments/index.js
Normal file
54
src/components/video-library/VideoComments/index.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import React, {useEffect} from 'react';
|
||||
|
||||
const DiscourseEmbed = ({discourseEmbedUrl, topicId}) => {
|
||||
useEffect(() => {
|
||||
const discourseUrl = 'https://developer.sailpoint.com/discuss/';
|
||||
const embedUrl = `https://d1vrqvoe9hgpx0.cloudfront.net/videos/${discourseEmbedUrl}/index.html`;
|
||||
|
||||
// Set up Discourse Embed
|
||||
|
||||
window.DiscourseEmbed = {
|
||||
discourseUrl,
|
||||
topicId: topicId,
|
||||
// discourseEmbedUrl: embedUrl,
|
||||
className: 'EMBEDDED_BODY',
|
||||
};
|
||||
|
||||
// Create and append meta tag for discourse username
|
||||
|
||||
const metaTag = document.createElement('meta');
|
||||
metaTag.name = 'discourse-username';
|
||||
metaTag.content = 'Darrell'; // Replace with your Discourse username
|
||||
metaTag.setAttribute('discourse-embed-url', embedUrl); // Add attribute to meta tag for Discourse Embed URL
|
||||
metaTag.setAttribute('discourse-embed-class-name', 'EMBEDDED_BODY'); // Add attribute to meta tag for Discourse Embed class name (optional)
|
||||
metaTag.setAttribute('discourse-embed-title', 'SailPoint Developer Community'); // Add attribute to meta tag for Discourse Embed title (optional)
|
||||
metaTag.setAttribute('discourse-embed-description', 'The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.'); // Add attribute to meta tag for Discourse Embed description (optional)
|
||||
metaTag.setAttribute('discourse-embed-color', '#00A2E8'); // Add attribute to meta tag for Discourse Embed color (optional)
|
||||
document.getElementsByTagName('head')[0].appendChild(metaTag); // Append to head to avoid duplicating if component re-renders
|
||||
|
||||
// Create and append Discourse embed script
|
||||
const scriptTag = document.createElement('script');
|
||||
scriptTag.type = 'text/javascript';
|
||||
scriptTag.async = true;
|
||||
scriptTag.src = `${discourseUrl}javascripts/embed.js`;
|
||||
document.body.appendChild(scriptTag); // Append to body to avoid duplicating if component re-renders
|
||||
|
||||
// Cleanup on component unmount
|
||||
return () => {
|
||||
scriptTag.remove(); // Remove script tag
|
||||
if (metaTag.parentNode) {
|
||||
metaTag.parentNode.removeChild(metaTag); // Remove meta tag if it has been appended
|
||||
}
|
||||
};
|
||||
}, [discourseEmbedUrl]); // Effect dependency array includes discourseEmbedUrl
|
||||
|
||||
return (
|
||||
<>
|
||||
<meta name="discourse-username" content="Darrell-Thobe" />
|
||||
<meta name="discourse-embed-url" content={discourseEmbedUrl} />
|
||||
<div style={{display: 'flex', paddingBottom: '2%'}} id="discourse-comments"></div>
|
||||
</>
|
||||
); // Container for the Discourse comments
|
||||
};
|
||||
|
||||
export default DiscourseEmbed;
|
||||
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
export default function MarketplaceSidebarButton({
|
||||
filterCallback,
|
||||
text,
|
||||
id,
|
||||
isCategory,
|
||||
category,
|
||||
}) {
|
||||
const [isActive, setIsActive] = React.useState(false);
|
||||
const activeClass = isActive ? styles.tagSelected : '';
|
||||
|
||||
function setFilters(e, id) {
|
||||
filterCallback({tag: id});
|
||||
setIsActive((current) => !current);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={id}
|
||||
onClick={(e) => setFilters(e, id)}
|
||||
className={activeClass + ' ' + styles.tag}>
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
.tag {
|
||||
font-size: 13px;
|
||||
font-weight: 300;
|
||||
color: var(--dev-secondary-text);
|
||||
text-align: center;
|
||||
margin-right: 0.5%;
|
||||
margin-top: 0.5%;
|
||||
padding: 1%;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: var(--dev-text-color-normal);
|
||||
transition: background-color 500ms;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.tagSelected {
|
||||
font-size: 13px;
|
||||
font-weight: 300;
|
||||
background-color: var(--dev-secondary-text);
|
||||
color: var(--dev-card-background);
|
||||
text-align: center;
|
||||
margin-right: 0.5%;
|
||||
margin-top: 0.5%;
|
||||
padding: 1%;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: var(--dev-text-color-normal);
|
||||
transition: background-color 500ms;
|
||||
}
|
||||
|
||||
.tag:hover {
|
||||
cursor: pointer;
|
||||
background-color: var(--dev-text-color-normal);
|
||||
color: var(--dev-card-background);
|
||||
}
|
||||
182
src/components/video-library/VideoSidebar/index.js
Normal file
182
src/components/video-library/VideoSidebar/index.js
Normal file
@@ -0,0 +1,182 @@
|
||||
import React from 'react';
|
||||
import styles from './styles.module.css';
|
||||
import {getVideoPosts, getTags} from '../../../services/DiscourseService';
|
||||
import {forEach} from 'lodash';
|
||||
|
||||
export default function MarketplaceSidebar({filterCallback}) {
|
||||
const [tagProductData, setTagProductData] = React.useState();
|
||||
const [videoTag, setVideoTag] = React.useState();
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const [productTags, setProductTags] = React.useState('Filter by Product');
|
||||
const [videoTags, setVideoTags] = React.useState('Filter by Video Type');
|
||||
const [checkedItemsProdcut, setCheckedItemsProduct] = React.useState({});
|
||||
const [checkedItemsVideo, setCheckedItemsVideo] = React.useState(null);
|
||||
const toggleDropdown = () => setIsOpen(!isOpen);
|
||||
|
||||
const handleCheckboxChangeProduct = (event) => {
|
||||
setCheckedItemsProduct({
|
||||
...checkedItemsProdcut,
|
||||
[event.target.name]: event.target.checked,
|
||||
});
|
||||
|
||||
let product = '';
|
||||
|
||||
if (event.target.checked) {
|
||||
product = event.target.name;
|
||||
} else {
|
||||
console.log('productTags', productTags);
|
||||
console.log('event.target.name', event.target.name);
|
||||
product = productTags.replace(event.target.name, '');
|
||||
console.log('product', product);
|
||||
}
|
||||
|
||||
let filters = [];
|
||||
if (event.target.checked) {
|
||||
filters.push(event.target.name);
|
||||
}
|
||||
|
||||
forEach(checkedItemsProdcut, (value, key) => {
|
||||
if (key !== event.target.name && value === true) {
|
||||
filters.push(key);
|
||||
if (!product.includes(key)) product = product + ' ' + key;
|
||||
}
|
||||
});
|
||||
|
||||
if (checkedItemsVideo) {
|
||||
filters.push(checkedItemsVideo);
|
||||
}
|
||||
|
||||
if (event.target.checked && product !== '') {
|
||||
setProductTags(product);
|
||||
} else {
|
||||
setProductTags(product);
|
||||
}
|
||||
|
||||
if (product === '') {
|
||||
setProductTags('Filter by Product');
|
||||
}
|
||||
|
||||
filterCallback({tag: filters});
|
||||
};
|
||||
|
||||
const handleCheckboxChangeVideo = (event) => {
|
||||
const newCheckedItems = event.target.checked ? event.target.name : null;
|
||||
setCheckedItemsVideo(newCheckedItems);
|
||||
if (event.target.checked) {
|
||||
setVideoTags(event.target.name);
|
||||
} else {
|
||||
setVideoTags('Filter by Video Type');
|
||||
}
|
||||
if (!checkedItemsProdcut) {
|
||||
filterCallback({tag: newCheckedItems});
|
||||
} else {
|
||||
let filters = [];
|
||||
if (newCheckedItems) filters.push(newCheckedItems);
|
||||
forEach(checkedItemsProdcut, (value, key) => {
|
||||
if (value === true) filters.push(key);
|
||||
});
|
||||
filterCallback({tag: filters});
|
||||
}
|
||||
};
|
||||
|
||||
const getTagData = async () => {
|
||||
const uniqueProductTags = new Set();
|
||||
const uniqueTags = new Set();
|
||||
const data = await getTags();
|
||||
|
||||
if (data.extras.tag_groups) {
|
||||
for (const tagGroup of data.extras.tag_groups) {
|
||||
if (tagGroup.name === 'Products') {
|
||||
for (const tag of tagGroup.tags) {
|
||||
uniqueProductTags.add(tag.name);
|
||||
}
|
||||
}
|
||||
|
||||
if (tagGroup.name === 'Video Library') {
|
||||
for (const tag of tagGroup.tags) {
|
||||
uniqueTags.add(tag.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setTagProductData(Array.from(uniqueProductTags));
|
||||
setVideoTag(Array.from(uniqueTags));
|
||||
};
|
||||
|
||||
function displayText(text) {
|
||||
if (text === 'identity-security-cloud') {
|
||||
return 'Identity Security Cloud';
|
||||
}
|
||||
if (text === 'access-intelligence-center') {
|
||||
return 'Access Intelligence Center';
|
||||
}
|
||||
if (text === 'developer-days-2023-iiq') {
|
||||
return 'Developer Days 2023 iiq';
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
getTagData();
|
||||
}, []);
|
||||
|
||||
if (tagProductData) {
|
||||
return (
|
||||
<div className={styles.tagContainer}>
|
||||
<div>
|
||||
<div className={styles.dropdownContainer}>
|
||||
<button onClick={toggleDropdown} className={styles.dropdownButton}>
|
||||
{productTags}
|
||||
</button>
|
||||
{isOpen && (
|
||||
<div className={styles.dropdownContent}>
|
||||
{tagProductData.map(function (a, index) {
|
||||
return (
|
||||
<div className={styles.dropdownItem} key={index}>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={a}
|
||||
name={a}
|
||||
checked={checkedItemsProdcut[a] || false}
|
||||
onChange={handleCheckboxChangeProduct}
|
||||
/>
|
||||
<label htmlFor={a}>{displayText(a)}</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.videoTypeFilter}>
|
||||
<div className={styles.dropdownContainer}>
|
||||
<button onClick={toggleDropdown} className={styles.dropdownButton}>
|
||||
{videoTags}
|
||||
</button>
|
||||
{isOpen && (
|
||||
<div className={styles.dropdownContent}>
|
||||
{videoTag.map(function (a, index) {
|
||||
return (
|
||||
<div className={styles.dropdownItem} key={index}>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={a}
|
||||
name={a}
|
||||
checked={checkedItemsVideo === a}
|
||||
onChange={handleCheckboxChangeVideo}
|
||||
/>
|
||||
<label htmlFor={a}>{displayText(a)}</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return <div></div>;
|
||||
}
|
||||
}
|
||||
181
src/components/video-library/VideoSidebar/styles.module.css
Normal file
181
src/components/video-library/VideoSidebar/styles.module.css
Normal file
@@ -0,0 +1,181 @@
|
||||
.sidebar {
|
||||
width: 400px;
|
||||
height: 100%;
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.filterBy {
|
||||
margin-top: 1%;
|
||||
}
|
||||
|
||||
.tagHeader {
|
||||
margin-top: 30px;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.seeAll {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
color: var(--dev-secondary-text);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
width: 100%;
|
||||
transition: background-color 500ms;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.seeAll:hover {
|
||||
cursor: pointer;
|
||||
background-color: var(--dev-text-color-normal);
|
||||
color: var(--dev-card-background);
|
||||
}
|
||||
|
||||
.tagContainer {
|
||||
margin: auto;
|
||||
width: 59%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.dropdownContainer {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.videoTypeFilter {
|
||||
margin-left: 2%;
|
||||
}
|
||||
|
||||
.dropdownButton {
|
||||
background-color: var(
|
||||
--dropdown-background
|
||||
); /* Dropdown background color */ /* Text color */
|
||||
padding: 5px 15px; /* Padding inside the dropdown button */
|
||||
border: 0.5px solid #cccccc; /* Border around the dropdown */
|
||||
border-radius: 5px; /* Rounded corners */
|
||||
cursor: pointer; /* Change mouse cursor to indicate it's clickable */
|
||||
position: relative; /* To position the arrow icon correctly */
|
||||
display: inline-block; /* To keep the button's block behavior */
|
||||
width: 200px;
|
||||
height: 50px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.dropdownButton:after {
|
||||
content: '▼'; /* Adds a dropdown arrow after the button text */
|
||||
position: absolute;
|
||||
right: 10px; /* Position the arrow to the right */
|
||||
top: 50%; /* Align vertically */
|
||||
transform: translateY(-50%); /* Center the arrow vertically */
|
||||
pointer-events: none; /* Prevent the arrow from being clickable */
|
||||
}
|
||||
|
||||
.dropdownButton:hover {
|
||||
background-color: var(
|
||||
--dev-card-background
|
||||
); /* Lighter background on hover */
|
||||
}
|
||||
|
||||
.dropdownButton:focus {
|
||||
outline: none; /* Remove default focus outline */
|
||||
border-color: #666666; /* Darker border color when focused */
|
||||
}
|
||||
|
||||
.dropdownContent {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: var(--dropdown-background);
|
||||
min-width: 300px;
|
||||
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
|
||||
z-index: 25;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.dropdownContainer .dropdownContent label {
|
||||
display: flex;
|
||||
margin: 5px 5px;
|
||||
}
|
||||
|
||||
.dropdownContainer:hover .dropdownContent {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdownItem {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.dropdownItem:hover {
|
||||
--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color),
|
||||
0 1px 2px -1px var(--tw-shadow-color);
|
||||
box-shadow: 0 0 transparent, 0 0 transparent, 0 1px 3px 0 rgba(0, 0, 0, 0.1),
|
||||
0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
background-color: var(--dev-tag-highlight);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1920px) {
|
||||
.tagContainer {
|
||||
width: 61%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1447px) {
|
||||
.tagContainer {
|
||||
width: 69%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1278px) {
|
||||
.tagContainer {
|
||||
width: 68%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1179px) {
|
||||
.tagContainer {
|
||||
margin-top: 10%;
|
||||
width: 83%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1085px) {
|
||||
.tagContainer {
|
||||
margin-top: 10%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 958px) {
|
||||
.tagContainer {
|
||||
width: 72%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 550px) {
|
||||
.tagContainer {
|
||||
margin-top: 12%;
|
||||
margin-bottom: 3%;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
.tagContainer {
|
||||
display: block;
|
||||
width: 50%;
|
||||
}
|
||||
.videoTypeFilter {
|
||||
margin-top: 5%;
|
||||
margin-left: 0%;
|
||||
}
|
||||
}
|
||||
@@ -243,14 +243,20 @@
|
||||
--dev-boarder-color-theme: black;
|
||||
--dev-text-color-normal: #415364;
|
||||
--dev-text-color-secondary: #0033a1;
|
||||
--dev-icon-color-primary: invert(12%) sepia(90%) saturate(3876%) hue-rotate(221deg) brightness(89%) contrast(102%);
|
||||
--dev-icon-color-primary: invert(12%) sepia(90%) saturate(3876%)
|
||||
hue-rotate(221deg) brightness(89%) contrast(102%);
|
||||
|
||||
--dev-secondary-text: #415364;
|
||||
--dev-tag-highlight: #eaeef1;
|
||||
|
||||
--text-on-primary: #ffffff;
|
||||
--text-color: black;
|
||||
|
||||
|
||||
--dropdown-background: #ffffff;
|
||||
|
||||
/*card css*/
|
||||
--dev-card-border: #dadce0;
|
||||
--dev-card-background: #e9e9e963;
|
||||
--dev-tag-selected-text: #ffffffef;
|
||||
--dev-popup-background: #fdfdfd;
|
||||
@@ -259,6 +265,8 @@
|
||||
--dev-card-selected: 0 4px 5px rgba(0, 0, 0, 0.2);
|
||||
--dev-button-hover: #c552ae10;
|
||||
|
||||
--dev-new-car-background: #ffffff;
|
||||
|
||||
--ifm-github-logo: url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E");
|
||||
--ifm-medium-logo: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 1770 1000"><circle cx="500" cy="500" r="500"/><ellipse ry="475" rx="250" cy="501" cx="1296"/><ellipse cx="1682" cy="502" rx="88" ry="424"/></svg>');
|
||||
--dev-sailpoint-small-logo: url('../../static/img/SailPoint-Logo-RGB-Color.png');
|
||||
@@ -286,11 +294,18 @@
|
||||
--dev-sailpoint-small-logo: url('../../static/img/SailPoint-Logo-RGB-Inverse.png');
|
||||
--dev-text-color-normal: #dae1e9;
|
||||
--dev-text-color-secondary: #54c0e8;
|
||||
--dev-icon-color-primary: invert(87%) sepia(26%) saturate(6104%) hue-rotate(165deg) brightness(96%) contrast(89%);
|
||||
--dev-icon-color-primary: invert(87%) sepia(26%) saturate(6104%)
|
||||
hue-rotate(165deg) brightness(96%) contrast(89%);
|
||||
|
||||
--text-on-primary: #ffffff;
|
||||
|
||||
--text-color: #ffffff;
|
||||
|
||||
--dropdown-background: #2a2b2d;
|
||||
|
||||
/*card css*/
|
||||
--dev-card-border: rgba(218,220,224,0.3);
|
||||
--dev-new-car-background: #2a2b2d;
|
||||
--dev-card-background: #2a2b2d;
|
||||
--dev-popup-background: #2a2b2d;
|
||||
--dev-card-shadow: 0 0px 0px rgba(0, 0, 0, 0.2);
|
||||
@@ -460,14 +475,24 @@ ul {
|
||||
}
|
||||
|
||||
div[class^='announcementBar_'] {
|
||||
background: repeating-linear-gradient(145deg,rgba(0,51,161,1),rgba(0,79,181,1),rgba(0,113,206,1));
|
||||
background: repeating-linear-gradient(
|
||||
145deg,
|
||||
rgba(0, 51, 161, 1),
|
||||
rgba(0, 79, 181, 1),
|
||||
rgba(0, 113, 206, 1)
|
||||
);
|
||||
color: #ffffff;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 750px) {
|
||||
div[class^='announcementBar_'] {
|
||||
background: repeating-linear-gradient(145deg,rgba(0,51,161,1),rgba(0,79,181,1),rgba(0,113,206,1));
|
||||
background: repeating-linear-gradient(
|
||||
145deg,
|
||||
rgba(0, 51, 161, 1),
|
||||
rgba(0, 79, 181, 1),
|
||||
rgba(0, 113, 206, 1)
|
||||
);
|
||||
color: #ffffff;
|
||||
height: 52.5px;
|
||||
}
|
||||
@@ -488,6 +513,25 @@ code[class^='openapi-explorer__code-block'] {
|
||||
max-height: 400px !important;
|
||||
}
|
||||
|
||||
iframe#webpack-dev-server-client-overlay{
|
||||
display:none!important
|
||||
iframe#webpack-dev-server-client-overlay {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
iframe[id^='discourse-embed-frame'] {
|
||||
border-radius: 0.5em !important;
|
||||
border: solid;
|
||||
border-width: thin;
|
||||
margin: auto;
|
||||
padding-bottom: -15%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
div[id^='discourseContainer'] {
|
||||
border-radius: 0.5em;
|
||||
}
|
||||
|
||||
div[id^='discourse-comments'] {
|
||||
display: flex;
|
||||
padding-bottom: 2%;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,33 +8,70 @@ import BlogBanner from '../components/blog/BlogBanner';
|
||||
import styles from './blog.module.css';
|
||||
import BlogCards from '../components/blog/BlogCards';
|
||||
import BlogSidebar from '../components/blog/BlogSidebar';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
export default function Blog() {
|
||||
const [filteredProduct, setFilteredProduct] = React.useState([]);
|
||||
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
|
||||
const handleClick = (data) => {
|
||||
var tempFilter = filteredProduct.slice()
|
||||
var tempFilter = [];
|
||||
|
||||
const index = tempFilter.indexOf(data);
|
||||
if (index !== -1) {
|
||||
tempFilter.splice(index, 1);
|
||||
} else {
|
||||
tempFilter.push(data)
|
||||
tempFilter.push(data);
|
||||
}
|
||||
|
||||
setFilteredProduct(tempFilter)
|
||||
setFilteredProduct(tempFilter);
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||
<main>
|
||||
<BlogBanner />
|
||||
<div className={styles.blogContainer}>
|
||||
<div className={styles.blogSidbarContainer}><BlogSidebar filterCallback={handleClick}/></div>
|
||||
<div className={styles.blogCardContainer}><BlogCards filterCallback={filteredProduct}/></div>
|
||||
</div>
|
||||
|
||||
<main className={styles.main}>
|
||||
<BlogBanner />
|
||||
<div>
|
||||
<div className={styles.mainCard}>
|
||||
<div className={styles.contentContainer}>
|
||||
<div className={styles.gettingStartedText}>
|
||||
<div className={styles.gettingStartedOne}>Community Blog</div>
|
||||
|
||||
<div className={styles.gettingStartedThree}>
|
||||
<span>
|
||||
Our community blog is a collection of technical writings
|
||||
provided by members of our community—your peers—discussing
|
||||
detailed walkthroughs, challenges faced (and how they were
|
||||
overcome), and thoughts on managing identity in a meaningful
|
||||
way.
|
||||
</span>{' '}
|
||||
<br />
|
||||
<br />
|
||||
<a href="https://developer.sailpoint.com/discuss/t/guide-for-writing-blog-posts/10277">
|
||||
Become an author →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.featuredBlogContainer} title="Featured Blog">
|
||||
<div className={styles.featuredGettingStartedText}>
|
||||
<div className={styles.gettingStartedOne}>Featured</div>
|
||||
</div>
|
||||
<BlogCards
|
||||
filterCallback={filteredProduct}
|
||||
limit={1}
|
||||
featured={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.blogContainer}>
|
||||
<div className={styles.blogSidbarContainer}>
|
||||
<BlogSidebar filterCallback={handleClick} />
|
||||
</div>
|
||||
<div className={styles.blogCardContainer}>
|
||||
<BlogCards filterCallback={filteredProduct} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
|
||||
@@ -1,17 +1,141 @@
|
||||
.blogContainer {
|
||||
display: flex;
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.mainCard {
|
||||
display: grid;
|
||||
grid-gap: 20px;
|
||||
max-width: 1180px;
|
||||
justify-content: center;
|
||||
min-height: 587.22px;
|
||||
}
|
||||
|
||||
.featuredGettingStartedText {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.gettingStartedText,
|
||||
.featuredGettingStartedText {
|
||||
margin-top: 50px;
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.gettingStartedOne {
|
||||
color: var(--ifm-color-primary);
|
||||
font-size: 30px;
|
||||
max-width: 396px;
|
||||
font-weight: bold;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
.gettingStartedTwo {
|
||||
margin-top: 20px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.gettingStartedThree {
|
||||
margin-top: 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Getting Started Card container */
|
||||
.gridContainer {
|
||||
display: grid;
|
||||
margin-left: 50px;
|
||||
margin-bottom: 50px;
|
||||
grid-gap: 20px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
|
||||
place-content: center;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
.video {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.blogSidbarContainer {
|
||||
flex: 5%;
|
||||
margin: auto;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 870px) {
|
||||
.blogSidbarContainer {
|
||||
display: none;
|
||||
}
|
||||
.featuredBlogContainer {
|
||||
margin-left: 8%;
|
||||
}
|
||||
|
||||
.blogCardContainer {
|
||||
flex: 95%;
|
||||
}
|
||||
.contentContainer {
|
||||
margin-left: 5%;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1178px) {
|
||||
.carousel {
|
||||
margin-top: 0px;
|
||||
margin-left: 50px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
.contentContainer {
|
||||
width: 600px;
|
||||
margin-left: 10%;
|
||||
}
|
||||
|
||||
.featuredGettingStartedText {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1179px) {
|
||||
.carousel {
|
||||
margin-top: 35px;
|
||||
padding-bottom: 5%;
|
||||
}
|
||||
.mainCard {
|
||||
grid-template-columns: repeat(auto-fit, minmax(520px, 1fr));
|
||||
/* UI Properties */
|
||||
background: var(--main-hero-card-background);
|
||||
box-shadow: var(--dev-main-card-shadow);
|
||||
border: 1px solid var(--dev-card-background);
|
||||
border-radius: 40px;
|
||||
opacity: 1;
|
||||
margin: 50px auto;
|
||||
width: calc(100% - 100px);
|
||||
height: 545px;
|
||||
min-height: 535px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 570px) {
|
||||
|
||||
|
||||
.gettingStartedThree {
|
||||
padding-right: 15%;
|
||||
}
|
||||
|
||||
.contentContainer {
|
||||
margin-left: 0%;
|
||||
width: auto;
|
||||
}
|
||||
.featuredBlogContainer {
|
||||
margin-left: 0%;
|
||||
}
|
||||
.video {
|
||||
display: none;
|
||||
}
|
||||
.carousel {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
.blogSidbarContainer {
|
||||
width: 325px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +1,173 @@
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import Link from '@docusaurus/Link';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import Layout from '@theme/Layout';
|
||||
import MarketplaceBanner from '../components/marketplace/MarketplaceBanner';
|
||||
|
||||
import Link from '@docusaurus/Link';
|
||||
import styles from './exchange.module.css';
|
||||
import MarketplaceCards from '../components/marketplace/MarketplaceCards';
|
||||
import MarketplaceSidebar from '../components/marketplace/MarketplaceSidebar';
|
||||
import HomepageCard from '../components/homepage/HomepageCard';
|
||||
|
||||
export default function Marketplace() {
|
||||
const [filteredProduct, setFilteredProduct] = React.useState({"category": "colab", "tags": []});
|
||||
const [plugins] = React.useState({
|
||||
category: 'colab-iiq-plugins',
|
||||
tags: [],
|
||||
});
|
||||
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
const [rules] = React.useState({
|
||||
category: 'colab-rules',
|
||||
tags: ['identity-security-cloud'],
|
||||
});
|
||||
|
||||
const handleClick = (data) => {
|
||||
var tempFilter = filteredProduct.tags.slice()
|
||||
const [saas] = React.useState({
|
||||
category: 'colab-saas-connectors',
|
||||
tags: [],
|
||||
});
|
||||
|
||||
if (data.tag) {
|
||||
const index = tempFilter.indexOf(data.tag);
|
||||
if (index !== -1) {
|
||||
tempFilter.splice(index, 1);
|
||||
} else {
|
||||
tempFilter.push(data.tag)
|
||||
}
|
||||
}
|
||||
const [transforms] = React.useState({
|
||||
category: 'colab-transforms',
|
||||
tags: [],
|
||||
});
|
||||
|
||||
if (data.category) {
|
||||
setFilteredProduct({"category": data.category, "tags": tempFilter})
|
||||
} else {
|
||||
setFilteredProduct({"category": filteredProduct.category, "tags": tempFilter})
|
||||
}
|
||||
const [workflows] = React.useState({
|
||||
category: 'colab',
|
||||
tags: ['workflows'],
|
||||
});
|
||||
|
||||
const [communityTools] = React.useState({
|
||||
category: 'colab-community-tools',
|
||||
tags: [],
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
return (
|
||||
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||
<main>
|
||||
<MarketplaceBanner />
|
||||
<div className={styles.blogContainer}>
|
||||
<div className={styles.blogSidbarContainer}><MarketplaceSidebar selectedCategory={filteredProduct.category} filterCallback={handleClick}/></div>
|
||||
<div className={styles.blogCardContainer}><MarketplaceCards filterCallback={filteredProduct}/></div>
|
||||
</div>
|
||||
|
||||
<MarketplaceBanner />
|
||||
<div>
|
||||
<div className={styles.mainCard}>
|
||||
<div className={styles.contentContainer}>
|
||||
<div className={styles.gettingStartedText}>
|
||||
<div className={styles.gettingStartedOne}>
|
||||
CoLab Marketplace
|
||||
</div>
|
||||
<div className={styles.gettingStartedTwo}>
|
||||
What is the CoLab?
|
||||
</div>
|
||||
<div className={styles.gettingStartedThree}>
|
||||
<span>
|
||||
The community CoLab is a place where members of our
|
||||
community can build fully-featured solutions on our platform
|
||||
and share those solutions with each other. Users collaborate
|
||||
on these solutions to benefit both themselves and the
|
||||
community at large.
|
||||
</span>{' '}
|
||||
<br />
|
||||
<br />
|
||||
<a href="https://developer.sailpoint.com/discuss/t/developer-community-colab-getting-started-guide/11230">
|
||||
Get started with the CoLab →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.featuredGettingStartedText}>
|
||||
<div className={styles.gettingStartedOne}>Featured</div>
|
||||
</div>
|
||||
<div className={styles.carousel}>
|
||||
<div className={styles.featured} title="Featured CoLab">
|
||||
<MarketplaceCards
|
||||
filterCallback={['']}
|
||||
limit={1}
|
||||
featured={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.container}>
|
||||
<div>
|
||||
<div className={styles.cardContainer}>
|
||||
<div className={styles.titleContainer}>
|
||||
<h1 className={styles.title}>Workflows</h1>
|
||||
<Link to={'/colab/workflows'} className={styles.link}>
|
||||
View All →
|
||||
</Link>
|
||||
</div>
|
||||
<MarketplaceCards
|
||||
filterCallback={workflows}
|
||||
limit={5}
|
||||
multiple={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.cardContainer}>
|
||||
<div className={styles.titleContainer}>
|
||||
<h1 className={styles.title}>SaaS Connectors</h1>
|
||||
<Link to={'/colab/saasconnectors'} className={styles.link}>
|
||||
View All →
|
||||
</Link>
|
||||
</div>
|
||||
<MarketplaceCards
|
||||
filterCallback={saas}
|
||||
limit={5}
|
||||
multiple={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.cardContainer}>
|
||||
<div className={styles.titleContainer}>
|
||||
<h1 className={styles.title}>Community Tools</h1>
|
||||
<Link to={'/colab/communitytools'} className={styles.link}>
|
||||
View All →
|
||||
</Link>
|
||||
</div>
|
||||
<MarketplaceCards
|
||||
filterCallback={communityTools}
|
||||
limit={5}
|
||||
multiple={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.cardContainer}>
|
||||
<div className={styles.titleContainer}>
|
||||
<h1 className={styles.title}>Rules</h1>
|
||||
<Link to={'/colab/rules'} className={styles.link}>
|
||||
View All →
|
||||
</Link>
|
||||
</div>
|
||||
<MarketplaceCards
|
||||
filterCallback={rules}
|
||||
limit={5}
|
||||
multiple={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.cardContainer}>
|
||||
<div className={styles.titleContainer}>
|
||||
<h1 className={styles.title}>Transforms</h1>
|
||||
<Link to={'/colab/transforms'} className={styles.link}>
|
||||
View All →
|
||||
</Link>
|
||||
</div>
|
||||
<MarketplaceCards
|
||||
filterCallback={transforms}
|
||||
limit={5}
|
||||
multiple={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.cardContainer}>
|
||||
<div>
|
||||
<h1 className={styles.title}>IIQ Plugins</h1>
|
||||
<Link to={'/colab/plugins'} className={styles.link}>
|
||||
View All →
|
||||
</Link>
|
||||
</div>
|
||||
<MarketplaceCards
|
||||
filterCallback={plugins}
|
||||
limit={5}
|
||||
multiple={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
|
||||
44
src/pages/colab/communitytools.js
Normal file
44
src/pages/colab/communitytools.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
import styles from './filter.module.css';
|
||||
import BlogSidebar from '../../components/blog/BlogSidebar';
|
||||
import MarketplaceCards from '../../components/marketplace/MarketplaceCards';
|
||||
import MarketplaceBanner from '../../components/marketplace/MarketplaceBanner';
|
||||
|
||||
export default function CommunityTools() {
|
||||
const [filteredProduct, setFilteredProduct] = React.useState({
|
||||
category: 'colab-community-tools',
|
||||
tags: ['identity-security-cloud'],
|
||||
});
|
||||
|
||||
const handleClick = (data) => {
|
||||
var tempFilter = [];
|
||||
|
||||
const index = tempFilter.indexOf(data);
|
||||
if (index !== -1) {
|
||||
tempFilter.splice(index, 1);
|
||||
} else {
|
||||
tempFilter.push(data);
|
||||
}
|
||||
|
||||
setFilteredProduct({
|
||||
category: 'colab-community-tools',
|
||||
tags: tempFilter,
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||
<main>
|
||||
<MarketplaceBanner />
|
||||
<div className={styles.container}>
|
||||
<div className={styles.filterContainer}>
|
||||
<BlogSidebar filterCallback={handleClick} isChecked={true} />
|
||||
</div>
|
||||
<div className={styles.cardContainer}>
|
||||
<MarketplaceCards filterCallback={filteredProduct} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
20
src/pages/colab/filter.module.css
Normal file
20
src/pages/colab/filter.module.css
Normal file
@@ -0,0 +1,20 @@
|
||||
.colabContainer {
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.filterContainer {
|
||||
margin: auto;
|
||||
width: 400px;
|
||||
margin-top: 3%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 550px) {
|
||||
.filterContainer {
|
||||
width: 325px;
|
||||
}
|
||||
}
|
||||
|
||||
.cardContainer {
|
||||
width: 63%;
|
||||
margin: auto;
|
||||
}
|
||||
25
src/pages/colab/plugins.js
Normal file
25
src/pages/colab/plugins.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
import styles from './filter.module.css';
|
||||
import MarketplaceCards from '../../components/marketplace/MarketplaceCards';
|
||||
import MarketplaceBanner from '../../components/marketplace/MarketplaceBanner';
|
||||
|
||||
export default function Workflows() {
|
||||
const [filteredProduct] = React.useState({
|
||||
category: 'colab-iiq-plugins',
|
||||
tags: ['Identityiq'],
|
||||
});
|
||||
|
||||
return (
|
||||
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||
<main>
|
||||
<MarketplaceBanner />
|
||||
<div className={styles.container}>
|
||||
<div className={styles.cardContainer}>
|
||||
<MarketplaceCards filterCallback={filteredProduct} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
46
src/pages/colab/rules.js
Normal file
46
src/pages/colab/rules.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
import styles from './filter.module.css';
|
||||
|
||||
import BlogSidebar from '../../components/blog/BlogSidebar';
|
||||
import MarketplaceCards from '../../components/marketplace/MarketplaceCards';
|
||||
import MarketplaceBanner from '../../components/marketplace/MarketplaceBanner';
|
||||
|
||||
export default function Rules() {
|
||||
const [filteredProduct, setFilteredProduct] = React.useState({
|
||||
category: 'colab-rules',
|
||||
tags: ['identity-security-cloud'],
|
||||
});
|
||||
|
||||
const handleClick = (data) => {
|
||||
var tempFilter = [];
|
||||
|
||||
const index = tempFilter.indexOf(data);
|
||||
if (index !== -1) {
|
||||
tempFilter.splice(index, 1);
|
||||
} else {
|
||||
tempFilter.push(data);
|
||||
}
|
||||
|
||||
setFilteredProduct({
|
||||
category: 'colab-rules',
|
||||
tags: tempFilter,
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||
<main>
|
||||
<MarketplaceBanner />
|
||||
<div className={styles.container}>
|
||||
<div className={styles.filterContainer}>
|
||||
<BlogSidebar filterCallback={handleClick} isChecked={true} />
|
||||
</div>
|
||||
<div className={styles.cardContainer}>
|
||||
<MarketplaceCards filterCallback={filteredProduct} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
46
src/pages/colab/saasconnectors.js
Normal file
46
src/pages/colab/saasconnectors.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
import styles from './filter.module.css';
|
||||
|
||||
import BlogSidebar from '../../components/blog/BlogSidebar';
|
||||
import MarketplaceCards from '../../components/marketplace/MarketplaceCards';
|
||||
import MarketplaceBanner from '../../components/marketplace/MarketplaceBanner';
|
||||
|
||||
export default function SaasConnector() {
|
||||
const [filteredProduct, setFilteredProduct] = React.useState({
|
||||
category: 'colab-saas-connectors',
|
||||
tags: [],
|
||||
});
|
||||
|
||||
const handleClick = (data) => {
|
||||
var tempFilter = [];
|
||||
|
||||
const index = tempFilter.indexOf(data);
|
||||
if (index !== -1) {
|
||||
tempFilter.splice(index, 1);
|
||||
} else {
|
||||
tempFilter.push(data);
|
||||
}
|
||||
|
||||
setFilteredProduct({
|
||||
category: 'colab-saas-connectors',
|
||||
tags: tempFilter,
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||
<main>
|
||||
<MarketplaceBanner />
|
||||
<div className={styles.container}>
|
||||
<div className={styles.filterContainer}>
|
||||
<BlogSidebar filterCallback={handleClick} isChecked={true} />
|
||||
</div>
|
||||
<div className={styles.cardContainer}>
|
||||
<MarketplaceCards filterCallback={filteredProduct} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
46
src/pages/colab/transforms.js
Normal file
46
src/pages/colab/transforms.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
import styles from './filter.module.css';
|
||||
|
||||
import BlogSidebar from '../../components/blog/BlogSidebar';
|
||||
import MarketplaceCards from '../../components/marketplace/MarketplaceCards';
|
||||
import MarketplaceBanner from '../../components/marketplace/MarketplaceBanner';
|
||||
|
||||
export default function Transforms() {
|
||||
const [filteredProduct, setFilteredProduct] = React.useState({
|
||||
category: 'colab-transforms',
|
||||
tags: ['identity-security-cloud'],
|
||||
});
|
||||
|
||||
const handleClick = (data) => {
|
||||
var tempFilter = [];
|
||||
|
||||
const index = tempFilter.indexOf(data);
|
||||
if (index !== -1) {
|
||||
tempFilter.splice(index, 1);
|
||||
} else {
|
||||
tempFilter.push(data);
|
||||
}
|
||||
|
||||
setFilteredProduct({
|
||||
category: 'colab-transforms',
|
||||
tags: tempFilter,
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||
<main>
|
||||
<MarketplaceBanner />
|
||||
<div className={styles.container}>
|
||||
<div className={styles.filterContainer}>
|
||||
<BlogSidebar filterCallback={handleClick} isChecked={true} />
|
||||
</div>
|
||||
<div className={styles.cardContainer}>
|
||||
<MarketplaceCards filterCallback={filteredProduct} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
46
src/pages/colab/workflows.js
Normal file
46
src/pages/colab/workflows.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
import styles from './filter.module.css';
|
||||
|
||||
import BlogSidebar from '../../components/blog/BlogSidebar';
|
||||
import MarketplaceCards from '../../components/marketplace/MarketplaceCards';
|
||||
import MarketplaceBanner from '../../components/marketplace/MarketplaceBanner';
|
||||
|
||||
export default function Workflows() {
|
||||
const [filteredProduct, setFilteredProduct] = React.useState({
|
||||
category: 'colab',
|
||||
tags: ['workflows'],
|
||||
});
|
||||
|
||||
const handleClick = (data) => {
|
||||
var tempFilter = [];
|
||||
|
||||
const index = tempFilter.indexOf(data);
|
||||
if (index !== -1) {
|
||||
tempFilter.splice(index, 1);
|
||||
} else {
|
||||
tempFilter.push(data);
|
||||
}
|
||||
|
||||
setFilteredProduct({
|
||||
category: 'colab-workflows',
|
||||
tags: tempFilter,
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||
<main>
|
||||
<MarketplaceBanner />
|
||||
<div className={styles.container}>
|
||||
<div className={styles.filterContainer}>
|
||||
<BlogSidebar filterCallback={handleClick} />
|
||||
</div>
|
||||
<div className={styles.cardContainer}>
|
||||
<MarketplaceCards filterCallback={filteredProduct} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
@@ -1,17 +1,176 @@
|
||||
.blogContainer {
|
||||
.cardContainer {
|
||||
min-height: 400px;
|
||||
width: 1500px;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
margin: auto;
|
||||
width: 1500px;
|
||||
}
|
||||
|
||||
.featured {
|
||||
margin-left: 8%;
|
||||
}
|
||||
|
||||
.discourseContainer {
|
||||
border-radius: 0.5em;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: 1%;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.link {
|
||||
margin-top: 3%;
|
||||
margin-left: 1%;
|
||||
}
|
||||
|
||||
.mainCard {
|
||||
display: grid;
|
||||
grid-gap: 20px;
|
||||
max-width: 1180px;
|
||||
justify-content: center;
|
||||
min-height: 535px;
|
||||
}
|
||||
|
||||
.featuredGettingStartedText {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.gettingStartedText,
|
||||
.featuredGettingStartedText {
|
||||
margin-top: 50px;
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.gettingStartedOne {
|
||||
color: var(--ifm-color-primary);
|
||||
font-size: 30px;
|
||||
max-width: 396px;
|
||||
font-weight: bold;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
.gettingStartedTwo {
|
||||
margin-top: 20px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.gettingStartedThree {
|
||||
margin-top: 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Getting Started Card container */
|
||||
.gridContainer {
|
||||
display: grid;
|
||||
margin-left: 50px;
|
||||
margin-bottom: 50px;
|
||||
grid-gap: 20px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
|
||||
place-content: center;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
.video {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.contentContainer {
|
||||
margin-left: 5%;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1950px) {
|
||||
.container {
|
||||
width: 1225px;
|
||||
}
|
||||
.cardContainer {
|
||||
width: 1225px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1350px) {
|
||||
.container {
|
||||
width: 950px;
|
||||
}
|
||||
.cardContainer {
|
||||
width: 950px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1050px) {
|
||||
.container {
|
||||
width: 675px;
|
||||
}
|
||||
.cardContainer {
|
||||
width: 675px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 700px) {
|
||||
.container {
|
||||
width: 275px;
|
||||
}
|
||||
|
||||
.cardContainer {
|
||||
width: 275px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1178px) {
|
||||
.carousel {
|
||||
margin-top: 0px;
|
||||
margin-left: 50px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
.contentContainer {
|
||||
width: 600px;
|
||||
margin-left: 10%;
|
||||
}
|
||||
}
|
||||
@media only screen and (min-width: 1179px) {
|
||||
.mainCard {
|
||||
grid-template-columns: repeat(auto-fit, minmax(520px, 1fr));
|
||||
/* UI Properties */
|
||||
background: var(--main-hero-card-background);
|
||||
box-shadow: var(--dev-main-card-shadow);
|
||||
border: 1px solid var(--dev-card-background);
|
||||
border-radius: 40px;
|
||||
opacity: 1;
|
||||
margin: 50px auto;
|
||||
width: calc(100% - 100px);
|
||||
height: 535px;
|
||||
min-height: 535px;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 570px) {
|
||||
.featured {
|
||||
margin-left: 0%;
|
||||
}
|
||||
|
||||
.gettingStartedThree {
|
||||
padding-right: 15%;
|
||||
}
|
||||
|
||||
.featuredGettingStartedText {
|
||||
display: flex;
|
||||
}
|
||||
.contentContainer {
|
||||
width: auto;
|
||||
margin-left: 0%;
|
||||
}
|
||||
.carousel {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.blogSidbarContainer {
|
||||
flex: 5%;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 870px) {
|
||||
.blogSidbarContainer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.blogCardContainer {
|
||||
flex: 95%;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import Link from '@docusaurus/Link';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import Layout from '@theme/Layout';
|
||||
import HomepageGettingStarted from '@site/src/components/homepage/HomepageGettingStarted';
|
||||
import HomepageDeveloperDays from '@site/src/components/homepage/HomepageDeveloperDays';
|
||||
import HomepageBasics from '../components/homepage/HomepageBasics';
|
||||
import HomepageTrainingGuides from '../components/homepage/HomepageTrainingGuides';
|
||||
import HomepageDiscuss from '../components/homepage/HomepageDiscuss';
|
||||
@@ -16,14 +17,15 @@ export default function Home() {
|
||||
return (
|
||||
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||
<main>
|
||||
<HomepageGettingStarted />
|
||||
{/* <HomepageGettingStarted /> */}
|
||||
<HomepageDeveloperDays />
|
||||
<HomepageBasics
|
||||
description={
|
||||
"If you still aren't sure where to get started, try one of the <b>Getting Started Guides</b> below, or see what our platform has to offer."
|
||||
}
|
||||
link={'https://www.sailpoint.com/products/IdentityNow/'}
|
||||
title={'Start With the Basics'}
|
||||
image={'/homepage/person-head.png'}
|
||||
image={'user'}
|
||||
buttonText={'Explore our platform'}
|
||||
/>
|
||||
<HomepageTrainingGuides />
|
||||
@@ -33,19 +35,22 @@ export default function Home() {
|
||||
}
|
||||
link={'https://developer.sailpoint.com/discuss/'}
|
||||
title={'What is the Community saying?'}
|
||||
image={'/homepage/discuss.png'}
|
||||
image={'discuss'}
|
||||
buttonText={'Join the Discussion'}
|
||||
/>
|
||||
|
||||
<HomepageDiscuss />
|
||||
<HomepageBasics
|
||||
description={
|
||||
"The Developer Relations team is responsible for creating a better developer experience on our platform. Click on someone to reach out to them, or <a href='https://developer.sailpoint.com/discuss/new-message?groupname=developer_relations/'>contact our team directly</a>."
|
||||
}
|
||||
title={'Meet Our Team'}
|
||||
image={'/homepage/team.png'}
|
||||
buttonText={''}
|
||||
/>
|
||||
<HomepageTeam />
|
||||
<div>
|
||||
<HomepageBasics
|
||||
description={
|
||||
"The Developer Relations team is responsible for creating a better developer experience on our platform. Click on someone to reach out to them, or <a href='https://developer.sailpoint.com/discuss/new-message?groupname=developer_relations/'>contact our team directly</a>."
|
||||
}
|
||||
title={'Meet Our Team'}
|
||||
image={'team'}
|
||||
buttonText={''}
|
||||
/>
|
||||
<HomepageTeam />
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
|
||||
@@ -21,3 +21,5 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
70
src/pages/videos.js
Normal file
70
src/pages/videos.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import VideoCards from '../components/video-library/VideoCards';
|
||||
import VideoSidebar from '../components/video-library/VideoSidebar';
|
||||
import DiscourseEmbed from '../components/video-library/VideoComments';
|
||||
import styles from './videos.module.css';
|
||||
|
||||
export default function VideoLibrary() {
|
||||
const [filteredProduct, setFilteredProduct] = React.useState({
|
||||
tags: [],
|
||||
});
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
|
||||
const handleClick = (data) => {
|
||||
setFilteredProduct({tags: data.tag});
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||
<main>
|
||||
<div>
|
||||
<div className={styles.titleContainer}></div>
|
||||
<div>
|
||||
<div className={styles.mainCard}>
|
||||
<div className={styles.contentContainer}>
|
||||
<div className={styles.gettingStartedText}>
|
||||
<div className={styles.gettingStartedOne}>Video Library</div>
|
||||
<div className={styles.gettingStartedThree}>
|
||||
<span>
|
||||
Our video library is a collection of educational videos
|
||||
from our Developer Relations team, live streams,
|
||||
conferences, and other community members.
|
||||
</span>{' '}
|
||||
<br />
|
||||
<br />
|
||||
<a href="https://developer.sailpoint.com/discuss/new-message?groupname=developer_relations&title=Proposal%20for%20Developer%20Community%20Video&body=Write%20your%20request%20here.">
|
||||
Contribute to our library →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.featuredGettingStartedText}>
|
||||
<div className={styles.gettingStartedOne}>Featured</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.featuredVideo} title="Featured Video">
|
||||
<VideoCards
|
||||
filterCallback={filteredProduct}
|
||||
limit={1}
|
||||
featured={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.videosCardContainer}>
|
||||
<div className={styles.videoSideBar}>
|
||||
<VideoSidebar
|
||||
selectedCategory={filteredProduct}
|
||||
filterCallback={handleClick}
|
||||
/>
|
||||
</div>
|
||||
<VideoCards filterCallback={filteredProduct} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
147
src/pages/videos.module.css
Normal file
147
src/pages/videos.module.css
Normal file
@@ -0,0 +1,147 @@
|
||||
.videosCardContainer {
|
||||
flex: 95%;
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.featuredVideo {
|
||||
margin-left: 75px;
|
||||
}
|
||||
|
||||
.videosTitle {
|
||||
text-align: center;
|
||||
margin-bottom: 2%;
|
||||
color: #ffffff;
|
||||
position: relative;
|
||||
top: 25px;
|
||||
}
|
||||
|
||||
.titleContainer {
|
||||
width: 100%;
|
||||
height: 45px;
|
||||
background: rgb(0, 51, 161);
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 51, 161, 1) 0%,
|
||||
rgba(84, 192, 232, 1) 100%
|
||||
);
|
||||
align-content: center;
|
||||
margin-bottom: 2%;
|
||||
}
|
||||
|
||||
.mainCard {
|
||||
display: grid;
|
||||
grid-gap: 20px;
|
||||
max-width: 1180px;
|
||||
justify-content: center;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.featuredGettingStartedText {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.gettingStartedText,
|
||||
.featuredGettingStartedText {
|
||||
margin-top: 50px;
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.gettingStartedOne {
|
||||
color: var(--ifm-color-primary);
|
||||
font-size: 30px;
|
||||
max-width: 396px;
|
||||
font-weight: bold;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
.gettingStartedTwo {
|
||||
margin-top: 20px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.gettingStartedThree {
|
||||
margin-top: 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.video {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.contentContainer {
|
||||
margin-left: 75px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1178px) {
|
||||
.carousel {
|
||||
margin-top: 0px;
|
||||
margin-left: 50px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
.contentContainer {
|
||||
width: 600px;
|
||||
margin-left: 75px;
|
||||
}
|
||||
|
||||
.featuredVideo {
|
||||
margin-left: 175px;
|
||||
}
|
||||
.videoSideBar {
|
||||
margin-left: 5%;
|
||||
}
|
||||
|
||||
.featuredGettingStartedText {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@media only screen and (min-width: 1179px) {
|
||||
.carousel {
|
||||
margin-top: 35px;
|
||||
padding-bottom: 5%;
|
||||
}
|
||||
.mainCard {
|
||||
grid-template-columns: repeat(auto-fit, minmax(520px, 1fr));
|
||||
/* UI Properties */
|
||||
background: var(--main-hero-card-background);
|
||||
box-shadow: var(--dev-main-card-shadow);
|
||||
border: 1px solid var(--dev-card-background);
|
||||
border-radius: 40px;
|
||||
opacity: 1;
|
||||
margin: 50px auto;
|
||||
width: calc(100% - 100px);
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 900px) {
|
||||
.videoSideBar {
|
||||
margin-left: 0%;
|
||||
}
|
||||
.featuredVideo {
|
||||
margin: auto;
|
||||
}
|
||||
.carousel {
|
||||
margin-bottom: 1%;
|
||||
}
|
||||
|
||||
.gettingStartedThree {
|
||||
padding-right: 15%;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 570px) {
|
||||
|
||||
.contentContainer {
|
||||
width: auto;
|
||||
margin: auto;
|
||||
}
|
||||
.carousel {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
@@ -57,9 +57,52 @@ export async function checkImage(url) {
|
||||
export async function getBlogPosts(tags) {
|
||||
let url = '';
|
||||
if (tags) {
|
||||
url = discourseBaseURL() + 'c/blog/l/latest.json?tags=' + tags;
|
||||
url =
|
||||
discourseBaseURL() +
|
||||
'c/content/community-blog/l/latest.json?tags=' +
|
||||
tags;
|
||||
} else {
|
||||
url = discourseBaseURL() + 'c/blog/l/latest.json';
|
||||
url = discourseBaseURL() + 'c/content/community-blog/l/latest.json';
|
||||
}
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getUserTitle(primary_group_name) {
|
||||
let url = discourseBaseURL() + 'g/' + primary_group_name + '.json';
|
||||
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getVideoPosts(tags) {
|
||||
let url = '';
|
||||
if (tags) {
|
||||
if (tags.length < 1) {
|
||||
url = discourseBaseURL() + 'c/content/video-library/l/latest.json';
|
||||
}
|
||||
if (tags.length === 1) {
|
||||
url =
|
||||
discourseBaseURL() +
|
||||
'c/content/video-library/l/latest.json?tags=' +
|
||||
tags;
|
||||
}
|
||||
if (tags.length === 2) {
|
||||
url =
|
||||
discourseBaseURL() +
|
||||
`filter.json?q=category%3Avideo-library%20tag%3A${tags[0]}%2B${tags[1]}`;
|
||||
}
|
||||
} else {
|
||||
url = discourseBaseURL() + 'c/content/video-library/l/latest.json';
|
||||
}
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
|
||||
@@ -9,8 +9,7 @@ import isInternalUrl from '@docusaurus/isInternalUrl';
|
||||
import {translate} from '@docusaurus/Translate';
|
||||
import styles from './styles.module.css';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faFolderOpen, faLink, faBook, faArrowUpRightFromSquare } from '@fortawesome/pro-duotone-svg-icons'
|
||||
import { useColorMode } from '@docusaurus/theme-common';
|
||||
import { faFolderOpen, faBook, faArrowUpRightFromSquare } from '@fortawesome/pro-duotone-svg-icons'
|
||||
|
||||
function CardContainer({href, children}) {
|
||||
return (
|
||||
@@ -39,10 +38,6 @@ function CardLayout({href, icon, title, description}) {
|
||||
}
|
||||
function CardCategory({item}) {
|
||||
const href = findFirstCategoryLink(item);
|
||||
const {colorMode} = useColorMode();
|
||||
//const icon = colorMode === 'dark' ? <FontAwesomeIcon icon={faFolderOpen} style={{marginRight: "0.5em"}} color='#0033a1' /> : <FontAwesomeIcon icon={faFolderOpen} style={{marginRight: "0.5em"}} color='#7ecfee' />;
|
||||
//const icon = <FontAwesomeIcon icon={faFolderOpen} style={{marginRight: "0.5em"}} color='#0033a1' />;
|
||||
//console.log(item)
|
||||
// Unexpected: categories that don't have a link have been filtered upfront
|
||||
if (!href) {
|
||||
return null;
|
||||
@@ -50,7 +45,7 @@ function CardCategory({item}) {
|
||||
return (
|
||||
<CardLayout
|
||||
href={href}
|
||||
icon={<FontAwesomeIcon icon={faFolderOpen} style={{marginRight: "0.5em"}} color={colorMode === 'dark' ? '#7ecfee' : '#0033a1'} />}
|
||||
icon={<FontAwesomeIcon icon={faFolderOpen} className={styles.docCardIcon} />}
|
||||
//icon={icon}
|
||||
title={item.label}
|
||||
description={
|
||||
@@ -69,8 +64,7 @@ function CardCategory({item}) {
|
||||
);
|
||||
}
|
||||
function CardLink({item}) {
|
||||
const {colorMode} = useColorMode();
|
||||
const icon = isInternalUrl(item.href) ? <FontAwesomeIcon icon={faBook} style={{marginRight: "0.5em"}} color={colorMode === 'dark' ? '#7ecfee' : '#0033a1'} /> : <FontAwesomeIcon icon={faArrowUpRightFromSquare} style={{marginRight: "0.5em"}} color={colorMode === 'dark' ? '#7ecfee' : '#0033a1'} />;
|
||||
const icon = isInternalUrl(item.href) ? <FontAwesomeIcon icon={faBook} className={styles.docCardIcon} /> : <FontAwesomeIcon icon={faArrowUpRightFromSquare} className={styles.docCardIcon} />;
|
||||
const doc = useDocById(item.docId ?? undefined);
|
||||
return (
|
||||
<CardLayout
|
||||
|
||||
@@ -26,3 +26,8 @@
|
||||
.cardDescription {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.docCardIcon {
|
||||
margin-right: .5em;
|
||||
color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
@@ -2,23 +2,34 @@ export function addDarkToFileName(filename) {
|
||||
const parts = filename.split('.');
|
||||
return parts[0] + '-dark.' + parts[1];
|
||||
}
|
||||
|
||||
export function discourseBaseURL() {return 'https://developer.sailpoint.com/discuss/'}
|
||||
export function developerWebsiteDomain() {return 'developer.sailpoint.com'}
|
||||
export function videoThumbnailBaseURL() {
|
||||
return 'https://play.vidyard.com/';
|
||||
}
|
||||
export function videoBaseURL() {
|
||||
return '/videos/';
|
||||
}
|
||||
export function discourseBaseURL() {
|
||||
return 'https://developer.sailpoint.com/discuss/';
|
||||
}
|
||||
export function developerWebsiteDomain() {
|
||||
return 'developer.sailpoint.com';
|
||||
}
|
||||
export function discourseMarketplaceCatagoryId() {
|
||||
if (discourseBaseURL().includes('soon')) {
|
||||
return 57
|
||||
return 57;
|
||||
} else {
|
||||
return 59
|
||||
return 59;
|
||||
}
|
||||
}
|
||||
|
||||
export function discourseProductTag() {
|
||||
if (discourseBaseURL().includes('soon')) {
|
||||
return 11
|
||||
return 11;
|
||||
} else {
|
||||
return 45
|
||||
}
|
||||
}
|
||||
|
||||
export function CMSBaseURL() { return process.env.CMS_APP_API_ENDPOINT}
|
||||
export function CMSBaseURL() {
|
||||
return process.env.CMS_APP_API_ENDPOINT;
|
||||
}
|
||||
|
||||
@@ -42,11 +42,15 @@ patch:
|
||||
- Accounts
|
||||
summary: Update Account
|
||||
description: >-
|
||||
Use this endpoint to update an account with a PATCH request.
|
||||
This updates account details.
|
||||
A token with ORG_ADMIN, SOURCE_ADMIN, or SOURCE_SUBADMIN authority is required to call this API.
|
||||
|
||||
The request must provide a JSONPatch payload.
|
||||
|
||||
A token with ORG_ADMIN authority is required to call this API.
|
||||
This endpoint supports updating an account's correlation. It can only modify the identityId and manuallyCorrelated
|
||||
attributes. To re-assign an account from one identity to another, replace the current identityId with a new value.
|
||||
If the account you're assigning was provisioned by IdentityNow, it's possible IdentityNow could create a new account
|
||||
for the previous identity as soon as the account is moved. If the account you're assigning is authoritative,
|
||||
this will cause the previous identity to become uncorrelated and could even result in its deletion. All accounts
|
||||
that are are reassigned will be set to manuallyCorrelated: true.
|
||||
security:
|
||||
- UserContextAuth: [idn:accounts:manage]
|
||||
parameters:
|
||||
@@ -180,4 +184,4 @@ delete:
|
||||
"429":
|
||||
$ref: "../../v3/responses/429.yaml"
|
||||
"500":
|
||||
$ref: "../../v3/responses/500.yaml"
|
||||
$ref: "../../v3/responses/500.yaml"
|
||||
|
||||
@@ -6,16 +6,18 @@ post:
|
||||
description: >-
|
||||
This API submits a task to unlock an account and returns the task ID.
|
||||
|
||||
To use this endpoint to unlock an account that has the `forceProvisioning` option set to true, the `idn:accounts-provisioning:manage` scope is required.
|
||||
|
||||
A token with ORG_ADMIN authority is required to call this API.
|
||||
security:
|
||||
- UserContextAuth: [idn:accounts-state:manage]
|
||||
- UserContextAuth: [idn:accounts-state:manage, idn:accounts-provisioning:manage]
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: The account id
|
||||
description: The account ID.
|
||||
example: ef38f94347e94562b5bb8424a56397d8
|
||||
requestBody:
|
||||
required: true
|
||||
|
||||
@@ -26,38 +26,6 @@ get:
|
||||
$ref: '../../v3/responses/429.yaml'
|
||||
'500':
|
||||
$ref: '../../v3/responses/500.yaml'
|
||||
post:
|
||||
operationId: createProfileConfig
|
||||
tags:
|
||||
- Auth Profile
|
||||
summary: Create Auth Profile.
|
||||
description: >-
|
||||
This API creates an auth profile.
|
||||
security:
|
||||
- UserContextAuth: [sp:auth-profile:create]
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../schemas/AuthProfileRequest.yaml"
|
||||
responses:
|
||||
'202':
|
||||
description: Auth Profile details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../schemas/AuthProfile.yaml'
|
||||
'400':
|
||||
$ref: '../../v3/responses/400.yaml'
|
||||
'401':
|
||||
$ref: '../../v3/responses/401.yaml'
|
||||
'403':
|
||||
$ref: '../../v3/responses/403.yaml'
|
||||
'429':
|
||||
$ref: '../../v3/responses/429.yaml'
|
||||
'500':
|
||||
$ref: '../../v3/responses/500.yaml'
|
||||
patch:
|
||||
operationId: patchProfileConfig
|
||||
tags:
|
||||
@@ -70,7 +38,7 @@ patch:
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: ID of the Auth Profile to patch
|
||||
description: ID of the Auth Profile to patch.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
@@ -85,7 +53,7 @@ patch:
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: Responds with the Access Profile as updated.
|
||||
description: Responds with the Auth Profile as updated.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -102,33 +70,3 @@ patch:
|
||||
$ref: '../../v3/responses/500.yaml'
|
||||
security:
|
||||
- UserContextAuth: [sp:auth-profile:update]
|
||||
delete:
|
||||
operationId: deleteProfileConfig
|
||||
tags:
|
||||
- Auth Profile
|
||||
summary: Delete the specified Auth Profile
|
||||
description: >-
|
||||
This API deletes an existing Auth Profile.
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: ID of the Access Profile to delete
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
example: 2c91808a7813090a017814121919ecca
|
||||
responses:
|
||||
'204':
|
||||
$ref: "../../v3/responses/204.yaml"
|
||||
'400':
|
||||
$ref: '../../v3/responses/400.yaml'
|
||||
'401':
|
||||
$ref: '../../v3/responses/401.yaml'
|
||||
'403':
|
||||
$ref: '../../v3/responses/403.yaml'
|
||||
'429':
|
||||
$ref: '../../v3/responses/429.yaml'
|
||||
'500':
|
||||
$ref: '../../v3/responses/500.yaml'
|
||||
security:
|
||||
- UserContextAuth: [sp:auth-profile:delete]
|
||||
|
||||
61
static/api-specs/idn/beta/paths/discovered-applications.yaml
Normal file
61
static/api-specs/idn/beta/paths/discovered-applications.yaml
Normal file
@@ -0,0 +1,61 @@
|
||||
get:
|
||||
operationId: getDiscoveredApplications
|
||||
tags:
|
||||
- Discovered Applications
|
||||
summary: Retrieve discovered applications for tenant
|
||||
description: >
|
||||
Fetches a list of applications that have been identified within the environment. This includes details such as application names, discovery dates, potential correlated saas_vendors and related suggested connectors.
|
||||
security:
|
||||
- UserContextAuth:
|
||||
- 'idn:application-discovery:read'
|
||||
parameters:
|
||||
- $ref: '../../v3/parameters/limit.yaml'
|
||||
- $ref: '../../v3/parameters/offset.yaml'
|
||||
- in: query
|
||||
name: filter
|
||||
schema:
|
||||
type: string
|
||||
description: >
|
||||
Filter results using the standard syntax described in [V3 API Standard Collection Parameters](https://developer.sailpoint.com/idn/api/standard-collection-parameters#filtering-results)
|
||||
|
||||
|
||||
Filtering is supported for the following fields and operators:
|
||||
|
||||
|
||||
**name**: *eq, sw, co*
|
||||
|
||||
|
||||
**description**: *eq, sw, co*
|
||||
example: name eq "Okta" and description co "Okta"
|
||||
required: false
|
||||
style: form
|
||||
- in: query
|
||||
name: sorters
|
||||
schema:
|
||||
type: string
|
||||
format: comma-separated
|
||||
description: >-
|
||||
Sort results using the standard syntax described in [V3 API Standard Collection Parameters](https://developer.sailpoint.com/idn/api/standard-collection-parameters#sorting-results)
|
||||
|
||||
|
||||
Sorting is supported for the following fields: **name, description, discoveredAt, discoverySource**
|
||||
example: name
|
||||
responses:
|
||||
'200':
|
||||
description: Successfully retrieved list of discovered applications.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '../../beta/schemas/DiscoveredApplications.yaml'
|
||||
'400':
|
||||
$ref: '../../v3/responses/400.yaml'
|
||||
'401':
|
||||
$ref: '../../v3/responses/401.yaml'
|
||||
'403':
|
||||
$ref: '../../v3/responses/403.yaml'
|
||||
'429':
|
||||
$ref: '../../v3/responses/429.yaml'
|
||||
'500':
|
||||
$ref: '../../v3/responses/500.yaml'
|
||||
103
static/api-specs/idn/beta/paths/icon.yaml
Normal file
103
static/api-specs/idn/beta/paths/icon.yaml
Normal file
@@ -0,0 +1,103 @@
|
||||
put:
|
||||
operationId: setIcon
|
||||
tags:
|
||||
- Icons
|
||||
summary: Update an icon
|
||||
description: >-
|
||||
This API endpoint updates an icon by object type and object id.
|
||||
A token with ORG_ADMIN authority is required to call this API.
|
||||
parameters:
|
||||
- in: path
|
||||
name: objectType
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: Object type. Available options ['application']
|
||||
example: application
|
||||
- in: path
|
||||
name: objectId
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: Object id.
|
||||
example: a291e870-48c3-4953-b656-fb5ce2a93169
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- image
|
||||
properties:
|
||||
image:
|
||||
type: string
|
||||
format: binary
|
||||
description: file with icon. Allowed mime-types ['image/png', 'image/jpeg']
|
||||
example: \x00\x00\x00\x02
|
||||
security:
|
||||
- UserContextAuth: [ ]
|
||||
responses:
|
||||
'200':
|
||||
description: Icon updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
icon:
|
||||
type: string
|
||||
description: url to file with icon
|
||||
example: ""
|
||||
'400':
|
||||
$ref: '../../v3/responses/400.yaml'
|
||||
'401':
|
||||
$ref: '../../v3/responses/401.yaml'
|
||||
'403':
|
||||
$ref: '../../v3/responses/403.yaml'
|
||||
'404':
|
||||
$ref: '../../v3/responses/404.yaml'
|
||||
'429':
|
||||
$ref: '../../v3/responses/429.yaml'
|
||||
'500':
|
||||
$ref: '../../v3/responses/500.yaml'
|
||||
delete:
|
||||
operationId: deleteIcon
|
||||
tags:
|
||||
- Icons
|
||||
summary: Delete an icon
|
||||
description: >-
|
||||
This API endpoint delete an icon by object type and object id.
|
||||
A token with ORG_ADMIN authority is required to call this API.
|
||||
parameters:
|
||||
- in: path
|
||||
name: objectType
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: Object type. Available options ['application']
|
||||
example: application
|
||||
- in: path
|
||||
name: objectId
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: Object id.
|
||||
example: a291e870-48c3-4953-b656-fb5ce2a93169
|
||||
security:
|
||||
- UserContextAuth: [ ]
|
||||
responses:
|
||||
'204':
|
||||
$ref: '../../v3/responses/204.yaml'
|
||||
'400':
|
||||
$ref: '../../v3/responses/400.yaml'
|
||||
'401':
|
||||
$ref: '../../v3/responses/401.yaml'
|
||||
'403':
|
||||
$ref: '../../v3/responses/403.yaml'
|
||||
'404':
|
||||
$ref: '../../v3/responses/404.yaml'
|
||||
'429':
|
||||
$ref: '../../v3/responses/429.yaml'
|
||||
'500':
|
||||
$ref: '../../v3/responses/500.yaml'
|
||||
@@ -4,16 +4,19 @@ post:
|
||||
- Identities
|
||||
summary: Process a list of identityIds
|
||||
description: |
|
||||
You could use this endpoint to:
|
||||
This operation should not be used to schedule your own identity processing or to perform system wide identity refreshes. The system will use a combination of [event-based processing](https://documentation.sailpoint.com/saas/help/setup/identity_processing.html?h=process#event-based-processing) and [scheduled processing](https://documentation.sailpoint.com/saas/help/setup/identity_processing.html?h=process#scheduled-processing) that runs every day at 8:00 AM and 8:00 PM in the tenant's timezone to keep your identities synchronized.
|
||||
|
||||
This endpoint will perform the following tasks:
|
||||
1. Calculate identity attributes, including applying or running any rules or transforms (e.g. calculate Lifecycle State at a point-in-time it's expected to change).
|
||||
2. Evaluate role assignments, leading to assignment of new roles and removal of existing roles.
|
||||
3. Enforce provisioning for any assigned accesses that haven't been fulfilled (e.g. failure due to source health).
|
||||
4. Recalculate manager relationships.
|
||||
5. Potentially clean-up identity processing errors, assuming the error has been resolved.
|
||||
|
||||
To learn more, refer to the [identity processing documentation](https://documentation.sailpoint.com/saas/help/setup/identity_processing.html).
|
||||
|
||||
A token with ORG_ADMIN or HELPDESK authority is required to call this API.
|
||||
externalDocs:
|
||||
description: 'Learn more about manually processing identities here'
|
||||
url: 'https://documentation.sailpoint.com/saas/help/setup/identity_processing.html'
|
||||
security:
|
||||
- UserContextAuth:
|
||||
- "idn:identity:manage"
|
||||
|
||||
@@ -5,6 +5,10 @@ get:
|
||||
summary: List Identities
|
||||
description: >-
|
||||
This API returns a list of identities.
|
||||
security:
|
||||
- UserContextAuth:
|
||||
- "idn:identity:read"
|
||||
- "idn:identity:manage"
|
||||
parameters:
|
||||
- in: query
|
||||
name: filters
|
||||
|
||||
@@ -6,8 +6,21 @@ post:
|
||||
description: >-
|
||||
Process identities under the profile
|
||||
|
||||
This operation should not be used to schedule your own identity processing or to perform system wide identity refreshes. The system will use a combination of [event-based processing](https://documentation.sailpoint.com/saas/help/setup/identity_processing.html?h=process#event-based-processing) and [scheduled processing](https://documentation.sailpoint.com/saas/help/setup/identity_processing.html?h=process#scheduled-processing) that runs every day at 8:00 AM and 8:00 PM in the tenant's timezone to keep your identities synchronized.
|
||||
|
||||
This should only be run on identity profiles that have the `identityRefreshRequired` attribute set to `true`. If `identityRefreshRequired` is false, then there is no benefit to running this operation. Typically, this operation is performed when a change is made to the identity profile or its related lifecycle states that requires a refresh.
|
||||
|
||||
This operation will perform the following activities on all identities under the identity profile.
|
||||
|
||||
1. Updates identity attribute according to the identity profile mappings.
|
||||
2. Determines the identity's correct manager through manager correlation.
|
||||
3. Updates the identity's access according to their assigned lifecycle state.
|
||||
4. Updates the identity's access based on role assignment criteria.
|
||||
|
||||
A token with ORG_ADMIN authority is required to call this API.
|
||||
externalDocs:
|
||||
description: 'Learn more about manually processing identities here'
|
||||
url: 'https://documentation.sailpoint.com/saas/help/setup/identity_processing.html'
|
||||
parameters:
|
||||
- in: path
|
||||
name: identity-profile-id
|
||||
|
||||
34
static/api-specs/idn/beta/paths/identity-reset.yaml
Normal file
34
static/api-specs/idn/beta/paths/identity-reset.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
post:
|
||||
operationId: resetIdentity
|
||||
tags:
|
||||
- Identities
|
||||
summary: Reset an identity
|
||||
description: >-
|
||||
Use this endpoint to reset a user's identity if they have forgotten their authentication information like their answers to knowledge-based questions.
|
||||
Resetting an identity de-registers the user and removes any elevated user levels they have.
|
||||
security:
|
||||
- UserContextAuth:
|
||||
- "idn:identity:update"
|
||||
parameters:
|
||||
- in: path
|
||||
name: identityId
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: Identity Id
|
||||
example: "ef38f94347e94562b5bb8424a56397d8"
|
||||
responses:
|
||||
"202":
|
||||
description: Accepted. The reset request accepted and is in progress.
|
||||
"400":
|
||||
$ref: "../../v3/responses/400.yaml"
|
||||
"401":
|
||||
$ref: "../../v3/responses/401.yaml"
|
||||
"403":
|
||||
$ref: "../../v3/responses/403.yaml"
|
||||
"404":
|
||||
$ref: "../../v3/responses/404.yaml"
|
||||
"429":
|
||||
$ref: "../../v3/responses/429.yaml"
|
||||
"500":
|
||||
$ref: "../../v3/responses/500.yaml"
|
||||
@@ -4,14 +4,14 @@ post:
|
||||
- Lifecycle States
|
||||
summary: Set Lifecycle State
|
||||
description: |
|
||||
This endpoint will set/update an identity's lifecycle state to the one provided and updates the corresponding Identity Profile.
|
||||
This endpoint will set/update an identity's lifecycle state to the one provided and updates the corresponding identity profile.
|
||||
|
||||
A token with ORG_ADMIN or API authority is required to call this API.
|
||||
parameters:
|
||||
- in: path
|
||||
name: identity-id
|
||||
description: >-
|
||||
The ID of the identity to update
|
||||
The ID of the identity to update.
|
||||
required: true
|
||||
example: 2c9180857893f1290178944561990364
|
||||
schema:
|
||||
@@ -27,7 +27,7 @@ post:
|
||||
lifecycleStateId:
|
||||
type: string
|
||||
format: uuid
|
||||
description: The ID of the lifecycle state to set
|
||||
description: The ID of the lifecycle state to set.
|
||||
example: 2c9180877a86e408017a8c19fefe046c
|
||||
responses:
|
||||
'200':
|
||||
@@ -41,7 +41,7 @@ post:
|
||||
type: string
|
||||
format: uuid
|
||||
example: 2c9180837ab5b716017ab7c6c9ef1e20
|
||||
description: The ID of the IdentityRequest object that was generated when the workflow launches
|
||||
description: The ID of the IdentityRequest object that is generated when the workflow launches. To follow the IdentityRequest, you can provide this ID with a [Get Account Activity request](https://developer.sailpoint.com/docs/api/beta/get-account-activity/). The response will contain relevant information about the IdentityRequest, such as its status.
|
||||
'401':
|
||||
$ref: '../../v3/responses/401.yaml'
|
||||
'403':
|
||||
|
||||
@@ -8,6 +8,7 @@ get:
|
||||
security:
|
||||
- UserContextAuth:
|
||||
- "idn:identity:read"
|
||||
- "idn:identity:manage"
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
post:
|
||||
tags:
|
||||
- Entitlements
|
||||
summary: Import Entitlement CSV File
|
||||
operationId: importEntitlementCsv
|
||||
summary: Aggregate Entitlements
|
||||
operationId: importEntitlements
|
||||
description: >-
|
||||
Uploads a comma separated file (CSV) to a delimited file source and starts an entitlement aggregation on the source.
|
||||
|
||||
Starts an entitlement aggregation on the specified source.
|
||||
|
||||
If the target source is a direct connection, then the request body must be empty. You will also need to make sure the Content-Type header is not set. If you set the Content-Type header without specifying a body, then you will receive a 500 error.
|
||||
|
||||
If the target source is a delimited file source, then the CSV file needs to be included in the request body. You will also need to set the Content-Type header to `multipart/form-data`.
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
@@ -27,7 +30,7 @@ post:
|
||||
- csvFile
|
||||
responses:
|
||||
"202":
|
||||
description: Load Entitlements Task
|
||||
description: Aggregate Entitlements Task
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
|
||||
@@ -3,6 +3,7 @@ get:
|
||||
- Managed Clients
|
||||
summary: Specified Managed Client Status.
|
||||
description: Retrieve Managed Client Status by ID.
|
||||
deprecated: true
|
||||
operationId: getManagedClientStatus
|
||||
parameters:
|
||||
- name: id
|
||||
@@ -45,6 +46,7 @@ post:
|
||||
- Managed Clients
|
||||
summary: Handle status request from client
|
||||
description: Update a status detail passed in from the client
|
||||
deprecated: true
|
||||
operationId: updateManagedClientStatus
|
||||
parameters:
|
||||
- name: id
|
||||
|
||||
@@ -3,6 +3,7 @@ get:
|
||||
- Managed Clusters
|
||||
summary: Get managed cluster's log configuration
|
||||
description: Get managed cluster's log configuration.
|
||||
deprecated: true
|
||||
operationId: getClientLogConfiguration
|
||||
parameters:
|
||||
- name: id
|
||||
@@ -40,6 +41,7 @@ put:
|
||||
- Managed Clusters
|
||||
summary: Update managed cluster's log configuration
|
||||
description: Update managed cluster's log configuration
|
||||
deprecated: true
|
||||
operationId: putClientLogConfiguration
|
||||
parameters:
|
||||
- name: id
|
||||
|
||||
@@ -3,6 +3,7 @@ get:
|
||||
- Managed Clusters
|
||||
summary: Get a specified ManagedCluster.
|
||||
description: Retrieve a ManagedCluster by ID.
|
||||
deprecated: true
|
||||
operationId: getManagedCluster
|
||||
parameters:
|
||||
- name: id
|
||||
|
||||
@@ -3,6 +3,7 @@ get:
|
||||
- Managed Clusters
|
||||
summary: Retrieve all Managed Clusters.
|
||||
description: Retrieve all Managed Clusters for the current Org, based on request context.
|
||||
deprecated: true
|
||||
operationId: getManagedClusters
|
||||
parameters:
|
||||
- $ref: '../../v3/parameters/offset.yaml'
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
get:
|
||||
summary: CSV template download for discovery
|
||||
tags:
|
||||
- Manual Discover Applications Template
|
||||
description: >
|
||||
Allows the user to download an example CSV file with two columns `application_name` and `domain`.
|
||||
The CSV file contains a single row with the values 'Example Application' and 'Example Description'.
|
||||
security:
|
||||
- UserContextAuth:
|
||||
- 'idn:application-discovery:read'
|
||||
operationId: getManualDiscoverApplicationsCsvTemplate
|
||||
responses:
|
||||
'200':
|
||||
description: A CSV file download was successful.
|
||||
content:
|
||||
text/csv:
|
||||
schema:
|
||||
$ref: '../schemas/ManualDiscoverApplicationsTemplate.yaml'
|
||||
'400':
|
||||
$ref: '../../v3/responses/400.yaml'
|
||||
'401':
|
||||
$ref: '../../v3/responses/401.yaml'
|
||||
'403':
|
||||
$ref: '../../v3/responses/403.yaml'
|
||||
'429':
|
||||
$ref: '../../v3/responses/429.yaml'
|
||||
'500':
|
||||
$ref: '../../v3/responses/500.yaml'
|
||||
@@ -0,0 +1,43 @@
|
||||
post:
|
||||
summary: CSV Upload to discover applications
|
||||
tags:
|
||||
- Manual Discover Applications
|
||||
description: >-
|
||||
This API allows for the upload of a CSV file containing application data to
|
||||
be manually correlated to potential IDN connector(s).
|
||||
security:
|
||||
- UserContextAuth:
|
||||
- 'idn:application-discovery:write'
|
||||
operationId: sendManualDiscoverApplicationsCsvTemplate
|
||||
requestBody:
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
csvFile:
|
||||
type: string
|
||||
format: binary
|
||||
required:
|
||||
- csvFile
|
||||
responses:
|
||||
'200':
|
||||
description: The CSV has been successfully processed.
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
$ref: '../schemas/ManualDiscoverApplications.yaml'
|
||||
'400':
|
||||
$ref: '../../v3/responses/400.yaml'
|
||||
description: >
|
||||
Bad request - There was an error with the CSV format or validation
|
||||
failed (e.g., `application_name` missing). Error message should be
|
||||
provided in response.
|
||||
'401':
|
||||
$ref: '../../v3/responses/401.yaml'
|
||||
'403':
|
||||
$ref: '../../v3/responses/403.yaml'
|
||||
'429':
|
||||
$ref: '../../v3/responses/429.yaml'
|
||||
'500':
|
||||
$ref: '../../v3/responses/500.yaml'
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user