@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
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # <img src="https://provider-logos.metorial-cdn.com/tableau.png" height="20"> Tableau
2
+
3
+ Manage Tableau Cloud and Tableau Server resources programmatically through the Tableau REST API. Query and manage workbooks, data sources, views, custom views, flows, users, groups, projects, permissions, favorites, collections, jobs, and data-driven alerts. Export views as CSV, PNG, or PDF. Authentication supports Tableau personal access tokens, username/password sign-in, and connected-app or unified-access-token JWT sign-in.
4
+
5
+ ## Tools
6
+
7
+ ### Get Site Info
8
+
9
+ Retrieve information about the current Tableau site, including name, URL, storage usage, and configuration settings.
10
+
11
+ ### Get View Data
12
+
13
+ Export the underlying data from a Tableau view as CSV. Useful for retrieving the tabular data behind a dashboard visualization.
14
+
15
+ ### Export View
16
+
17
+ Export a Tableau view as CSV data, a PNG image, or a PDF file. Supports Tableau view filter query parameters and cache max-age controls.
18
+
19
+ ### List Data Sources
20
+
21
+ List and search data sources on the Tableau site. Supports pagination, filtering, and sorting.
22
+
23
+ ### List Views
24
+
25
+ List and search views across the Tableau site. Supports pagination, filtering, and sorting.
26
+
27
+ ### List Workbooks
28
+
29
+ List and search workbooks on the Tableau site. Supports pagination, filtering, and sorting to find specific workbooks.
30
+
31
+ ### Manage Data-Driven Alerts
32
+
33
+ List, get, delete data-driven alerts, and add or remove users from alert recipient lists. Data-driven alerts trigger when data in a view meets specified conditions.
34
+
35
+ ### Manage Collections
36
+
37
+ List, get, create, update, or delete collections, and add, remove, or list collection items. Collections are curated groups of Tableau content.
38
+
39
+ ### Manage Custom Views
40
+
41
+ List, get, update, delete, or export Tableau custom views. Custom views are saved user-specific configurations of workbook views.
42
+
43
+ ### Manage Data Source
44
+
45
+ Get details, update, delete, or trigger extract refresh for a data source. Use the **action** field to select the operation.
46
+
47
+ ### Manage Favorites
48
+
49
+ List, add, or remove favorites for a user. Supports workbooks, views, data sources, projects, and flows.
50
+
51
+ ### Manage Flows
52
+
53
+ List, get, update, delete, or run Tableau Prep flows. Use the **action** field to select the operation.
54
+
55
+ ### Manage Groups
56
+
57
+ List, create, update, delete groups, and add or remove users from groups. Use the **action** field to select the operation.
58
+
59
+ ### Manage Jobs
60
+
61
+ List, get details, or cancel background jobs (extract refreshes, flow runs, subscriptions). Use the **action** field to select the operation.
62
+
63
+ ### Manage Permissions
64
+
65
+ Query, add, or delete permissions on Tableau resources (workbooks, datasources, projects, views, flows). Permissions are granted to users or groups with specific capability modes.
66
+
67
+ ### Manage Projects
68
+
69
+ List, create, update, or delete projects. Projects organize workbooks, data sources, and other content in Tableau.
70
+
71
+ ### Manage Users
72
+
73
+ List, get, add, update, or remove users on the Tableau site. Use the **action** field to select the operation.
74
+
75
+ ### Manage Workbook
76
+
77
+ Get details, update properties, delete, refresh extracts, or manage tags for a workbook. Use the **action** field to select the operation.
78
+
79
+ ## License
80
+
81
+ This integration is licensed under the [FSL-1.1](https://github.com/metorial/metorial-platform/blob/dev/LICENSE).
82
+
83
+ <div align="center">
84
+ <sub>Built with ❤️ by <a href="https://metorial.com">Metorial</a></sub>
85
+ </div>
package/docs/SPEC.md ADDED
@@ -0,0 +1,61 @@
1
+ # Tableau Integration Specification
2
+
3
+ ## Overview
4
+
5
+ This integration uses Tableau's REST API to manage common Tableau Cloud and Tableau Server resources. It focuses on practical content and administration workflows: querying content, exporting views, managing users and groups, managing projects and permissions, monitoring jobs, managing favorites, managing current collections endpoints, and handling custom views and data-driven alerts.
6
+
7
+ The default REST API version is `3.28`, matching Tableau 2026.1 documentation. Classic endpoints use `/api/{api-version}/sites/{site-luid}`. Current collections CRUD and item endpoints use Tableau's per-resource path under `/api/-/collections`.
8
+
9
+ ## Authentication
10
+
11
+ The integration signs in to Tableau and stores the returned credentials token, site LUID, user LUID, estimated expiration time, and auth method.
12
+
13
+ Supported sign-in methods:
14
+
15
+ - Personal access token (PAT)
16
+ - Username and password
17
+ - Connected app JWT
18
+ - Unified access token JWT by setting `isUat: true`
19
+
20
+ Tableau credentials tokens expire. Tableau Cloud tokens are documented as valid for 120 minutes, while Tableau Server tokens are typically valid for 240 minutes unless the server setting has changed. The integration records a conservative estimated expiration and can refresh PAT and username/password profiles by signing in again with the stored auth input. Non-refreshable auth methods report a user-facing `ServiceError` if a stored token is already expired.
21
+
22
+ ## Tools
23
+
24
+ - `get_site_info`: Get current site details.
25
+ - `list_workbooks`: List and filter workbooks.
26
+ - `manage_workbook`: Get, update, delete, refresh, and tag workbooks.
27
+ - `list_datasources`: List and filter published data sources.
28
+ - `manage_datasource`: Get, update, delete, and refresh data sources.
29
+ - `list_views`: List and filter views.
30
+ - `get_view_data`: Export view underlying data as CSV.
31
+ - `export_view`: Export a view as CSV, PNG, or PDF.
32
+ - `manage_custom_views`: List, get, update, delete, and export custom views.
33
+ - `manage_users`: List, get, add, update, and remove site users.
34
+ - `manage_groups`: List, create, update, delete groups, and manage group membership.
35
+ - `manage_projects`: List, create, update, and delete projects.
36
+ - `manage_permissions`: Query, add, and delete permissions for supported Tableau resources.
37
+ - `manage_jobs`: List, get, and cancel background jobs.
38
+ - `manage_favorites`: List, add, and remove user favorites.
39
+ - `manage_flows`: List, get, update, delete, and run flows.
40
+ - `manage_collections`: List, get, create, update, delete collections, and add, remove, or list collection items.
41
+ - `manage_alerts`: List, get, delete, and manage recipients for data-driven alerts.
42
+
43
+ ## Error Handling
44
+
45
+ Tool validation failures, auth failures, and upstream Tableau API failures are normalized to `ServiceError` from `@lowerdeck/error`. Upstream failures preserve the HTTP status when Tableau provides one.
46
+
47
+ ## Live E2E
48
+
49
+ The private live E2E suite lives at `tests/integrations/tableau/tools.e2e.ts`. Stable content IDs can be supplied through `SLATES_E2E_FIXTURES`:
50
+
51
+ - `workbookId`
52
+ - `datasourceId`
53
+ - `viewId`
54
+ - `userId`
55
+ - `groupId`
56
+ - `customViewId`
57
+ - `collectionItemContentLuid`
58
+ - `collectionItemContentType`
59
+ - `collectionItemContentName`
60
+
61
+ The suite creates and deletes its own collection for collection CRUD coverage.
package/logo.png ADDED
Binary file
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@slates-integrations/tableau",
3
+ "main": "src/index.ts",
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "bunx @vercel/ncc build src/index.ts -o dist -m -s",
7
+ "typecheck": "tsc --noEmit"
8
+ },
9
+ "dependencies": {
10
+ "@lowerdeck/error": "^1.1.0",
11
+ "@types/node": "^20",
12
+ "slates": "1.0.0-rc.10",
13
+ "zod": "^4.2"
14
+ },
15
+ "devDependencies": {
16
+ "typescript": "^5"
17
+ },
18
+ "version": "0.2.0-rc.8"
19
+ }
package/slate.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@metorial/tableau",
3
+ "description": "Manage Tableau Cloud and Tableau Server resources through the Tableau REST API. Query and manage workbooks, data sources, views, custom views, flows, users, groups, projects, permissions, favorites, collections, jobs, and data-driven alerts. Export views as CSV, PNG, or PDF.",
4
+ "categories": ["apis-and-http-requests", "document-processing"],
5
+ "skills": [
6
+ "query and manage workbooks",
7
+ "export views as CSV, PNG, or PDF",
8
+ "manage data source extracts",
9
+ "administer users and groups",
10
+ "configure permissions",
11
+ "monitor background jobs",
12
+ "manage flows and runs",
13
+ "manage data-driven alerts",
14
+ "manage collections and favorites",
15
+ "manage custom views"
16
+ ],
17
+ "logoUrl": "https://provider-logos.metorial-cdn.com/tableau.png"
18
+ }
package/src/auth.ts ADDED
@@ -0,0 +1,237 @@
1
+ import { SlateAuth, createAxios } from 'slates';
2
+ import { z } from 'zod';
3
+ import { tableauApiError, tableauServiceError } from './lib/errors';
4
+
5
+ type TableauAuthOutput = {
6
+ token: string;
7
+ siteId: string;
8
+ userId: string;
9
+ expiresAt?: string;
10
+ authMethod?: 'personal_access_token' | 'username_password' | 'connected_app_jwt';
11
+ };
12
+
13
+ type TableauSignInInput = {
14
+ serverUrl: string;
15
+ siteContentUrl: string;
16
+ apiVersion: string;
17
+ };
18
+
19
+ type TableauPersonalAccessTokenInput = TableauSignInInput & {
20
+ tokenName: string;
21
+ tokenSecret: string;
22
+ };
23
+
24
+ type TableauUsernamePasswordInput = TableauSignInInput & {
25
+ username: string;
26
+ password: string;
27
+ };
28
+
29
+ type TableauConnectedAppJwtInput = TableauSignInInput & {
30
+ jwt: string;
31
+ isUat?: boolean;
32
+ };
33
+
34
+ type TableauRefreshContext<Input> = {
35
+ output: TableauAuthOutput;
36
+ input: Input;
37
+ clientId: string;
38
+ clientSecret: string;
39
+ scopes: string[];
40
+ };
41
+
42
+ let estimateTokenExpiresAt = (serverUrl: string) => {
43
+ let lifetimeMinutes = /\.online\.tableau\.com/i.test(serverUrl) ? 110 : 230;
44
+ return new Date(Date.now() + lifetimeMinutes * 60 * 1000).toISOString();
45
+ };
46
+
47
+ let signIn = async (
48
+ input: TableauSignInInput,
49
+ credentials: Record<string, unknown>,
50
+ authMethod: NonNullable<TableauAuthOutput['authMethod']>
51
+ ) => {
52
+ let baseUrl = input.serverUrl.replace(/\/+$/, '');
53
+ let http = createAxios({ baseURL: baseUrl });
54
+
55
+ try {
56
+ let response = await http.post(`/api/${input.apiVersion}/auth/signin`, {
57
+ credentials: {
58
+ ...credentials,
59
+ site: {
60
+ contentUrl: input.siteContentUrl
61
+ }
62
+ }
63
+ });
64
+
65
+ let responseCredentials = response.data?.credentials;
66
+ if (
67
+ !responseCredentials?.token ||
68
+ !responseCredentials?.site?.id ||
69
+ !responseCredentials?.user?.id
70
+ ) {
71
+ throw tableauServiceError(
72
+ 'Tableau sign-in response did not include token, site ID, and user ID.'
73
+ );
74
+ }
75
+
76
+ return {
77
+ output: {
78
+ token: responseCredentials.token,
79
+ siteId: responseCredentials.site.id,
80
+ userId: responseCredentials.user.id,
81
+ expiresAt: estimateTokenExpiresAt(input.serverUrl),
82
+ authMethod
83
+ }
84
+ };
85
+ } catch (error) {
86
+ throw tableauApiError(error, 'sign-in');
87
+ }
88
+ };
89
+
90
+ let getProfile = async (ctx: { output: TableauAuthOutput; input: any }) => {
91
+ return {
92
+ profile: {
93
+ id: ctx.output.userId,
94
+ siteId: ctx.output.siteId,
95
+ authMethod: ctx.output.authMethod,
96
+ expiresAt: ctx.output.expiresAt
97
+ }
98
+ };
99
+ };
100
+
101
+ let personalAccessTokenAuth = {
102
+ type: 'auth.custom' as const,
103
+ name: 'Personal Access Token',
104
+ key: 'personal_access_token',
105
+
106
+ inputSchema: z.object({
107
+ serverUrl: z.string().describe('Tableau Server or Cloud URL'),
108
+ siteContentUrl: z.string().default('').describe('Site content URL'),
109
+ apiVersion: z.string().default('3.28').describe('API version'),
110
+ tokenName: z.string().describe('Personal access token name'),
111
+ tokenSecret: z.string().describe('Personal access token secret')
112
+ }),
113
+
114
+ getOutput: async (ctx: { input: TableauPersonalAccessTokenInput }) => {
115
+ let { serverUrl, siteContentUrl, apiVersion, tokenName, tokenSecret } = ctx.input;
116
+
117
+ return await signIn(
118
+ { serverUrl, siteContentUrl, apiVersion },
119
+ {
120
+ personalAccessTokenName: tokenName,
121
+ personalAccessTokenSecret: tokenSecret
122
+ },
123
+ 'personal_access_token'
124
+ );
125
+ },
126
+
127
+ handleTokenRefresh: async (
128
+ ctx: TableauRefreshContext<TableauPersonalAccessTokenInput>
129
+ ) => {
130
+ let { serverUrl, siteContentUrl, apiVersion, tokenName, tokenSecret } = ctx.input;
131
+
132
+ return await signIn(
133
+ { serverUrl, siteContentUrl, apiVersion },
134
+ {
135
+ personalAccessTokenName: tokenName,
136
+ personalAccessTokenSecret: tokenSecret
137
+ },
138
+ 'personal_access_token'
139
+ );
140
+ },
141
+
142
+ getProfile
143
+ };
144
+
145
+ let usernamePasswordAuth = {
146
+ type: 'auth.custom' as const,
147
+ name: 'Username & Password',
148
+ key: 'username_password',
149
+
150
+ inputSchema: z.object({
151
+ serverUrl: z.string().describe('Tableau Server or Cloud URL'),
152
+ siteContentUrl: z.string().default('').describe('Site content URL'),
153
+ apiVersion: z.string().default('3.28').describe('API version'),
154
+ username: z.string().describe('Tableau username'),
155
+ password: z.string().describe('Tableau password')
156
+ }),
157
+
158
+ getOutput: async (ctx: { input: TableauUsernamePasswordInput }) => {
159
+ let { serverUrl, siteContentUrl, apiVersion, username, password } = ctx.input;
160
+
161
+ return await signIn(
162
+ { serverUrl, siteContentUrl, apiVersion },
163
+ {
164
+ name: username,
165
+ password
166
+ },
167
+ 'username_password'
168
+ );
169
+ },
170
+
171
+ handleTokenRefresh: async (ctx: TableauRefreshContext<TableauUsernamePasswordInput>) => {
172
+ let { serverUrl, siteContentUrl, apiVersion, username, password } = ctx.input;
173
+
174
+ return await signIn(
175
+ { serverUrl, siteContentUrl, apiVersion },
176
+ {
177
+ name: username,
178
+ password
179
+ },
180
+ 'username_password'
181
+ );
182
+ },
183
+
184
+ getProfile
185
+ };
186
+
187
+ let connectedAppJwtAuth = {
188
+ type: 'auth.custom' as const,
189
+ name: 'Connected App JWT',
190
+ key: 'connected_app_jwt',
191
+
192
+ inputSchema: z.object({
193
+ serverUrl: z.string().describe('Tableau Server or Cloud URL'),
194
+ siteContentUrl: z.string().default('').describe('Site content URL'),
195
+ apiVersion: z.string().default('3.28').describe('API version'),
196
+ jwt: z.string().describe('JWT generated for a Tableau connected app or UAT'),
197
+ isUat: z
198
+ .boolean()
199
+ .optional()
200
+ .describe('Set true when signing in with a Tableau Cloud unified access token JWT')
201
+ }),
202
+
203
+ getOutput: async (ctx: { input: TableauConnectedAppJwtInput }) => {
204
+ let { serverUrl, siteContentUrl, apiVersion, jwt, isUat } = ctx.input;
205
+
206
+ return await signIn(
207
+ { serverUrl, siteContentUrl, apiVersion },
208
+ {
209
+ jwt,
210
+ ...(isUat !== undefined ? { isUat } : {})
211
+ },
212
+ 'connected_app_jwt'
213
+ );
214
+ },
215
+
216
+ getProfile
217
+ };
218
+
219
+ export let auth = SlateAuth.create()
220
+ .output(
221
+ z.object({
222
+ token: z.string().describe('Tableau credentials token for API requests'),
223
+ siteId: z.string().describe('Site LUID returned from sign-in'),
224
+ userId: z.string().describe('User LUID returned from sign-in'),
225
+ expiresAt: z
226
+ .string()
227
+ .optional()
228
+ .describe('Estimated ISO timestamp when the Tableau credentials token expires'),
229
+ authMethod: z
230
+ .enum(['personal_access_token', 'username_password', 'connected_app_jwt'])
231
+ .optional()
232
+ .describe('Authentication method used to obtain the Tableau credentials token')
233
+ })
234
+ )
235
+ .addCustomAuth(personalAccessTokenAuth)
236
+ .addCustomAuth(usernamePasswordAuth)
237
+ .addCustomAuth(connectedAppJwtAuth);
package/src/config.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { SlateConfig } from 'slates';
2
+ import { z } from 'zod';
3
+
4
+ export let config = SlateConfig.create(
5
+ z.object({
6
+ serverUrl: z
7
+ .string()
8
+ .describe('Tableau Server or Tableau Cloud URL (e.g., https://10ay.online.tableau.com)'),
9
+ siteContentUrl: z
10
+ .string()
11
+ .default('')
12
+ .describe(
13
+ 'Site content URL identifier (e.g., "my-site"). Leave empty for the default site.'
14
+ ),
15
+ apiVersion: z.string().default('3.28').describe('Tableau REST API version (e.g., "3.28")')
16
+ })
17
+ );
package/src/index.ts ADDED
@@ -0,0 +1,55 @@
1
+ import { Slate } from 'slates';
2
+ import { spec } from './spec';
3
+ import {
4
+ listWorkbooks,
5
+ manageWorkbook,
6
+ listDatasources,
7
+ manageDatasource,
8
+ listViews,
9
+ getViewData,
10
+ exportView,
11
+ manageCustomViews,
12
+ manageUsers,
13
+ manageGroups,
14
+ manageProjects,
15
+ managePermissions,
16
+ manageJobs,
17
+ manageFavorites,
18
+ manageFlows,
19
+ manageCollections,
20
+ manageAlerts,
21
+ getSiteInfo
22
+ } from './tools';
23
+ import {
24
+ datasourceEvents,
25
+ workbookEvents,
26
+ userEvents,
27
+ labelEvents,
28
+ siteEvents,
29
+ viewEvents
30
+ } from './triggers';
31
+
32
+ export let provider = Slate.create({
33
+ spec,
34
+ tools: [
35
+ listWorkbooks,
36
+ manageWorkbook,
37
+ listDatasources,
38
+ manageDatasource,
39
+ listViews,
40
+ getViewData,
41
+ exportView,
42
+ manageCustomViews,
43
+ manageUsers,
44
+ manageGroups,
45
+ manageProjects,
46
+ managePermissions,
47
+ manageJobs,
48
+ manageFavorites,
49
+ manageFlows,
50
+ manageCollections,
51
+ manageAlerts,
52
+ getSiteInfo
53
+ ],
54
+ triggers: [datasourceEvents, workbookEvents, userEvents, labelEvents, siteEvents, viewEvents]
55
+ });