Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/odd-tables-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hyperdx/api": patch
---

feat: Add Raw SQL Chart support to external dashboard APIs
281 changes: 269 additions & 12 deletions packages/api/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@
},
"tileId": {
"type": "string",
"description": "Tile ID for tile-based alerts.",
"description": "Tile ID for tile-based alerts. May not be a Raw-SQL-based tile.",
"nullable": true,
"example": "65f5e4a3b9e77c001a901234"
},
Expand Down Expand Up @@ -1002,14 +1002,14 @@
}
}
},
"LineChartConfig": {
"LineBuilderChartConfig": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"description": "Configuration for a line time-series chart.",
"description": "Builder configuration for a line time-series chart.",
"properties": {
"displayType": {
"type": "string",
Expand Down Expand Up @@ -1063,14 +1063,14 @@
}
}
},
"BarChartConfig": {
"BarBuilderChartConfig": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"description": "Configuration for a stacked-bar time-series chart.",
"description": "Builder configuration for a stacked-bar time-series chart.",
"properties": {
"displayType": {
"type": "string",
Expand Down Expand Up @@ -1119,14 +1119,14 @@
}
}
},
"TableChartConfig": {
"TableBuilderChartConfig": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"description": "Configuration for a table aggregation chart.",
"description": "Builder configuration for a table aggregation chart.",
"properties": {
"displayType": {
"type": "string",
Expand Down Expand Up @@ -1177,14 +1177,14 @@
}
}
},
"NumberChartConfig": {
"NumberBuilderChartConfig": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"description": "Configuration for a single big-number chart.",
"description": "Builder configuration for a single big-number chart.",
"properties": {
"displayType": {
"type": "string",
Expand Down Expand Up @@ -1212,14 +1212,14 @@
}
}
},
"PieChartConfig": {
"PieBuilderChartConfig": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"description": "Configuration for a pie chart tile. Each slice represents one group value.",
"description": "Builder configuration for a pie chart tile. Each slice represents one group value.",
"properties": {
"displayType": {
"type": "string",
Expand Down Expand Up @@ -1315,8 +1315,265 @@
}
}
},
"RawSqlChartConfigBase": {
"type": "object",
"required": [
"configType",
"connectionId",
"sqlTemplate"
],
"description": "Shared fields for Raw SQL chart configs. Set configType to \"sql\" and provide connectionId + sqlTemplate instead of sourceId + select.",
"properties": {
"configType": {
"type": "string",
"enum": [
"sql"
],
"example": "sql"
},
"connectionId": {
"type": "string",
"description": "ID of the ClickHouse connection to execute the query against.",
"example": "65f5e4a3b9e77c001a567890"
},
"sqlTemplate": {
"type": "string",
"maxLength": 100000,
"description": "SQL query template to execute. Supports HyperDX template variables.",
"example": "SELECT count() FROM otel_logs WHERE timestamp > now() - INTERVAL 1 HOUR"
},
"numberFormat": {
"$ref": "#/components/schemas/NumberFormat"
}
}
},
"LineRawSqlChartConfig": {
"description": "Raw SQL configuration for a line time-series chart.",
"allOf": [
{
"$ref": "#/components/schemas/RawSqlChartConfigBase"
},
{
"type": "object",
"required": [
"displayType"
],
"properties": {
"displayType": {
"type": "string",
"enum": [
"line"
],
"example": "line"
},
"compareToPreviousPeriod": {
"type": "boolean",
"description": "Overlay the equivalent previous time period for comparison.",
"default": false
},
"fillNulls": {
"type": "boolean",
"description": "Fill missing time buckets with zero instead of leaving gaps.",
"default": true
},
"alignDateRangeToGranularity": {
"type": "boolean",
"description": "Expand date range boundaries to the query granularity interval.",
"default": true
}
}
}
]
},
"BarRawSqlChartConfig": {
"description": "Raw SQL configuration for a stacked-bar time-series chart.",
"allOf": [
{
"$ref": "#/components/schemas/RawSqlChartConfigBase"
},
{
"type": "object",
"required": [
"displayType"
],
"properties": {
"displayType": {
"type": "string",
"enum": [
"stacked_bar"
],
"example": "stacked_bar"
},
"fillNulls": {
"type": "boolean",
"description": "Fill missing time buckets with zero instead of leaving gaps.",
"default": true
},
"alignDateRangeToGranularity": {
"type": "boolean",
"description": "Expand date range boundaries to the query granularity interval.",
"default": true
}
}
}
]
},
"TableRawSqlChartConfig": {
"description": "Raw SQL configuration for a table chart.",
"allOf": [
{
"$ref": "#/components/schemas/RawSqlChartConfigBase"
},
{
"type": "object",
"required": [
"displayType"
],
"properties": {
"displayType": {
"type": "string",
"enum": [
"table"
],
"example": "table"
}
}
}
]
},
"NumberRawSqlChartConfig": {
"description": "Raw SQL configuration for a single big-number chart.",
"allOf": [
{
"$ref": "#/components/schemas/RawSqlChartConfigBase"
},
{
"type": "object",
"required": [
"displayType"
],
"properties": {
"displayType": {
"type": "string",
"enum": [
"number"
],
"example": "number"
}
}
}
]
},
"PieRawSqlChartConfig": {
"description": "Raw SQL configuration for a pie chart.",
"allOf": [
{
"$ref": "#/components/schemas/RawSqlChartConfigBase"
},
{
"type": "object",
"required": [
"displayType"
],
"properties": {
"displayType": {
"type": "string",
"enum": [
"pie"
],
"example": "pie"
}
}
}
]
},
"LineChartConfig": {
"description": "Line chart. Omit configType for the builder variant (requires sourceId and select). Set configType to \"sql\" for the Raw SQL variant (requires connectionId and sqlTemplate).\n",
"oneOf": [
{
"$ref": "#/components/schemas/LineBuilderChartConfig"
},
{
"$ref": "#/components/schemas/LineRawSqlChartConfig"
}
],
"discriminator": {
"propertyName": "configType",
"mapping": {
"sql": "#/components/schemas/LineRawSqlChartConfig"
}
}
},
"BarChartConfig": {
"description": "Stacked-bar chart. Omit configType for the builder variant (requires sourceId and select). Set configType to \"sql\" for the Raw SQL variant (requires connectionId and sqlTemplate).\n",
"oneOf": [
{
"$ref": "#/components/schemas/BarBuilderChartConfig"
},
{
"$ref": "#/components/schemas/BarRawSqlChartConfig"
}
],
"discriminator": {
"propertyName": "configType",
"mapping": {
"sql": "#/components/schemas/BarRawSqlChartConfig"
}
}
},
"TableChartConfig": {
"description": "Table chart. Omit configType for the builder variant (requires sourceId and select). Set configType to \"sql\" for the Raw SQL variant (requires connectionId and sqlTemplate).\n",
"oneOf": [
{
"$ref": "#/components/schemas/TableBuilderChartConfig"
},
{
"$ref": "#/components/schemas/TableRawSqlChartConfig"
}
],
"discriminator": {
"propertyName": "configType",
"mapping": {
"sql": "#/components/schemas/TableRawSqlChartConfig"
}
}
},
"NumberChartConfig": {
"description": "Single big-number chart. Omit configType for the builder variant (requires sourceId and select). Set configType to \"sql\" for the Raw SQL variant (requires connectionId and sqlTemplate).\n",
"oneOf": [
{
"$ref": "#/components/schemas/NumberBuilderChartConfig"
},
{
"$ref": "#/components/schemas/NumberRawSqlChartConfig"
}
],
"discriminator": {
"propertyName": "configType",
"mapping": {
"sql": "#/components/schemas/NumberRawSqlChartConfig"
}
}
},
"PieChartConfig": {
"description": "Pie chart. Omit configType for the builder variant (requires sourceId and select). Set configType to \"sql\" for the Raw SQL variant (requires connectionId and sqlTemplate).\n",
"oneOf": [
{
"$ref": "#/components/schemas/PieBuilderChartConfig"
},
{
"$ref": "#/components/schemas/PieRawSqlChartConfig"
}
],
"discriminator": {
"propertyName": "configType",
"mapping": {
"sql": "#/components/schemas/PieRawSqlChartConfig"
}
}
},
"TileConfig": {
"description": "Tile chart configuration. The displayType field determines which variant is used.\n",
"description": "Tile chart configuration. displayType is the primary discriminant and determines which variant group applies. For displayTypes that support both builder and Raw SQL modes (line, stacked_bar, table, number, pie), configType is the secondary discriminant: omit it for the builder variant or set it to \"sql\" for the Raw SQL variant. The search and markdown displayTypes only have a builder variant.\n",
"oneOf": [
{
"$ref": "#/components/schemas/LineChartConfig"
Expand Down
9 changes: 8 additions & 1 deletion packages/api/src/controllers/alerts.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isRawSqlSavedChartConfig } from '@hyperdx/common-utils/dist/guards';
import { sign, verify } from 'jsonwebtoken';
import { groupBy } from 'lodash';
import ms from 'ms';
Expand Down Expand Up @@ -74,9 +75,15 @@ export const validateAlertInput = async (
throw new Api400Error('Dashboard not found');
}

if (dashboard.tiles.find(tile => tile.id === alertInput.tileId) == null) {
const tile = dashboard.tiles.find(tile => tile.id === alertInput.tileId);

if (tile == null) {
throw new Api400Error('Tile not found');
}

if (tile.config != null && isRawSqlSavedChartConfig(tile.config)) {
throw new Api400Error('Cannot create an alert on a raw SQL tile');
}
}

if (alertInput.source === AlertSource.SAVED_SEARCH) {
Expand Down
4 changes: 4 additions & 0 deletions packages/api/src/controllers/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export function getConnections() {
return Connection.find({});
}

export function getConnectionsByTeam(team: string) {
return Connection.find({ team });
}

export function getConnectionById(
team: string,
connectionId: string,
Expand Down
Loading
Loading