@pipedream/tableau 0.0.1 → 0.1.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.
@@ -0,0 +1,72 @@
1
+ import app from "../../tableau.app.mjs";
2
+
3
+ export default {
4
+ key: "tableau-create-project",
5
+ name: "Create Project",
6
+ description: "Creates a project on the specified site. You can also create project hierarchies by creating a project under the specified parent project on the site. [See the documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_projects.htm#create_project)",
7
+ version: "0.0.1",
8
+ type: "action",
9
+ props: {
10
+ app,
11
+ siteId: {
12
+ propDefinition: [
13
+ app,
14
+ "siteId",
15
+ ],
16
+ },
17
+ name: {
18
+ type: "string",
19
+ label: "Project Name",
20
+ description: "The name of the new project to create",
21
+ },
22
+ description: {
23
+ type: "string",
24
+ label: "Project Description",
25
+ description: "The description of the new project to create",
26
+ optional: true,
27
+ },
28
+ parentProjectId: {
29
+ propDefinition: [
30
+ app,
31
+ "parentProjectId",
32
+ ({ siteId }) => ({
33
+ siteId,
34
+ }),
35
+ ],
36
+ },
37
+ },
38
+ methods: {
39
+ createProject({
40
+ siteId, ...args
41
+ } = {}) {
42
+ return this.app.post({
43
+ path: `/sites/${siteId}/projects`,
44
+ ...args,
45
+ });
46
+ },
47
+ },
48
+ async run({ $ }) {
49
+ const {
50
+ createProject,
51
+ siteId,
52
+ name,
53
+ description,
54
+ parentProjectId,
55
+ } = this;
56
+
57
+ const response = await createProject({
58
+ $,
59
+ siteId,
60
+ data: {
61
+ project: {
62
+ name,
63
+ description,
64
+ parentProjectId,
65
+ },
66
+ },
67
+ });
68
+
69
+ $.export("$summary", `Successfully created project with ID \`${response.project?.id}\``);
70
+ return response;
71
+ },
72
+ };
@@ -0,0 +1,40 @@
1
+ import app from "../../tableau.app.mjs";
2
+ import constants from "../../common/constants.mjs";
3
+
4
+ export default {
5
+ key: "tableau-query-projects",
6
+ name: "Query Projects",
7
+ description: "Returns a list of projects on the specified site. [See the documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_projects.htm)",
8
+ version: "0.0.1",
9
+ type: "action",
10
+ props: {
11
+ app,
12
+ siteId: {
13
+ propDefinition: [
14
+ app,
15
+ "siteId",
16
+ ],
17
+ },
18
+ },
19
+ async run({ $ }) {
20
+ const {
21
+ app,
22
+ siteId,
23
+ } = this;
24
+
25
+ const projects = await app.paginate({
26
+ resourcesFn: app.listProjects,
27
+ resourcesFnArgs: {
28
+ $,
29
+ siteId,
30
+ params: {
31
+ pageSize: constants.DEFAULT_LIMIT,
32
+ },
33
+ },
34
+ resourceName: "projects.project",
35
+ });
36
+
37
+ $.export("$summary", `Successfully retrieved \`${projects.length}\` project(s)`);
38
+ return projects;
39
+ },
40
+ };
@@ -0,0 +1,11 @@
1
+ const VERSION_PATH = "/api/3.21";
2
+ const DEFAULT_MAX = 600;
3
+ const DEFAULT_LIMIT = 100;
4
+ const WEBHOOK_ID = "webhookId";
5
+
6
+ export default {
7
+ VERSION_PATH,
8
+ DEFAULT_MAX,
9
+ DEFAULT_LIMIT,
10
+ WEBHOOK_ID,
11
+ };
@@ -0,0 +1,17 @@
1
+ async function iterate(iterations) {
2
+ const items = [];
3
+ for await (const item of iterations) {
4
+ items.push(item);
5
+ }
6
+ return items;
7
+ }
8
+
9
+ function getNestedProperty(obj, propertyString) {
10
+ const properties = propertyString.split(".");
11
+ return properties.reduce((prev, curr) => prev && prev[curr], obj);
12
+ }
13
+
14
+ export default {
15
+ iterate,
16
+ getNestedProperty,
17
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipedream/tableau",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "Pipedream Tableau Components",
5
5
  "main": "tableau.app.mjs",
6
6
  "keywords": [
@@ -11,5 +11,8 @@
11
11
  "author": "Pipedream <support@pipedream.com> (https://pipedream.com/)",
12
12
  "publishConfig": {
13
13
  "access": "public"
14
+ },
15
+ "dependencies": {
16
+ "@pipedream/platform": "^1.6.0"
14
17
  }
15
18
  }
@@ -0,0 +1,24 @@
1
+ export default {
2
+ ADMIN_PROMOTED: "AdminPromoted",
3
+ ADMIN_DEMOTED: "AdminDemoted",
4
+ DATASOURCE_UPDATED: "DatasourceUpdated",
5
+ DATASOURCE_CREATED: "DatasourceCreated",
6
+ DATASOURCE_DELETED: "DatasourceDeleted",
7
+ DATASOURCE_REFRESH_STARTED: "DatasourceRefreshStarted",
8
+ DATASOURCE_REFRESH_SUCCEEDED: "DatasourceRefreshSucceeded",
9
+ DATASOURCE_REFRESH_FAILED: "DatasourceRefreshFailed",
10
+ LABEL_CREATED: "LabelCreated",
11
+ LABEL_UPDATED: "LabelUpdated",
12
+ LABEL_DELETED: "LabelDeleted",
13
+ SITE_CREATED: "SiteCreated",
14
+ SITE_UPDATED: "SiteUpdated",
15
+ SITE_DELETED: "SiteDeleted",
16
+ USER_DELETED: "UserDeleted",
17
+ VIEW_DELETED: "ViewDeleted",
18
+ WORKBOOK_UPDATED: "WorkbookUpdated",
19
+ WORKBOOK_CREATED: "WorkbookCreated",
20
+ WORKBOOK_DELETED: "WorkbookDeleted",
21
+ WORKBOOK_REFRESH_STARTED: "WorkbookRefreshStarted",
22
+ WORKBOOK_REFRESH_SUCCEEDED: "WorkbookRefreshSucceeded",
23
+ WORKBOOK_REFRESH_FAILED: "WorkbookRefreshFailed",
24
+ };
@@ -0,0 +1,105 @@
1
+ import { ConfigurationError } from "@pipedream/platform";
2
+ import app from "../../tableau.app.mjs";
3
+ import constants from "../../common/constants.mjs";
4
+
5
+ export default {
6
+ props: {
7
+ app,
8
+ db: "$.service.db",
9
+ http: "$.interface.http",
10
+ siteId: {
11
+ propDefinition: [
12
+ app,
13
+ "siteId",
14
+ ],
15
+ },
16
+ },
17
+ hooks: {
18
+ async activate() {
19
+ const {
20
+ createWebhook,
21
+ siteId,
22
+ getWebhookName,
23
+ getEventName,
24
+ http,
25
+ setWebhookId,
26
+ } = this;
27
+
28
+ const { webhook: { id: webhookId } } =
29
+ await createWebhook({
30
+ siteId,
31
+ data: {
32
+ webhook: {
33
+ "name": getWebhookName(),
34
+ "event": getEventName(),
35
+ "isEnabled": true,
36
+ "webhook-destination": {
37
+ "webhook-destination-http": {
38
+ "method": "POST",
39
+ "url": http.endpoint,
40
+ },
41
+ },
42
+ },
43
+ },
44
+ });
45
+
46
+ setWebhookId(webhookId);
47
+ },
48
+ async deactivate() {
49
+ const {
50
+ getWebhookId,
51
+ siteId,
52
+ deleteWebhook,
53
+ } = this;
54
+
55
+ const webhookId = getWebhookId();
56
+ if (webhookId) {
57
+ await deleteWebhook({
58
+ siteId,
59
+ webhookId,
60
+ });
61
+ }
62
+ },
63
+ },
64
+ methods: {
65
+ setWebhookId(value) {
66
+ this.db.set(constants.WEBHOOK_ID, value);
67
+ },
68
+ getWebhookId() {
69
+ return this.db.get(constants.WEBHOOK_ID);
70
+ },
71
+ generateMeta() {
72
+ throw new ConfigurationError("generateMeta is not implemented");
73
+ },
74
+ getWebhookName() {
75
+ throw new ConfigurationError("getWebhookName is not implemented");
76
+ },
77
+ getEventName() {
78
+ throw new ConfigurationError("getEventName is not implemented");
79
+ },
80
+ processResource(resource) {
81
+ this.$emit(resource, this.generateMeta(resource));
82
+ },
83
+ createWebhook({
84
+ siteId, ...args
85
+ } = {}) {
86
+ return this.app.post({
87
+ debug: true,
88
+ path: `/sites/${siteId}/webhooks`,
89
+ ...args,
90
+ });
91
+ },
92
+ deleteWebhook({
93
+ siteId, webhookId, ...args
94
+ } = {}) {
95
+ return this.app.delete({
96
+ debug: true,
97
+ path: `/sites/${siteId}/webhooks/${webhookId}`,
98
+ ...args,
99
+ });
100
+ },
101
+ },
102
+ run({ body }) {
103
+ this.processResource(body);
104
+ },
105
+ };
@@ -0,0 +1,28 @@
1
+ import common from "../common/webhook.mjs";
2
+ import events from "../common/events.mjs";
3
+
4
+ export default {
5
+ ...common,
6
+ key: "tableau-label-created-instant",
7
+ name: "New Label Created (Instant)",
8
+ description: "Emit new event when a label is created in Tableau. [See the documentation](https://help.tableau.com/current/developer/webhooks/en-us/docs/webhooks-events-payload.html)",
9
+ version: "0.0.1",
10
+ type: "source",
11
+ dedupe: "unique",
12
+ methods: {
13
+ ...common.methods,
14
+ getWebhookName() {
15
+ return "label-creation";
16
+ },
17
+ getEventName() {
18
+ return events.LABEL_CREATED;
19
+ },
20
+ generateMeta(resource) {
21
+ return {
22
+ id: resource.resource_luid,
23
+ summary: `New Label: ${resource.resource_luid}`,
24
+ ts: Date.parse(resource.created_at),
25
+ };
26
+ },
27
+ },
28
+ };
@@ -0,0 +1,28 @@
1
+ import common from "../common/webhook.mjs";
2
+ import events from "../common/events.mjs";
3
+
4
+ export default {
5
+ ...common,
6
+ key: "tableau-workbook-created-instant",
7
+ name: "New Workbook Created (Instant)",
8
+ description: "Emit new event each time a new workbook is created in Tableau. [See the documentation](https://help.tableau.com/current/developer/webhooks/en-us/docs/webhooks-events-payload.html)",
9
+ version: "0.0.1",
10
+ type: "source",
11
+ dedupe: "unique",
12
+ methods: {
13
+ ...common.methods,
14
+ getWebhookName() {
15
+ return "workbook-creation";
16
+ },
17
+ getEventName() {
18
+ return events.WORKBOOK_CREATED;
19
+ },
20
+ generateMeta(resource) {
21
+ return {
22
+ id: resource.resource_luid,
23
+ summary: `New Workbook: ${resource.resource_luid}`,
24
+ ts: Date.parse(resource.created_at),
25
+ };
26
+ },
27
+ },
28
+ };
package/tableau.app.mjs CHANGED
@@ -1,11 +1,145 @@
1
+ import { axios } from "@pipedream/platform";
2
+ import utils from "./common/utils.mjs";
3
+ import constants from "./common/constants.mjs";
4
+
1
5
  export default {
2
6
  type: "app",
3
7
  app: "tableau",
4
- propDefinitions: {},
8
+ propDefinitions: {
9
+ siteId: {
10
+ type: "string",
11
+ label: "Site ID",
12
+ description: "The ID of the site where the project or event is located",
13
+ async options() {
14
+ const { session: { site } } = await this.getCurrentSession();
15
+ return [
16
+ {
17
+ label: site.name,
18
+ value: site.id,
19
+ },
20
+ ];
21
+ },
22
+ },
23
+ parentProjectId: {
24
+ type: "string",
25
+ label: "Parent Project ID",
26
+ description: "The ID of the parent project under which the new project will be created",
27
+ optional: true,
28
+ async options({
29
+ siteId, page,
30
+ }) {
31
+ if (!siteId) {
32
+ return [];
33
+ }
34
+ const { projects: { project: data } } =
35
+ await this.listProjects({
36
+ siteId,
37
+ params: {
38
+ pageSize: constants.DEFAULT_LIMIT,
39
+ pageNumber: page + 1,
40
+ },
41
+ });
42
+ return data.map(({
43
+ id: value, name: label,
44
+ }) => ({
45
+ label,
46
+ value,
47
+ }));
48
+ },
49
+ },
50
+ },
5
51
  methods: {
6
- // this.$auth contains connected account data
7
- authKeys() {
8
- console.log(Object.keys(this.$auth));
52
+ getUrl(path) {
53
+ return `https://${this.$auth.domain}${constants.VERSION_PATH}${path}`;
54
+ },
55
+ getHeaders(headers) {
56
+ return {
57
+ ...headers,
58
+ "Accept": "application/json",
59
+ "Content-Type": "application/json",
60
+ "X-Tableau-Auth": this.$auth.oauth_access_token,
61
+ };
62
+ },
63
+ _makeRequest({
64
+ $ = this, path, headers, ...args
65
+ } = {}) {
66
+ return axios($, {
67
+ ...args,
68
+ url: this.getUrl(path),
69
+ headers: this.getHeaders(headers),
70
+ });
71
+ },
72
+ post(args = {}) {
73
+ return this._makeRequest({
74
+ method: "POST",
75
+ ...args,
76
+ });
77
+ },
78
+ delete(args = {}) {
79
+ return this._makeRequest({
80
+ method: "DELETE",
81
+ ...args,
82
+ });
83
+ },
84
+ getCurrentSession(args = {}) {
85
+ return this._makeRequest({
86
+ path: "/sessions/current",
87
+ ...args,
88
+ });
89
+ },
90
+ listProjects({
91
+ siteId, ...args
92
+ }) {
93
+ return this._makeRequest({
94
+ path: `/sites/${siteId}/projects`,
95
+ ...args,
96
+ });
97
+ },
98
+ async *getIterations({
99
+ resourcesFn, resourcesFnArgs, resourceName,
100
+ max = constants.DEFAULT_MAX,
101
+ }) {
102
+ let pageNumber = 1;
103
+ let resourcesCount = 0;
104
+
105
+ while (true) {
106
+ const response =
107
+ await resourcesFn({
108
+ ...resourcesFnArgs,
109
+ params: {
110
+ ...resourcesFnArgs?.params,
111
+ pageNumber,
112
+ },
113
+ });
114
+
115
+ const nextResources = utils.getNestedProperty(response, resourceName);
116
+
117
+ if (!nextResources?.length) {
118
+ console.log("No more resources found");
119
+ return;
120
+ }
121
+
122
+ for (const resource of nextResources) {
123
+ yield resource;
124
+ resourcesCount += 1;
125
+
126
+ if (resourcesCount >= max) {
127
+ return;
128
+ }
129
+ }
130
+
131
+ const totalAvailable = response.pagination?.totalAvailable;
132
+
133
+ if (resourcesCount >= totalAvailable) {
134
+ console.log("There are no more resources to fetch");
135
+ return;
136
+ }
137
+
138
+ pageNumber += 1;
139
+ }
140
+ },
141
+ paginate(args = {}) {
142
+ return utils.iterate(this.getIterations(args));
9
143
  },
10
144
  },
11
- };
145
+ };