Skip to content

Commit f53e989

Browse files
committed
[Components] Metabase - new components
1 parent 27ae00a commit f53e989

File tree

12 files changed

+543
-20
lines changed

12 files changed

+543
-20
lines changed

components/metabase/.gitignore

Lines changed: 0 additions & 3 deletions
This file was deleted.

components/metabase/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,24 @@
22

33
The Metabase API opens a gateway to interact with Metabase programmatically, enabling you to automate reporting, dashboards, and data analysis operations. With Pipedream, you can harness this API to trigger workflows, manipulate data, and integrate with various other apps to create a seamless data ecosystem. Think of syncing Metabase insights with other tools, automating report generation, or reacting to events within your Metabase instance in real-time.
44

5+
# Available Actions
6+
7+
This Metabase integration provides the following actions:
8+
9+
- **Run Query** - Execute a saved question/card and return the results
10+
- **Create Card** - Create a new question/card in Metabase
11+
- **Get Dashboard** - Retrieve dashboard information and its cards
12+
- **Create Dashboard** - Create a new dashboard in Metabase
13+
- **Get Database** - Retrieve database information and metadata
14+
515
# Example Use Cases
616

717
- **Automated Reporting**: Use Pipedream to set up scheduled triggers that fetch reports from Metabase and send them via email or Slack. This workflow can help teams stay updated with the latest insights without manual intervention.
818

919
- **Dashboard Sync**: Create a workflow that listens for updates in a specific Metabase dashboard and synchronizes those changes with a Google Sheets document. This allows for easy sharing and collaboration on data insights with stakeholders who prefer working in spreadsheets.
1020

1121
- **Alerting on Metrics**: Set up a Pipedream workflow that monitors specific metrics within Metabase. If certain thresholds are crossed, actions can be taken automatically, like sending alerts through SMS using Twilio or creating a task in project management tools like Trello.
22+
23+
- **Data Pipeline Automation**: Automatically create new cards and dashboards when new data sources are added, or when specific business events occur.
24+
25+
- **Cross-Platform Integration**: Sync Metabase insights with CRM systems, marketing tools, or business intelligence platforms to create a unified view of your data across all systems.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import app from "../../metabase.app.mjs";
2+
import { VISUALIZATION_TYPES } from "../../common/constants.mjs";
3+
4+
export default {
5+
key: "metabase-create-card",
6+
name: "Create Card",
7+
description: "Create a new question/card in Metabase. [See the documentation](https://www.metabase.com/docs/latest/api#tag/apicard/POST/api/card/).",
8+
version: "0.0.1",
9+
type: "action",
10+
props: {
11+
app,
12+
name: {
13+
type: "string",
14+
label: "Name",
15+
description: "The name of the card",
16+
},
17+
databaseId: {
18+
propDefinition: [
19+
app,
20+
"databaseId",
21+
],
22+
},
23+
query: {
24+
type: "object",
25+
label: "Query",
26+
description: "The query definition object. For native queries, use {\"native\": {\"query\": \"SELECT * FROM table\"}}. For structured queries, provide the query object.",
27+
},
28+
collectionId: {
29+
propDefinition: [
30+
app,
31+
"collectionId",
32+
],
33+
optional: true,
34+
},
35+
description: {
36+
type: "string",
37+
label: "Description",
38+
description: "Description of the card",
39+
optional: true,
40+
},
41+
visualizationType: {
42+
type: "string",
43+
label: "Visualization Type",
44+
description: "The type of visualization",
45+
options: VISUALIZATION_TYPES,
46+
default: "table",
47+
optional: true,
48+
},
49+
},
50+
async run({ $ }) {
51+
const {
52+
name,
53+
databaseId,
54+
query,
55+
collectionId,
56+
description,
57+
visualizationType,
58+
} = this;
59+
60+
const data = {
61+
name,
62+
database_id: databaseId,
63+
dataset_query: {
64+
database: databaseId,
65+
...query,
66+
},
67+
display: visualizationType || "table",
68+
visualization_settings: {},
69+
};
70+
71+
if (collectionId !== undefined) {
72+
data.collection_id = collectionId;
73+
}
74+
75+
if (description) {
76+
data.description = description;
77+
}
78+
79+
const response = await this.app.createCard({
80+
$,
81+
data,
82+
});
83+
84+
$.export("$summary", `Successfully created card "${name}" with ID ${response.id}`);
85+
86+
return response;
87+
},
88+
};
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import app from "../../metabase.app.mjs";
2+
3+
export default {
4+
key: "metabase-create-dashboard",
5+
name: "Create Dashboard",
6+
description: "Create a new dashboard in Metabase. [See the documentation](https://www.metabase.com/docs/latest/api#tag/apidashboard/POST/api/dashboard/).",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
app,
11+
name: {
12+
type: "string",
13+
label: "Name",
14+
description: "The name of the dashboard",
15+
},
16+
description: {
17+
type: "string",
18+
label: "Description",
19+
description: "Description of the dashboard",
20+
optional: true,
21+
},
22+
collectionId: {
23+
propDefinition: [
24+
app,
25+
"collectionId",
26+
],
27+
optional: true,
28+
},
29+
parameters: {
30+
type: "object",
31+
label: "Parameters",
32+
description: "Dashboard parameters configuration",
33+
optional: true,
34+
},
35+
},
36+
async run({ $ }) {
37+
const {
38+
name,
39+
description,
40+
collectionId,
41+
parameters,
42+
} = this;
43+
44+
const data = {
45+
name,
46+
parameters: parameters || [],
47+
};
48+
49+
if (description) {
50+
data.description = description;
51+
}
52+
53+
if (collectionId !== undefined) {
54+
data.collection_id = collectionId;
55+
}
56+
57+
const response = await this.app.createDashboard({
58+
$,
59+
data,
60+
});
61+
62+
$.export("$summary", `Successfully created dashboard "${name}" with ID ${response.id}`);
63+
64+
return response;
65+
},
66+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import app from "../../metabase.app.mjs";
2+
3+
export default {
4+
key: "metabase-get-dashboard",
5+
name: "Get Dashboard",
6+
description: "Retrieve dashboard information and its cards. [See the documentation](https://www.metabase.com/docs/latest/api#tag/apidashboard/GET/api/dashboard/).",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
app,
11+
dashboardId: {
12+
propDefinition: [
13+
app,
14+
"dashboardId",
15+
],
16+
},
17+
},
18+
async run({ $ }) {
19+
const { dashboardId } = this;
20+
21+
const response = await this.app.getDashboard({
22+
$,
23+
dashboardId,
24+
});
25+
26+
$.export("$summary", `Successfully retrieved dashboard "${response.name}" with ${response.dashcards?.length || 0} cards`);
27+
28+
return response;
29+
},
30+
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import app from "../../metabase.app.mjs";
2+
3+
export default {
4+
key: "metabase-get-database",
5+
name: "Get Database",
6+
description: "Retrieve database information and metadata. [See the documentation](https://www.metabase.com/docs/latest/api#tag/apidatabase/GET/api/database/).",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
app,
11+
databaseId: {
12+
propDefinition: [
13+
app,
14+
"databaseId",
15+
],
16+
},
17+
includeMetadata: {
18+
type: "boolean",
19+
label: "Include Metadata",
20+
description: "Whether to include detailed metadata about tables and fields",
21+
default: false,
22+
optional: true,
23+
},
24+
},
25+
async run({ $ }) {
26+
const {
27+
databaseId, includeMetadata,
28+
} = this;
29+
30+
let response = await this.app.getDatabase({
31+
$,
32+
databaseId,
33+
});
34+
35+
if (includeMetadata) {
36+
response = await this.app._makeRequest({
37+
$,
38+
path: `/database/${databaseId}/metadata`,
39+
});
40+
}
41+
42+
$.export("$summary", `Successfully retrieved database "${response.name}" information`);
43+
44+
return response;
45+
},
46+
};
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import app from "../../metabase.app.mjs";
2+
3+
export default {
4+
key: "metabase-run-query",
5+
name: "Run Query",
6+
description: "Execute a saved question/card and return the results. [See the documentation](https://www.metabase.com/docs/latest/api#tag/apicard/POST/api/card/{card-id}/query).",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
app,
11+
cardId: {
12+
propDefinition: [
13+
app,
14+
"cardId",
15+
],
16+
},
17+
parameters: {
18+
type: "object",
19+
label: "Parameters",
20+
description: "Parameters to pass to the query (if the question has parameters)",
21+
optional: true,
22+
},
23+
},
24+
async run({ $ }) {
25+
const {
26+
cardId, parameters,
27+
} = this;
28+
29+
const response = await this.app.runCardQuery({
30+
$,
31+
cardId,
32+
data: parameters || {},
33+
});
34+
35+
$.export("$summary", `Successfully executed query for card ${cardId}`);
36+
37+
return response;
38+
},
39+
};

components/metabase/app/metabase.app.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
export const VISUALIZATION_TYPES = [
2+
"table",
3+
"bar",
4+
"line",
5+
"area",
6+
"pie",
7+
"scalar",
8+
"smartscalar",
9+
"gauge",
10+
"progress",
11+
"combo",
12+
"row",
13+
"waterfall",
14+
"funnel",
15+
"scatter",
16+
"map",
17+
];
18+
19+
export const QUERY_TYPES = {
20+
NATIVE: "native",
21+
STRUCTURED: "query",
22+
};
23+
24+
export const parseMetabaseError = (error) => {
25+
if (error.response?.data?.message) {
26+
return error.response.data.message;
27+
}
28+
if (error.response?.data?.errors) {
29+
return Object.values(error.response.data.errors).join(", ");
30+
}
31+
return error.message || "An error occurred";
32+
};
33+
34+
export const formatCardSummary = (card) => {
35+
const {
36+
id, name, display,
37+
} = card;
38+
return `Card "${name}" (ID: ${id}, Type: ${display})`;
39+
};
40+
41+
export const formatDashboardSummary = (dashboard) => {
42+
const {
43+
id, name, dashcards = [],
44+
} = dashboard;
45+
return `Dashboard "${name}" (ID: ${id}, Cards: ${dashcards.length})`;
46+
};

0 commit comments

Comments
 (0)