diff --git a/components/hex/actions/create-data-connection/create-data-connection.mjs b/components/hex/actions/create-data-connection/create-data-connection.mjs new file mode 100644 index 0000000000000..43dfc0144ebb5 --- /dev/null +++ b/components/hex/actions/create-data-connection/create-data-connection.mjs @@ -0,0 +1,124 @@ +import { parseObject } from "../../common/utils.mjs"; +import hex from "../../hex.app.mjs"; + +export default { + key: "hex-create-data-connection", + name: "Create Data Connection", + description: "Create a data connection. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/CreateDataConnection)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + hex, + sharingWorkspacePublic: { + propDefinition: [ + hex, + "sharingWorkspacePublic", + ], + }, + sharingWorkspaceGuests: { + propDefinition: [ + hex, + "sharingWorkspaceGuests", + ], + }, + sharingWorkspaceMembers: { + propDefinition: [ + hex, + "sharingWorkspaceMembers", + ], + }, + schemaRefreshAccess: { + propDefinition: [ + hex, + "schemaRefreshAccess", + ], + }, + schemaRefreshSchedule: { + propDefinition: [ + hex, + "schemaRefreshSchedule", + ], + }, + schemaFilters: { + propDefinition: [ + hex, + "schemaFilters", + ], + }, + allowWritebackCells: { + propDefinition: [ + hex, + "allowWritebackCells", + ], + }, + includeMagic: { + propDefinition: [ + hex, + "includeMagic", + ], + }, + connectViaSsh: { + propDefinition: [ + hex, + "connectViaSsh", + ], + }, + description: { + propDefinition: [ + hex, + "description", + ], + }, + connectionDetails: { + propDefinition: [ + hex, + "connectionDetails", + ], + }, + type: { + propDefinition: [ + hex, + "type", + ], + }, + name: { + propDefinition: [ + hex, + "name", + ], + }, + }, + async run({ $ }) { + const response = await this.hex.createDataConnection({ + $, + data: { + sharing: { + workspace: { + public: this.sharingWorkspacePublic, + guests: this.sharingWorkspaceGuests, + members: this.sharingWorkspaceMembers, + }, + }, + schemaRefreshAccess: this.schemaRefreshAccess, + schemaRefreshSchedule: + this.schemaRefreshSchedule && parseObject(this.schemaRefreshSchedule), + schemaFilters: this.schemaFilters && parseObject(this.schemaFilters), + allowWritebackCells: this.allowWritebackCells, + includeMagic: this.includeMagic, + connectViaSsh: this.connectViaSsh, + description: this.description, + connectionDetails: this.connectionDetails && parseObject(this.connectionDetails), + type: this.type, + name: this.name, + }, + }); + + $.export("$summary", `Successfully created data connection with ID: ${response.id}`); + return response; + }, +}; diff --git a/components/hex/actions/create-group/create-group.mjs b/components/hex/actions/create-group/create-group.mjs new file mode 100644 index 0000000000000..a95fb4a3481fa --- /dev/null +++ b/components/hex/actions/create-group/create-group.mjs @@ -0,0 +1,49 @@ +import { parseObject } from "../../common/utils.mjs"; +import hex from "../../hex.app.mjs"; + +export default { + key: "hex-create-group", + name: "Create Group", + description: "Create a group to manage users. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/CreateGroup)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + hex, + name: { + type: "string", + label: "Name", + description: "The name of the group.", + }, + users: { + propDefinition: [ + hex, + "userId", + ], + type: "string[]", + label: "User IDs", + description: "A list of user IDs to add to the group.", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.hex.createGroup({ + $, + data: { + name: this.name, + members: { + users: this.users && parseObject(this.users)?.map((user) => ({ + id: user, + })), + }, + }, + }); + + $.export("$summary", `Successfully created group with ID: ${response.id}`); + return response; + }, +}; diff --git a/components/hex/actions/deactivate-user/deactivate-user.mjs b/components/hex/actions/deactivate-user/deactivate-user.mjs new file mode 100644 index 0000000000000..cd464360a711c --- /dev/null +++ b/components/hex/actions/deactivate-user/deactivate-user.mjs @@ -0,0 +1,37 @@ +import { ConfigurationError } from "@pipedream/platform"; +import hex from "../../hex.app.mjs"; + +export default { + key: "hex-deactivate-user", + name: "Deactivate User", + description: "Deactivate a user. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/DeactivateUser)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + hex, + userId: { + propDefinition: [ + hex, + "userId", + ], + }, + }, + async run({ $ }) { + try { + const response = await this.hex.deactivateUser({ + $, + userId: this.userId, + }); + + $.export("$summary", `Successfully deactivated user with ID: ${this.userId}`); + return response; + } catch ({ response }) { + throw new ConfigurationError(response.data.reason); + } + }, +}; diff --git a/components/hex/actions/delete-group/delete-group.mjs b/components/hex/actions/delete-group/delete-group.mjs new file mode 100644 index 0000000000000..dc19c98a28d8f --- /dev/null +++ b/components/hex/actions/delete-group/delete-group.mjs @@ -0,0 +1,32 @@ +import hex from "../../hex.app.mjs"; + +export default { + key: "hex-delete-group", + name: "Delete Group", + description: "Delete a group to manage users. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/DeleteGroup)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + hex, + groupId: { + propDefinition: [ + hex, + "groupId", + ], + }, + }, + async run({ $ }) { + const response = await this.hex.deleteGroup({ + $, + groupId: this.groupId, + }); + + $.export("$summary", `Successfully deleted group with ID: ${this.groupId}`); + return response; + }, +}; diff --git a/components/hex/actions/edit-data-connection/edit-data-connection.mjs b/components/hex/actions/edit-data-connection/edit-data-connection.mjs new file mode 100644 index 0000000000000..c8ea32051debb --- /dev/null +++ b/components/hex/actions/edit-data-connection/edit-data-connection.mjs @@ -0,0 +1,126 @@ +import { parseObject } from "../../common/utils.mjs"; +import hex from "../../hex.app.mjs"; + +export default { + key: "hex-edit-data-connection", + name: "Edit Data Connection", + description: "Edit a specific data connection. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/EditDataConnection)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + hex, + connectionId: { + propDefinition: [ + hex, + "connectionId", + ], + }, + sharingWorkspacePublic: { + propDefinition: [ + hex, + "sharingWorkspacePublic", + ], + }, + sharingWorkspaceGuests: { + propDefinition: [ + hex, + "sharingWorkspaceGuests", + ], + }, + sharingWorkspaceMembers: { + propDefinition: [ + hex, + "sharingWorkspaceMembers", + ], + }, + schemaRefreshAccess: { + propDefinition: [ + hex, + "schemaRefreshAccess", + ], + }, + schemaRefreshSchedule: { + propDefinition: [ + hex, + "schemaRefreshSchedule", + ], + }, + schemaFilters: { + propDefinition: [ + hex, + "schemaFilters", + ], + }, + allowWritebackCells: { + propDefinition: [ + hex, + "allowWritebackCells", + ], + }, + includeMagic: { + propDefinition: [ + hex, + "includeMagic", + ], + }, + connectViaSsh: { + propDefinition: [ + hex, + "connectViaSsh", + ], + }, + description: { + propDefinition: [ + hex, + "description", + ], + }, + connectionDetails: { + propDefinition: [ + hex, + "connectionDetails", + ], + optional: true, + }, + name: { + propDefinition: [ + hex, + "name", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.hex.updateDataConnection({ + $, + connectionId: this.connectionId, + data: { + sharing: { + workspace: { + public: this.sharingWorkspacePublic, + guests: this.sharingWorkspaceGuests, + members: this.sharingWorkspaceMembers, + }, + }, + schemaRefreshAccess: this.schemaRefreshAccess, + schemaRefreshSchedule: + this.schemaRefreshSchedule && parseObject(this.schemaRefreshSchedule), + schemaFilters: this.schemaFilters && parseObject(this.schemaFilters), + allowWritebackCells: this.allowWritebackCells, + includeMagic: this.includeMagic, + connectViaSsh: this.connectViaSsh, + description: this.description, + connectionDetails: this.connectionDetails && parseObject(this.connectionDetails), + name: this.name, + }, + }); + + $.export("$summary", `Successfully updated data connection with ID: ${response.id}`); + return response; + }, +}; diff --git a/components/hex/actions/get-project-runs/get-project-runs.mjs b/components/hex/actions/get-project-runs/get-project-runs.mjs new file mode 100644 index 0000000000000..b6818bec599a5 --- /dev/null +++ b/components/hex/actions/get-project-runs/get-project-runs.mjs @@ -0,0 +1,60 @@ +import { RUN_STATUS_OPTIONS } from "../../common/constants.mjs"; +import hex from "../../hex.app.mjs"; + +export default { + key: "hex-get-project-runs", + name: "Get Project Runs", + description: "Get the status of the API-triggered runs of a project. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/GetProjectRuns)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + hex, + projectId: { + propDefinition: [ + hex, + "projectId", + ], + }, + status: { + type: "string", + label: "Status", + description: "The status of the runs to return.", + options: RUN_STATUS_OPTIONS, + optional: true, + }, + maxResults: { + type: "integer", + label: "Max Results", + description: "Maximum number of results to return.", + default: 100, + optional: true, + }, + }, + async run({ $ }) { + const response = this.hex.paginateProjectRuns({ + $, + fn: this.hex.getProjectRuns, + projectId: this.projectId, + params: { + status: this.status, + }, + maxResults: this.maxResults, + }); + + const runs = []; + for await (const run of response) { + runs.push(run); + } + + $.export("$summary", `Successfully retrieved ${runs.length} run${runs.length === 1 + ? "" + : "s"} for project ID: ${this.projectId}`); + + return runs; + }, +}; diff --git a/components/hex/actions/get-run-status/get-run-status.mjs b/components/hex/actions/get-run-status/get-run-status.mjs new file mode 100644 index 0000000000000..f38205e6d1ca7 --- /dev/null +++ b/components/hex/actions/get-run-status/get-run-status.mjs @@ -0,0 +1,42 @@ +import hex from "../../hex.app.mjs"; + +export default { + key: "hex-get-run-status", + name: "Get Run Status", + description: "Get the status of a specific run. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/GetRunStatus)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + hex, + projectId: { + propDefinition: [ + hex, + "projectId", + ], + }, + runId: { + propDefinition: [ + hex, + "runId", + ({ projectId }) => ({ + projectId, + }), + ], + }, + }, + async run({ $ }) { + const response = await this.hex.getRunStatus({ + $, + projectId: this.projectId, + runId: this.runId, + }); + + $.export("$summary", `Successfully retrieved status for run ${this.runId}`); + return response; + }, +}; diff --git a/components/hex/actions/list-data-connections/list-data-connections.mjs b/components/hex/actions/list-data-connections/list-data-connections.mjs new file mode 100644 index 0000000000000..a7474d78be2d6 --- /dev/null +++ b/components/hex/actions/list-data-connections/list-data-connections.mjs @@ -0,0 +1,64 @@ +import hex from "../../hex.app.mjs"; + +export default { + key: "hex-list-data-connections", + name: "List Data Connections", + description: "List all data connections. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/ListDataConnections)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + type: "action", + props: { + hex, + sortBy: { + type: "string", + label: "Sort By", + description: "Sort the data connections by a field.", + options: [ + "CREATED_AT", + "NAME", + ], + optional: true, + }, + sortDirection: { + type: "string", + label: "Sort Direction", + description: "The direction to sort the data connections.", + options: [ + "ASC", + "DESC", + ], + optional: true, + }, + maxResults: { + type: "integer", + label: "Max Results", + description: "The maximum number of results to return.", + optional: true, + }, + }, + async run({ $ }) { + const response = this.hex.paginate({ + $, + maxResults: this.maxResults, + fn: this.hex.listDataConnections, + params: { + sortBy: this.sortBy, + sortDirection: this.sortDirection, + }, + }); + + const results = []; + for await (const item of response) { + results.push(item); + } + + $.export("$summary", `Successfully listed ${results.length} data connection${results.length === 1 + ? "" + : "s"}`); + return results; + }, +}; diff --git a/components/hex/actions/list-projects/list-projects.mjs b/components/hex/actions/list-projects/list-projects.mjs new file mode 100644 index 0000000000000..4248b6ab4bdad --- /dev/null +++ b/components/hex/actions/list-projects/list-projects.mjs @@ -0,0 +1,136 @@ +import { ConfigurationError } from "@pipedream/platform"; +import { parseObject } from "../../common/utils.mjs"; +import hex from "../../hex.app.mjs"; + +export default { + key: "hex-list-projects", + name: "List Projects", + description: "List all viewable projects. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/ListProjects)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + hex, + includeArchived: { + type: "boolean", + label: "Include Archived", + description: "Whether to include archived projects in the results.", + optional: true, + }, + includeComponents: { + type: "boolean", + label: "Include Components", + description: "Whether to include components in the results.", + optional: true, + }, + includeTrashed: { + type: "boolean", + label: "Include Trashed", + description: "Whether to include trashed projects in the results.", + optional: true, + }, + includeSharing: { + type: "boolean", + label: "Include Sharing", + description: "Whether to include sharing information in the results.", + optional: true, + }, + statuses: { + type: "string[]", + label: "Statuses", + description: "The statuses to filter the projects by.", + optional: true, + }, + categories: { + type: "string[]", + label: "Categories", + description: "The categories to filter the projects by.", + optional: true, + }, + creatorEmail: { + type: "string", + label: "Creator Email", + description: "The email of the creator of the projects.", + optional: true, + }, + ownerEmail: { + type: "string", + label: "Owner Email", + description: "The email of the owner of the projects.", + optional: true, + }, + collectionId: { + type: "string", + label: "Collection ID", + description: "The ID of the collection of the projects.", + optional: true, + }, + sortBy: { + type: "string", + label: "Sort By", + description: "The field to sort the projects by.", + optional: true, + options: [ + "CREATED_AT", + "LAST_EDITED_AT", + "LAST_PUBLISHED_AT", + ], + }, + sortDirection: { + type: "string", + label: "Sort Direction", + description: "The direction to sort the projects by.", + optional: true, + options: [ + "ASC", + "DESC", + ], + }, + maxResults: { + type: "integer", + label: "Max Results", + description: "The maximum number of results to return.", + optional: true, + }, + }, + async run({ $ }) { + try { + const response = this.hex.paginate({ + $, + maxResults: this.maxResults, + fn: this.hex.listProjects, + params: { + includeArchived: this.includeArchived, + includeComponents: this.includeComponents, + includeTrashed: this.includeTrashed, + includeSharing: this.includeSharing, + statuses: this.statuses && parseObject(this.statuses), + categories: this.categories && parseObject(this.categories), + creatorEmail: this.creatorEmail, + ownerEmail: this.ownerEmail, + collectionId: this.collectionId, + sortBy: this.sortBy, + sortDirection: this.sortDirection, + }, + }); + + const results = []; + for await (const project of response) { + results.push(project); + } + + $.export("$summary", `Successfully listed ${results.length} project${results.length === 1 + ? "" + : "s"}`); + + return results; + } catch (error) { + const reason = error.response?.data?.reason || error.message || "An unknown error occurred"; + throw new ConfigurationError(reason); + } + }, +}; diff --git a/components/hex/actions/run-project/run-project.mjs b/components/hex/actions/run-project/run-project.mjs new file mode 100644 index 0000000000000..2fe3848c16fe9 --- /dev/null +++ b/components/hex/actions/run-project/run-project.mjs @@ -0,0 +1,84 @@ +import { ConfigurationError } from "@pipedream/platform"; +import hex from "../../hex.app.mjs"; + +export default { + key: "hex-run-project", + name: "Run Project", + description: "Trigger a run of the latest published version of a project. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/RunProject)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + hex, + projectId: { + propDefinition: [ + hex, + "projectId", + ], + }, + inputParams: { + type: "object", + label: "Input Parameters", + description: `Specify input parameters for this project run. These should be structured as a dictionary of key/value pairs, where the key name matches the name of the variable in the Hex project. + \n\nOnly parameters that are added to the published app can be set via this request parameter. Any additional inputs will be ignored. It is invalid to pass in both a viewId and inputParams. + \n\nIf no input parameters are provided, the project will be run with the default input values.`, + optional: true, + }, + dryRun: { + type: "boolean", + label: "Dry Run", + description: "When true, this endpoint will perform a dry run that does not run the project. This can be useful for validating the structure of an API call, and inspecting a dummy response, without running a project.", + optional: true, + }, + notifications: { + type: "string[]", + label: "Notifications", + description: "Specify a list of notification details that will be delivered once a project run completes. Notifications can be configured for delivery to Slack channels, Hex users, or Hex groups. **E.g. `[{\"type\": \"SUCCESS\", \"includeSuccessScreenshot\": \"general\"}]`**. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/RunProject) for more details.", + optional: true, + }, + updatePublishedResults: { + type: "boolean", + label: "Update Published Results", + description: "When true, the cached state of the published app will be updated with the latest run results. You must have at least \"Can Edit\" permissions on the project to do so. Note: this cannot be set to true if custom input parameters are provided.", + optional: true, + }, + useCachedSqlResults: { + type: "boolean", + label: "Use Cached SQL Results", + description: "When false, the project will run without using any cached SQL results, and will update those cached SQL results.", + optional: true, + }, + viewId: { + type: "string", + label: "View ID", + description: "Specify a SavedView viewId to use for the project run. If specified, the saved view's inputs will be used for the project run. It is invalid to pass in both a viewId and inputParams. If not specified, the default inputs will be used.", + optional: true, + }, + }, + async run({ $ }) { + try { + const response = await this.hex.runProject({ + $, + projectId: this.projectId, + data: { + inputParams: this.inputParams, + dryRun: this.dryRun, + notifications: this.notifications, + updatePublishedResults: this.updatePublishedResults, + useCachedSqlResults: this.useCachedSqlResults, + viewId: this.viewId, + }, + }); + + $.export("$summary", `Successfully triggered project run for project ID: ${this.projectId}`); + + return response; + } catch ({ response }) { + throw new ConfigurationError(response.data.reason); + } + }, +}; diff --git a/components/hex/actions/update-group/update-group.mjs b/components/hex/actions/update-group/update-group.mjs new file mode 100644 index 0000000000000..5d61d7607a446 --- /dev/null +++ b/components/hex/actions/update-group/update-group.mjs @@ -0,0 +1,57 @@ +import { parseObject } from "../../common/utils.mjs"; +import hex from "../../hex.app.mjs"; + +export default { + key: "hex-update-group", + name: "Update Group", + description: "Update a group to manage users. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/EditGroup)", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + type: "action", + props: { + hex, + groupId: { + propDefinition: [ + hex, + "groupId", + ], + }, + name: { + type: "string", + label: "Name", + description: "The name of the group.", + optional: true, + }, + users: { + propDefinition: [ + hex, + "userId", + ], + type: "string[]", + label: "User IDs", + description: "A list of user IDs to add to the group.", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.hex.updateGroup({ + $, + groupId: this.groupId, + data: { + name: this.name, + members: { + users: this.users && parseObject(this.users)?.map((user) => ({ + id: user, + })), + }, + }, + }); + + $.export("$summary", `Successfully updated group with ID: ${response.id}`); + return response; + }, +}; diff --git a/components/hex/common/constants.mjs b/components/hex/common/constants.mjs new file mode 100644 index 0000000000000..e06226acb8e57 --- /dev/null +++ b/components/hex/common/constants.mjs @@ -0,0 +1,34 @@ +export const LIMIT = 100; + +export const SHARING_WORKSPACE_PUBLIC_OPTIONS = [ + "NONE", + "VIEW_RESULTS", +]; + +export const SHARING_WORKSPACE_GUESTS_OPTIONS = [ + "NONE", + "QUERY", + "VIEW_RESULTS", +]; + +export const SCHEMA_REFRESH_ACCESS_OPTIONS = [ + "ADMINS", + "USERS_WITH_QUERY_ACCESS", +]; + +export const TYPE_OPTIONS = [ + "athena", + "bigquery", + "databricks", + "postgres", + "redshift", + "snowflake", +]; + +export const RUN_STATUS_OPTIONS = [ + "PENDING", + "RUNNING", + "COMPLETED", + "FAILED", + "CANCELLED", +]; diff --git a/components/hex/common/utils.mjs b/components/hex/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/hex/common/utils.mjs @@ -0,0 +1,24 @@ +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; diff --git a/components/hex/hex.app.mjs b/components/hex/hex.app.mjs index ca851c737d608..3e8073120fc79 100644 --- a/components/hex/hex.app.mjs +++ b/components/hex/hex.app.mjs @@ -1,11 +1,383 @@ +import { axios } from "@pipedream/platform"; +import { + LIMIT, + SCHEMA_REFRESH_ACCESS_OPTIONS, + SHARING_WORKSPACE_GUESTS_OPTIONS, + SHARING_WORKSPACE_PUBLIC_OPTIONS, + TYPE_OPTIONS, +} from "./common/constants.mjs"; + export default { type: "app", app: "hex", - propDefinitions: {}, + propDefinitions: { + projectId: { + type: "string", + label: "Project ID", + description: "The ID of the project to run.", + async options({ prevContext }) { + return await this.parseOptions({ + fn: this.listProjects, + params: { + after: prevContext.after, + }, + mapper: (item) => ({ + label: item.title, + value: item.id, + }), + }); + }, + }, + runId: { + type: "string", + label: "Run ID", + description: "The ID of the run to get the status of.", + async options({ + projectId, page, + }) { + const { runs } = await this.listRuns({ + projectId, + params: { + limit: LIMIT, + offset: LIMIT * page, + }, + }); + return runs.map((item) => item.runId); + }, + }, + userId: { + type: "string", + label: "User ID", + description: "The ID of the user to deactivate.", + async options({ prevContext }) { + return await this.parseOptions({ + fn: this.listUsers, + params: { + after: prevContext.after, + }, + mapper: (item) => ({ + label: `${item.name} (${item.email})`, + value: item.id, + }), + }); + }, + }, + groupId: { + type: "string", + label: "Group ID", + description: "The ID of the group to update.", + async options({ prevContext }) { + return await this.parseOptions({ + fn: this.listGroups, + params: { + after: prevContext.after, + }, + mapper: (item) => ({ + label: item.name, + value: item.id, + }), + }); + }, + }, + connectionId: { + type: "string", + label: "Connection ID", + description: "The ID of the connection to update.", + async options({ prevContext }) { + return await this.parseOptions({ + fn: this.listDataConnections, + params: { + after: prevContext.after, + }, + mapper: (item) => ({ + label: item.name, + value: item.id, + }), + }); + }, + }, + sharingWorkspacePublic: { + type: "string", + label: "Sharing Workspace Public", + description: "Data connection public sharing access level.", + optional: true, + options: SHARING_WORKSPACE_PUBLIC_OPTIONS, + }, + sharingWorkspaceGuests: { + type: "string", + label: "Sharing Workspace Guests", + description: "Data connection guests sharing access level.", + optional: true, + options: SHARING_WORKSPACE_GUESTS_OPTIONS, + }, + sharingWorkspaceMembers: { + type: "string", + label: "Sharing Workspace Members", + description: "Data connection members sharing access level.", + optional: true, + options: SHARING_WORKSPACE_GUESTS_OPTIONS, + }, + groups: { + type: "string[]", + label: "Groups", + description: "A list of group objects containing the group ID and access level. Example: [{ \"group\": {\"id\": \"5dddb613-224d-41b2-93ae-399755ad5fb3\"}, \"access\": \"VIEW_RESULTS\" }]", + optional: true, + }, + schemaRefreshAccess: { + type: "string", + label: "Schema Refresh Access", + description: "Schema refresh access level.", + optional: true, + options: SCHEMA_REFRESH_ACCESS_OPTIONS, + }, + schemaRefreshSchedule: { + type: "object", + label: "Schema Refresh Schedule", + description: "An object with the schema refresh schedule data. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/CreateDataConnection) for more information. E.g. { \"cadence\": \"DAILY\", \"enabled\": true, \"daily\": {\"timezoneString\": \"America/New_York\", \"hour\": 12, \"minute\": 0 } }", + optional: true, + }, + schemaFilters: { + type: "object", + label: "Schema Filters", + description: "An object with the schema filters data. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/CreateDataConnection) for more information. E.g. { \"tables\": {\"exclude\": {\"values\": [\"table1\", \"table2\"], \"matchType\": \"EXACT\"}}, \"schemas\": {\"include\": {\"values\": [\"schema1\", \"schema2\"], \"matchType\": \"PREFIX\"}}}", + optional: true, + }, + allowWritebackCells: { + type: "boolean", + label: "Allow Writeback Cells", + description: "Allow writeback cells.", + optional: true, + }, + includeMagic: { + type: "boolean", + label: "Include Magic", + description: "Include magic.", + optional: true, + }, + connectViaSsh: { + type: "boolean", + label: "Connect Via SSH", + description: "Connect via SSH.", + optional: true, + }, + description: { + type: "string", + label: "Description", + description: "The description of the data connection.", + optional: true, + }, + connectionDetails: { + type: "object", + label: "Connection Details", + description: "An object with the connection details data. [See the documentation](https://learn.hex.tech/docs/api/api-reference#operation/CreateDataConnection) for more information. E.g. { \"bigquery\": { \"serviceAccountJsonConfig\": \"string\", \"enableStorageApi\": true, \"enableDriveAccess\": true, \"projectId\": \"string\" }}", + }, + type: { + type: "string", + label: "Type", + description: "The type of the data connection.", + options: TYPE_OPTIONS, + }, + name: { + type: "string", + label: "Name", + description: "The name of the data connection.", + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _apiUrl() { + return `https://${this.$auth.subdomain}.hex.tech/api/v1`; + }, + _getHeaders() { + return { + "Authorization": `Bearer ${this.$auth.api_key}`, + }; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: `${this._apiUrl()}/${path}`, + headers: this._getHeaders(), + ...opts, + }); + }, + async parseOptions({ + fn, params = {}, mapper = (item) => item, ...opts + }) { + const { + values, pagination, + } = await fn({ + params, + ...opts, + }); + return { + options: values.map(mapper), + context: { + after: pagination.after, + }, + }; + }, + listProjects(opts = {}) { + return this._makeRequest({ + ...opts, + path: "projects", + }); + }, + listRuns({ + projectId, ...opts + }) { + return this._makeRequest({ + ...opts, + path: `projects/${projectId}/runs`, + }); + }, + listUsers(opts = {}) { + return this._makeRequest({ + ...opts, + path: "users", + }); + }, + deactivateUser({ + userId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `users/${userId}/deactivate`, + ...opts, + }); + }, + runProject({ + projectId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `projects/${projectId}/runs`, + ...opts, + }); + }, + createGroup(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "groups", + ...opts, + }); + }, + listGroups(opts = {}) { + return this._makeRequest({ + ...opts, + path: "groups", + }); + }, + listDataConnections(opts = {}) { + return this._makeRequest({ + ...opts, + path: "data-connections", + }); + }, + updateGroup({ + groupId, ...opts + }) { + return this._makeRequest({ + method: "PATCH", + path: `groups/${groupId}`, + ...opts, + }); + }, + deleteGroup({ + groupId, ...opts + }) { + return this._makeRequest({ + method: "DELETE", + path: `groups/${groupId}`, + ...opts, + }); + }, + createDataConnection(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "data-connections", + ...opts, + }); + }, + updateDataConnection({ + connectionId, ...opts + }) { + return this._makeRequest({ + method: "PATCH", + path: `data-connections/${connectionId}`, + ...opts, + }); + }, + getProjectRuns({ + projectId, ...opts + }) { + return this._makeRequest({ + ...opts, + path: `projects/${projectId}/runs`, + }); + }, + getRunStatus({ + projectId, runId, ...opts + }) { + return this._makeRequest({ + ...opts, + path: `projects/${projectId}/runs/${runId}`, + }); + }, + async *paginate({ + fn, params = {}, maxResults = null, ...opts + }) { + let hasMore = false; + let count = 0; + + do { + if (hasMore) { + params.after = hasMore; + } + const { + values: data, + pagination: { after }, + } = await fn({ + params, + ...opts, + }); + for (const d of data) { + yield d; + + if (maxResults && ++count === maxResults) { + return count; + } + } + + hasMore = after; + + } while (hasMore); + }, + async *paginateProjectRuns({ + fn, params = {}, maxResults = null, ...opts + }) { + let hasMore = false; + let count = 0; + let page = 0; + + do { + params.limit = LIMIT; + params.offset = LIMIT * page++; + const { runs } = await fn({ + params, + ...opts, + }); + for (const run of runs) { + yield run; + + if (maxResults && ++count === maxResults) { + return count; + } + } + + hasMore = runs.length; + + } while (hasMore); }, }, }; diff --git a/components/hex/package.json b/components/hex/package.json index 60f1af9404f11..64a52f0ca1786 100644 --- a/components/hex/package.json +++ b/components/hex/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/hex", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Hex Components", "main": "hex.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.1.0" } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3833634c633c6..912ea592ef682 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6615,7 +6615,11 @@ importers: specifier: ^3.0.3 version: 3.0.3 - components/hex: {} + components/hex: + dependencies: + '@pipedream/platform': + specifier: ^3.1.0 + version: 3.1.0 components/heygen: dependencies: