Shared TypeScript library for the Lightdash platform containing common types, utilities, and business logic for analytics workflows
Overall
score
72%
Evaluation — 72%
↑ 1.09xAgent success when using this tile
This document contains utility types, conditional formatting, parameters, Google Drive integration, comments, and AI Agent types.
This module provides the following functionality:
type ArgumentsOf<F extends Function> = F extends (...args: infer A) => unknown
? A
: never;Generic utility type for extracting function argument types.
Visual formatting rules for charts and tables with single color rules, color gradients, field comparisons, and automatic min/max calculation.
type ConditionalFormattingMinMax<T = number> = {
min: T;
max: T;
};
type ConditionalFormattingColorRange = {
start: string;
end: string;
};
type ConditionalFormattingWithValues<T = number | string> =
BaseFilterRule<FilterOperator, T> & {
values: T[];
};
type ConditionalFormattingWithCompareTarget<T = number | string> =
BaseFilterRule<FilterOperator, T> & {
compareTarget: FieldTarget | null;
values?: T[];
};
type ConditionalFormattingWithFilterOperator<T = number | string> =
| ConditionalFormattingWithValues<T>
| ConditionalFormattingWithCompareTarget<T>;
type ConditionalFormattingConfigWithSingleColor = {
target: FieldTarget | null;
color: string;
rules: ConditionalFormattingWithFilterOperator[];
};
type ConditionalFormattingConfigWithColorRange = {
target: FieldTarget | null;
color: ConditionalFormattingColorRange;
rule: ConditionalFormattingMinMax<number | 'auto'>;
};
type ConditionalFormattingConfig =
| ConditionalFormattingConfigWithSingleColor
| ConditionalFormattingConfigWithColorRange;
enum ConditionalFormattingConfigType {
Single = 'single',
Range = 'range',
}
function isConditionalFormattingWithValues(
rule: ConditionalFormattingWithFilterOperator
): rule is ConditionalFormattingWithValues;
function isConditionalFormattingWithCompareTarget(
rule: ConditionalFormattingWithFilterOperator
): rule is ConditionalFormattingWithCompareTarget;
function isConditionalFormattingConfigWithSingleColor(
rule: ConditionalFormattingConfig
): rule is ConditionalFormattingConfigWithSingleColor;
function isConditionalFormattingConfigWithColorRange(
config: ConditionalFormattingConfig
): config is ConditionalFormattingConfigWithColorRange;
function getConditionalFormattingConfigType(
rule: ConditionalFormattingConfig
): ConditionalFormattingConfigType;Types for parameterized queries and dashboards enabling dynamic SQL and dashboard filters.
/** Base type for parameter values - can be extended later for new types (dates, booleans, etc.) */
type ParameterValue = string | number | string[] | number[];
/** Used anywhere we have parameters */
type ParametersValuesMap = Record<string, ParameterValue>;
type ParameterDefinitions = Record<string, LightdashProjectParameter>;
/** Used in dashboards where we may have properties specific to dashboard tiles */
interface DashboardParameterValue {
parameterName: string;
value: ParameterValue;
}
type DashboardParameters = Record<string, DashboardParameterValue>;Types for exporting metrics and query results to Google Sheets and Google Drive.
/** API response for Google Drive access token */
interface ApiGdriveAccessTokenResponse {
status: 'ok';
results: string;
}
/** Custom labels mapping for columns in Google Sheets export */
type CustomLabel = {
[key: string]: string;
};
/** Configuration for uploading metrics to Google Sheets */
interface UploadMetricGsheet {
projectUuid: string;
exploreId: string;
metricQuery: MetricQueryResponse;
showTableNames: boolean;
columnOrder: string[];
customLabels?: CustomLabel;
hiddenFields?: string[];
pivotConfig?: PivotConfig;
}
/** Payload for uploading metrics to Google Sheets with task tracking */
type UploadMetricGsheetPayload = TraceTaskBase & UploadMetricGsheet;Types for the commenting and collaboration features on dashboards and charts.
/** A comment on a dashboard or chart with support for replies and mentions */
interface Comment {
commentId: string;
text: string;
textHtml: string;
createdAt: Date;
user: {
name: string;
};
replyTo: string | undefined;
replies?: Comment[];
resolved: boolean;
canRemove: boolean;
mentions: string[];
}Types for pinning dashboards, charts, and spaces to project home pages for quick access.
/**
* A pinned list that belongs to a project
*/
interface PinnedList {
/** UUID of the pinned list */
pinnedListUuid: string;
/** UUID of the project this list belongs to */
projectUuid: string;
}
/**
* An item pinned to a list
*/
interface PinnedItem {
/** UUID of the pinned item */
pinnedItemUuid: string;
/** UUID of the pinned list this item belongs to */
pinnedListUuid: string;
/** UUID of the saved chart (if this is a chart) */
savedChartUuid?: string;
/** UUID of the dashboard (if this is a dashboard) */
dashboardUuid?: string;
/** UUID of the space (if this is a space) */
spaceUuid?: string;
/** Timestamp when the item was pinned */
createdAt: Date;
}
/**
* A pinned list with its items
*/
interface PinnedListAndItems extends PinnedList {
/** Array of pinned items */
items: PinnedItem[];
}
/**
* Data required to pin a chart
*/
interface CreateChartPinnedItem {
/** UUID of the project */
projectUuid: string;
/** UUID of the chart to pin */
savedChartUuid: string;
}
/**
* Data required to pin a dashboard
*/
interface CreateDashboardPinnedItem {
/** UUID of the project */
projectUuid: string;
/** UUID of the dashboard to pin */
dashboardUuid: string;
}
/**
* Data required to pin a space
*/
interface CreateSpacePinnedItem {
/** UUID of the project */
projectUuid: string;
/** UUID of the space to pin */
spaceUuid: string;
}
/**
* Data required to delete a pinned chart
*/
interface DeleteChartPinnedItem {
/** UUID of the pinned list */
pinnedListUuid: string;
/** UUID of the chart to unpin */
savedChartUuid: string;
}
/**
* Data required to delete a pinned dashboard
*/
interface DeleteDashboardPinnedItem {
/** UUID of the pinned list */
pinnedListUuid: string;
/** UUID of the dashboard to unpin */
dashboardUuid: string;
}
/**
* Data required to delete a pinned space
*/
interface DeleteSpacePinnedItem {
/** UUID of the pinned list */
pinnedListUuid: string;
/** UUID of the space to unpin */
spaceUuid: string;
}
/**
* Union type for deleting any pinned item
*/
type DeletePinnedItem =
| DeleteChartPinnedItem
| DeleteDashboardPinnedItem
| DeleteSpacePinnedItem;
/**
* Union type for creating any pinned item
*/
type CreatePinnedItem =
| CreateChartPinnedItem
| CreateDashboardPinnedItem
| CreateSpacePinnedItem;
/**
* Data for updating the order of a pinned item
*/
interface UpdatePinnedItemOrder {
/** Type of the resource being reordered */
type: ResourceViewItemType;
/** Data containing uuid and pinnedListOrder */
data: Pick<ResourceViewItem['data'], 'uuid' | 'pinnedListOrder'>;
}
/**
* Type guard to check if item is a pinned chart
*/
function isCreateChartPinnedItem(
item: CreatePinnedItem
): item is CreateChartPinnedItem;
/**
* Type guard to check if delete target is a chart
*/
function isDeleteChartPinnedItem(
item: DeletePinnedItem
): item is DeleteChartPinnedItem;
/**
* Type guard to check if item is a pinned space
*/
function isCreateSpacePinnedItem(
item: CreatePinnedItem
): item is CreateSpacePinnedItem;
/**
* Type guard to check if delete target is a space
*/
function isDeleteSpacePinnedItem(
item: DeletePinnedItem
): item is DeleteSpacePinnedItem;
/**
* API response for pinned items
*/
interface ApiPinnedItems {
status: 'ok';
results: PinnedItems;
}
/**
* Array of pinned items with full resource details
*/
type PinnedItems = Array<
ResourceViewDashboardItem | ResourceViewChartItem | ResourceViewSpaceItem
>;
/**
* Information returned when toggling pin status
*/
interface TogglePinnedItemInfo {
/** UUID of the pinned list */
pinnedListUuid: string;
/** UUID of the project */
projectUuid: string;
/** UUID of the space */
spaceUuid: string;
/** Whether the item is currently pinned */
isPinned: boolean;
}
/**
* API response for toggling pin status
*/
interface ApiTogglePinnedItem {
status: 'ok';
results: TogglePinnedItemInfo;
}Types for the AI Agent system including agent configuration, threads, messages, tool calls, evaluations, and artifacts.
// Base Agent Types
interface BaseAiAgent {
uuid: string;
projectUuid: string;
organizationUuid: string;
name: string;
description: string | null;
imageUrl: string | null;
tags: string[] | null;
integrations: Array<{
type: 'slack';
channelId: string;
}>;
createdAt: Date;
updatedAt: Date;
instruction: string | null;
provider: string;
model: string;
groupAccess: string[];
userAccess: string[];
spaceAccess: string[];
enableDataAccess: boolean;
enableSelfImprovement: boolean;
enableReasoning: boolean;
version: number;
}
type AiAgent = Pick<
BaseAiAgent,
| 'uuid'
| 'projectUuid'
| 'organizationUuid'
| 'integrations'
| 'tags'
| 'name'
| 'description'
| 'createdAt'
| 'updatedAt'
| 'instruction'
| 'imageUrl'
| 'groupAccess'
| 'userAccess'
| 'spaceAccess'
| 'enableDataAccess'
| 'enableSelfImprovement'
| 'enableReasoning'
| 'version'
>;
type AiAgentSummary = Pick<
AiAgent,
| 'uuid'
| 'name'
| 'description'
| 'integrations'
| 'tags'
| 'projectUuid'
| 'organizationUuid'
| 'createdAt'
| 'updatedAt'
| 'instruction'
| 'imageUrl'
| 'groupAccess'
| 'userAccess'
| 'spaceAccess'
| 'enableDataAccess'
| 'enableSelfImprovement'
| 'enableReasoning'
| 'version'
>;
// Agent User and Message Types
interface AiAgentUser {
uuid: string;
name: string;
}
interface AiAgentMessageUser<TUser extends AiAgentUser = AiAgentUser> {
role: 'user';
uuid: string;
threadUuid: string;
message: string;
createdAt: string;
user: TUser;
}
interface AiAgentMessageAssistantArtifact {
artifactUuid: string;
versionNumber: number;
versionUuid: string;
title: string | null;
description: string | null;
artifactType: 'chart' | 'dashboard';
}
interface AiAgentMessageAssistant {
role: 'assistant';
status: 'idle' | 'pending' | 'error';
uuid: string;
threadUuid: string;
message: string | null;
createdAt: string;
humanScore: number | null;
humanFeedback?: string | null;
toolCalls: AiAgentToolCall[];
toolResults: AiAgentToolResult[];
reasoning: AiAgentReasoning[];
savedQueryUuid: string | null;
artifacts: AiAgentMessageAssistantArtifact[] | null;
referencedArtifacts: AiAgentMessageAssistantArtifact[] | null;
modelConfig: {
modelName: string;
modelProvider: string;
reasoning?: boolean;
} | null;
}
type AiAgentMessage<TUser extends AiAgentUser = AiAgentUser> =
| AiAgentMessageUser<TUser>
| AiAgentMessageAssistant;
// Thread Types
interface AiAgentThreadSummary<TUser extends AiAgentUser = AiAgentUser> {
uuid: string;
agentUuid: string;
createdAt: string;
createdFrom: string;
title: string | null;
titleGeneratedAt: string | null;
firstMessage: {
uuid: string;
message: string;
};
user: TUser;
}
type AiAgentThread<TUser extends AiAgentUser = AiAgentUser> = AiAgentThreadSummary<TUser> & {
messages: AiAgentMessage<TUser>[];
};
// Tool Call and Result Types
interface AiAgentToolCall {
uuid: string;
promptUuid: string;
toolCallId: string;
createdAt: Date;
toolName: string;
toolArgs: object;
}
type AiAgentToolResult = {
uuid: string;
promptUuid: string;
result: string;
createdAt: Date;
toolCallId: string;
} & (
| {
toolName: 'proposeChange';
metadata: object;
}
| {
toolName: string;
metadata: object;
}
);
interface AiAgentReasoning {
uuid: string;
promptUuid: string;
reasoningId: string;
text: string;
createdAt: Date;
}
// Artifact Types
interface AiArtifact {
artifactUuid: string;
threadUuid: string;
promptUuid: string | null;
artifactType: 'chart' | 'dashboard';
savedQueryUuid: string | null;
savedDashboardUuid: string | null;
createdAt: Date;
versionNumber: number;
versionUuid: string;
title: string | null;
description: string | null;
chartConfig: Record<string, unknown> | null;
dashboardConfig: Record<string, unknown> | null;
versionCreatedAt: Date;
verifiedByUserUuid: string | null;
verifiedAt: Date | null;
}
interface AiAgentVerifiedArtifact {
artifactUuid: string;
versionUuid: string;
artifactType: 'chart' | 'dashboard';
title: string | null;
description: string | null;
verifiedAt: Date;
verifiedBy: {
userUuid: string;
firstName: string;
lastName: string;
};
referenceCount: number;
threadUuid: string;
promptUuid: string | null;
}
// Evaluation Types
type AiAgentEvaluationPrompt = {
evalPromptUuid: string;
createdAt: Date;
} & (
| {
type: 'string';
prompt: string;
expectedResponse: string | null;
}
| {
type: 'thread';
promptUuid: string;
threadUuid: string;
expectedResponse: string | null;
}
);
interface AiAgentEvaluation {
evalUuid: string;
agentUuid: string;
title: string;
description: string | null;
createdAt: Date;
updatedAt: Date;
prompts: AiAgentEvaluationPrompt[];
}
interface AiAgentEvaluationSummary {
evalUuid: string;
agentUuid: string;
title: string;
description: string | null;
createdAt: Date;
updatedAt: Date;
}
interface AiAgentEvaluationRunSummary {
runUuid: string;
evalUuid: string;
status: 'pending' | 'running' | 'completed' | 'failed';
completedAt: Date | null;
createdAt: Date;
passedAssessments: number;
failedAssessments: number;
}
type AiAgentEvaluationRun = AiAgentEvaluationRunSummary & {
results: AiAgentEvaluationRunResult[];
};
interface AiAgentEvaluationRunResult {
resultUuid: string;
evalPromptUuid: string | null;
threadUuid: string | null;
status: 'pending' | 'running' | 'completed' | 'assessing' | 'failed';
errorMessage: string | null;
completedAt: Date | null;
createdAt: Date;
assessment: object | null;
prompt: string | null;
expectedResponse: string | null;
}
type CreateEvaluationPrompt =
| { prompt: string; expectedResponse: string | null }
| {
promptUuid: string;
threadUuid: string;
expectedResponse: string | null;
};
function isStringPrompt(
prompt: CreateEvaluationPrompt
): prompt is { prompt: string; expectedResponse: string | null };
function isThreadPrompt(
prompt: CreateEvaluationPrompt
): prompt is {
promptUuid: string;
threadUuid: string;
expectedResponse: string | null;
};
// Agent Configuration Types
interface AiAgentUserPreferences {
defaultAgentUuid: string;
}
interface AiModelOption {
name: string;
displayName: string;
description: string;
provider: string;
default: boolean;
supportsReasoning: boolean;
}
interface AiAgentExploreAccessSummary {
exploreName: string;
joinedTables: string[];
dimensions: string[];
metrics: string[];
}
interface AgentSummaryContext {
uuid: string;
projectUuid: string;
name: string;
description: string | null;
explores: string[];
verifiedQuestions: string[];
instruction: string | null;
}
type AiAgentWithContext = AiAgentSummary & {
context: AgentSummaryContext;
};
// API Request/Response Types
type ApiAiAgentResponse = ApiSuccess<AiAgent>;
type ApiAiAgentSummaryResponse = ApiSuccess<AiAgentSummary[]>;
type ApiCreateAiAgent = Pick<
AiAgent,
| 'projectUuid'
| 'integrations'
| 'tags'
| 'name'
| 'description'
| 'instruction'
| 'imageUrl'
| 'groupAccess'
| 'userAccess'
| 'spaceAccess'
| 'enableDataAccess'
| 'enableSelfImprovement'
| 'enableReasoning'
| 'version'
>;
type ApiUpdateAiAgent = Partial<
Pick<
AiAgent,
| 'projectUuid'
| 'integrations'
| 'tags'
| 'name'
| 'description'
| 'instruction'
| 'imageUrl'
| 'groupAccess'
| 'userAccess'
| 'spaceAccess'
| 'enableDataAccess'
| 'enableSelfImprovement'
| 'enableReasoning'
| 'version'
>
> & {
uuid: string;
};
type ApiCreateAiAgentResponse = ApiSuccess<AiAgent>;
type ApiAiAgentThreadSummaryListResponse = ApiSuccess<AiAgentThreadSummary[]>;
type ApiAiAgentThreadResponse = ApiSuccess<AiAgentThread>;
interface ApiAiAgentThreadCreateRequest {
prompt?: string;
modelConfig?: {
modelName: string;
modelProvider: string;
reasoning?: boolean;
};
}
type ApiAiAgentThreadCreateResponse = ApiSuccess<AiAgentThreadSummary>;
interface ApiAiAgentThreadMessageCreateRequest {
prompt: string;
modelConfig?: {
modelName: string;
modelProvider: string;
reasoning?: boolean;
};
}
type ApiAiAgentThreadMessageCreateResponse = ApiSuccess<
AiAgentMessageUser<AiAgentUser>
>;
interface ApiAiAgentStartThreadResponse {
status: 'ok';
results: {
jobId: string;
threadUuid: string;
};
}
interface ApiAiAgentThreadGenerateResponse {
status: 'ok';
results: {
response: string;
};
}
interface ApiAiAgentThreadGenerateTitleResponse {
status: 'ok';
results: {
title: string;
};
}
interface ApiAiAgentThreadMessageViz {
type: string;
metricQuery: object;
chartOptions?: object;
results: {
rows: Record<string, unknown>[];
cacheMetadata: object;
fields: object;
};
}
type ApiAiAgentThreadMessageVizResponse = ApiSuccess<ApiAiAgentThreadMessageViz>;
type ApiAiAgentThreadMessageVizQueryResponse = ApiSuccess<object>;
type ApiGetUserAgentPreferencesResponse =
| ApiSuccess<AiAgentUserPreferences>
| ApiSuccessEmpty;
type ApiUpdateUserAgentPreferences = AiAgentUserPreferences;
type ApiUpdateUserAgentPreferencesResponse = ApiSuccessEmpty;
type ApiAiAgentExploreAccessSummaryResponse = ApiSuccess<
AiAgentExploreAccessSummary[]
>;
type ApiAiAgentArtifactResponse = ApiSuccess<AiArtifact>;
type ApiAiAgentVerifiedArtifactsResponse = ApiSuccess<object>;
type ApiAiAgentVerifiedQuestionsResponse = ApiSuccess<
{ question: string; uuid: string }[]
>;
// Evaluation API Types
interface ApiCreateEvaluationRequest {
title: string;
description?: string;
prompts: CreateEvaluationPrompt[];
}
interface ApiUpdateEvaluationRequest {
title?: string;
description?: string;
prompts?: CreateEvaluationPrompt[];
}
interface ApiAppendEvaluationRequest {
prompts: CreateEvaluationPrompt[];
}
type ApiAiAgentEvaluationSummaryListResponse = ApiSuccess<
AiAgentEvaluationSummary[]
>;
type ApiAiAgentEvaluationResponse = ApiSuccess<AiAgentEvaluation>;
type ApiAiAgentEvaluationRunResponse = ApiSuccess<AiAgentEvaluationRunSummary>;
type ApiAiAgentEvaluationRunSummaryListResponse = ApiSuccess<object>;
type ApiAiAgentEvaluationRunResultsResponse = ApiSuccess<AiAgentEvaluationRun>;
type ApiCreateEvaluationResponse = ApiSuccess<
Pick<AiAgentEvaluation, 'evalUuid'>
>;
type ApiUpdateEvaluationResponse = ApiSuccess<AiAgentEvaluation>;
type ApiCloneThreadResponse = ApiSuccess<AiAgentThreadSummary>;
interface ApiAppendInstructionRequest {
instruction: string;
}
interface ApiAppendInstructionResponse {
status: 'ok';
results: {
updatedInstruction: string;
};
}
interface ApiRevertChangeRequest {
changeUuid: string;
}
type ApiRevertChangeResponse = ApiSuccessEmpty;
type ApiAiAgentModelOptionsResponse = ApiSuccess<AiModelOption[]>;Types for unified resource views displaying charts, dashboards, and spaces in lists with metadata.
import { type ContentType as ResourceViewItemType } from '@lightdash/common';
/** Export ContentType as ResourceViewItemType for resource views */
export { ResourceViewItemType };
/**
* Category classification for resources in views
*/
enum ResourceItemCategory {
MOST_POPULAR = 'mostPopular',
RECENTLY_UPDATED = 'recentlyUpdated',
PINNED = 'pinned',
}
/**
* Resource view item for a chart with summary details
*/
interface ResourceViewChartItem {
type: ResourceViewItemType.CHART;
data: Pick<
SpaceQuery,
| 'uuid'
| 'name'
| 'chartType'
| 'chartKind'
| 'firstViewedAt'
| 'views'
| 'pinnedListUuid'
| 'pinnedListOrder'
| 'spaceUuid'
| 'description'
| 'updatedAt'
| 'updatedByUser'
| 'validationErrors'
| 'slug'
> & { source?: ChartSourceType };
category?: ResourceItemCategory;
}
/**
* Resource view item for a dashboard with summary details
*/
interface ResourceViewDashboardItem {
type: ResourceViewItemType.DASHBOARD;
data: Pick<
DashboardBasicDetails,
| 'uuid'
| 'spaceUuid'
| 'description'
| 'name'
| 'views'
| 'firstViewedAt'
| 'pinnedListUuid'
| 'pinnedListOrder'
| 'updatedAt'
| 'updatedByUser'
| 'validationErrors'
>;
category?: ResourceItemCategory;
}
/**
* Resource view item for a space with summary details
*/
interface ResourceViewSpaceItem {
type: ResourceViewItemType.SPACE;
data: Pick<
Space,
| 'projectUuid'
| 'uuid'
| 'name'
| 'isPrivate'
| 'pinnedListUuid'
| 'pinnedListOrder'
| 'organizationUuid'
| 'parentSpaceUuid'
| 'path'
> & {
/** User UUIDs with access */
access: string[];
/** Total number of users with access */
accessListLength: number;
/** Number of dashboards in the space */
dashboardCount: number;
/** Number of charts in the space */
chartCount: number;
};
}
/**
* Union type for any resource view item
*/
type ResourceViewItem =
| ResourceViewChartItem
| ResourceViewDashboardItem
| ResourceViewSpaceItem;
/**
* Type guard for chart resource items
*/
function isResourceViewItemChart(
item: ResourceViewItem
): item is ResourceViewChartItem;
/**
* Type guard for dashboard resource items
*/
function isResourceViewItemDashboard(
item: ResourceViewItem
): item is ResourceViewDashboardItem;
/**
* Type guard for space resource items
*/
function isResourceViewSpaceItem(
item: ResourceViewItem
): item is ResourceViewSpaceItem;
/**
* Wrap a resource object in a ResourceViewItem
* @param resource - The resource data
* @param type - The resource type
* @returns Wrapped resource view item
*/
function wrapResource<T>(
resource: T,
type: ResourceViewItemType
): ResourceViewItem;
/**
* Wrap multiple resources in ResourceViewItems
* @param resources - Array of resource data
* @param type - The resource type
* @returns Array of wrapped resource view items
*/
function wrapResourceView(
resources: any[],
type: ResourceViewItemType
): ResourceViewItem[];
/**
* Convert a SpaceSummary to ResourceViewSpaceItem data
*/
function spaceToResourceViewItem(
space: SpaceSummary
): ResourceViewSpaceItem['data'];
/**
* Convert SummaryContent to a ResourceViewItem
*/
function contentToResourceViewItem(content: SummaryContent): ResourceViewItem;
/**
* Extract the data from a ResourceViewItem
*/
function resourceToContent(resource: ResourceViewItem): any;
/**
* Type for most popular and recently updated resources
*/
interface MostPopularAndRecentlyUpdated {
mostPopular: (DashboardBasicDetails | SpaceQuery)[];
recentlyUpdated: (DashboardBasicDetails | SpaceQuery)[];
}Usage Example:
import {
type ResourceViewItem,
type ResourceViewChartItem,
isResourceViewItemChart,
wrapResource,
ResourceViewItemType,
} from '@lightdash/common';
// Wrap a chart in a resource view item
const chartItem: ResourceViewChartItem = wrapResource(
chartData,
ResourceViewItemType.CHART
);
// Type-safe handling of resource items
function handleResource(item: ResourceViewItem) {
if (isResourceViewItemChart(item)) {
console.log(`Chart: ${item.data.name}`);
console.log(`Views: ${item.data.views}`);
console.log(`Chart type: ${item.data.chartType}`);
} else if (isResourceViewItemDashboard(item)) {
console.log(`Dashboard: ${item.data.name}`);
} else {
console.log(`Space: ${item.data.name}`);
console.log(`Contains ${item.data.chartCount} charts`);
}
}
// Display resources by category
function displayResourcesByCategory(items: ResourceViewItem[]) {
const pinned = items.filter(item => item.category === 'pinned');
const popular = items.filter(item => item.category === 'mostPopular');
const recent = items.filter(item => item.category === 'recentlyUpdated');
console.log(`Pinned: ${pinned.length}`);
console.log(`Most Popular: ${popular.length}`);
console.log(`Recently Updated: ${recent.length}`);
}Types for configuring the Spotlight metrics table column visibility.
/**
* Available columns in the Spotlight metrics table
* These must match the keys of CatalogField type
*/
enum SpotlightTableColumns {
METRIC = 'label',
TABLE = 'tableLabel',
DESCRIPTION = 'description',
CATEGORIES = 'categories',
CHART_USAGE = 'chartUsage',
}
/**
* Configuration for a single Spotlight table column
*/
type ColumnConfig = Array<{
column: SpotlightTableColumns;
isVisible: boolean;
}>;
/**
* Spotlight table configuration for a project
*/
interface SpotlightTableConfig {
/** UUID of the configuration */
spotlightTableConfigUuid: string;
/** UUID of the project this config belongs to */
projectUuid: string;
/** Column visibility configuration */
columnConfig: ColumnConfig;
}
/**
* Default column configuration for Spotlight tables
* METRIC: visible, TABLE: hidden, DESCRIPTION: visible,
* CATEGORIES: visible, CHART_USAGE: visible
*/
const DEFAULT_SPOTLIGHT_TABLE_COLUMN_CONFIG: ColumnConfig = [
{ column: SpotlightTableColumns.METRIC, isVisible: true },
{ column: SpotlightTableColumns.TABLE, isVisible: false },
{ column: SpotlightTableColumns.DESCRIPTION, isVisible: true },
{ column: SpotlightTableColumns.CATEGORIES, isVisible: true },
{ column: SpotlightTableColumns.CHART_USAGE, isVisible: true },
];Usage Example:
import {
type SpotlightTableConfig,
SpotlightTableColumns,
DEFAULT_SPOTLIGHT_TABLE_COLUMN_CONFIG,
} from '@lightdash/common';
// Use default configuration
const defaultConfig = DEFAULT_SPOTLIGHT_TABLE_COLUMN_CONFIG;
// Create custom configuration
const customConfig: SpotlightTableConfig = {
spotlightTableConfigUuid: 'uuid-123',
projectUuid: 'project-456',
columnConfig: [
{ column: SpotlightTableColumns.METRIC, isVisible: true },
{ column: SpotlightTableColumns.TABLE, isVisible: true }, // Show table column
{ column: SpotlightTableColumns.DESCRIPTION, isVisible: true },
{ column: SpotlightTableColumns.CATEGORIES, isVisible: false }, // Hide categories
{ column: SpotlightTableColumns.CHART_USAGE, isVisible: true },
],
};
// Check which columns are visible
function getVisibleColumns(config: SpotlightTableConfig): SpotlightTableColumns[] {
return config.columnConfig
.filter(col => col.isVisible)
.map(col => col.column);
}Timezone support for date/time formatting and display across the Lightdash platform.
/**
* Supported timezone values for date/time display
* Covers major timezones across all continents
*/
enum TimeZone {
'UTC' = 'UTC',
// Americas - Pacific
'Pacific/Pago_Pago' = 'Pacific/Pago_Pago',
'Pacific/Honolulu' = 'Pacific/Honolulu',
'America/Anchorage' = 'America/Anchorage',
'America/Los_Angeles' = 'America/Los_Angeles',
'America/Denver' = 'America/Denver',
'America/Chicago' = 'America/Chicago',
'America/New_York' = 'America/New_York',
// Americas - Atlantic & South
'America/Santo_Domingo' = 'America/Santo_Domingo',
'America/Buenos_Aires' = 'America/Buenos_Aires',
'America/Noronha' = 'America/Noronha',
'Atlantic/Cape_Verde' = 'Atlantic/Cape_Verde',
// Europe
'Europe/London' = 'Europe/London',
'Europe/Paris' = 'Europe/Paris',
'Europe/Athens' = 'Europe/Athens',
'Europe/Moscow' = 'Europe/Moscow',
// Asia
'Asia/Dubai' = 'Asia/Dubai',
'Asia/Karachi' = 'Asia/Karachi',
'Asia/Dhaka' = 'Asia/Dhaka',
'Asia/Bangkok' = 'Asia/Bangkok',
'Asia/Shanghai' = 'Asia/Shanghai',
'Asia/Tokyo' = 'Asia/Tokyo',
// Pacific
'Australia/Sydney' = 'Australia/Sydney',
'Pacific/Noumea' = 'Pacific/Noumea',
'Pacific/Auckland' = 'Pacific/Auckland',
'Pacific/Apia' = 'Pacific/Apia',
'Pacific/Kiritimati' = 'Pacific/Kiritimati',
}
/**
* Type guard to check if a string is a valid TimeZone value
*/
function isTimeZone(timezone: string): timezone is TimeZone;Usage Example:
import { TimeZone, isTimeZone } from '@lightdash/common';
// Use specific timezone
const userTimezone: TimeZone = TimeZone.UTC;
const australianTz: TimeZone = TimeZone['Australia/Sydney'];
const newYorkTz: TimeZone = TimeZone['America/New_York'];
// Validate timezone string
function setUserTimezone(tz: string): TimeZone {
if (isTimeZone(tz)) {
return tz;
}
throw new Error(`Invalid timezone: ${tz}`);
}
// Get all available timezones
const allTimezones = Object.values(TimeZone);
console.log(`Available timezones: ${allTimezones.length}`);Configuration for Slack workspace integration including AI features and channel mappings.
/**
* Slack workspace integration settings for an organization
* Includes OAuth scopes, notification channels, and AI feature consent
*/
type SlackSettings = {
/** UUID of the organization this Slack workspace is connected to */
organizationUuid: string;
/** Name of the Slack team/workspace */
slackTeamName: string;
/** Custom app name (optional override) */
appName?: string;
/** When this Slack connection was created */
createdAt: Date;
/** OAuth access token (sensitive - handle securely) */
token?: string;
/** OAuth scopes granted to the Lightdash app */
scopes: string[];
/** Default channel for sending notifications */
notificationChannel: string | undefined;
/** URL for the app's profile photo in Slack */
appProfilePhotoUrl: string | undefined;
/** Mapping of Slack channels to Lightdash projects */
slackChannelProjectMappings?: SlackChannelProjectMapping[];
/** Whether users have consented to AI thread access */
aiThreadAccessConsent?: boolean;
/** Whether all required OAuth scopes are granted */
hasRequiredScopes: boolean;
/** Whether AI features require explicit OAuth per user */
aiRequireOAuth?: boolean;
/** Channel ID for multi-agent AI conversations */
aiMultiAgentChannelId?: string;
};Usage Example:
import { type SlackSettings } from '@lightdash/common';
// Configure Slack integration
const slackConfig: SlackSettings = {
organizationUuid: 'org-uuid-123',
slackTeamName: 'Acme Corp',
appName: 'Lightdash',
createdAt: new Date(),
scopes: ['channels:read', 'chat:write', 'commands'],
notificationChannel: 'C01234567',
appProfilePhotoUrl: 'https://example.com/logo.png',
hasRequiredScopes: true,
aiThreadAccessConsent: true,
aiRequireOAuth: false,
};
// Check if AI features are enabled
function hasAiFeatures(settings: SlackSettings): boolean {
return (
settings.aiThreadAccessConsent === true &&
settings.hasRequiredScopes &&
!!settings.aiMultiAgentChannelId
);
}
// Validate required scopes
function validateSlackScopes(settings: SlackSettings): boolean {
const requiredScopes = ['channels:read', 'chat:write'];
return requiredScopes.every(scope => settings.scopes.includes(scope));
}Install with Tessl CLI
npx tessl i tessl/npm-lightdash--commondocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10
scenario-11
scenario-12
scenario-13
scenario-14
scenario-15
scenario-16
scenario-17
scenario-18
scenario-19
scenario-20