Skip to content

Commit f5ce1b2

Browse files
committed
[Components] grain #14678
Sources - New Highlight (Instant) - New Story (Instant) - New Recording (Instant) - Updated Highlight (Instant) - Updated Story (Instant) - Updated Recording (Instant) - Deleted Highlight (Instant) - Deleted Story (Instant) - Deleted Recording (Instant) Actions - Get Recording
1 parent 7643f8a commit f5ce1b2

File tree

24 files changed

+518
-677
lines changed

24 files changed

+518
-677
lines changed

components/grain/actions/get-recording/get-recording.mjs

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
import {
2+
INTELLIGENCE_NOTES_FORMAT_OPTIONS,
3+
TRANSCRIPT_FORMAT_OPTIONS,
4+
} from "../../common/constants.mjs";
5+
import { parseObject } from "../../common/utils.mjs";
16
import grain from "../../grain.app.mjs";
2-
import { axios } from "@pipedream/platform";
37

48
export default {
59
key: "grain-get-recording",
@@ -14,44 +18,36 @@ export default {
1418
grain,
1519
"recordId",
1620
],
17-
async options({ page }) {
18-
const recordings = await this.grain.listRecordings({
19-
page,
20-
});
21-
return recordings.map((recording) => ({
22-
label: recording.title,
23-
value: recording.id,
24-
}));
25-
},
2621
},
2722
transcriptFormat: {
28-
propDefinition: [
29-
grain,
30-
"transcriptFormat",
31-
],
23+
type: "string",
24+
label: "Transcript Format",
25+
description: "Format for the transcript",
26+
options: TRANSCRIPT_FORMAT_OPTIONS,
3227
optional: true,
3328
},
3429
intelligenceNotesFormat: {
35-
propDefinition: [
36-
grain,
37-
"intelligenceNotesFormat",
38-
],
30+
type: "string",
31+
label: "Intelligence Notes Format",
32+
description: "Format for the intelligence notes",
33+
options: INTELLIGENCE_NOTES_FORMAT_OPTIONS,
3934
optional: true,
4035
},
4136
allowedIntelligenceNotes: {
42-
propDefinition: [
43-
grain,
44-
"allowedIntelligenceNotes",
45-
],
37+
type: "string[]",
38+
label: "Allowed Intelligence Notes",
39+
description: "Whitelist of intelligence notes section titles",
4640
optional: true,
4741
},
4842
},
4943
async run({ $ }) {
5044
const response = await this.grain.fetchRecording({
5145
recordId: this.recordId,
52-
transcriptFormat: this.transcriptFormat,
53-
intelligenceNotesFormat: this.intelligenceNotesFormat,
54-
allowedIntelligenceNotes: this.allowedIntelligenceNotes,
46+
params: {
47+
transcript_format: this.transcriptFormat,
48+
intelligence_notes_format: this.intelligenceNotesFormat,
49+
allowed_intelligence_notes: parseObject(this.allowedIntelligenceNotes),
50+
},
5551
});
5652

5753
$.export("$summary", `Successfully fetched recording with ID ${this.recordId}`);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export const TRANSCRIPT_FORMAT_OPTIONS = [
2+
{
3+
label: "JSON",
4+
value: "json",
5+
},
6+
{
7+
label: "VTT",
8+
value: "vtt",
9+
},
10+
];
11+
12+
export const INTELLIGENCE_NOTES_FORMAT_OPTIONS = [
13+
{
14+
label: "JSON",
15+
value: "json",
16+
},
17+
{
18+
label: "Markdown",
19+
value: "md",
20+
},
21+
{
22+
label: "Text",
23+
value: "text",
24+
},
25+
];

components/grain/common/utils.mjs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export const parseObject = (obj) => {
2+
if (!obj) return undefined;
3+
4+
if (Array.isArray(obj)) {
5+
return obj.map((item) => {
6+
if (typeof item === "string") {
7+
try {
8+
return JSON.parse(item);
9+
} catch (e) {
10+
return item;
11+
}
12+
}
13+
return item;
14+
});
15+
}
16+
if (typeof obj === "string") {
17+
try {
18+
return JSON.parse(obj);
19+
} catch (e) {
20+
return obj;
21+
}
22+
}
23+
return obj;
24+
};

components/grain/grain.app.mjs

Lines changed: 78 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -8,126 +8,106 @@ export default {
88
type: "string",
99
label: "Record ID",
1010
description: "The ID of the recording to fetch",
11-
async options() {
12-
const recordings = await this.listRecordings();
13-
return recordings.map((recording) => ({
14-
value: recording.id,
15-
label: recording.title,
16-
}));
11+
async options({ prevContext: { nextPage } }) {
12+
const {
13+
recordings, cursor,
14+
} = await this.listRecordings({
15+
params: {
16+
cursor: nextPage,
17+
},
18+
});
19+
return {
20+
options: recordings.map(({
21+
id: value, title: label,
22+
}) => ({
23+
value,
24+
label,
25+
})),
26+
context: {
27+
nextPage: cursor,
28+
},
29+
};
1730
},
1831
},
19-
transcriptFormat: {
32+
viewId: {
2033
type: "string",
21-
label: "Transcript Format",
22-
description: "Format for the transcript",
23-
options: [
24-
{
25-
label: "JSON",
26-
value: "json",
27-
},
28-
{
29-
label: "VTT",
30-
value: "vtt",
31-
},
32-
],
33-
optional: true,
34-
},
35-
intelligenceNotesFormat: {
36-
type: "string",
37-
label: "Intelligence Notes Format",
38-
description: "Format for the intelligence notes",
39-
options: [
40-
{
41-
label: "JSON",
42-
value: "json",
43-
},
44-
{
45-
label: "Markdown",
46-
value: "md",
47-
},
48-
{
49-
label: "Text",
50-
value: "text",
51-
},
52-
],
53-
optional: true,
54-
},
55-
allowedIntelligenceNotes: {
56-
type: "string[]",
57-
label: "Allowed Intelligence Notes",
58-
description: "Whitelist of intelligence notes section titles",
59-
optional: true,
34+
label: "View ID",
35+
description: "The ID of the recording to fetch",
36+
async options({
37+
type, prevContext: { nextPage },
38+
}) {
39+
const {
40+
views, cursor,
41+
} = await this.listViews({
42+
params: {
43+
type_filter: type,
44+
cursor: nextPage,
45+
},
46+
});
47+
return {
48+
options: views.map(({
49+
id: value, name: label,
50+
}) => ({
51+
value,
52+
label,
53+
})),
54+
context: {
55+
nextPage: cursor,
56+
},
57+
};
58+
},
6059
},
6160
},
6261
methods: {
6362
_baseUrl() {
64-
return "https://grain.com";
63+
return "https://grain.com/_/public-api";
64+
},
65+
_headers() {
66+
return {
67+
Authorization: `Bearer ${this.$auth.oauth_access_token}`,
68+
};
6569
},
66-
async _makeRequest(opts = {}) {
67-
const {
68-
$ = this, method = "GET", path = "/", headers, ...otherOpts
69-
} = opts;
70+
_makeRequest({
71+
$ = this, path, ...opts
72+
}) {
7073
return axios($, {
71-
...otherOpts,
72-
method,
7374
url: this._baseUrl() + path,
74-
headers: {
75-
...headers,
76-
Authorization: `Bearer ${this.$auth.oauth_access_token}`,
77-
},
75+
headers: this._headers(),
76+
...opts,
7877
});
7978
},
80-
async listRecordings(opts = {}) {
79+
listRecordings(opts = {}) {
8180
return this._makeRequest({
82-
path: "/_/public-api/recordings",
81+
path: "/recordings",
8382
...opts,
8483
});
8584
},
86-
async fetchRecording({
87-
recordId, transcriptFormat, intelligenceNotesFormat, allowedIntelligenceNotes, ...opts
88-
}) {
85+
listViews(opts = {}) {
8986
return this._makeRequest({
90-
path: `/_/public-api/recordings/${recordId}`,
91-
params: {
92-
transcript_format: transcriptFormat,
93-
intelligence_notes_format: intelligenceNotesFormat,
94-
allowed_intelligence_notes: allowedIntelligenceNotes,
95-
},
87+
path: "/views",
9688
...opts,
9789
});
9890
},
99-
async emitNewEvent(eventType, entityType) {
100-
// Logic to emit event - placeholder implementation
101-
console.log(`Emit ${eventType} event for ${entityType}`);
102-
},
103-
},
104-
hooks: {
105-
async addedHighlight() {
106-
await this.emitNewEvent("added", "highlight");
107-
},
108-
async addedStory() {
109-
await this.emitNewEvent("added", "story");
110-
},
111-
async addedRecording() {
112-
await this.emitNewEvent("added", "recording");
113-
},
114-
async updatedHighlight() {
115-
await this.emitNewEvent("updated", "highlight");
116-
},
117-
async updatedStory() {
118-
await this.emitNewEvent("updated", "story");
119-
},
120-
async updatedRecording() {
121-
await this.emitNewEvent("updated", "recording");
122-
},
123-
async removedHighlight() {
124-
await this.emitNewEvent("removed", "highlight");
91+
fetchRecording({
92+
recordId, ...opts
93+
}) {
94+
return this._makeRequest({
95+
path: `/recordings/${recordId}`,
96+
...opts,
97+
});
12598
},
126-
async removedStory() {
127-
await this.emitNewEvent("removed", "story");
99+
createWebhook(opts = {}) {
100+
return this._makeRequest({
101+
method: "POST",
102+
path: "/hooks",
103+
...opts,
104+
});
128105
},
129-
async removedRecording() {
130-
await this.emitNewEvent("removed", "recording");
106+
deleteWebhook(hookId) {
107+
return this._makeRequest({
108+
method: "DELETE",
109+
path: `/hooks/${hookId}`,
110+
});
131111
},
132112
},
133113
};

components/grain/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pipedream/grain",
3-
"version": "0.0.1",
3+
"version": "0.1.0",
44
"description": "Pipedream Grain Components",
55
"main": "grain.app.mjs",
66
"keywords": [
@@ -11,5 +11,8 @@
1111
"author": "Pipedream <[email protected]> (https://pipedream.com/)",
1212
"publishConfig": {
1313
"access": "public"
14+
},
15+
"dependencies": {
16+
"@pipedream/platform": "^3.0.3"
1417
}
1518
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import grain from "../../grain.app.mjs";
2+
3+
export default {
4+
props: {
5+
grain,
6+
http: "$.interface.http",
7+
db: "$.service.db",
8+
},
9+
methods: {
10+
_getHookId() {
11+
return this.db.get("hookId");
12+
},
13+
_setHookId(hookId) {
14+
this.db.set("hookId", hookId);
15+
},
16+
getExtraData() {
17+
return {};
18+
},
19+
},
20+
hooks: {
21+
async activate() {
22+
const response = await this.grain.createWebhook({
23+
data: {
24+
version: 2,
25+
hook_url: this.http.endpoint,
26+
view_id: this.viewId,
27+
actions: this.getAction(),
28+
},
29+
});
30+
this._setHookId(response.id);
31+
},
32+
async deactivate() {
33+
const webhookId = this._getHookId();
34+
await this.grain.deleteWebhook(webhookId);
35+
},
36+
},
37+
async run({ body }) {
38+
if (!body.data) return;
39+
40+
const ts = Date.parse(new Date());
41+
this.$emit(body, {
42+
id: `${body.data.id}-${ts}`,
43+
summary: this.getSummary(body),
44+
ts: ts,
45+
});
46+
},
47+
};

0 commit comments

Comments
 (0)