Skip to content

Commit ff70ac9

Browse files
authored
New Components - attio (#14236)
* wip * new components * pnpm-lock.yaml * updates
1 parent edd4923 commit ff70ac9

File tree

14 files changed

+673
-7
lines changed

14 files changed

+673
-7
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import attio from "../../attio.app.mjs";
2+
3+
export default {
4+
key: "attio-create-note",
5+
name: "Create Note",
6+
description: "Creates a new note for a given record. The note will be linked to the specified record. [See the documentation](https://developers.attio.com/reference/post_v2-notes)",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
attio,
11+
parentObject: {
12+
propDefinition: [
13+
attio,
14+
"objectId",
15+
],
16+
label: "Parent Object ID",
17+
description: "The ID of the parent object the note belongs to",
18+
},
19+
parentRecordId: {
20+
propDefinition: [
21+
attio,
22+
"recordId",
23+
(c) => ({
24+
objectId: c.parentObject,
25+
}),
26+
],
27+
label: "Parent Record ID",
28+
description: "The ID of the parent record the note belongs to",
29+
},
30+
title: {
31+
type: "string",
32+
label: "Title",
33+
description: "The note title",
34+
},
35+
content: {
36+
type: "string",
37+
label: "Content",
38+
description: "The content of the note",
39+
},
40+
},
41+
async run({ $ }) {
42+
const response = await this.attio.createNote({
43+
$,
44+
data: {
45+
data: {
46+
parent_object: this.parentObject,
47+
parent_record_id: this.parentRecordId,
48+
title: this.title,
49+
format: "plaintext",
50+
content: this.content,
51+
},
52+
},
53+
});
54+
$.export("$summary", `Successfully created note with ID: ${response.data.id.note_id}`);
55+
return response;
56+
},
57+
};
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import attio from "../../attio.app.mjs";
2+
import utils from "../../common/utils.mjs";
3+
4+
export default {
5+
key: "attio-create-update-record",
6+
name: "Create or Update Record",
7+
description: "Creates or updates a specific record such as a person or a deal. If the record already exists, it's updated. Otherwise, a new record is created. [See the documentation](https://developers.attio.com/reference/put_v2-objects-object-records)",
8+
version: "0.0.1",
9+
type: "action",
10+
props: {
11+
attio,
12+
objectId: {
13+
propDefinition: [
14+
attio,
15+
"objectId",
16+
],
17+
},
18+
attributeId: {
19+
propDefinition: [
20+
attio,
21+
"attributeId",
22+
(c) => ({
23+
objectId: c.objectId,
24+
}),
25+
],
26+
reloadProps: true,
27+
},
28+
},
29+
async additionalProps() {
30+
const props = {};
31+
if (!this.attributeId) {
32+
return props;
33+
}
34+
const attributes = await this.getRelevantAttributes();
35+
for (const attribute of attributes) {
36+
props[attribute.id.attribute_id] = {
37+
type: attribute.is_multiselect
38+
? "string[]"
39+
: "string",
40+
label: attribute.title,
41+
optional: attribute.id.attribute_id !== this.attributeId && !attribute.is_required,
42+
};
43+
}
44+
return props;
45+
},
46+
methods: {
47+
async getRelevantAttributes() {
48+
const stream = utils.paginate({
49+
fn: this.attio.listAttributes,
50+
args: {
51+
objectId: this.objectId,
52+
},
53+
});
54+
const attributes = await utils.streamIterator(stream);
55+
return attributes.filter((a) => a.is_writable || a.id.attribute_id === this.attributeId);
56+
},
57+
},
58+
async run({ $ }) {
59+
const {
60+
attio,
61+
getRelevantAttributes,
62+
objectId,
63+
attributeId,
64+
...values
65+
} = this;
66+
67+
const attributes = await getRelevantAttributes();
68+
69+
const response = await attio.upsertRecord({
70+
$,
71+
objectId,
72+
params: {
73+
matching_attribute: attributeId,
74+
},
75+
data: {
76+
data: {
77+
values: utils.parseValues(attributes, values),
78+
},
79+
},
80+
});
81+
$.export("$summary", "Successfully created or updated record");
82+
return response;
83+
},
84+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import attio from "../../attio.app.mjs";
2+
3+
export default {
4+
key: "attio-delete-list-entry",
5+
name: "Delete List Entry",
6+
description: "Deletes an existing entry from a specific list. [See the documentation](https://developers.attio.com/reference/delete_v2-lists-list-entries-entry-id)",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
attio,
11+
listId: {
12+
propDefinition: [
13+
attio,
14+
"listId",
15+
],
16+
},
17+
entryId: {
18+
propDefinition: [
19+
attio,
20+
"entryId",
21+
(c) => ({
22+
listId: c.listId,
23+
}),
24+
],
25+
},
26+
},
27+
async run({ $ }) {
28+
const response = await this.attio.deleteListEntry({
29+
$,
30+
listId: this.listId,
31+
entryId: this.entryId,
32+
});
33+
$.export("$summary", `Successfully deleted list entry with ID: ${this.entryId}`);
34+
return response;
35+
},
36+
};

components/attio/attio.app.mjs

Lines changed: 185 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,192 @@
1+
import { axios } from "@pipedream/platform";
2+
const DEFAULT_LIMIT = 20;
3+
14
export default {
25
type: "app",
36
app: "attio",
4-
propDefinitions: {},
7+
propDefinitions: {
8+
listId: {
9+
type: "string",
10+
label: "List ID",
11+
description: "The identifier of a list",
12+
async options() {
13+
const { data } = await this.listLists();
14+
return data?.map(({
15+
id, name: label,
16+
}) => ({
17+
value: id.list_id,
18+
label,
19+
})) || [];
20+
},
21+
},
22+
entryId: {
23+
type: "string",
24+
label: "Entry ID",
25+
description: "The identifier of a list entry",
26+
async options({
27+
listId, page,
28+
}) {
29+
const { data } = await this.listEntries({
30+
listId,
31+
params: {
32+
limit: DEFAULT_LIMIT,
33+
offset: page * DEFAULT_LIMIT,
34+
},
35+
});
36+
return data?.map(({ id }) => id.entry_id) || [];
37+
},
38+
},
39+
objectId: {
40+
type: "string",
41+
label: "Object ID",
42+
description: "The identifier of an object",
43+
async options() {
44+
const { data } = await this.listObjects();
45+
return data?.map(({
46+
id, singular_noun: label,
47+
}) => ({
48+
value: id.object_id,
49+
label,
50+
})) || [];
51+
},
52+
},
53+
recordId: {
54+
type: "string",
55+
label: "Record ID",
56+
description: "Identifier of a record",
57+
async options({
58+
objectId, page,
59+
}) {
60+
const { data } = await this.listRecords({
61+
objectId,
62+
params: {
63+
limit: DEFAULT_LIMIT,
64+
offset: page * DEFAULT_LIMIT,
65+
},
66+
});
67+
return data?.map(({ id }) => id.record_id) || [];
68+
},
69+
},
70+
attributeId: {
71+
type: "string",
72+
label: "Attribute ID",
73+
description: "The ID or slug of the attribute to use to check if a record already exists. The attribute must be unique.",
74+
async options({
75+
objectId, page,
76+
}) {
77+
const { data } = await this.listAttributes({
78+
objectId,
79+
params: {
80+
limit: DEFAULT_LIMIT,
81+
offset: page * DEFAULT_LIMIT,
82+
},
83+
});
84+
return data
85+
?.filter((attribute) => attribute.is_unique)
86+
?.map(({
87+
id, title: label,
88+
}) => ({
89+
value: id.attribute_id,
90+
label,
91+
})) || [];
92+
},
93+
},
94+
},
595
methods: {
6-
// this.$auth contains connected account data
7-
authKeys() {
8-
console.log(Object.keys(this.$auth));
96+
_baseUrl() {
97+
return "https://api.attio.com/v2";
98+
},
99+
_makeRequest({
100+
$ = this,
101+
path,
102+
...opts
103+
}) {
104+
return axios($, {
105+
url: `${this._baseUrl()}${path}`,
106+
headers: {
107+
Authorization: `Bearer ${this.$auth.oauth_access_token}`,
108+
},
109+
...opts,
110+
});
111+
},
112+
createWebhook(opts = {}) {
113+
return this._makeRequest({
114+
method: "POST",
115+
path: "/webhooks",
116+
...opts,
117+
});
118+
},
119+
deleteWebhook({
120+
hookId, ...opts
121+
}) {
122+
return this._makeRequest({
123+
method: "DELETE",
124+
path: `/webhooks/${hookId}`,
125+
...opts,
126+
});
127+
},
128+
listLists(opts = {}) {
129+
return this._makeRequest({
130+
path: "/lists",
131+
...opts,
132+
});
133+
},
134+
listEntries({
135+
listId, ...opts
136+
}) {
137+
return this._makeRequest({
138+
method: "POST",
139+
path: `/lists/${listId}/entries/query`,
140+
...opts,
141+
});
142+
},
143+
listObjects(opts = {}) {
144+
return this._makeRequest({
145+
path: "/objects",
146+
...opts,
147+
});
148+
},
149+
listRecords({
150+
objectId, ...opts
151+
}) {
152+
return this._makeRequest({
153+
method: "POST",
154+
path: `/objects/${objectId}/records/query`,
155+
...opts,
156+
});
157+
},
158+
listAttributes({
159+
objectId, ...opts
160+
}) {
161+
return this._makeRequest({
162+
path: `/objects/${objectId}/attributes`,
163+
...opts,
164+
});
165+
},
166+
createNote(opts = {}) {
167+
return this._makeRequest({
168+
method: "POST",
169+
path: "/notes",
170+
...opts,
171+
});
172+
},
173+
upsertRecord({
174+
objectId, ...opts
175+
}) {
176+
return this._makeRequest({
177+
method: "PUT",
178+
path: `/objects/${objectId}/records`,
179+
...opts,
180+
});
181+
},
182+
deleteListEntry({
183+
listId, entryId, ...opts
184+
}) {
185+
return this._makeRequest({
186+
method: "DELETE",
187+
path: `/lists/${listId}/entries/${entryId}`,
188+
...opts,
189+
});
9190
},
10191
},
11192
};

0 commit comments

Comments
 (0)