-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #87 from linear/gui/usp-7514-add-trigger-search-an…
…d-create-for-customer Add support for `Customer` entity (Create, Search, Trigger)
- Loading branch information
Showing
5 changed files
with
341 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { Bundle, ZObject } from "zapier-platform-core"; | ||
import { fetchFromLinear } from "../fetchFromLinear"; | ||
import { omitBy } from "lodash"; | ||
|
||
interface CustomerCreateResponse { | ||
data?: { customerCreate: { customer: { id: string; name: string, domains: string[], externalIds: string[] }; success: boolean } }; | ||
errors?: { | ||
message: string; | ||
extensions?: { | ||
userPresentableMessage?: string; | ||
}; | ||
}[]; | ||
} | ||
|
||
const createCustomerRequest = async (z: ZObject, bundle: Bundle) => { | ||
const variables = omitBy( | ||
{ | ||
name: bundle.inputData.name, | ||
domains: bundle.inputData.domains || [], | ||
externalIds: bundle.inputData.externalIds || [], | ||
revenue: bundle.inputData.revenue, | ||
size: bundle.inputData.size, | ||
tierId: bundle.inputData.tierId, | ||
}, | ||
(v) => v === undefined | ||
); | ||
const query = ` | ||
mutation ZapierCustomerCreate( | ||
$name: String!, | ||
$domains: [String!], | ||
$externalIds: [String!], | ||
$revenue: Int, | ||
$size: Int, | ||
$tierId: String, | ||
) { | ||
customerCreate(input: { | ||
name: $name, | ||
domains: $domains, | ||
externalIds: $externalIds, | ||
revenue: $revenue, | ||
size: $size, | ||
tierId: $tierId | ||
}) { | ||
customer { | ||
id | ||
name | ||
domains | ||
externalIds | ||
} | ||
success | ||
} | ||
}`; | ||
|
||
const response = await fetchFromLinear(z, bundle, query, variables); | ||
const data = response.json as CustomerCreateResponse; | ||
|
||
if (data.errors && data.errors.length) { | ||
const error = data.errors[0]; | ||
throw new z.errors.Error( | ||
(error.extensions && error.extensions.userPresentableMessage) || error.message, | ||
"invalid_input", | ||
400 | ||
); | ||
} | ||
|
||
if (data.data && data.data.customerCreate && data.data.customerCreate.success) { | ||
return data.data.customerCreate.customer; | ||
} else { | ||
const error = data.errors ? data.errors[0].message : "Something went wrong"; | ||
throw new z.errors.Error("Failed to create a customer", error, 400); | ||
} | ||
}; | ||
|
||
export const createCustomer = { | ||
key: "createCustomer", | ||
display: { | ||
hidden: false, | ||
description: "Create a new customer in Linear", | ||
label: "Create Customer", | ||
}, | ||
noun: "Customer", | ||
operation: { | ||
perform: createCustomerRequest, | ||
inputFields: [ | ||
{ | ||
required: true, | ||
label: "Name", | ||
helpText: "The name of the customer", | ||
key: "name", | ||
}, | ||
{ | ||
required: false, | ||
label: "Domains", | ||
helpText: "The domains associated with this customer", | ||
key: "domains", | ||
type: "text", | ||
list: true, | ||
}, | ||
{ | ||
required: false, | ||
label: "External IDs", | ||
helpText: "The ids of the customers in external systems", | ||
key: "externalIds", | ||
type: "text", | ||
list: true, | ||
}, | ||
{ | ||
required: false, | ||
label: "Revenue", | ||
helpText: "The annual revenue generated by the customer", | ||
key: "revenue", | ||
type: "number", | ||
}, | ||
{ | ||
required: false, | ||
label: "Size", | ||
helpText: "The size of the customer", | ||
key: "size", | ||
type: "number", | ||
}, | ||
{ | ||
required: false, | ||
label: "Tier ID", | ||
helpText: "The tier of the customer", | ||
key: "tierId", | ||
type: "text", | ||
}, | ||
], | ||
sample: { | ||
data: { | ||
customerCreate: { | ||
customer: { id: "068fbd0a-c1d5-448b-af2d-432127520cbd", domains: ["https://www.example.com"], name: "Example customer" }, | ||
success: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"id": "ccf432b1-6899-4f1e-9d6c-59e21fae2a17", | ||
"name": "Example", | ||
"createdAt": "2024-10-04T22:38:43.396Z", | ||
"updatedAt": "2024-10-04T22:39:43.396Z", | ||
"domains": [ | ||
"example.com" | ||
], | ||
"externalIds": ["123456789"], | ||
"revenue": 10000, | ||
"size": 100, | ||
"tier": { | ||
"id": "565dbccb-aab4-4b63-bf55-fc8ea634084b", | ||
"name": "Enterprise" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { ZObject, Bundle } from "zapier-platform-core"; | ||
import sample from "../samples/customer.json"; | ||
import {CustomerCommon} from "../triggers/customer"; | ||
|
||
interface CustomerResponse { | ||
data: { | ||
customer: CustomerCommon; | ||
}; | ||
} | ||
|
||
const getCustomer = async (z: ZObject, bundle: Bundle) => { | ||
const response = await z.request({ | ||
url: "https://api.linear.app/graphql", | ||
headers: { | ||
"Content-Type": "application/json", | ||
Accept: "application/json", | ||
authorization: bundle.authData.api_key, | ||
}, | ||
body: { | ||
query: ` | ||
query Customer { | ||
customer(id: "${bundle.inputData.id}") { | ||
id | ||
name | ||
domains | ||
externalIds | ||
createdAt | ||
updatedAt | ||
revenue | ||
size | ||
tier { | ||
id | ||
name | ||
} | ||
} | ||
}`, | ||
}, | ||
method: "POST", | ||
}); | ||
const data = (response.json as CustomerResponse).data; | ||
const customer = data.customer; | ||
|
||
return [customer]; | ||
}; | ||
|
||
export const findCustomerByID = { | ||
key: "customer", | ||
noun: "Customer", | ||
|
||
display: { | ||
label: "Find Customer by ID", | ||
hidden: false, | ||
description: "Find a customer by ID", | ||
}, | ||
|
||
operation: { | ||
perform: getCustomer, | ||
inputFields: [ | ||
{ | ||
key: "id", | ||
required: true, | ||
label: "Customer ID", | ||
}, | ||
], | ||
sample, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import {Bundle, ZObject} from "zapier-platform-core"; | ||
import sample from "../samples/customer.json"; | ||
import {getWebhookData, unsubscribeHook} from "../handleWebhook"; | ||
import {jsonToGraphQLQuery} from "json-to-graphql-query"; | ||
import {fetchFromLinear} from "../fetchFromLinear"; | ||
|
||
export interface CustomerCommon { | ||
id: string; | ||
name: string; | ||
domains: string[]; | ||
externalIds: string[]; | ||
createdAt: Date; | ||
updatedAt: Date; | ||
revenue?: number; | ||
size?: number; | ||
tier?: { | ||
id: string; | ||
name: string; | ||
}; | ||
} | ||
|
||
interface CustomersResponse { | ||
data: { | ||
customers: { | ||
nodes: CustomerCommon[]; | ||
}; | ||
}; | ||
} | ||
|
||
const subscribeHook = (eventType: "create" | "update") => async (z: ZObject, bundle: Bundle) => { | ||
const data = { | ||
url: bundle.targetUrl, | ||
}; | ||
const webhookType = eventType === "create" ? "createCustomer" : "updateCustomer"; | ||
|
||
return z | ||
.request({ | ||
url: `https://client-api.linear.app/connect/zapier/subscribe/${webhookType}`, | ||
method: "POST", | ||
body: data, | ||
}) | ||
.then((response) => response.data); | ||
}; | ||
|
||
const getCustomerList = | ||
() => | ||
async (z: ZObject, bundle: Bundle): Promise<CustomerCommon[]> => { | ||
const variables: Record<string, string> = {}; | ||
const variableSchema: Record<string, string> = {}; | ||
|
||
const jsonQuery = { | ||
query: { | ||
__variables: variableSchema, | ||
customers: { | ||
__args: { | ||
first: 25, | ||
}, | ||
nodes: { | ||
id: true, | ||
name: true, | ||
domains: true, | ||
externalIds: true, | ||
createdAt: true, | ||
updatedAt: true, | ||
revenue: true, | ||
size: true, | ||
tier: { | ||
id: true, | ||
name: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}; | ||
const query = jsonToGraphQLQuery(jsonQuery); | ||
const response = await fetchFromLinear(z, bundle, query, variables); | ||
const data = (response.json as CustomersResponse).data; | ||
return data.customers.nodes; | ||
}; | ||
|
||
const operationBase = { | ||
type: "hook", | ||
perform: getWebhookData, | ||
performUnsubscribe: unsubscribeHook, | ||
performList: getCustomerList(), | ||
sample, | ||
}; | ||
|
||
export const newCustomerInstant = { | ||
noun: "Customer", | ||
key: "newCustomerInstant", | ||
display: { | ||
label: "New Customer", | ||
description: "Triggers when a new customer is created.", | ||
}, | ||
operation: { | ||
...operationBase, | ||
performSubscribe: subscribeHook("create"), | ||
}, | ||
}; | ||
|
||
export const updatedCustomerInstant = { | ||
noun: "Customer", | ||
key: "updatedCustomerInstant", | ||
display: { | ||
label: "Updated Customer", | ||
description: "Triggers when a customer is updated.", | ||
}, | ||
operation: { | ||
...operationBase, | ||
performSubscribe: subscribeHook("update"), | ||
}, | ||
}; |