Skip to main content
Glama
by MikelA92
urlDecoder.js•3.8 kB
import { ValidationError } from '../errors/MetabaseError.js'; /** * Utilities for decoding Metabase dashboard URLs and extracting parameters */ export class DashboardUrlDecoder { /** * Decode a Metabase dashboard URL and extract the card configuration * @param {string} url - The Metabase dashboard URL with encoded parameters * @returns {Object} Decoded data with card ID and parameters * @throws {ValidationError} If URL is invalid or cannot be decoded */ static decode(url) { try { // Extract the base64 fragment after the # const fragment = url.split('#')[1]; if (!fragment) { throw new ValidationError( 'No fragment found in URL', 'url', url ); } // Decode base64 const decoded = Buffer.from(fragment, 'base64').toString('utf-8'); const data = JSON.parse(decoded); return { originalCardId: data.original_card_id, datasetQuery: data.dataset_query, parameters: DashboardUrlDecoder.extractParametersFromQuery(data.dataset_query), display: data.display, visualizationSettings: data.visualization_settings, name: data.name, description: data.description, }; } catch (error) { if (error instanceof ValidationError) { throw error; } throw new ValidationError( `Failed to decode dashboard URL: ${error.message}`, 'url', url ); } } /** * Extract parameters from a query builder dataset query * @param {Object} datasetQuery - The dataset query object * @returns {Object} Extracted parameters */ static extractParametersFromQuery(datasetQuery) { if (!datasetQuery || datasetQuery.type !== 'query') { return {}; } const query = datasetQuery.query; const parameters = {}; // Extract filters if (query.filter) { parameters.filters = query.filter; } // Extract aggregations if (query.aggregation) { parameters.aggregations = query.aggregation; } // Extract breakouts if (query.breakout) { parameters.breakouts = query.breakout; } // Extract source table if (query['source-table']) { parameters.sourceTable = query['source-table']; } // Extract order by if (query['order-by']) { parameters.orderBy = query['order-by']; } // Extract limit if (query.limit) { parameters.limit = query.limit; } return parameters; } /** * Convert query builder parameters to Metabase API format * @param {Object} parameters - Query builder parameters * @returns {Object} API-formatted parameters */ static convertParametersToApiFormat(parameters) { const apiParams = {}; // Handle filters if (parameters.filters) { parameters.filters.forEach((filter, index) => { if (Array.isArray(filter) && filter[0] === 'time-interval') { // Convert time-interval filter to API format apiParams[`time-interval-${index}`] = { type: 'time-interval', field: filter[1], value: filter[2], unit: filter[3], }; } else if (Array.isArray(filter) && filter[0] === '=') { // Convert equality filter to API format apiParams[`filter-${index}`] = { type: '=', field: filter[1], value: filter[2], }; } else if (Array.isArray(filter) && filter[0] === 'and') { // Handle AND filters filter.slice(1).forEach((subFilter, subIndex) => { apiParams[`and-filter-${index}-${subIndex}`] = subFilter; }); } }); } return apiParams; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/MikelA92/metabase-mcp-mab'

If you have feedback or need assistance with the MCP directory API, please join our Discord server