Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Pendo integration #643

Merged
merged 13 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
Binary file added integrations/pendo/assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added integrations/pendo/assets/preview-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added integrations/pendo/assets/preview-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions integrations/pendo/gitbook-manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: pendo
title: Pendo
icon: ./assets/icon.png
previewImages:
- ./assets/preview-1.png
- ./assets/preview-2.png
description: Plug your GitBook site to your Pendo Analytics instance.
externalLinks:
- label: Documentation
url: https://www.gitbook.com/integrations/pendo
visibility: private
script: ./src/index.tsx
# The following scope(s) are available only to GitBook Staff
# See https://developer.gitbook.com/integrations/configurations#scopes
scopes:
- site:script:inject
organization: gitbook
contentSecurityPolicy:
script-src: https://cdn.eu.pendo.io https://cdn.pendo.io
summary: |
# Overview
This integration allows to add Pendo Analytics on your published GitBook site.

# How it works
The integration injects the Pendo Analytics script on your page, using the configured API Key,
so that you can get analytics information from your GitBook site directly inside of Heap.

# Configure
Install the integration on the GitBook site of your choice.
Locate the Pendo API Key you want to use from Pendo and paste it in the GitBook integration's configuration screen

categories:
- analytics
configurations:
site:
componentId: config
target: site
19 changes: 19 additions & 0 deletions integrations/pendo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@gitbook/integration-pendo",
"version": "0.0.1",
"private": true,
"dependencies": {
"@gitbook/api": "*",
"@gitbook/runtime": "*"
},
"devDependencies": {
"@gitbook/cli": "workspace:*",
"@gitbook/tsconfig": "workspace:*"
},
"scripts": {
"typecheck": "tsc --noEmit",
"publish-integrations-staging": "gitbook publish .",
"check": "gitbook check",
"publish-integrations": "gitbook publish ."
}
}
148 changes: 148 additions & 0 deletions integrations/pendo/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import {
createIntegration,
FetchPublishScriptEventCallback,
RuntimeContext,
RuntimeEnvironment,
createComponent,
} from '@gitbook/runtime';
import { IntegrationInstallationConfiguration } from '@gitbook/api';

import script from './script.raw.js';

type PendoRuntimeContext = RuntimeContext<
RuntimeEnvironment<{}, PendoSiteInstallationConfiguration>
>;
type PendoRuntimeEnvironment = RuntimeEnvironment<{}, PendoSiteInstallationConfiguration>;

type PendoSiteInstallationConfiguration = {
api_key?: string;
is_eu_region?: boolean;
};

type PendoState = PendoSiteInstallationConfiguration;

type PendoProps = {
installation: {
configuration?: IntegrationInstallationConfiguration;
};
siteInstallation?: {
configuration?: PendoSiteInstallationConfiguration;
};
};
export type PendoAction = { action: 'save.config' };

const configBlock = createComponent<PendoProps, PendoState, PendoAction, PendoRuntimeContext>({
componentId: 'config',
initialState: (props) => {
const siteInstallation = props.siteInstallation;
return {
api_key: siteInstallation?.configuration?.api_key || '',
is_eu_region: siteInstallation?.configuration?.is_eu_region || false,
};
},
action: async (element, action, context) => {
switch (action.action) {
case 'save.config':
const { api, environment } = context;
const siteInstallation = assertSiteInstallation(environment);

const configurationBody = {
...siteInstallation.configuration,
apiKey: element.state.api_key,
is_eu_region: element.state.is_eu_region,
};

await api.integrations.updateIntegrationSiteInstallation(
siteInstallation.integration,
siteInstallation.installation,
siteInstallation.site,
{
configuration: {
...configurationBody,
},
},
);

return { type: 'complete' };
}
},
render: async (element, context) => {
return (
<configuration>
<box>
<markdown content="### Pendo Analytics" />
<vstack>
<input
label="Pendo API Key"
hint={<text>The Pendo API Key.</text>}
element={<textinput state="api_key" placeholder="API Key" />}
/>
</vstack>
<divider size="medium" />

<markdown content="### Region of your Pendo App" />
<input
label="Is your app in the EU Region"
hint="Toggle on if your app is in EU Region"
element={<switch state="is_eu_region" />}
/>

<input
label=""
hint=""
element={
<button
style="primary"
disabled={false}
label="Save"
tooltip="Save configuration"
onPress={{
action: 'save.config',
}}
/>
}
/>
</box>
</configuration>
);
},
});

function assertSiteInstallation(environment: PendoRuntimeEnvironment) {
const siteInstallation = environment.siteInstallation;
if (!siteInstallation) {
throw new Error('No site installation found');
}

return siteInstallation;
}

export const handleFetchEvent: FetchPublishScriptEventCallback = async (
event,
{ environment }: PendoRuntimeContext,
) => {
const apiKey = environment.siteInstallation?.configuration?.api_key;
const isEURegion = environment.siteInstallation?.configuration?.is_eu_region;
if (!apiKey) {
throw new Error(
`The API key is missing from the configuration (ID: ${
'spaceId' in event ? event.spaceId : event.siteId
}).`,
);
}
const region = isEURegion ? 'EU' : 'US';
vibhanshub marked this conversation as resolved.
Show resolved Hide resolved
return new Response(
(script as string).replace('<TO_REPLACE>', apiKey).replace('<REGION>', region),
{
headers: {
'Content-Type': 'application/javascript',
'Cache-Control': 'max-age=604800',
},
},
);
};

export default createIntegration<PendoRuntimeContext>({
fetch_published_script: handleFetchEvent,
components: [configBlock],
});
24 changes: 24 additions & 0 deletions integrations/pendo/src/script.raw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
(function (apiKey) {
(function (p, e, n, d, o) {
var v, w, x, y, z;
o = p[d] = p[d] || {};
o._q = o._q || [];
v = ['initialize', 'identify', 'updateOptions', 'pageLoad', 'track'];
for (w = 0, x = v.length; w < x; ++w)
(function (m) {
o[m] =
o[m] ||
function () {
o._q[m === v[0] ? 'unshift' : 'push'](
[m].concat([].slice.call(arguments, 0)),
);
};
})(v[w]);
y = e.createElement(n);
y.async = !0;
cdn = '<REGION>' === 'EU' ? 'https://cdn.eu.pendo.io' : 'https://cdn.pendo.io';
vibhanshub marked this conversation as resolved.
Show resolved Hide resolved
y.src = `${cdn}/agent/static/` + apiKey + '/pendo.js';
z = e.getElementsByTagName(n)[0];
z.parentNode.insertBefore(y, z);
})(window, document, 'script', 'pendo');
})('<TO_REPLACE>');
3 changes: 3 additions & 0 deletions integrations/pendo/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "@gitbook/tsconfig/integration.json"
}
Loading