Skip to content

Commit

Permalink
Zendesk Connection Oauth UI behind FF (#7974)
Browse files Browse the repository at this point in the history
* Zendesk Connection Oauth UI behind FF

* Lint

* Use Zendesklogo

* fix: mock connector initialization for zendesk

* feat: add a ConfigurationModel for zendesk

* misc: remove a TODO (to be reconsidered)

---------

Co-authored-by: Aubin <[email protected]>
  • Loading branch information
albandum and aubin-tchoi authored Oct 18, 2024
1 parent 82a3143 commit b21288f
Show file tree
Hide file tree
Showing 18 changed files with 127 additions and 0 deletions.
1 change: 1 addition & 0 deletions connectors/src/api/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ const _patchConnectorConfiguration = async (
case "intercom":
case "microsoft":
case "snowflake":
case "zendesk":
case "slack": {
throw new Error(
`Connector type ${connector.type} does not support configuration patching`
Expand Down
1 change: 1 addition & 0 deletions connectors/src/api/create_connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ const _createConnectorAPIHandler = async (
case "google_drive":
case "intercom":
case "snowflake":
case "zendesk":
case "microsoft": {
connectorRes = await createConnector({
connectorProvider: req.params.connector_provider,
Expand Down
4 changes: 4 additions & 0 deletions connectors/src/connectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export function getConnectorManager({
return new WebcrawlerConnectorManager(connectorId);
case "snowflake":
return new SnowflakeConnectorManager(connectorId);
case "zendesk":
throw new Error("Zendesk connector not implemented yet");
default:
assertNever(connectorProvider);
}
Expand Down Expand Up @@ -108,6 +110,8 @@ export function createConnector({
return WebcrawlerConnectorManager.create(params);
case "snowflake":
return SnowflakeConnectorManager.create(params);
case "zendesk":
throw new Error("Zendesk connector not implemented yet");
default:
assertNever(connectorProvider);
}
Expand Down
57 changes: 57 additions & 0 deletions connectors/src/lib/models/zendesk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type {
CreationOptional,
ForeignKey,
InferAttributes,
InferCreationAttributes,
} from "sequelize";
import { DataTypes, Model } from "sequelize";

import { sequelizeConnection } from "@connectors/resources/storage";
import { ConnectorModel } from "@connectors/resources/storage/models/connector_model";

export class ZendeskConfigurationModel extends Model<
InferAttributes<ZendeskConfigurationModel>,
InferCreationAttributes<ZendeskConfigurationModel>
> {
declare id: CreationOptional<number>;
declare createdAt: CreationOptional<Date>;
declare updatedAt: CreationOptional<Date>;

declare conversationsSlidingWindow: number;

declare connectorId: ForeignKey<ConnectorModel["id"]>;
}
ZendeskConfigurationModel.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
},
conversationsSlidingWindow: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 90,
},
},
{
sequelize: sequelizeConnection,
modelName: "zendesk_configurations",
indexes: [{ fields: ["connectorId"], unique: true }],
}
);
ConnectorModel.hasMany(ZendeskConfigurationModel, {
foreignKey: { allowNull: false },
onDelete: "RESTRICT",
});
ZendeskConfigurationModel.belongsTo(ConnectorModel);
6 changes: 6 additions & 0 deletions connectors/src/resources/connector/strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { NotionConnectorState } from "@connectors/lib/models/notion";
import type { SlackConfigurationModel } from "@connectors/lib/models/slack";
import type { SnowflakeConfigurationModel } from "@connectors/lib/models/snowflake";
import type { WebCrawlerConfigurationModel } from "@connectors/lib/models/webcrawler";
import type { ZendeskConfigurationModel } from "@connectors/lib/models/zendesk";
import { ConfluenceConnectorStrategy } from "@connectors/resources/connector/confluence";
import { GithubConnectorStrategy } from "@connectors/resources/connector/github";
import { GoogleDriveConnectorStrategy } from "@connectors/resources/connector/google_drive";
Expand Down Expand Up @@ -44,6 +45,7 @@ export interface ConnectorProviderModelM {
slack: SlackConfigurationModel;
webcrawler: WebCrawlerConfigurationModel;
snowflake: SnowflakeConfigurationModel;
zendesk: ZendeskConfigurationModel;
}

export type ConnectorProviderModelMapping = {
Expand Down Expand Up @@ -77,6 +79,7 @@ export interface ConnectorProviderConfigurationTypeM {
snowflake: null;
slack: SlackConfigurationType;
webcrawler: WebCrawlerConfigurationType;
zendesk: null;
}

export type ConnectorProviderConfigurationTypeMapping = {
Expand Down Expand Up @@ -135,6 +138,9 @@ export function getConnectorProviderStrategy(
case "snowflake":
return new SnowflakeConnectorStrategy();

case "zendesk":
throw new Error(`Not implemented yet.`);

default:
assertNever(type);
}
Expand Down
3 changes: 3 additions & 0 deletions connectors/src/start_worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ const workerFunctions: Record<WorkerType, () => Promise<void>> = {
slack: runSlackWorker,
webcrawler: runWebCrawlerWorker,
snowflake: runSnowflakeWorker,
zendesk: async () => {
logger.info("Zendesk worker not implemented yet.");
},
};

const ALL_WORKERS = Object.keys(workerFunctions) as WorkerType[];
Expand Down
1 change: 1 addition & 0 deletions front/components/ConnectorPermissionsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ const CONNECTOR_TYPE_TO_PERMISSIONS: Record<
},
notion: undefined,
github: undefined,
zendesk: undefined,
intercom: {
selected: "read",
unselected: "none",
Expand Down
2 changes: 2 additions & 0 deletions front/components/assistant_builder/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const CONNECTOR_PROVIDER_TO_RESOURCE_NAME: Record<
intercom: { singular: "element", plural: "elements" },
webcrawler: { singular: "page", plural: "pages" },
snowflake: { singular: "table", plural: "tables" },
zendesk: { singular: "element", plural: "elements" },
};

export const getConnectorProviderResourceName = (
Expand Down Expand Up @@ -314,6 +315,7 @@ export function getTableIdForContentNode(
case "intercom":
case "slack":
case "github":
case "zendesk":
case "webcrawler":
throw new Error(
`Provider ${dataSource.connectorProvider} is not supported`
Expand Down
3 changes: 3 additions & 0 deletions front/lib/api/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ const config = {
getOAuthMicrosoftClientId: (): string => {
return EnvironmentConfig.getEnvVariable("OAUTH_MICROSOFT_CLIENT_ID");
},
getOAuthZendeskClientId: (): string => {
return EnvironmentConfig.getEnvVariable("OAUTH_ZENDESK_CLIENT_ID");
},
// Text extraction.
getTextExtractionUrl: (): string => {
return EnvironmentConfig.getEnvVariable("TEXT_EXTRACTION_URL");
Expand Down
1 change: 1 addition & 0 deletions front/lib/api/content_nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export function getContentNodeInternalIdFromTableId(
case "confluence":
case "github":
case "slack":
case "zendesk":
case "webcrawler":
throw new Error(
`Provider ${dataSource.connectorProvider} is not supported`
Expand Down
19 changes: 19 additions & 0 deletions front/lib/api/oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,25 @@ const PROVIDER_STRATEGIES: Record<
return getStringFromQuery(query, "state");
},
},
zendesk: {
setupUri: (connection) => {
const scopes = ["tickets:read", "hc:read"];
return (
`https://d3v-dust.zendesk.com/oauth/authorizations/new?` +
`client_id=${config.getOAuthZendeskClientId()}` +
`&scope=${encodeURIComponent(scopes.join(" "))}` +
`&response_type=code` +
`&state=${connection.connection_id}` +
`&redirect_uri=${encodeURIComponent(finalizeUriForProvider("zendesk"))}`
);
},
codeFromQuery: (query) => {
return getStringFromQuery(query, "code");
},
connectionIdFromQuery: (query) => {
return getStringFromQuery(query, "state");
},
},
};

export async function createConnectionAndGetSetupUrl(
Expand Down
20 changes: 20 additions & 0 deletions front/lib/connector_providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
NotionLogo,
SlackLogo,
SnowflakeLogo,
ZendeskLogo,
} from "@dust-tt/sparkle";
import type {
ConnectorProvider,
Expand Down Expand Up @@ -184,6 +185,21 @@ export const CONNECTOR_CONFIGURATIONS: Record<
selectLabel: "Select tables",
rollingOutFlag: "snowflake_connector_feature",
},
zendesk: {
name: "Zendesk",
connectorProvider: "zendesk",
status: "rolling_out",
hide: false,
description:
"Authorize access to Zendesk for indexing tickets from your support center and articles from your help center.",
limitations:
"Dust will index the content accessible to the authorized account only. Attachments are not indexed.",
guideLink: "https://docs.dust.tt/docs/zendesk",
logoComponent: ZendeskLogo,
isNested: true,
isSearchEnabled: false,
rollingOutFlag: "zendesk_connector_feature",
},
};

export function getConnectorProviderLogoWithFallback(
Expand Down Expand Up @@ -224,6 +240,8 @@ export const isConnectorProviderAllowedForPlan = (
case "snowflake":
// TODO(SNOWFLAKE): Add a isSnowflakeAllowed column to the plan model.
return true;
case "zendesk":
return true;
default:
assertNever(provider);
}
Expand All @@ -240,6 +258,7 @@ export const isConnectorProviderAssistantDefaultSelected = (
case "google_drive":
case "intercom":
case "microsoft":
case "zendesk":
case "snowflake":
return true;
case "webcrawler":
Expand All @@ -260,6 +279,7 @@ export const isConnectionIdRequiredForProvider = (
case "google_drive":
case "intercom":
case "microsoft":
case "zendesk":
case "snowflake":
return true;
case "webcrawler":
Expand Down
1 change: 1 addition & 0 deletions front/lib/data_sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function getDisplayNameForDataSource(ds: DataSourceType) {
case "intercom":
case "microsoft":
case "notion":
case "zendesk":
case "snowflake":
return CONNECTOR_CONFIGURATIONS[ds.connectorProvider].name;
case "webcrawler":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ async function handler(
case "notion":
case "microsoft":
case "slack":
case "zendesk":
case "snowflake":
if (!auth.isAdmin()) {
return apiError(req, res, {
Expand Down
1 change: 1 addition & 0 deletions front/pages/api/w/[wId]/data_sources/managed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ async function handler(
case "notion":
case "microsoft":
case "snowflake":
case "zendesk":
case "slack": {
if (!auth.isAdmin()) {
return apiError(req, res, {
Expand Down
4 changes: 4 additions & 0 deletions types/src/front/data_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const CONNECTOR_PROVIDERS = [
"microsoft",
"webcrawler",
"snowflake",
"zendesk",
] as const;

export const MANAGED_DS_DELETABLE: ConnectorProvider[] = [
Expand All @@ -29,6 +30,7 @@ export const CONNECTOR_TYPE_TO_NAME: Record<ConnectorProvider, string> = {
microsoft: "Microsoft",
webcrawler: "Website",
snowflake: "Snowflake",
zendesk: "Zendesk",
};

export const CONNECTOR_TYPE_TO_MISMATCH_ERROR: Record<
Expand All @@ -49,6 +51,8 @@ export const CONNECTOR_TYPE_TO_MISMATCH_ERROR: Record<
webcrawler: "You cannot change the URL. Please add a new Public URL instead.",
snowflake:
"You cannot change the Snowflake account. Please add a new Snowflake connection instead.",
zendesk:
"You cannot select another Zendesk Workspace.\nPlease contact us at [email protected] if you initially selected a wrong Workspace.",
};

export type ConnectorProvider = (typeof CONNECTOR_PROVIDERS)[number];
Expand Down
1 change: 1 addition & 0 deletions types/src/oauth/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const OAUTH_PROVIDERS = [
"slack",
"gong",
"microsoft",
"zendesk",
] as const;

export type OAuthProvider = (typeof OAUTH_PROVIDERS)[number];
Expand Down
1 change: 1 addition & 0 deletions types/src/shared/feature_flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const WHITELISTABLE_FEATURES = [
"openai_o1_feature",
"openai_o1_mini_feature",
"snowflake_connector_feature",
"zendesk_connector_feature",
] as const;
export type WhitelistableFeature = (typeof WHITELISTABLE_FEATURES)[number];
export function isWhitelistableFeature(
Expand Down

0 comments on commit b21288f

Please sign in to comment.