@slates-integrations/tableau 0.2.0-rc.8

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.
Files changed (40) hide show
  1. package/README.md +85 -0
  2. package/docs/SPEC.md +61 -0
  3. package/logo.png +0 -0
  4. package/package.json +19 -0
  5. package/slate.json +18 -0
  6. package/src/auth.ts +237 -0
  7. package/src/config.ts +17 -0
  8. package/src/index.ts +55 -0
  9. package/src/lib/client.ts +959 -0
  10. package/src/lib/errors.ts +94 -0
  11. package/src/lib/helpers.ts +15 -0
  12. package/src/lib/normalizers.ts +9 -0
  13. package/src/spec.ts +12 -0
  14. package/src/tools/export-view.ts +112 -0
  15. package/src/tools/get-site-info.ts +47 -0
  16. package/src/tools/get-view-data.ts +31 -0
  17. package/src/tools/index.ts +18 -0
  18. package/src/tools/list-datasources.ts +78 -0
  19. package/src/tools/list-views.ts +70 -0
  20. package/src/tools/list-workbooks.ts +88 -0
  21. package/src/tools/manage-alerts.ts +139 -0
  22. package/src/tools/manage-collections.ts +254 -0
  23. package/src/tools/manage-custom-views.ts +159 -0
  24. package/src/tools/manage-datasource.ts +129 -0
  25. package/src/tools/manage-favorites.ts +80 -0
  26. package/src/tools/manage-flows.ts +170 -0
  27. package/src/tools/manage-groups.ts +178 -0
  28. package/src/tools/manage-jobs.ts +120 -0
  29. package/src/tools/manage-permissions.ts +118 -0
  30. package/src/tools/manage-projects.ts +162 -0
  31. package/src/tools/manage-users.ts +184 -0
  32. package/src/tools/manage-workbook.ts +160 -0
  33. package/src/triggers/datasource-events.ts +119 -0
  34. package/src/triggers/index.ts +6 -0
  35. package/src/triggers/label-events.ts +98 -0
  36. package/src/triggers/site-events.ts +97 -0
  37. package/src/triggers/user-events.ts +98 -0
  38. package/src/triggers/view-events.ts +83 -0
  39. package/src/triggers/workbook-events.ts +108 -0
  40. package/tsconfig.json +23 -0
@@ -0,0 +1,98 @@
1
+ import { SlateTrigger } from 'slates';
2
+ import { z } from 'zod';
3
+ import { spec } from '../spec';
4
+ import { createClient } from '../lib/helpers';
5
+
6
+ let eventNameMap: Record<string, string> = {
7
+ LabelCreated: 'label.created',
8
+ LabelUpdated: 'label.updated',
9
+ LabelDeleted: 'label.deleted'
10
+ };
11
+
12
+ let webhookEventNames = ['LabelCreated', 'LabelUpdated', 'LabelDeleted'];
13
+
14
+ export let labelEvents = SlateTrigger.create(spec, {
15
+ name: 'Label Events',
16
+ key: 'label_events',
17
+ description:
18
+ 'Triggers when data quality labels or certifications are created, updated, or deleted. Tableau Cloud only.'
19
+ })
20
+ .input(
21
+ z.object({
22
+ eventType: z.string().describe('Tableau webhook event type'),
23
+ resourceId: z.string().describe('LUID of the affected label'),
24
+ resourceName: z.string().describe('Name of the affected label'),
25
+ siteId: z.string().describe('LUID of the site'),
26
+ timestamp: z.string().describe('Event timestamp')
27
+ })
28
+ )
29
+ .output(
30
+ z.object({
31
+ labelId: z.string().describe('LUID of the affected label'),
32
+ labelName: z.string().describe('Name of the label'),
33
+ siteId: z.string().describe('LUID of the site'),
34
+ timestamp: z.string().describe('When the event occurred')
35
+ })
36
+ )
37
+ .webhook({
38
+ autoRegisterWebhook: async ctx => {
39
+ let client = createClient(ctx.config, ctx.auth);
40
+ let webhookIds: Record<string, string> = {};
41
+
42
+ for (let eventName of webhookEventNames) {
43
+ let webhook = await client.createWebhook(
44
+ `slates-label-${eventName}`,
45
+ eventName,
46
+ ctx.input.webhookBaseUrl
47
+ );
48
+ webhookIds[eventName] = webhook.id;
49
+ }
50
+
51
+ return { registrationDetails: { webhookIds } };
52
+ },
53
+
54
+ autoUnregisterWebhook: async ctx => {
55
+ let client = createClient(ctx.config, ctx.auth);
56
+ let webhookIds = ctx.input.registrationDetails?.webhookIds || {};
57
+
58
+ for (let webhookId of Object.values(webhookIds) as string[]) {
59
+ try {
60
+ await client.deleteWebhook(webhookId);
61
+ } catch (e) {
62
+ // Webhook may already be deleted
63
+ }
64
+ }
65
+ },
66
+
67
+ handleRequest: async ctx => {
68
+ let body = (await ctx.request.json()) as any;
69
+
70
+ return {
71
+ inputs: [
72
+ {
73
+ eventType: body.eventType || body['webhook-source-event-name'] || 'unknown',
74
+ resourceId: body.resource_luid || body.resourceId || '',
75
+ resourceName: body.resource_name || body.resourceName || '',
76
+ siteId: body.site_luid || body.siteId || '',
77
+ timestamp: body.created_at || body.timestamp || new Date().toISOString()
78
+ }
79
+ ]
80
+ };
81
+ },
82
+
83
+ handleEvent: async ctx => {
84
+ let mappedType = eventNameMap[ctx.input.eventType] || `label.${ctx.input.eventType}`;
85
+
86
+ return {
87
+ type: mappedType,
88
+ id: `${ctx.input.resourceId}-${ctx.input.timestamp}`,
89
+ output: {
90
+ labelId: ctx.input.resourceId,
91
+ labelName: ctx.input.resourceName,
92
+ siteId: ctx.input.siteId,
93
+ timestamp: ctx.input.timestamp
94
+ }
95
+ };
96
+ }
97
+ })
98
+ .build();
@@ -0,0 +1,97 @@
1
+ import { SlateTrigger } from 'slates';
2
+ import { z } from 'zod';
3
+ import { spec } from '../spec';
4
+ import { createClient } from '../lib/helpers';
5
+
6
+ let eventNameMap: Record<string, string> = {
7
+ SiteCreated: 'site.created',
8
+ SiteUpdated: 'site.updated',
9
+ SiteDeleted: 'site.deleted'
10
+ };
11
+
12
+ let webhookEventNames = ['SiteCreated', 'SiteUpdated', 'SiteDeleted'];
13
+
14
+ export let siteEvents = SlateTrigger.create(spec, {
15
+ name: 'Site Events',
16
+ key: 'site_events',
17
+ description: 'Triggers when a site is created, updated, or deleted.'
18
+ })
19
+ .input(
20
+ z.object({
21
+ eventType: z.string().describe('Tableau webhook event type'),
22
+ resourceId: z.string().describe('LUID of the affected site'),
23
+ resourceName: z.string().describe('Name of the affected site'),
24
+ siteId: z.string().describe('LUID of the site'),
25
+ timestamp: z.string().describe('Event timestamp')
26
+ })
27
+ )
28
+ .output(
29
+ z.object({
30
+ affectedSiteId: z.string().describe('LUID of the affected site'),
31
+ siteName: z.string().describe('Name of the site'),
32
+ siteId: z.string().describe('LUID of the site context'),
33
+ timestamp: z.string().describe('When the event occurred')
34
+ })
35
+ )
36
+ .webhook({
37
+ autoRegisterWebhook: async ctx => {
38
+ let client = createClient(ctx.config, ctx.auth);
39
+ let webhookIds: Record<string, string> = {};
40
+
41
+ for (let eventName of webhookEventNames) {
42
+ let webhook = await client.createWebhook(
43
+ `slates-site-${eventName}`,
44
+ eventName,
45
+ ctx.input.webhookBaseUrl
46
+ );
47
+ webhookIds[eventName] = webhook.id;
48
+ }
49
+
50
+ return { registrationDetails: { webhookIds } };
51
+ },
52
+
53
+ autoUnregisterWebhook: async ctx => {
54
+ let client = createClient(ctx.config, ctx.auth);
55
+ let webhookIds = ctx.input.registrationDetails?.webhookIds || {};
56
+
57
+ for (let webhookId of Object.values(webhookIds) as string[]) {
58
+ try {
59
+ await client.deleteWebhook(webhookId);
60
+ } catch (e) {
61
+ // Webhook may already be deleted
62
+ }
63
+ }
64
+ },
65
+
66
+ handleRequest: async ctx => {
67
+ let body = (await ctx.request.json()) as any;
68
+
69
+ return {
70
+ inputs: [
71
+ {
72
+ eventType: body.eventType || body['webhook-source-event-name'] || 'unknown',
73
+ resourceId: body.resource_luid || body.resourceId || '',
74
+ resourceName: body.resource_name || body.resourceName || '',
75
+ siteId: body.site_luid || body.siteId || '',
76
+ timestamp: body.created_at || body.timestamp || new Date().toISOString()
77
+ }
78
+ ]
79
+ };
80
+ },
81
+
82
+ handleEvent: async ctx => {
83
+ let mappedType = eventNameMap[ctx.input.eventType] || `site.${ctx.input.eventType}`;
84
+
85
+ return {
86
+ type: mappedType,
87
+ id: `${ctx.input.resourceId}-${ctx.input.timestamp}`,
88
+ output: {
89
+ affectedSiteId: ctx.input.resourceId,
90
+ siteName: ctx.input.resourceName,
91
+ siteId: ctx.input.siteId,
92
+ timestamp: ctx.input.timestamp
93
+ }
94
+ };
95
+ }
96
+ })
97
+ .build();
@@ -0,0 +1,98 @@
1
+ import { SlateTrigger } from 'slates';
2
+ import { z } from 'zod';
3
+ import { spec } from '../spec';
4
+ import { createClient } from '../lib/helpers';
5
+
6
+ let eventNameMap: Record<string, string> = {
7
+ AdminPromoted: 'user.admin_promoted',
8
+ AdminDemoted: 'user.admin_demoted',
9
+ UserDeleted: 'user.deleted'
10
+ };
11
+
12
+ let webhookEventNames = ['AdminPromoted', 'AdminDemoted', 'UserDeleted'];
13
+
14
+ export let userEvents = SlateTrigger.create(spec, {
15
+ name: 'User Events',
16
+ key: 'user_events',
17
+ description:
18
+ 'Triggers when a user is promoted to or demoted from Site Administrator, or when a user is deleted.'
19
+ })
20
+ .input(
21
+ z.object({
22
+ eventType: z.string().describe('Tableau webhook event type'),
23
+ resourceId: z.string().describe('LUID of the affected user'),
24
+ resourceName: z.string().describe('Name of the affected user'),
25
+ siteId: z.string().describe('LUID of the site'),
26
+ timestamp: z.string().describe('Event timestamp')
27
+ })
28
+ )
29
+ .output(
30
+ z.object({
31
+ userId: z.string().describe('LUID of the affected user'),
32
+ userName: z.string().describe('Name of the user'),
33
+ siteId: z.string().describe('LUID of the site'),
34
+ timestamp: z.string().describe('When the event occurred')
35
+ })
36
+ )
37
+ .webhook({
38
+ autoRegisterWebhook: async ctx => {
39
+ let client = createClient(ctx.config, ctx.auth);
40
+ let webhookIds: Record<string, string> = {};
41
+
42
+ for (let eventName of webhookEventNames) {
43
+ let webhook = await client.createWebhook(
44
+ `slates-user-${eventName}`,
45
+ eventName,
46
+ ctx.input.webhookBaseUrl
47
+ );
48
+ webhookIds[eventName] = webhook.id;
49
+ }
50
+
51
+ return { registrationDetails: { webhookIds } };
52
+ },
53
+
54
+ autoUnregisterWebhook: async ctx => {
55
+ let client = createClient(ctx.config, ctx.auth);
56
+ let webhookIds = ctx.input.registrationDetails?.webhookIds || {};
57
+
58
+ for (let webhookId of Object.values(webhookIds) as string[]) {
59
+ try {
60
+ await client.deleteWebhook(webhookId);
61
+ } catch (e) {
62
+ // Webhook may already be deleted
63
+ }
64
+ }
65
+ },
66
+
67
+ handleRequest: async ctx => {
68
+ let body = (await ctx.request.json()) as any;
69
+
70
+ return {
71
+ inputs: [
72
+ {
73
+ eventType: body.eventType || body['webhook-source-event-name'] || 'unknown',
74
+ resourceId: body.resource_luid || body.resourceId || '',
75
+ resourceName: body.resource_name || body.resourceName || '',
76
+ siteId: body.site_luid || body.siteId || '',
77
+ timestamp: body.created_at || body.timestamp || new Date().toISOString()
78
+ }
79
+ ]
80
+ };
81
+ },
82
+
83
+ handleEvent: async ctx => {
84
+ let mappedType = eventNameMap[ctx.input.eventType] || `user.${ctx.input.eventType}`;
85
+
86
+ return {
87
+ type: mappedType,
88
+ id: `${ctx.input.resourceId}-${ctx.input.timestamp}`,
89
+ output: {
90
+ userId: ctx.input.resourceId,
91
+ userName: ctx.input.resourceName,
92
+ siteId: ctx.input.siteId,
93
+ timestamp: ctx.input.timestamp
94
+ }
95
+ };
96
+ }
97
+ })
98
+ .build();
@@ -0,0 +1,83 @@
1
+ import { SlateTrigger } from 'slates';
2
+ import { z } from 'zod';
3
+ import { spec } from '../spec';
4
+ import { createClient } from '../lib/helpers';
5
+
6
+ export let viewEvents = SlateTrigger.create(spec, {
7
+ name: 'View Events',
8
+ key: 'view_events',
9
+ description: 'Triggers when a view is deleted.'
10
+ })
11
+ .input(
12
+ z.object({
13
+ eventType: z.string().describe('Tableau webhook event type'),
14
+ resourceId: z.string().describe('LUID of the affected view'),
15
+ resourceName: z.string().describe('Name of the affected view'),
16
+ siteId: z.string().describe('LUID of the site'),
17
+ timestamp: z.string().describe('Event timestamp')
18
+ })
19
+ )
20
+ .output(
21
+ z.object({
22
+ viewId: z.string().describe('LUID of the affected view'),
23
+ viewName: z.string().describe('Name of the view'),
24
+ siteId: z.string().describe('LUID of the site'),
25
+ timestamp: z.string().describe('When the event occurred')
26
+ })
27
+ )
28
+ .webhook({
29
+ autoRegisterWebhook: async ctx => {
30
+ let client = createClient(ctx.config, ctx.auth);
31
+
32
+ let webhook = await client.createWebhook(
33
+ 'slates-view-ViewDeleted',
34
+ 'ViewDeleted',
35
+ ctx.input.webhookBaseUrl
36
+ );
37
+
38
+ return { registrationDetails: { webhookId: webhook.id } };
39
+ },
40
+
41
+ autoUnregisterWebhook: async ctx => {
42
+ let client = createClient(ctx.config, ctx.auth);
43
+ let webhookId = ctx.input.registrationDetails?.webhookId;
44
+
45
+ if (webhookId) {
46
+ try {
47
+ await client.deleteWebhook(webhookId);
48
+ } catch (e) {
49
+ // Webhook may already be deleted
50
+ }
51
+ }
52
+ },
53
+
54
+ handleRequest: async ctx => {
55
+ let body = (await ctx.request.json()) as any;
56
+
57
+ return {
58
+ inputs: [
59
+ {
60
+ eventType: body.eventType || body['webhook-source-event-name'] || 'ViewDeleted',
61
+ resourceId: body.resource_luid || body.resourceId || '',
62
+ resourceName: body.resource_name || body.resourceName || '',
63
+ siteId: body.site_luid || body.siteId || '',
64
+ timestamp: body.created_at || body.timestamp || new Date().toISOString()
65
+ }
66
+ ]
67
+ };
68
+ },
69
+
70
+ handleEvent: async ctx => {
71
+ return {
72
+ type: 'view.deleted',
73
+ id: `${ctx.input.resourceId}-${ctx.input.timestamp}`,
74
+ output: {
75
+ viewId: ctx.input.resourceId,
76
+ viewName: ctx.input.resourceName,
77
+ siteId: ctx.input.siteId,
78
+ timestamp: ctx.input.timestamp
79
+ }
80
+ };
81
+ }
82
+ })
83
+ .build();
@@ -0,0 +1,108 @@
1
+ import { SlateTrigger } from 'slates';
2
+ import { z } from 'zod';
3
+ import { spec } from '../spec';
4
+ import { createClient } from '../lib/helpers';
5
+
6
+ let eventNameMap: Record<string, string> = {
7
+ WorkbookCreated: 'workbook.created',
8
+ WorkbookUpdated: 'workbook.updated',
9
+ WorkbookDeleted: 'workbook.deleted',
10
+ WorkbookRefreshStarted: 'workbook.refresh_started',
11
+ WorkbookRefreshSucceeded: 'workbook.refresh_succeeded',
12
+ WorkbookRefreshFailed: 'workbook.refresh_failed'
13
+ };
14
+
15
+ let webhookEventNames = [
16
+ 'WorkbookCreated',
17
+ 'WorkbookUpdated',
18
+ 'WorkbookDeleted',
19
+ 'WorkbookRefreshStarted',
20
+ 'WorkbookRefreshSucceeded',
21
+ 'WorkbookRefreshFailed'
22
+ ];
23
+
24
+ export let workbookEvents = SlateTrigger.create(spec, {
25
+ name: 'Workbook Events',
26
+ key: 'workbook_events',
27
+ description:
28
+ 'Triggers when a workbook is created, updated, deleted, or when an extract refresh starts, succeeds, or fails.'
29
+ })
30
+ .input(
31
+ z.object({
32
+ eventType: z.string().describe('Tableau webhook event type'),
33
+ resourceId: z.string().describe('LUID of the affected workbook'),
34
+ resourceName: z.string().describe('Name of the affected workbook'),
35
+ siteId: z.string().describe('LUID of the site'),
36
+ timestamp: z.string().describe('Event timestamp')
37
+ })
38
+ )
39
+ .output(
40
+ z.object({
41
+ workbookId: z.string().describe('LUID of the affected workbook'),
42
+ workbookName: z.string().describe('Name of the workbook'),
43
+ siteId: z.string().describe('LUID of the site'),
44
+ timestamp: z.string().describe('When the event occurred')
45
+ })
46
+ )
47
+ .webhook({
48
+ autoRegisterWebhook: async ctx => {
49
+ let client = createClient(ctx.config, ctx.auth);
50
+ let webhookIds: Record<string, string> = {};
51
+
52
+ for (let eventName of webhookEventNames) {
53
+ let webhook = await client.createWebhook(
54
+ `slates-workbook-${eventName}`,
55
+ eventName,
56
+ ctx.input.webhookBaseUrl
57
+ );
58
+ webhookIds[eventName] = webhook.id;
59
+ }
60
+
61
+ return { registrationDetails: { webhookIds } };
62
+ },
63
+
64
+ autoUnregisterWebhook: async ctx => {
65
+ let client = createClient(ctx.config, ctx.auth);
66
+ let webhookIds = ctx.input.registrationDetails?.webhookIds || {};
67
+
68
+ for (let webhookId of Object.values(webhookIds) as string[]) {
69
+ try {
70
+ await client.deleteWebhook(webhookId);
71
+ } catch (e) {
72
+ // Webhook may already be deleted
73
+ }
74
+ }
75
+ },
76
+
77
+ handleRequest: async ctx => {
78
+ let body = (await ctx.request.json()) as any;
79
+
80
+ return {
81
+ inputs: [
82
+ {
83
+ eventType: body.eventType || body['webhook-source-event-name'] || 'unknown',
84
+ resourceId: body.resource_luid || body.resourceId || '',
85
+ resourceName: body.resource_name || body.resourceName || '',
86
+ siteId: body.site_luid || body.siteId || '',
87
+ timestamp: body.created_at || body.timestamp || new Date().toISOString()
88
+ }
89
+ ]
90
+ };
91
+ },
92
+
93
+ handleEvent: async ctx => {
94
+ let mappedType = eventNameMap[ctx.input.eventType] || `workbook.${ctx.input.eventType}`;
95
+
96
+ return {
97
+ type: mappedType,
98
+ id: `${ctx.input.resourceId}-${ctx.input.timestamp}`,
99
+ output: {
100
+ workbookId: ctx.input.resourceId,
101
+ workbookName: ctx.input.resourceName,
102
+ siteId: ctx.input.siteId,
103
+ timestamp: ctx.input.timestamp
104
+ }
105
+ };
106
+ }
107
+ })
108
+ .build();
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "types": ["node"],
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "Preserve",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+ "moduleResolution": "bundler",
11
+
12
+ "noEmit": true,
13
+ "strict": true,
14
+ "skipLibCheck": true,
15
+ "noFallthroughCasesInSwitch": true,
16
+ "noUncheckedIndexedAccess": true,
17
+ "noImplicitOverride": true,
18
+ "noUnusedLocals": false,
19
+ "noUnusedParameters": false,
20
+ "noPropertyAccessFromIndexSignature": false
21
+ },
22
+ "include": ["src"]
23
+ }