Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "linear-zapier",
"version": "4.6.0",
"version": "4.7.0",
"description": "Linear's Zapier integration",
"main": "index.js",
"license": "MIT",
Expand Down
13 changes: 11 additions & 2 deletions src/creates/createCustomer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import { fetchFromLinear } from "../fetchFromLinear";
import { omitBy } from "lodash";

interface CustomerCreateResponse {
data?: { customerCreate: { customer: { id: string; name: string, domains: string[], externalIds: string[] }; success: boolean } };
data?: {
customerCreate: {
customer: { id: string; name: string; domains: string[]; externalIds: string[] };
success: boolean;
};
};
errors?: {
message: string;
extensions?: {
Expand Down Expand Up @@ -129,7 +134,11 @@ export const createCustomer = {
sample: {
data: {
customerCreate: {
customer: { id: "068fbd0a-c1d5-448b-af2d-432127520cbd", domains: ["https://www.example.com"], name: "Example customer" },
customer: {
id: "068fbd0a-c1d5-448b-af2d-432127520cbd",
domains: ["https://www.example.com"],
name: "Example customer",
},
success: true,
},
},
Expand Down
221 changes: 115 additions & 106 deletions src/creates/createCustomerNeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,41 @@ import { fetchFromLinear } from "../fetchFromLinear";
import { omitBy } from "lodash";

interface CustomerNeedCreateResponse {
data?: { customerNeedCreate: { need: { id: string; customerId?: string, issueId?: string, attachmentId?: string }; success: boolean } };
errors?: {
message: string;
extensions?: {
userPresentableMessage?: string;
};
}[];
data?: {
customerNeedCreate: {
need: { id: string; customerId?: string; issueId?: string; attachmentId?: string };
success: boolean;
};
};
errors?: {
message: string;
extensions?: {
userPresentableMessage?: string;
};
}[];
}

const createCustomerNeedRequest = async (z: ZObject, bundle: Bundle) => {
const variables = omitBy(
{
customerId: bundle.inputData.customerId,
customerExternalId: bundle.inputData.customerExternalId,
issueId: bundle.inputData.issueId,
attachmentId: bundle.inputData.attachmentId,
attachmentUrl: bundle.inputData.attachmentUrl,
body: bundle.inputData.body,
priority: bundle.inputData.priority,
},
(v) => v === undefined
);
const variables = omitBy(
{
customerId: bundle.inputData.customerId,
customerExternalId: bundle.inputData.customerExternalId,
issueId: bundle.inputData.issueId,
attachmentId: bundle.inputData.attachmentId,
attachmentUrl: bundle.inputData.attachmentUrl,
body: bundle.inputData.body,
priority: bundle.inputData.priority,
},
(v) => v === undefined
);

if(variables.attachmentId && variables.attachmentUrl) {
throw new Error ("Cannot specify both attachmentId and attachmentUrl");
} else if (variables.customerId && variables.customerExternalId) {
throw new Error ("Cannot specify both customerId and customerExternalId");
}
if (variables.attachmentId && variables.attachmentUrl) {
throw new Error("Cannot specify both attachmentId and attachmentUrl");
} else if (variables.customerId && variables.customerExternalId) {
throw new Error("Cannot specify both customerId and customerExternalId");
}

const query = `
const query = `
mutation ZapierCustomerNeedCreate(
$customerId: String,
$customerExternalId: String,
Expand Down Expand Up @@ -67,92 +72,96 @@ const createCustomerNeedRequest = async (z: ZObject, bundle: Bundle) => {
}
}`;

const response = await fetchFromLinear(z, bundle, query, variables);
const data = response.json as CustomerNeedCreateResponse;
const response = await fetchFromLinear(z, bundle, query, variables);
const data = response.json as CustomerNeedCreateResponse;

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.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.customerNeedCreate && data.data.customerNeedCreate.success) {
return data.data.customerNeedCreate.need;
} else {
const error = data.errors ? data.errors[0].message : "Something went wrong";
throw new z.errors.Error("Failed to create a customer need", error, 400);
}
if (data.data && data.data.customerNeedCreate && data.data.customerNeedCreate.success) {
return data.data.customerNeedCreate.need;
} else {
const error = data.errors ? data.errors[0].message : "Something went wrong";
throw new z.errors.Error("Failed to create a customer need", error, 400);
}
};

export const createCustomerNeed = {
key: "createCustomerNeed",
display: {
hidden: false,
description: "Create a new customer need in Linear",
label: "Create Customer Need",
},
noun: "Customer Need",
operation: {
perform: createCustomerNeedRequest,
inputFields: [
{
required: false,
label: "Customer ID",
helpText: "The ID of the customer to create the need for",
key: "customerId",
},
{
required: false,
label: "External Customer ID",
helpText: "The external ID of the customer the need belongs to",
key: "customerExternalId",
},
{
required: false,
label: "Issue ID",
helpText: "The ID of the issue this need is for",
key: "issueId",
type: "text",
},
{
required: false,
label: "Attachment ID",
helpText: "The ID of the attachment this need is associated with",
key: "attachmentId",
type: "text",
},
{
required: false,
label: "Attachment URL",
helpText: "Optional URL for the attachment associated with the customer need",
key: "attachmentUrl",
type: "text",
},
{
required: false,
label: "Body",
helpText: "The content of the need in markdown format.",
key: "body",
type: "text",
},
{
required: false,
label: "Priority",
helpText: "Whether the customer need is important or not. 0 = Not important, 1 = Important.",
key: "priority",
type: "number",
},
],
sample: {
data: {
customerNeedCreate: {
need: { id: "93a02c29-da90-4d06-ab1c-96956e94bcd0", customerId: "6465f500-6626-4253-9073-144535a6c658", issueId: "a8ea3bfa-5420-492a-84e9-ffe49ca5f22a" },
success: true,
},
},
key: "createCustomerNeed",
display: {
hidden: false,
description: "Create a new customer need in Linear",
label: "Create Customer Need",
},
noun: "Customer Need",
operation: {
perform: createCustomerNeedRequest,
inputFields: [
{
required: false,
label: "Customer ID",
helpText: "The ID of the customer to create the need for",
key: "customerId",
},
{
required: false,
label: "External Customer ID",
helpText: "The external ID of the customer the need belongs to",
key: "customerExternalId",
},
{
required: false,
label: "Issue ID",
helpText: "The ID of the issue this need is for",
key: "issueId",
type: "text",
},
{
required: false,
label: "Attachment ID",
helpText: "The ID of the attachment this need is associated with",
key: "attachmentId",
type: "text",
},
{
required: false,
label: "Attachment URL",
helpText: "Optional URL for the attachment associated with the customer need",
key: "attachmentUrl",
type: "text",
},
{
required: false,
label: "Body",
helpText: "The content of the need in markdown format.",
key: "body",
type: "text",
},
{
required: false,
label: "Priority",
helpText: "Whether the customer need is important or not. 0 = Not important, 1 = Important.",
key: "priority",
type: "number",
},
],
sample: {
data: {
customerNeedCreate: {
need: {
id: "93a02c29-da90-4d06-ab1c-96956e94bcd0",
customerId: "6465f500-6626-4253-9073-144535a6c658",
issueId: "a8ea3bfa-5420-492a-84e9-ffe49ca5f22a",
},
success: true,
},
},
},
},
};
14 changes: 8 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ import { updateIssue } from "./creates/updateIssue";
import { issueTemplates } from "./triggers/issueTemplates";
import { findIssueByID } from "./searches/issue";
import { findProjectByID } from "./searches/project";
import {createCustomer} from "./creates/createCustomer";
import {findCustomerByID} from "./searches/customer";
import {newCustomerInstant, updatedCustomerInstant} from "./triggers/customer";
import {createCustomerNeed} from "./creates/createCustomerNeed";
import {newCustomerNeedInstant, updatedCustomerNeedInstant} from "./triggers/customerNeed";
import { newInitiativeUpdateInstant, updatedInitiativeUpdateInstant } from "./triggers/initiativeUpdate";
import { createCustomer } from "./creates/createCustomer";
import { findCustomerByID } from "./searches/customer";
import { newCustomerInstant, updatedCustomerInstant } from "./triggers/customer";
import { createCustomerNeed } from "./creates/createCustomerNeed";
import { newCustomerNeedInstant, updatedCustomerNeedInstant } from "./triggers/customerNeed";

const handleErrors = (response: HttpResponse, z: ZObject) => {
if (response.request.url !== "https://api.linear.app/graphql") {
Expand Down Expand Up @@ -80,6 +81,8 @@ const App = {
[newDocumentCommentInstant.key]: newDocumentCommentInstant,
[updatedProjectUpdate.key]: updatedProjectUpdate,
[updatedProjectUpdateInstant.key]: updatedProjectUpdateInstant,
[newInitiativeUpdateInstant.key]: newInitiativeUpdateInstant,
[updatedInitiativeUpdateInstant.key]: updatedInitiativeUpdateInstant,
[team.key]: team,
[issueTemplates.key]: issueTemplates,
[status.key]: status,
Expand All @@ -97,7 +100,6 @@ const App = {
[updatedCustomerInstant.key]: updatedCustomerInstant,
[newCustomerNeedInstant.key]: newCustomerNeedInstant,
[updatedCustomerNeedInstant.key]: updatedCustomerNeedInstant,

},
searches: {
[findIssueByID.key]: findIssueByID,
Expand Down
4 changes: 1 addition & 3 deletions src/samples/customer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
"name": "Example",
"createdAt": "2024-10-04T22:38:43.396Z",
"updatedAt": "2024-10-04T22:39:43.396Z",
"domains": [
"example.com"
],
"domains": ["example.com"],
"externalIds": ["123456789"],
"revenue": 10000,
"size": 100,
Expand Down
18 changes: 18 additions & 0 deletions src/samples/initiativeUpdate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"id": "722c8d97-f01e-4d2a-85da-271592463f8d",
"body": "This is an initiative update body in Markdown format!",
"health": "onTrack",
"url": "https://local.linear.dev/linear/updateA",
"editedAt": "2022-10-27T21:20:59.199Z",
"createdAt": "2022-10-27T21:20:59.199Z",
"updatedAt": "2022-10-27T21:20:59.199Z",
"initiative": {
"id": "e632a843-19da-4199-9489-3a962a96b549",
"name": "My Initiative"
},
"user": {
"id": "e632a843-19da-4199-9489-3a962a96b549",
"name": "Zapier User",
"email": "creator@example.com"
}
}
29 changes: 29 additions & 0 deletions src/samples/initiativeUpdateComment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"id": "e632a843-19da-4199-9489-3a962a96b549",
"body": "A great update! I'm looking forward to trying it out.",
"createdAt": "2024-01-05T23:36:40.311Z",
"resolvedAt": null,
"initiativeUpdate": {
"id": "799e7b95-2902-4c0a-86d8-d817a60f7f9f",
"body": "This week I focused on getting email attachments working and an initial implementation is now in review on GitHub.",
"user": {
"id": "a3188fa9-f757-4046-a847-b5174a39b978",
"name": "John Smith",
"email": "user@example.com",
"avatarUrl": null
},
"url": "https://linear.app/example/initiative/the-bext-initiative-4437c60bc5ec#initiativeUpdate-bb1cfa33",
"initiative": {
"id": "a3188fa9-f757-4046-a847-b5174a39b978",
"name": "The Best Initiative",
"url": "https://linear.app/example/initiative/the-bext-initiative-4437c60bc5ec"
}
},
"user": {
"id": "fda6d8ba-2d19-4776-affa-0cdd7ab158de",
"email": "another-user@example.com",
"name": "Tom Lee",
"avatarUrl": null
},
"parent": null
}
2 changes: 1 addition & 1 deletion src/searches/customer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ZObject, Bundle } from "zapier-platform-core";
import sample from "../samples/customer.json";
import {CustomerCommon} from "../triggers/customer";
import { CustomerCommon } from "../triggers/customer";

interface CustomerResponse {
data: {
Expand Down
8 changes: 4 additions & 4 deletions src/triggers/customer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {Bundle, ZObject} from "zapier-platform-core";
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";
import { getWebhookData, unsubscribeHook } from "../handleWebhook";
import { jsonToGraphQLQuery } from "json-to-graphql-query";
import { fetchFromLinear } from "../fetchFromLinear";

export interface CustomerCommon {
id: string;
Expand Down
Loading