Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/mit-27/Panora into github-c…
Browse files Browse the repository at this point in the history
…onnector
  • Loading branch information
mit-27 committed Jul 25, 2024
2 parents c41d76f + be34cd6 commit cb092b7
Show file tree
Hide file tree
Showing 613 changed files with 7,419 additions and 23,922 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/stainless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Upload OpenAPI spec to Stainless

on:
push:
branches: [main]
workflow_dispatch:

jobs:
stainless:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: stainless-api/upload-openapi-spec-action@main
with:
stainless_api_key: ${{ secrets.STAINLESS_API_KEY }}
input_path: 'packages/api/swagger/swagger-spec.yaml'
project_name: 'panora2'
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ Your customers expect all of their tools to work well together. Panora avoids yo

Panora supports integration with the following objects across multiple platforms:

[Here is an extensive list of all integrations !](https://docs.panora.dev/integrations-catalog)

### CRM

| | Contacts | Deals | Notes | Engagements | Tasks | Users | Companies |
Expand Down Expand Up @@ -90,7 +92,13 @@ Your favourite software is missing? [Ask the community to build a connector!](ht
docker compose up
```

Visit our [Quickstart Guide](https://docs.panora.dev/quick-start) to start adding integrations to your product
Visit our [Quickstart Guide](https://docs.panora.dev/quick-start) to start adding integrations to your product !

See also [our selfhost guide here !](https://docs.panora.dev/open-source/selfhost/self-host-guide)

# 👾 Join the community

- [Join the Discord](https://discord.com/invite/PH5k7gGubt)

# 🤔 Questions? Ask the core team

Expand Down
6 changes: 6 additions & 0 deletions apps/embedded-catalog/react/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @panora/embedded-card-react

## 1.3.1

### Patch Changes

- ded2580: Readme patch

## 1.3.0

### Minor Changes
Expand Down
39 changes: 27 additions & 12 deletions apps/embedded-catalog/react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,36 +21,51 @@ or
yarn add @panora/embedded-card-react
```

## Import the component
## Import the components

```bash
# Import the css file
```ts
import "@panora/embedded-card-react/dist/index.css";

import PanoraProviderCard from "@panora/embedded-card-react";
import { PanoraDynamicCatalogCard, PanoraProviderCard } from '@panora/embedded-card-react';
```

## Use the component

- The `optionalApiUrl` is an optional prop to use the component with the self-hosted version of Panora.

```bash
```ts
<PanoraProviderCard
name={"hubspot"} // name of the provider
projectId={"c9a1b1f8-466d-442d-a95e-11cdd00baf49"} // the project id tied to your organization
returnUrl={"https://acme.inc"} // the url you want to redirect users to after the connection flow is successful
linkedUserId={"b860d6c1-28f9-485c-86cd-fb09e60f10a2"} // the linked id of the user if already created in Panora system or user's info in your system
optionalApiUrl={"http://localhost:3000"} // Only add this prop to use the component with a self-hosted version of Panora. Without this prop, the component uses the cloud version of Panora.
projectId={"c9a1b1f8-466d-442d-a95e-11cdd00baf49"} // Copy it from your dahshboard
linkedUserId={"b860d6c1-28f9-485c-86cd-fb09e60f10a2"} // You can copy it from your Panora dahsbord under /configuration tab
optionalApiUrl={"http://localhost:3000"} // Optional (only if you are in selfhost mode and want to use localhost:3000), by default: api.panora.dev
/>

<PanoraDynamicCatalogCard
category={ConnectorCategory.Crm}
projectId={"f9e9601e-d6da-471a-9777-94257e9b4f00"}
linkedUserId={"4c6ca51b-7b23-4e3a-9309-24d2d331a04d"}
optionalApiUrl="http://localhost:3000"
/>
```

```ts
These are the types needed for the component.
These are the types needed for the components.

The `<PanoraProviderCard />` takes this props type:

interface ProviderCardProp {
name: string;
projectId: string;
returnUrl: string;
linkedUserIdOrRemoteUserInfo: string;
linkedUserId: string;
}

The `<PanoraDynamicCatalogCard />` takes this props type:

interface DynamicCardProp {
projectId: string;
linkedUserId: string;
category?: ConnectorCategory;
optionalApiUrl?: string,
}
```
2 changes: 1 addition & 1 deletion apps/embedded-catalog/react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@panora/embedded-card-react",
"version": "1.3.0",
"version": "1.3.1",
"description": "",
"main": "dist/index.js",
"scripts": {
Expand Down
6 changes: 6 additions & 0 deletions apps/frontend-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @panora/frontend-sdk

## 1.1.1

### Patch Changes

- ded2580: Readme patch

## 1.1.0

### Minor Changes
Expand Down
75 changes: 75 additions & 0 deletions apps/frontend-sdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@

## Frontend SDK (React)

It is a React component aimed to be used in any of your pages so end-users can connect their 3rd parties in 1-click!

## Installation

```bash
npm i @panora/frontend-sdk
```

or

```bash
pnpm i @panora/frontend-sdk
```

or

```bash
yarn add @panora/frontend-sdk
```

## Use the component

```ts
import { ConnectorCategory } from '@panora/shared'
import Panora from '@panora/frontend-sdk'

const panora = new Panora({ apiKey: 'YOUR_PRIVATE_API_KEY' });

// kickstart the connection (OAuth, ApiKey, Basic)
panora.connect({
providerName: "hubspot",
vertical: ConnectorCategory.Crm,
linkedUserId: "4c6ca51b-7b23-4e3a-9309-24d2d331a04d",
})
```

```ts
The Panora SDK must be instantiated with this type:

interface PanoraConfig {
apiKey: string;
overrideApiUrl: string;
// Optional (only if you are in selfhost mode and want to use localhost:3000), by default: api.panora.dev
}

The .connect() function takes this type:

interface ConnectOptions {
providerName: string;
vertical: ConnectorCategory; // Must be imported from @panora/shared
linkedUserId: string; // You can copy it from your Panora dahsbord under /configuration tab
credentials?: Credentials; // Optional if you try to use OAuth
options?: {
onSuccess?: () => void;
onError?: (error: Error) => void;
overrideReturnUrl?: string;
}
}

By default, for OAuth we use Panora managed OAuth apps but if we dont have one registered OR you want to use your own, you must register that under /configuration tab from the webapp and it will automatically use these custom credentials !

interface Credentials {
username?: string; // Used for Basic Auth
password?: string; // Used for Basic Auth
apiKey?: string; // Used for Api Key Auth
}

For Basic Auth some providers may only ask for username or password.

In this case just specify either password or username depending on the 3rd party reference.

```
2 changes: 1 addition & 1 deletion apps/frontend-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@panora/frontend-sdk",
"version": "1.1.0",
"version": "1.1.1",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions apps/frontend-sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface ConnectOptions {
vertical: ConnectorCategory;
linkedUserId: string;
credentials?: Credentials;
options: {
options?: {
onSuccess?: () => void;
onError?: (error: Error) => void;
overrideReturnUrl?: string;
Expand Down Expand Up @@ -65,7 +65,7 @@ class Panora {
}

async connect(options: ConnectOptions): Promise<Window | null> {
const { providerName, vertical, linkedUserId, credentials, options: {onSuccess, onError, overrideReturnUrl} } = options;
const { providerName, vertical, linkedUserId, credentials, options: {onSuccess, onError, overrideReturnUrl} = {} } = options;

try {
const projectId = await this.fetchProjectId();
Expand Down
1 change: 0 additions & 1 deletion apps/magic-link/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
},
"dependencies": {
"@panora/shared": "^1.4.0",
"@panora/typescript-sdk": "^1.0.3",
"@radix-ui/react-label": "^2.0.2",
"react-hook-form": "^7.51.2",
"@hookform/resolvers": "^3.3.4",
Expand Down
22 changes: 14 additions & 8 deletions apps/magic-link/src/hooks/queries/useProjectConnectors.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import { useQuery } from '@tanstack/react-query';
import config from '@/helpers/config';

const useProjectConnectors = (id: string) => {
const useProjectConnectors = (id: string | null) => {
return useQuery({
queryKey: ['project-connectors', id],
queryKey: ['project-connectors', id],
queryFn: async (): Promise<any> => {
if (!id) {
throw new Error('Project ID is not available');
}
const response = await fetch(`${config.API_URL}/project-connectors?projectId=${id}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
}
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
},
enabled: !!id, // Only run the query if id is truthy
retry: false, // Don't retry if the project ID is not available
});
};
export default useProjectConnectors;

export default useProjectConnectors;
16 changes: 11 additions & 5 deletions apps/magic-link/src/hooks/queries/useUniqueMagicLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,22 @@ import config from '@/helpers/config';

type Mlink = MagicLink & {id_project: string}

const useUniqueMagicLink = (id: string) => {
return useQuery({
queryKey: ['magic-link', id],
const useUniqueMagicLink = (id: string | null) => {
return useQuery<Mlink, Error>({
queryKey: ['magic-link', id],
queryFn: async (): Promise<Mlink> => {
if (!id) {
throw new Error('Magic Link ID is not available');
}
const response = await fetch(`${config.API_URL}/magic-links/single?id=${id.trim()}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
}
},
enabled: !!id && id.trim().length > 0, // Only run the query if id is truthy and not just whitespace
retry: false, // Don't retry if the magic link ID is not available
});
};
export default useUniqueMagicLink;

export default useUniqueMagicLink;
12 changes: 6 additions & 6 deletions apps/magic-link/src/hooks/useOAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ type UseOAuthProps = {
returnUrl: string; // Return URL after OAuth flow
projectId: string; // Project ID
linkedUserId: string; // Linked User ID
optionalApiUrl?: string; // URL of the User's Server
redirectIngressUri: string | null; // URL of the User's Server
onSuccess: () => void;
};

const useOAuth = ({ providerName, vertical, returnUrl, projectId, linkedUserId, onSuccess }: UseOAuthProps) => {
const useOAuth = ({ providerName, vertical, returnUrl, projectId, linkedUserId, redirectIngressUri, onSuccess }: UseOAuthProps) => {
const [isReady, setIsReady] = useState(false);
const intervalRef = useRef<number | ReturnType<typeof setInterval> | null>(null);
const authWindowRef = useRef<Window | null>(null);
const authWindowRef = useRef<Window | null>(null);

useEffect(() => {
// Perform any setup logic here
Expand All @@ -41,12 +41,12 @@ const useOAuth = ({ providerName, vertical, returnUrl, projectId, linkedUserId,
}
};


const openModal = async (onWindowClose: () => void) => {
const apiUrl = config.API_URL!;
const authUrl = await constructAuthUrl({
projectId, linkedUserId, providerName, returnUrl, apiUrl, vertical
projectId, linkedUserId, providerName, returnUrl, apiUrl , vertical, rediectUriIngress: redirectIngressUri
});
console.log('auth url is '+ authUrl)

if (!authUrl) {
throw new Error("Auth Url is Invalid " + authUrl);
Expand All @@ -56,7 +56,7 @@ const useOAuth = ({ providerName, vertical, returnUrl, projectId, linkedUserId,
const left = (window.innerWidth - width) / 2;
const top = (window.innerHeight - height) / 2;
const authWindow = window.open(authUrl as string, '_blank', `width=${width},height=${height},top=${top},left=${left}`);
authWindowRef.current = authWindow;
authWindowRef.current = authWindow;

clearExistingInterval(false);

Expand Down
Loading

0 comments on commit cb092b7

Please sign in to comment.