diff --git a/components/gainsight_nxt/actions/create-or-update-company/create-or-update-company.mjs b/components/gainsight_nxt/actions/create-or-update-company/create-or-update-company.mjs new file mode 100644 index 0000000000000..9e0f536672c31 --- /dev/null +++ b/components/gainsight_nxt/actions/create-or-update-company/create-or-update-company.mjs @@ -0,0 +1,133 @@ +import { parseObjectEntries } from "../../common/utils.mjs"; +import app from "../../gainsight_nxt.app.mjs"; + +export default { + key: "gainsight_nxt-create-or-update-company", + name: "Create or Update Company", + description: "Create or update a company record. [See the documentation](https://support.gainsight.com/gainsight_nxt/API_and_Developer_Docs/Company_and_Relationship_API/Company_API_Documentation#Parameters)", + version: "0.0.1", + type: "action", + props: { + app, + name: { + type: "string", + label: "Name", + description: "The name of the company. If a company record with this name exists, it will be updated, otherwise a new one will be created.", + }, + industry: { + type: "string", + label: "Industry", + description: "The industry name of the company.", + optional: true, + }, + arr: { + type: "string", + label: "Annual Recurring Revenue (ARR)", + description: "The annual recurring revenue of the company, as a currency value.", + optional: true, + }, + employees: { + type: "integer", + label: "Employees", + description: "The number of employees the company has.", + optional: true, + }, + lifecycleInWeeks: { + type: "integer", + label: "Life Cycle in Weeks", + description: "The number of weeks the entire process goes through.", + optional: true, + }, + originalContractDate: { + type: "string", + label: "Original Contract Date", + description: "The date the engagement with the client started, in `YYYY-MM-DD` format.", + optional: true, + }, + renewalDate: { + type: "string", + label: "Renewal Date", + description: "The upcoming renewal date of the contract, in `YYYY-MM-DD` format.", + optional: true, + }, + stage: { + type: "string", + label: "Stage", + description: "The current stage of the company in the sales pipeline.", + optional: true, + options: [ + "New Customer", + "Kicked Off", + "Launched", + "Adopting", + "Will Churn", + "Churn", + ], + }, + status: { + type: "string", + label: "Status", + description: "The current status of the company.", + optional: true, + options: [ + "Active", + "Inactive", + "Churn", + ], + }, + additionalOptions: { + type: "object", + label: "Additional Options", + description: + "Additional parameters to send in the request. [See the documentation](https://support.gainsight.com/gainsight_nxt/API_and_Developer_Docs/Company_and_Relationship_API/Company_API_Documentation#Parameters) for available parameters. Values will be parsed as JSON where applicable.", + optional: true, + }, + }, + async run({ $ }) { + const data = { + records: [ + { + Name: this.name, + Industry: this.industry, + ARR: this.arr, + Employees: this.employees, + LifecycleInWeeks: this.lifecycleInWeeks, + OriginalContractDate: this.originalContractDate, + RenewalDate: this.renewalDate, + Stage: this.stage, + Status: this.status, + ...(this.additionalOptions && parseObjectEntries(this.additionalOptions)), + }, + ], + }; + + let summary = ""; + let result; + try { + const updateReq = await this.app.updateCompany({ + $, + data, + }); + result = updateReq; + summary = updateReq.result === true + ? `Successfully updated company '${this.name}'` + : `Error updating company '${this.name}'`; + } + catch (err) { + const createReq = await this.app.createCompany({ + $, + data, + }); + result = createReq; + summary = createReq.result === true + ? `Successfully created company '${this.name}'` + : `Error creating company '${this.name}'`; + } + + $.export( + "$summary", + summary, + ); + return result; + }, +}; diff --git a/components/gainsight_nxt/actions/create-or-update-custom-object/create-or-update-custom-object.mjs b/components/gainsight_nxt/actions/create-or-update-custom-object/create-or-update-custom-object.mjs new file mode 100644 index 0000000000000..f097bcae5e394 --- /dev/null +++ b/components/gainsight_nxt/actions/create-or-update-custom-object/create-or-update-custom-object.mjs @@ -0,0 +1,73 @@ +import app from "../../gainsight_nxt.app.mjs"; + +export default { + key: "gainsight_nxt-create-or-update-custom-object", + name: "Create or Update Custom Object", + description: "Create or update a custom object record. [See the documentation](https://support.gainsight.com/gainsight_nxt/API_and_Developer_Docs/Custom_Object_API/Gainsight_Custom_Object_API_Documentation#Insert_API)", + version: "0.0.1", + type: "action", + props: { + app, + objectName: { + propDefinition: [ + app, + "objectName", + ], + }, + infoBox: { + type: "alert", + alertType: "info", + content: "Custom object fields may be suffixed with `__gc`, e.g. if you've named your field \"Object Name\", its key would be `Object_Name__gc`. Check the object configuration in the Gainsight platform for the correct field names.", + }, + fields: { + type: "string[]", + label: "Key Field(s)", + description: "The field(s) which identify this object (max 3), e.g. `fieldName1`. If a record with the same key field(s) exists, it will be updated, otherwise a new one will be created.", + }, + fieldValues: { + type: "object", + label: "Field Values", + description: "The record data to create or update, as key-value pairs.", + }, + }, + async run({ $ }) { + const { objectName } = this; + const data = { + records: [ + this.fieldValues, + ], + }; + + let summary = ""; + let result; + try { + result = await this.app.updateCustomObject({ + $, + objectName, + data, + params: { + keys: this.fields.join?.() ?? this.fields, + }, + }); + summary = result.result === true + ? `Successfully updated custom object ${objectName}` + : `Error updating custom object ${objectName}`; + } + catch (err) { + result = await this.app.createCustomObject({ + $, + objectName, + data, + }); + summary = result.result === true + ? `Successfully created custom object ${objectName}` + : `Error creating custom object ${objectName}`; + } + + $.export( + "$summary", + summary, + ); + return result; + }, +}; diff --git a/components/gainsight_nxt/actions/create-or-update-person/create-or-update-person.mjs b/components/gainsight_nxt/actions/create-or-update-person/create-or-update-person.mjs new file mode 100644 index 0000000000000..64042f8158fb2 --- /dev/null +++ b/components/gainsight_nxt/actions/create-or-update-person/create-or-update-person.mjs @@ -0,0 +1,63 @@ +import app from "../../gainsight_nxt.app.mjs"; + +export default { + key: "gainsight_nxt-create-or-update-person", + name: "Create or Update Person", + description: "Create or update a person's record. [See the documentation](https://support.gainsight.com/gainsight_nxt/API_and_Developer_Docs/Person_API/People_API_Documentation#Person)", + version: "0.0.1", + type: "action", + props: { + app, + email: { + type: "string", + label: "Email", + description: "The email address of the person. If a record with this email exists, it will be updated, otherwise a new one will be created.", + }, + firstName: { + type: "string", + label: "First Name", + description: "The first name of the person.", + optional: true, + }, + lastName: { + type: "string", + label: "Last Name", + description: "The last name of the person.", + optional: true, + }, + linkedinUrl: { + type: "string", + label: "LinkedIn URL", + description: "The LinkedIn URL of the person.", + optional: true, + }, + location: { + type: "string", + label: "Location", + description: "The location of the person.", + optional: true, + }, + additionalFields: { + type: "object", + label: "Additional Fields", + description: "Additional fields to include in the request body. [See the documentation](https://support.gainsight.com/gainsight_nxt/API_and_Developer_Docs/Person_API/People_API_Documentation#Person) for all available fields.", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.app.createOrUpdatePerson({ + $, + data: { + Email: this.email, + FirstName: this.firstName, + LastName: this.lastName, + LinkedinUrl: this.linkedinUrl, + Location: this.location, + ...this.additionalFields, + }, + }); + + $.export("$summary", `Successfully upserted person with email ${this.email}`); + return response; + }, +}; diff --git a/components/gainsight_nxt/common/utils.mjs b/components/gainsight_nxt/common/utils.mjs new file mode 100644 index 0000000000000..9c3cdbf569744 --- /dev/null +++ b/components/gainsight_nxt/common/utils.mjs @@ -0,0 +1,22 @@ +function optionalParseAsJSON(value) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } +} + +export function parseObjectEntries(value) { + const obj = typeof value === "string" + ? JSON.parse(value) + : value; + return Object.fromEntries( + Object.entries(obj).map(([ + key, + value, + ]) => [ + key, + optionalParseAsJSON(value), + ]), + ); +} diff --git a/components/gainsight_nxt/gainsight_nxt.app.mjs b/components/gainsight_nxt/gainsight_nxt.app.mjs index 7e2c5ff525189..aef6c222e128a 100644 --- a/components/gainsight_nxt/gainsight_nxt.app.mjs +++ b/components/gainsight_nxt/gainsight_nxt.app.mjs @@ -1,11 +1,92 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "gainsight_nxt", - propDefinitions: {}, + propDefinitions: { + objectName: { + type: "string", + label: "Custom Object", + description: "The name of the custom object.", + async options() { + const { data } = await this.listCustomObjects(); + return data?.filter?.((obj) => obj.objectType === "CUSTOM").map(( { + label, objectName, + }) => ({ + label, + value: objectName, + })); + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return `${this.$auth.customer_domain}/v1`; + }, + async _makeRequest({ + $ = this, + path, + headers = {}, + ...otherOpts + } = {}) { + return axios($, { + ...otherOpts, + url: this._baseUrl() + path, + headers: { + "content-type": "application/json", + "accept": "application/json, text/plain, */*", + "accept-language": "en-GB,en-US;q=0.9,en;q=0.8", + "accesskey": `${this.$auth.access_key}`, + ...headers, + }, + }); + }, + async updateCompany(args) { + return this._makeRequest({ + path: "/data/objects/Company", + method: "PUT", + params: { + keys: "Name", + }, + ...args, + }); + }, + async createCompany(args) { + return this._makeRequest({ + path: "/data/objects/Company", + method: "POST", + ...args, + }); + }, + async createOrUpdatePerson(args) { + return this._makeRequest({ + path: "/peoplemgmt/v1.0/people", + method: "PUT", + ...args, + }); + }, + async listCustomObjects() { + return this._makeRequest({ + path: "/meta/services/objects/list", + }); + }, + async updateCustomObject({ + objectName, ...args + }) { + return this._makeRequest({ + path: `/data/objects/${objectName}`, + method: "PUT", + ...args, + }); + }, + async createCustomObject({ + objectName, ...args + }) { + return this._makeRequest({ + path: `/data/objects/${objectName}`, + method: "POST", + ...args, + }); }, }, }; diff --git a/components/gainsight_nxt/package.json b/components/gainsight_nxt/package.json index af6a3f4ee80c8..567d30336b6b0 100644 --- a/components/gainsight_nxt/package.json +++ b/components/gainsight_nxt/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/gainsight_nxt", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Gainsight Components", "main": "gainsight_nxt.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 44c19222e41ae..a996d97a3d280 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3764,7 +3764,10 @@ importers: '@pipedream/platform': 3.0.0 components/gainsight_nxt: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/gainsight_px: specifiers: {} @@ -13160,6 +13163,55 @@ packages: - aws-crt dev: false + /@aws-sdk/client-sso-oidc/3.600.0_tdq3komn4zwyd65w7klbptsu34: + resolution: {integrity: sha512-7+I8RWURGfzvChyNQSyj5/tKrqRbzRl7H+BnTOf/4Vsw1nFOi5ROhlhD4X/Y0QCTacxnaoNcIrqnY7uGGvVRzw==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.3 + '@smithy/core': 2.2.3 + '@smithy/fetch-http-handler': 3.2.1 + '@smithy/hash-node': 3.0.2 + '@smithy/invalid-dependency': 3.0.2 + '@smithy/middleware-content-length': 3.0.2 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-retry': 3.0.6 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/node-http-handler': 3.1.2 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.6 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.6 + '@smithy/util-defaults-mode-node': 3.0.6 + '@smithy/util-endpoints': 2.0.3 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.2 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + transitivePeerDependencies: + - '@aws-sdk/client-sts' + - aws-crt + dev: false + /@aws-sdk/client-sso/3.423.0: resolution: {integrity: sha512-znIufHkwhCIePgaYciIs3x/+BpzR57CZzbCKHR9+oOvGyufEPPpUT5bFLvbwTgfiVkTjuk6sG/ES3U5Bc+xtrA==} engines: {node: '>=14.0.0'} @@ -13395,7 +13447,7 @@ packages: dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.600.0 + '@aws-sdk/client-sso-oidc': 3.600.0_tdq3komn4zwyd65w7klbptsu34 '@aws-sdk/core': 3.598.0 '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 '@aws-sdk/middleware-host-header': 3.598.0 @@ -13437,55 +13489,6 @@ packages: - aws-crt dev: false - /@aws-sdk/client-sts/3.600.0_dseaa2p5u2yk67qiepewcq3hkq: - resolution: {integrity: sha512-KQG97B7LvTtTiGmjlrG1LRAY8wUvCQzrmZVV5bjrJ/1oXAU7DITYwVbSJeX9NWg6hDuSk0VE3MFwIXS2SvfLIA==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.600.0 - '@aws-sdk/core': 3.598.0 - '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 - '@aws-sdk/middleware-host-header': 3.598.0 - '@aws-sdk/middleware-logger': 3.598.0 - '@aws-sdk/middleware-recursion-detection': 3.598.0 - '@aws-sdk/middleware-user-agent': 3.598.0 - '@aws-sdk/region-config-resolver': 3.598.0 - '@aws-sdk/types': 3.598.0 - '@aws-sdk/util-endpoints': 3.598.0 - '@aws-sdk/util-user-agent-browser': 3.598.0 - '@aws-sdk/util-user-agent-node': 3.598.0 - '@smithy/config-resolver': 3.0.3 - '@smithy/core': 2.2.3 - '@smithy/fetch-http-handler': 3.2.1 - '@smithy/hash-node': 3.0.2 - '@smithy/invalid-dependency': 3.0.2 - '@smithy/middleware-content-length': 3.0.2 - '@smithy/middleware-endpoint': 3.0.4 - '@smithy/middleware-retry': 3.0.6 - '@smithy/middleware-serde': 3.0.3 - '@smithy/middleware-stack': 3.0.3 - '@smithy/node-config-provider': 3.1.3 - '@smithy/node-http-handler': 3.1.2 - '@smithy/protocol-http': 4.0.3 - '@smithy/smithy-client': 3.1.6 - '@smithy/types': 3.3.0 - '@smithy/url-parser': 3.0.3 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.6 - '@smithy/util-defaults-mode-node': 3.0.6 - '@smithy/util-endpoints': 2.0.3 - '@smithy/util-middleware': 3.0.3 - '@smithy/util-retry': 3.0.2 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - dev: false - /@aws-sdk/core/3.556.0: resolution: {integrity: sha512-vJaSaHw2kPQlo11j/Rzuz0gk1tEaKdz+2ser0f0qZ5vwFlANjt08m/frU17ctnVKC1s58bxpctO/1P894fHLrA==} engines: {node: '>=14.0.0'} @@ -17778,7 +17781,7 @@ packages: '@aws-sdk/client-sns': 3.423.0 '@aws-sdk/client-sqs': 3.423.0 '@aws-sdk/client-ssm': 3.423.0 - '@aws-sdk/client-sts': 3.600.0_dseaa2p5u2yk67qiepewcq3hkq + '@aws-sdk/client-sts': 3.600.0 '@aws-sdk/s3-request-presigner': 3.609.0 '@pipedream/helper_functions': 0.3.12 '@pipedream/platform': 1.6.6