Skip to content

Commit 8616b6d

Browse files
authored
[Components] Metabase - new components (#17008)
1 parent 101957f commit 8616b6d

File tree

11 files changed

+441
-22
lines changed

11 files changed

+441
-22
lines changed

components/metabase/.gitignore

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

components/metabase/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,23 @@
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+
- **Get Dashboard** - Retrieve dashboard information and its cards
11+
- **Create Dashboard** - Create a new dashboard in Metabase
12+
- **Get Database** - Retrieve database information and metadata
13+
514
# Example Use Cases
615

716
- **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.
817

918
- **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.
1019

1120
- **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.
21+
22+
- **Data Pipeline Automation**: Automatically create new cards and dashboards when new data sources are added, or when specific business events occur.
23+
24+
- **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: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import app from "../../metabase.app.mjs";
2+
import utils from "../../common/utils.mjs";
3+
4+
export default {
5+
key: "metabase-create-dashboard",
6+
name: "Create Dashboard",
7+
description: "Create a new Dashboard. [See the documentation](https://www.metabase.com/docs/latest/api#tag/apidashboard/post/api/dashboard/).",
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 dashboard",
16+
},
17+
description: {
18+
type: "string",
19+
label: "Description",
20+
description: "Description of the dashboard",
21+
optional: true,
22+
},
23+
collectionId: {
24+
propDefinition: [
25+
app,
26+
"collectionId",
27+
],
28+
optional: true,
29+
},
30+
collectionPosition: {
31+
type: "integer",
32+
label: "Collection Position",
33+
description: "Position within the collection (must be greater than zero)",
34+
min: 1,
35+
optional: true,
36+
},
37+
cacheTtl: {
38+
type: "integer",
39+
label: "Cache TTL",
40+
description: "Cache time-to-live in seconds (must be greater than zero)",
41+
min: 1,
42+
optional: true,
43+
},
44+
parameters: {
45+
type: "string[]",
46+
label: "Parameters",
47+
description: "Array of parameter definition objects.\n\n**Required properties:**\n- `id` (string) - Parameter identifier\n- `type` (string) - Parameter type (e.g., \"date/single\", \"text\", \"category\")\n\n**Optional properties:**\n- `name` (string) - Display name\n- `slug` (string) - URL-friendly identifier\n- `sectionId` (string) - Section grouping\n- `default` - Default value\n- `values_source_type` (enum) - \"static-list\", \"card\", or null\n- `values_source_config` (object) - Dynamic value configuration with `card_id`, `label_field`, `value_field`, `values`\n- `temporal_units` (array) - Time-based parameter units\n\n**Example:** `{\"id\": \"date_param\", \"type\": \"date/single\", \"name\": \"Date Filter\", \"slug\": \"date_filter\", \"default\": \"2024-01-01\"}`",
48+
optional: true,
49+
},
50+
},
51+
async run({ $ }) {
52+
const {
53+
app,
54+
name,
55+
description,
56+
collectionId,
57+
collectionPosition,
58+
cacheTtl,
59+
parameters,
60+
} = this;
61+
62+
const response = await app.createDashboard({
63+
$,
64+
data: {
65+
name,
66+
description,
67+
collection_id: collectionId,
68+
collection_position: collectionPosition,
69+
cache_ttl: cacheTtl,
70+
parameters: utils.parseArray(parameters),
71+
},
72+
});
73+
74+
$.export("$summary", `Successfully created dashboard with ID \`${response?.id}\``);
75+
76+
return response;
77+
},
78+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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/{id}).",
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 {
20+
app,
21+
dashboardId,
22+
} = this;
23+
24+
const response = await app.getDashboard({
25+
$,
26+
dashboardId,
27+
});
28+
29+
$.export("$summary", `Successfully retrieved dashboard with ID \`${response?.id}\``);
30+
31+
return response;
32+
},
33+
};
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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. [See the documentation](https://www.metabase.com/docs/latest/api#tag/apidatabase/get/api/database/{id}).",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
app,
11+
databaseId: {
12+
propDefinition: [
13+
app,
14+
"databaseId",
15+
],
16+
},
17+
include: {
18+
type: "string",
19+
label: "Include",
20+
description: "What to include in the response",
21+
options: [
22+
"tables",
23+
"tables.fields",
24+
],
25+
optional: true,
26+
},
27+
includeEditableDataModel: {
28+
type: "boolean",
29+
label: "Include Editable Data Model",
30+
description: "Whether to include editable data model information",
31+
optional: true,
32+
},
33+
excludeUneditableDetails: {
34+
type: "boolean",
35+
label: "Exclude Uneditable Details",
36+
description: "Whether to exclude uneditable details from the response",
37+
optional: true,
38+
},
39+
},
40+
async run({ $ }) {
41+
const {
42+
app,
43+
databaseId,
44+
include,
45+
includeEditableDataModel,
46+
excludeUneditableDetails,
47+
} = this;
48+
49+
const response = await app.getDatabase({
50+
$,
51+
databaseId,
52+
params: {
53+
include,
54+
include_editable_data_model: includeEditableDataModel,
55+
exclude_uneditable_details: excludeUneditableDetails,
56+
},
57+
});
58+
59+
$.export("$summary", `Successfully retrieved database with ID \`${response?.id}\``);
60+
61+
return response;
62+
},
63+
};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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/pivot/{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+
ignoreCache: {
18+
type: "boolean",
19+
label: "Ignore Cache",
20+
description: "Whether to ignore the cache and run the query again",
21+
optional: true,
22+
},
23+
},
24+
async run({ $ }) {
25+
const {
26+
app,
27+
cardId,
28+
ignoreCache,
29+
} = this;
30+
31+
const response = await app.runCardQuery({
32+
$,
33+
cardId,
34+
data: {
35+
ignore_cache: ignoreCache,
36+
},
37+
});
38+
39+
$.export("$summary", "Successfully executed query");
40+
41+
return response;
42+
},
43+
};

components/metabase/app/metabase.app.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const parseJson = (input, maxDepth = 100) => {
2+
const seen = new WeakSet();
3+
const parse = (value) => {
4+
if (maxDepth <= 0) {
5+
return value;
6+
}
7+
if (typeof(value) === "string") {
8+
// Only parse if the string looks like a JSON object or array
9+
const trimmed = value.trim();
10+
if (
11+
(trimmed.startsWith("{") && trimmed.endsWith("}")) ||
12+
(trimmed.startsWith("[") && trimmed.endsWith("]"))
13+
) {
14+
try {
15+
return parseJson(JSON.parse(value), maxDepth - 1);
16+
} catch (e) {
17+
return value;
18+
}
19+
}
20+
return value;
21+
} else if (typeof(value) === "object" && value !== null) {
22+
if (seen.has(value)) {
23+
return value;
24+
}
25+
seen.add(value);
26+
return Object.entries(value)
27+
.reduce((acc, [
28+
key,
29+
val,
30+
]) => Object.assign(acc, {
31+
[key]: parse(val),
32+
}), {});
33+
}
34+
return value;
35+
};
36+
37+
return parse(input);
38+
};
39+
40+
function parseArray(input, maxDepth = 100) {
41+
if (!Array.isArray(input)) {
42+
return input;
43+
}
44+
45+
return input.map((item) => parseJson(item, maxDepth));
46+
}
47+
48+
export default {
49+
parseArray,
50+
parseJson,
51+
};

0 commit comments

Comments
 (0)