@pipedream/jobnimbus 0.0.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,12 +1,11 @@
1
1
  # Overview
2
2
 
3
- Jobnimbus API can be used to create custom applications for managing job
4
- information.
3
+ The Jobnimbus API allows for the creation of complex workflows revolving around job and customer management within the construction and contracting industries. With this API, users can automate tasks such as updating job statuses, managing contacts, and creating tasks or appointments. This streamlines the process of moving a job from lead to completion, ensuring communication and record-keeping are seamless.
5
4
 
6
- Some examples of what you can build using the Jobnimbus API include:
5
+ # Example Use Cases
7
6
 
8
- - A custom job board
9
- - A job search engine
10
- - A job management system
11
- - A CRM for job-related information
12
- - A job-related data analytics platform
7
+ - **Automated Job Status Updates**: Trigger a Pipedream workflow whenever a job status is updated in Jobnimbus to send a custom notification via SMS or email through Twilio or SendGrid. This keeps team members in the loop in real-time about job progress.
8
+
9
+ - **Dynamic Contact Import**: When a new contact is added to a Google Sheet, use Pipedream to automatically create a corresponding contact in Jobnimbus. This ensures your customer database is always synchronized and up-to-date without manual entry.
10
+
11
+ - **Task Management with Calendar Integration**: On creation of a new task in Jobnimbus, trigger a Pipedream workflow to add an event to a Google Calendar, inviting all relevant team members. This automation helps in scheduling and making sure everyone is aware of their assignments.
@@ -0,0 +1,209 @@
1
+ import app from "../../jobnimbus.app.mjs";
2
+ import utils from "../../common/utils.mjs";
3
+
4
+ export default {
5
+ props: {
6
+ app,
7
+ firstName: {
8
+ type: "string",
9
+ label: "First Name",
10
+ description: "The first name of the person this contact record is associated with.",
11
+ optional: true,
12
+ },
13
+ lastName: {
14
+ type: "string",
15
+ label: "Last Name",
16
+ description: "The last name of the person this contact record is associated with.",
17
+ optional: true,
18
+ },
19
+ displayName: {
20
+ type: "string",
21
+ label: "Display Name",
22
+ description: "The company name that this contact record is associated with.",
23
+ optional: true,
24
+ },
25
+ company: {
26
+ type: "string",
27
+ label: "Company Name",
28
+ description: "Display name used mainly for QB syncing.",
29
+ optional: true,
30
+ },
31
+ number: {
32
+ type: "string",
33
+ label: "Number",
34
+ description: "The customer defined template generated number assigned to this record, based off of the record id.",
35
+ optional: true,
36
+ },
37
+ isActive: {
38
+ type: "boolean",
39
+ label: "Is Active",
40
+ description: "Whether this record is active(true) or deleted(false).",
41
+ optional: true,
42
+ },
43
+ isArchived: {
44
+ type: "boolean",
45
+ label: "Is Archived",
46
+ description: "Whether this record has been archived (true) or not (false).",
47
+ optional: true,
48
+ },
49
+ tags: {
50
+ type: "string[]",
51
+ label: "Tags",
52
+ description: "List of string tags",
53
+ optional: true,
54
+ },
55
+ description: {
56
+ type: "string",
57
+ label: "Description",
58
+ description: "The description of this record.",
59
+ optional: true,
60
+ },
61
+ address1: {
62
+ type: "string",
63
+ label: "Address Line 1",
64
+ description: "The line 1 portion of the physical address.",
65
+ optional: true,
66
+ },
67
+ address2: {
68
+ type: "string",
69
+ label: "Address Line 2",
70
+ description: "The line 2 portion of the physical address.",
71
+ optional: true,
72
+ },
73
+ city: {
74
+ type: "string",
75
+ label: "City",
76
+ description: "The city portion of the physical address.",
77
+ optional: true,
78
+ },
79
+ state: {
80
+ type: "string",
81
+ label: "State",
82
+ description: "The state text portion of the physical address.",
83
+ optional: true,
84
+ },
85
+ zip: {
86
+ type: "string",
87
+ label: "Zip",
88
+ description: "The postal code portion of the physical address.",
89
+ optional: true,
90
+ },
91
+ country: {
92
+ type: "string",
93
+ label: "Country",
94
+ description: "The country portion of the physical address.",
95
+ optional: true,
96
+ },
97
+ geoLat: {
98
+ type: "string",
99
+ label: "Geo Latitude",
100
+ description: "The latitude of geo coordinates of the address associated with this record.",
101
+ optional: true,
102
+ },
103
+ geoLong: {
104
+ type: "string",
105
+ label: "Geo Longitude",
106
+ description: "The longitude of geo coordinates of the address associated with this record.",
107
+ optional: true,
108
+ },
109
+ estimatedTime: {
110
+ type: "integer",
111
+ label: "Estimated Time",
112
+ description: "The number of minutes this record is estimated to take to complete.",
113
+ optional: true,
114
+ },
115
+ isLead: {
116
+ type: "boolean",
117
+ label: "Is Lead",
118
+ description: "Whether this record is a lead or not.",
119
+ optional: true,
120
+ },
121
+ isClosed: {
122
+ type: "boolean",
123
+ label: "Is Closed",
124
+ description: "Whether this record is closed or not.",
125
+ optional: true,
126
+ },
127
+ isSubcontractor: {
128
+ type: "boolean",
129
+ label: "Is Subcontractor",
130
+ description: "Whether this contact is a subcontractor or not for User.",
131
+ optional: true,
132
+ },
133
+ email: {
134
+ propDefinition: [
135
+ app,
136
+ "email",
137
+ ],
138
+ optional: true,
139
+ },
140
+ homePhone: {
141
+ type: "string",
142
+ label: "Home Phone",
143
+ description: "The home phone number associated with this contact.",
144
+ optional: true,
145
+ },
146
+ mobilePhone: {
147
+ type: "string",
148
+ label: "Mobile Phone",
149
+ description: "The mobile phone number associated with this contact.",
150
+ optional: true,
151
+ },
152
+ workPhone: {
153
+ type: "string",
154
+ label: "Work Phone",
155
+ description: "The work phone number associated with this contact.",
156
+ optional: true,
157
+ },
158
+ faxNumber: {
159
+ type: "string",
160
+ label: "Fax Number",
161
+ description: "The fax number associated with this contact.",
162
+ optional: true,
163
+ },
164
+ website: {
165
+ type: "string",
166
+ label: "Website",
167
+ description: "Website",
168
+ optional: true,
169
+ },
170
+ additionalFields: {
171
+ type: "object",
172
+ label: "Additional Fields",
173
+ description: "Additional fields that can be added according to API docs and custom fields.",
174
+ optional: true,
175
+ },
176
+ },
177
+ methods: {
178
+ prepareData() {
179
+ const pairs = {
180
+ firstName: "first_name",
181
+ lastName: "last_name",
182
+ displayName: "display_name",
183
+ isActive: "is_active",
184
+ isArchived: "is_archived",
185
+ address1: "address_line1",
186
+ address2: "address_line2",
187
+ state: "state_text",
188
+ country: "country_name",
189
+ estimatedTime: "estimated_time",
190
+ isLead: "is_lead",
191
+ isClosed: "is_closed",
192
+ isSubcontractor: "is_sub_contractor",
193
+ homePhone: "home_phone",
194
+ mobilePhone: "mobile_phone",
195
+ workPhone: "work_phone",
196
+ faxNumber: "fax_number",
197
+ };
198
+ const data = {
199
+ ...utils.extractProps(this, pairs),
200
+ geo: {
201
+ lat: parseFloat(this.geoLat),
202
+ lon: parseFloat(this.geoLong),
203
+ },
204
+ ...this.additionalFields,
205
+ };
206
+ return data;
207
+ },
208
+ },
209
+ };
@@ -0,0 +1,82 @@
1
+ import app from "../../jobnimbus.app.mjs";
2
+ import utils from "../../common/utils.mjs";
3
+ import { attachmentTypes } from "../../common/constants.mjs";
4
+ import {
5
+ ConfigurationError, getFileStream,
6
+ } from "@pipedream/platform";
7
+
8
+ export default {
9
+ key: "jobnimbus-create-attachment",
10
+ version: "1.0.0",
11
+ type: "action",
12
+ name: "Create Attachment",
13
+ description: "Creates an attachment. [See the documentation](https://documenter.getpostman.com/view/3919598/S11PpG4x#5f3f485b-91f9-4ed9-912c-99a07987ac6c)",
14
+ props: {
15
+ app,
16
+ file: {
17
+ type: "string",
18
+ label: "File Path or URL",
19
+ description: "The file to upload. Provide a file URL or a path to a file in the `/tmp` directory.",
20
+ },
21
+ type: {
22
+ type: "string",
23
+ label: "Type",
24
+ description: "The record type.",
25
+ options: attachmentTypes,
26
+ },
27
+ customerIdFromContacts: { //There is no endpoint that can be customers fetched from.
28
+ propDefinition: [
29
+ app,
30
+ "customerIdFromContacts",
31
+ ],
32
+ optional: true,
33
+ },
34
+ filename: {
35
+ type: "string",
36
+ label: "File Name",
37
+ description: "Name of the file to be uploaded.",
38
+ optional: true,
39
+ },
40
+ description: {
41
+ type: "string",
42
+ label: "Description",
43
+ description: "The description of the file.",
44
+ optional: true,
45
+ },
46
+ },
47
+ methods: {
48
+ streamToBase64(stream) {
49
+ return new Promise((resolve, reject) => {
50
+ const chunks = [];
51
+ stream.on("data", (chunk) => chunks.push(chunk));
52
+ stream.on("end", () => {
53
+ const buffer = Buffer.concat(chunks);
54
+ resolve(buffer.toString("base64"));
55
+ });
56
+ stream.on("error", reject);
57
+ });
58
+ },
59
+ },
60
+ async run ({ $ }) {
61
+ if (!this.file) {
62
+ throw new ConfigurationError("The `File Path or URL` prop is required.");
63
+ }
64
+
65
+ const stream = await getFileStream(this.file);
66
+ const fileData = await this.streamToBase64(stream);
67
+
68
+ const data = {
69
+ ...utils.extractProps(this, {
70
+ customerIdFromContacts: "customer",
71
+ }),
72
+ data: fileData,
73
+ };
74
+ delete data.file;
75
+ const resp = await this.app.createAttachment({
76
+ $,
77
+ data,
78
+ });
79
+ $.export("$summary", `Successfully created attachment with ID ${resp.jnid}`);
80
+ return resp;
81
+ },
82
+ };
@@ -0,0 +1,40 @@
1
+ /* eslint-disable pipedream/props-label */
2
+ /* eslint-disable pipedream/props-description */
3
+ import base from "../common/contact-base.mjs";
4
+
5
+ export default {
6
+ key: "jobnimbus-create-contact",
7
+ version: "0.0.1",
8
+ type: "action",
9
+ name: "Create Contact",
10
+ description: "Creates a contact. [See the documentation](https://documenter.getpostman.com/view/3919598/S11PpG4x#7ec1541f-7241-4840-9322-0ed83c01d48e)",
11
+ ...base,
12
+ props: {
13
+ ...base.props,
14
+ firstName: {
15
+ ...base.props.firstName,
16
+ optional: false,
17
+ },
18
+ lastName: {
19
+ ...base.props.lastName,
20
+ optional: false,
21
+ },
22
+ displayName: {
23
+ ...base.props.displayName,
24
+ optional: false,
25
+ },
26
+ company: {
27
+ ...base.props.company,
28
+ optional: false,
29
+ },
30
+ },
31
+ async run ({ $ }) {
32
+ const data = this.prepareData();
33
+ const resp = await this.app.createContact({
34
+ $,
35
+ data,
36
+ });
37
+ $.export("$summary", `Successfully created contact with ID ${resp.jnid}`);
38
+ return resp;
39
+ },
40
+ };
@@ -0,0 +1,36 @@
1
+ import app from "../../jobnimbus.app.mjs";
2
+
3
+ export default {
4
+ key: "jobnimbus-find-contact-by-email",
5
+ version: "0.0.1",
6
+ type: "action",
7
+ name: "Find Contact By Email",
8
+ description: "Finds contact by email. [See the documentation](https://documenter.getpostman.com/view/3919598/S11PpG4x#46dff3eb-80ae-46b1-a399-eb80ab2a09bc)",
9
+ props: {
10
+ app,
11
+ email: {
12
+ propDefinition: [
13
+ app,
14
+ "email",
15
+ ],
16
+ },
17
+ },
18
+ async run ({ $ }) {
19
+ const resp = await this.app.getContacts({
20
+ $,
21
+ params: {
22
+ filter: {
23
+ must: [
24
+ {
25
+ term: {
26
+ email: this.email,
27
+ },
28
+ },
29
+ ],
30
+ },
31
+ },
32
+ });
33
+ $.export("$summary", "Contact has been retrieved successfully.");
34
+ return resp;
35
+ },
36
+ };
@@ -0,0 +1,26 @@
1
+ import app from "../../jobnimbus.app.mjs";
2
+
3
+ export default {
4
+ key: "jobnimbus-find-contact-by-id",
5
+ version: "0.0.1",
6
+ type: "action",
7
+ name: "Find Contact By ID",
8
+ description: "Finds contact by ID. [See the documentation](https://documenter.getpostman.com/view/3919598/S11PpG4x#02875033-b94e-4ed9-83cc-d157fba8e5d5)",
9
+ props: {
10
+ app,
11
+ contactId: {
12
+ propDefinition: [
13
+ app,
14
+ "contactId",
15
+ ],
16
+ },
17
+ },
18
+ async run ({ $ }) {
19
+ const resp = await this.app.getContact({
20
+ $,
21
+ contactId: this.contactId,
22
+ });
23
+ $.export("$summary", "Contact has been retrieved successfully.");
24
+ return resp;
25
+ },
26
+ };
@@ -0,0 +1,30 @@
1
+ import base from "../common/contact-base.mjs";
2
+
3
+ export default {
4
+ key: "jobnimbus-update-contact",
5
+ version: "0.0.1",
6
+ type: "action",
7
+ name: "Update Contact",
8
+ description: "Updates a contact. [See the documentation](https://documenter.getpostman.com/view/3919598/S11PpG4x#6c94f9a6-2bac-4189-9b2e-5d856f0fe310)",
9
+ ...base,
10
+ props: {
11
+ app: base.props.app,
12
+ contactId: {
13
+ propDefinition: [
14
+ base.props.app,
15
+ "contactId",
16
+ ],
17
+ },
18
+ ...base.props,
19
+ },
20
+ async run ({ $ }) {
21
+ const data = this.prepareData();
22
+ const resp = await this.app.updateContact({
23
+ $,
24
+ contactId: this.contactId,
25
+ data,
26
+ });
27
+ $.export("$summary", "Contact has been updated successfully.");
28
+ return resp;
29
+ },
30
+ };
@@ -0,0 +1,38 @@
1
+ const attachmentTypes = [
2
+ {
3
+ label: "Document",
4
+ value: "1",
5
+ },
6
+ {
7
+ label: "Photo",
8
+ value: "2",
9
+ },
10
+ {
11
+ label: "Email Attachment",
12
+ value: "3",
13
+ },
14
+ {
15
+ label: "naturalForms",
16
+ value: "4",
17
+ },
18
+ {
19
+ label: "Invoice",
20
+ value: "5",
21
+ },
22
+ {
23
+ label: "Eagleview",
24
+ value: "6",
25
+ },
26
+ {
27
+ label: "Accurence",
28
+ value: "7",
29
+ },
30
+ {
31
+ label: "Credit Memo",
32
+ value: "8",
33
+ },
34
+ ];
35
+
36
+ export {
37
+ attachmentTypes,
38
+ };
@@ -0,0 +1,75 @@
1
+ import fs from "fs";
2
+
3
+ const PAGE_SIZE = 25;
4
+
5
+ export default {
6
+ isValidFile(filePath) {
7
+ const filePathWithTmp = `/tmp/${filePath}`;
8
+ if (fs.existsSync(filePathWithTmp)) {
9
+ return filePathWithTmp;
10
+ }
11
+ if (fs.existsSync(filePath)) {
12
+ return filePath;
13
+ }
14
+ return false;
15
+ },
16
+ extractProps(that, pairs) {
17
+ const {
18
+ // eslint-disable-next-line no-unused-vars
19
+ app,
20
+ ...props
21
+ } = that;
22
+ return Object.keys(props)
23
+ .reduce((acc, key) => {
24
+ const keyMapped = pairs[key];
25
+ const value = props[key];
26
+ const newKey = keyMapped ?? key;
27
+ return {
28
+ ...acc,
29
+ [newKey]: value,
30
+ };
31
+ }, {});
32
+ },
33
+ async asyncPropHandler({
34
+ resourceFn, page, mapper, params, resourceKey = "results",
35
+ } = {}) {
36
+ const { [resourceKey]: items } =
37
+ await resourceFn({
38
+ params: {
39
+ ...params,
40
+ ...(typeof page != "undefined" && {
41
+ from: page * PAGE_SIZE,
42
+ size: PAGE_SIZE,
43
+ }),
44
+ },
45
+ });
46
+ return items.map(mapper);
47
+ },
48
+ async *getResourcesStream({
49
+ resourceFn, resourceFnArgs, resourceKey,
50
+ }) {
51
+ let page = 0;
52
+ while (true) {
53
+ const { [resourceKey]: nextResources } =
54
+ await resourceFn({
55
+ ...resourceFnArgs,
56
+ params: {
57
+ ...resourceFnArgs?.params,
58
+ from: page++ * PAGE_SIZE,
59
+ size: PAGE_SIZE,
60
+ },
61
+ });
62
+ if (!nextResources?.length) {
63
+ console.log("No more resources");
64
+ return;
65
+ }
66
+ for (const resource of nextResources) {
67
+ yield resource;
68
+ }
69
+ if (nextResources?.length < PAGE_SIZE) {
70
+ console.log("Number of resources less than page size");
71
+ return;
72
+ }
73
+ }
74
+ },
75
+ };
@@ -0,0 +1,131 @@
1
+ import { axios } from "@pipedream/platform";
2
+ import utils from "./common/utils.mjs";
3
+
4
+ export default {
5
+ type: "app",
6
+ app: "jobnimbus",
7
+ propDefinitions: {
8
+ contactId: {
9
+ type: "string",
10
+ label: "Contact ID",
11
+ description: "JNID of the contact.",
12
+ async options({ page }) {
13
+ return utils.asyncPropHandler({
14
+ resourceFn: this.getContacts,
15
+ page,
16
+ params: {
17
+ fields: "jnid,display_name",
18
+ },
19
+ mapper: ({
20
+ display_name: label,
21
+ jnid: value,
22
+ }) => ({
23
+ label,
24
+ value,
25
+ }),
26
+ });
27
+ },
28
+ },
29
+ customerIdFromContacts: {
30
+ type: "string",
31
+ label: "Customer ID",
32
+ description: "JNID of the customer. These options are fetched from contacts. There can be missing customers or duplicates. If missing, please provide the ID manually.",
33
+ async options({ page }) {
34
+ return utils.asyncPropHandler({
35
+ resourceFn: this.getContacts,
36
+ page,
37
+ params: {
38
+ fields: "customer,company",
39
+ },
40
+ mapper: ({
41
+ company: label,
42
+ customer: value,
43
+ }) => ({
44
+ label,
45
+ value,
46
+ }),
47
+ });
48
+ },
49
+ },
50
+ email: {
51
+ type: "string",
52
+ label: "Email",
53
+ description: "The email address associated with the contact.",
54
+ },
55
+ },
56
+ methods: {
57
+ _getUrl(path) {
58
+ return `https://app.jobnimbus.com/api1${path}`;
59
+ },
60
+ _getHeaders(headers = {}) {
61
+ return {
62
+ "Authorization": `Bearer ${this.$auth.api_key}`,
63
+ "Content-Type": "application/json",
64
+ "Accept": "application/json",
65
+ "User-Agent": "@PipedreamHQ/pipedream v0.1",
66
+ ...headers,
67
+ };
68
+ },
69
+ _makeRequest({
70
+ $ = this, path, headers, ...args
71
+ } = {}) {
72
+ const config = {
73
+ url: this._getUrl(path),
74
+ headers: this._getHeaders(headers),
75
+ ...args,
76
+ };
77
+ return axios($, config);
78
+ },
79
+ getContact({
80
+ contactId, ...args
81
+ } = {}) {
82
+ return this._makeRequest({
83
+ path: `/contacts/${contactId}`,
84
+ ...args,
85
+ });
86
+ },
87
+ getJob({
88
+ jobId, ...args
89
+ } = {}) {
90
+ return this._makeRequest({
91
+ path: `/jobs/${jobId}`,
92
+ ...args,
93
+ });
94
+ },
95
+ getContacts(args = {}) {
96
+ return this._makeRequest({
97
+ path: "/contacts",
98
+ ...args,
99
+ });
100
+ },
101
+ getActivities(args = {}) {
102
+ return this._makeRequest({
103
+ path: "/activities",
104
+ ...args,
105
+ });
106
+ },
107
+ createContact(args = {}) {
108
+ return this._makeRequest({
109
+ path: "/contacts",
110
+ method: "POST",
111
+ ...args,
112
+ });
113
+ },
114
+ updateContact({
115
+ contactId, ...args
116
+ } = {}) {
117
+ return this._makeRequest({
118
+ path: `/contacts/${contactId}`,
119
+ method: "PUT",
120
+ ...args,
121
+ });
122
+ },
123
+ createAttachment(args = {}) {
124
+ return this._makeRequest({
125
+ path: "/files",
126
+ method: "POST",
127
+ ...args,
128
+ });
129
+ },
130
+ },
131
+ };
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@pipedream/jobnimbus",
3
- "version": "0.0.3",
3
+ "version": "1.0.0",
4
4
  "description": "Pipedream Jobnimbus Components",
5
- "main": "dist/app/jobnimbus.app.mjs",
5
+ "main": "jobnimbus.app.mjs",
6
6
  "keywords": [
7
7
  "pipedream",
8
8
  "jobnimbus"
9
9
  ],
10
- "files": [
11
- "dist"
12
- ],
13
10
  "homepage": "https://pipedream.com/apps/jobnimbus",
14
11
  "author": "Pipedream <support@pipedream.com> (https://pipedream.com/)",
15
12
  "publishConfig": {
16
13
  "access": "public"
14
+ },
15
+ "dependencies": {
16
+ "@pipedream/platform": "^3.1.0"
17
17
  }
18
18
  }
@@ -0,0 +1,11 @@
1
+ import common from "../common/activity-based.mjs";
2
+
3
+ export default {
4
+ ...common,
5
+ key: "jobnimbus-activity-created",
6
+ name: "New Activity Created Event",
7
+ description: "Emit new events when a new activity created. [See the docs](https://documenter.getpostman.com/view/3919598/S11PpG4x#62c713fe-5d46-4fd6-9953-db49255fd5e0)",
8
+ version: "0.0.1",
9
+ type: "source",
10
+ dedupe: "unique",
11
+ };
@@ -0,0 +1,38 @@
1
+ import common from "./common.mjs";
2
+
3
+ export default {
4
+ ...common,
5
+ methods: {
6
+ ...common.methods,
7
+ getResourceFnConfig() {
8
+ return {
9
+ resourceFn: this.app.getActivities,
10
+ resourceFnArgs: {
11
+ boardId: this.boardId,
12
+ params: {
13
+ must: [
14
+ {
15
+ range: {
16
+ date_created: {
17
+ gte: this.getLastComparable(),
18
+ },
19
+ },
20
+ },
21
+ ],
22
+ },
23
+ },
24
+ resourceKey: "activity",
25
+ };
26
+ },
27
+ getComparable(item) {
28
+ return item.date_created;
29
+ },
30
+ getMeta(item) {
31
+ return {
32
+ id: item.date_created,
33
+ summary: item.note,
34
+ ts: item.date_created * 1000,
35
+ };
36
+ },
37
+ },
38
+ };
@@ -0,0 +1,57 @@
1
+ import app from "../../jobnimbus.app.mjs";
2
+ import utils from "../../common/utils.mjs";
3
+ import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
4
+
5
+ export default {
6
+ props: {
7
+ app,
8
+ timer: {
9
+ type: "$.interface.timer",
10
+ default: {
11
+ intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
12
+ },
13
+ },
14
+ db: "$.service.db",
15
+ },
16
+ methods: {
17
+ setLastComparable(lastComparable) {
18
+ this.db.set("lastComparable", lastComparable);
19
+ },
20
+ getLastComparable() {
21
+ return this.db.get("lastComparable") || 0;
22
+ },
23
+ getResourceFnConfig() {
24
+ throw new Error("getResourceFnConfig() is not implemented!");
25
+ },
26
+ getItem(item) {
27
+ return item;
28
+ },
29
+ getMeta() {
30
+ throw new Error("getMeta() is not implemented!");
31
+ },
32
+ getComparable() {
33
+ throw new Error("getComparable() is not implemented!");
34
+ },
35
+ compareFn() {
36
+ return true;
37
+ },
38
+ },
39
+ async run() {
40
+ let lastComparable = this.getLastComparable();
41
+ const resourcesStream = utils.getResourcesStream(this.getResourceFnConfig());
42
+ for await (const resource of resourcesStream) {
43
+ const comparable = this.getComparable(resource);
44
+ if (lastComparable < comparable && this.compareFn(resource)) {
45
+ const item = await this.getItem(resource);
46
+ this.$emit(
47
+ item,
48
+ this.getMeta(item),
49
+ );
50
+ }
51
+ if (lastComparable < comparable) {
52
+ lastComparable = comparable;
53
+ }
54
+ }
55
+ this.setLastComparable(lastComparable);
56
+ },
57
+ };
@@ -0,0 +1,29 @@
1
+ import common from "../common/activity-based.mjs";
2
+
3
+ export default {
4
+ ...common,
5
+ key: "jobnimbus-contact-created",
6
+ name: "New Contact Created Event",
7
+ description: "Emit new events when a new contact is created. [See the docs](https://documenter.getpostman.com/view/3919598/S11PpG4x#62c713fe-5d46-4fd6-9953-db49255fd5e0)",
8
+ version: "0.0.1",
9
+ type: "source",
10
+ dedupe: "unique",
11
+ methods: {
12
+ ...common.methods,
13
+ compareFn(item) {
14
+ return item?.record_type_name == "Contact Created";
15
+ },
16
+ getItem(item) {
17
+ return this.app.getContact({
18
+ contactId: item.primary.id,
19
+ });
20
+ },
21
+ getMeta(item) {
22
+ return {
23
+ id: item.date_created,
24
+ summary: `New contact has been created - ID: ${item.jnid}`,
25
+ ts: item.date_created * 1000,
26
+ };
27
+ },
28
+ },
29
+ };
@@ -0,0 +1,24 @@
1
+ import common from "../common/activity-based.mjs";
2
+
3
+ export default {
4
+ ...common,
5
+ key: "jobnimbus-contact-deleted",
6
+ name: "New Contact Deleted Event",
7
+ description: "Emit new events when a contact is deleted. [See the docs](https://documenter.getpostman.com/view/3919598/S11PpG4x#62c713fe-5d46-4fd6-9953-db49255fd5e0)",
8
+ version: "0.0.1",
9
+ type: "source",
10
+ dedupe: "unique",
11
+ methods: {
12
+ ...common.methods,
13
+ compareFn(item) {
14
+ return item?.record_type_name == "Contact Deleted";
15
+ },
16
+ getMeta(item) {
17
+ return {
18
+ id: item.date_created,
19
+ summary: `Contact has been deleted - ID: ${item.primary.id}`,
20
+ ts: item.date_created * 1000,
21
+ };
22
+ },
23
+ },
24
+ };
@@ -0,0 +1,29 @@
1
+ import common from "../common/activity-based.mjs";
2
+
3
+ export default {
4
+ ...common,
5
+ key: "jobnimbus-contact-updated",
6
+ name: "New Contact Updated Event",
7
+ description: "Emit new events when a contact is updated. [See the docs](https://documenter.getpostman.com/view/3919598/S11PpG4x#62c713fe-5d46-4fd6-9953-db49255fd5e0)",
8
+ version: "0.0.1",
9
+ type: "source",
10
+ dedupe: "unique",
11
+ methods: {
12
+ ...common.methods,
13
+ compareFn(item) {
14
+ return item?.record_type_name == "Contact Modified";
15
+ },
16
+ async getItem(item) {
17
+ return this.app.getContact({
18
+ contactId: item.primary.id,
19
+ });
20
+ },
21
+ getMeta(item) {
22
+ return {
23
+ id: item.date_updated,
24
+ summary: `Contact has been updated - ID: ${item.jnid}`,
25
+ ts: item.date_updated * 1000,
26
+ };
27
+ },
28
+ },
29
+ };
@@ -0,0 +1,29 @@
1
+ import common from "../common/activity-based.mjs";
2
+
3
+ export default {
4
+ ...common,
5
+ key: "jobnimbus-job-created",
6
+ name: "New Job Created Event",
7
+ description: "Emit new events when a new job is created. [See the docs](https://documenter.getpostman.com/view/3919598/S11PpG4x#62c713fe-5d46-4fd6-9953-db49255fd5e0)",
8
+ version: "0.0.1",
9
+ type: "source",
10
+ dedupe: "unique",
11
+ methods: {
12
+ ...common.methods,
13
+ compareFn(item) {
14
+ return item?.record_type_name == "Job Created";
15
+ },
16
+ async getItem(item) {
17
+ return this.app.getJob({
18
+ jobId: item.primary.id,
19
+ });
20
+ },
21
+ getMeta(item) {
22
+ return {
23
+ id: item.date_created,
24
+ summary: `New job has been created - ID: ${item.jnid}`,
25
+ ts: item.date_created * 1000,
26
+ };
27
+ },
28
+ },
29
+ };
@@ -0,0 +1,24 @@
1
+ import common from "../common/activity-based.mjs";
2
+
3
+ export default {
4
+ ...common,
5
+ key: "jobnimbus-job-deleted",
6
+ name: "New Job Deleted Event",
7
+ description: "Emit new events when a job is deleted. [See the docs](https://documenter.getpostman.com/view/3919598/S11PpG4x#62c713fe-5d46-4fd6-9953-db49255fd5e0)",
8
+ version: "0.0.1",
9
+ type: "source",
10
+ dedupe: "unique",
11
+ methods: {
12
+ ...common.methods,
13
+ compareFn(item) {
14
+ return item?.record_type_name == "Job Deleted";
15
+ },
16
+ getMeta(item) {
17
+ return {
18
+ id: item.date_created,
19
+ summary: `Job has been deleted - ID: ${item.primary.id}`,
20
+ ts: item.date_created * 1000,
21
+ };
22
+ },
23
+ },
24
+ };
@@ -0,0 +1,29 @@
1
+ import common from "../common/activity-based.mjs";
2
+
3
+ export default {
4
+ ...common,
5
+ key: "jobnimbus-job-updated",
6
+ name: "New Job Updated Event",
7
+ description: "Emit new events when a job is updated. [See the docs](https://documenter.getpostman.com/view/3919598/S11PpG4x#62c713fe-5d46-4fd6-9953-db49255fd5e0)",
8
+ version: "0.0.1",
9
+ type: "source",
10
+ dedupe: "unique",
11
+ methods: {
12
+ ...common.methods,
13
+ compareFn(item) {
14
+ return item?.record_type_name == "Job Modified";
15
+ },
16
+ async getItem(item) {
17
+ return this.app.getJob({
18
+ jobId: item.primary.id,
19
+ });
20
+ },
21
+ getMeta(item) {
22
+ return {
23
+ id: item.date_updated,
24
+ summary: `Job has been updated - ID: ${item.jnid}`,
25
+ ts: item.date_updated * 1000,
26
+ };
27
+ },
28
+ },
29
+ };