ivy-create-dashboard
Create a Dashboard app with metrics, charts, and KPIs for an Ivy project.
Pre-flight: Read Learnings
If the file .ivy/learnings/ivy-create-dashboard.md exists in the project directory, read it first and apply any lessons learned from previous runs of this skill.
Reference Files
Read these before implementing:
- references/AGENTS.md -- Ivy framework API reference (widgets, hooks, layouts, inputs, colors)
- references/DashboardApp.cs -- app structure with HeaderLayout, date range selector, grid layout
- references/TotalSalesMetricView.cs -- MetricView with trend and goal
- references/OrdersMetricView.cs -- MetricView with count aggregation
- references/CustomerRetentionRateMetricView.cs -- MetricView with rate calculation
- references/SalesByDayLineChartView.cs -- line chart pattern (daily granularity)
- references/OrdersByChannelPieChartView.cs -- pie chart pattern
- references/SalesByCategoryBarChartView.cs -- bar chart pattern
- references/SalesByStoreTypeAreaChartView.cs -- area chart pattern
Workflow
This skill guides you through creating a complete dashboard application:
- Plan - Analyze the data models and propose metrics + charts
- Review - Present the plan for user approval (accept / request changes / cancel)
- Implement - Generate all dashboard files following reference patterns
Step 1: Plan the Dashboard
If the user has specified a database connection, read the connection context using ivy cli explain connections/{ConnectionName}. If not, ask the user which connection to use.
Analyze the data models and suggest approximately 6 metrics (numeric KPIs) and 6 charts.
Metric Guidelines
- At least one metric should be a "North Star Metric" - the single most important KPI capturing core value
- All metrics must be numerical (not categorical). Avoid metrics better represented as charts (e.g., "Sales by Region")
- The dashboard automatically compares metrics with the previous period - factor this into calculation descriptions
Chart Guidelines
- Prefer Line charts unless another type clearly fits better
- Line chart granularity should be daily
- Verify all data models and fields exist before suggesting metrics/charts
Plan Format
Present the plan using this markdown structure:
# Dashboard Plan
**Connection**: `{ConnectionName}`
**Icon**: `LayoutDashboard`
## Metrics
### Metric: [Title]
**Icon**: `[LucideIcon]`
**File**: `Apps/Dashboard/[ClassName]MetricView.cs`
**Namespace**: `{ProjectNamespace}.Apps.Dashboard`
**Calculation**: `[description of how to calculate, including comparison to previous period]`
## Charts
### Chart: [Title] ([ChartType])
**File**: `Apps/Dashboard/[ClassName][ChartType]ChartView.cs`
**Namespace**: `{ProjectNamespace}.Apps.Dashboard`
**Calculation**: `[description including dimensions and measures]`
Chrome Decision
- If the dashboard is the only app in the project and no multi-app navigation is needed, add a
### Update Program.cs section that replaces server.UseAppShell(...) with server.UseDefaultApp(typeof(DashboardApp));.
- If the project has multiple apps or the user explicitly wants sidebar navigation, add a
### Update Program.cs section that ensures server.UseAppShell(...) is present.
Present the plan to the user and ask them to Accept, Request Changes, or Cancel.
Step 2: Handle Changes
If the user requests changes, apply them to the plan and present the updated plan again.
Step 3: Implement
Once approved, implement all dashboard files following the reference patterns exactly.
Project Structure
Apps/
DashboardApp.cs # Namespace: {ProjectNamespace}.Apps
Dashboard/
{ClassName}MetricView.cs # Namespace: {ProjectNamespace}.Apps.Dashboard
{ClassName}{ChartType}ChartView.cs # Namespace: {ProjectNamespace}.Apps.Dashboard
Required Using Directives
Every generated .cs file must include explicit using statements. Do NOT rely on global usings.
Connection usings:
using {ProjectNamespace}.Connections.{ConnectionName}; -- for context factory
using {ProjectNamespace}.Connections.{ConnectionName}.Models; -- for entity classes (only if the project uses a Models subfolder; check the connection context)
using Microsoft.EntityFrameworkCore; -- for ToListAsync, SumAsync, CountAsync, etc.
Dashboard app: Ivy, Ivy.Apps, Ivy.Core.Hooks, Ivy.Hooks, Ivy.Shared, Ivy.Views, Ivy.Views.Dashboards
Metric views: Ivy, Ivy.Core.Hooks, Ivy.Hooks, Ivy.Shared, Ivy.Views, Ivy.Views.Dashboards
Chart views: Ivy, Ivy.Core.Hooks, Ivy.Hooks, Ivy.Shared, Ivy.Views, Ivy.Views.Charts
Program.cs Chrome Configuration
Check if the approved plan includes a ### Update Program.cs section. If it does:
- If it specifies
UseDefaultApp: Open Program.cs and replace the server.UseAppShell(...) line with server.UseDefaultApp(typeof(DashboardApp));. Remove the UseAppShell line entirely. Do NOT keep both.
- If it specifies
UseAppShell: Ensure server.UseAppShell(...) is present in Program.cs.
- Follow the approved plan exactly.
Implementation Instructions
- Read the reference files listed above for exact code patterns.
- Create
Apps/DashboardApp.cs:
- Namespace:
{ProjectNamespace}.Apps
- Using:
{ProjectNamespace}.Apps.Dashboard
- Attribute:
[App(icon: Icons.LayoutDashboard, group: ["Apps"])]
- Follow the DashboardApp reference exactly (date range selector, grid layout, HeaderLayout, etc.)
- For each metric in the plan, create
Apps/Dashboard/{ClassName}.cs:
- Namespace:
{ProjectNamespace}.Apps.Dashboard
- Follow the metric reference patterns (MetricView, UseQuery, trend calculation, goals)
- Constructor:
(DateTime fromDate, DateTime toDate)
- For each chart in the plan, create
Apps/Dashboard/{ClassName}.cs:
- Namespace:
{ProjectNamespace}.Apps.Dashboard
- Follow the chart reference patterns for the specific chart type
- Constructor:
(DateTime fromDate, DateTime toDate)
- Use the correct ContextFactory name based on the connection.
- Keep all numbers as double to avoid conversion issues.
- After writing all files, summarize what was created.
Common Pitfalls
These are critical rules for generating correct dashboard code:
EF Core Limitations
- Do NOT use
Split(), Join(), Reverse(), Last(), LastOrDefault(), or custom methods in LINQ queries - they cannot be translated to SQL.
- Use
Substring() and IndexOf() instead of Split() and Last().
- IMPORTANT: Never use positional record constructors (
new ChartData(...)) inside EF Core LINQ expressions (.Select(), .GroupBy().Select(), etc.). EF Core/SQLite cannot translate them to SQL. Instead:
- Use anonymous types in the server-side query:
.Select(x => new { x.Name, Total = x.Sum(...) })
- Materialize with
.ToArrayAsync() / .ToListAsync()
- Project to record types client-side:
raw.Select(x => new ChartData(x.Name, x.Total)).ToArray()
Nullable Types
DateTime? does not have .Date - use .Value.Date or filter nulls with .Where(x => x.Date.HasValue) first.
- For
UseState with nullable types, use explicit cast: (object?)null, not just null.
- Call
.Value.ToString("N2") on nullable types, not .ToString("N2") directly.
- Only use null-coalescing
?? with actually nullable types.
GroupBy
- Always use named types (not anonymous types) when using GroupBy followed by aggregation.
Aggregation
- Chart measures MUST use aggregation functions (
.Sum(), .Count(), .Average()), never direct property access - even on pre-aggregated data.
- Check
.Any() before calling .Average() to avoid exceptions on empty collections.
Include() navigation properties before referencing foreign key relationships.
Junction Tables
- Junction/bridge tables often lack
CreatedAt/UpdatedAt fields. Verify before filtering by date - use related entity timestamps instead.
Status Fields
- Always verify the actual type of status ID fields (
int, int?, string) before comparisons.
- Use actual database seed values, not undefined constants.
Date Fields
- Check entity definitions to determine if date fields are
DateTime or string. If string, use DateTime.Parse().
ViewBase Inheritance
- All metric and chart view classes MUST extend
ViewBase and use public override object? Build().
- Plain classes without
: ViewBase will render as their ToString() output when used with the | layout operator.
Post-run: Evaluate and Improve
After completing the task:
- Evaluate: Did the build succeed? Were there compilation errors, unexpected behavior, or manual corrections needed during this run?
- Update learnings: If anything required correction or was surprising, append a concise entry to
.ivy/learnings/ivy-create-dashboard.md (create the file and .ivy/learnings/ directory if they don't exist). Each entry should note: the date, what went wrong, why, and what to do differently next time.
- Skip if clean: If everything succeeded without issues, do not update the learnings file.
1---2name: ivy-create-dashboard3description: Create a Dashboard app with metrics, charts, and KPIs for an Ivy project. Use when the user asks for a dashboard, analytics page, KPI view, reporting view, data visualization app, or metrics overview. Handles MetricView cards, line charts, bar charts, pie charts, area charts, date range filtering, and grid layouts.4---56# ivy-create-dashboard78Create a Dashboard app with metrics, charts, and KPIs for an Ivy project.910## Pre-flight: Read Learnings1112If the file `.ivy/learnings/ivy-create-dashboard.md` exists in the project directory, read it first and apply any lessons learned from previous runs of this skill.1314## Reference Files1516Read these before implementing:17- [references/AGENTS.md](references/AGENTS.md) -- Ivy framework API reference (widgets, hooks, layouts, inputs, colors)18- [references/DashboardApp.cs](references/DashboardApp.cs) -- app structure with HeaderLayout, date range selector, grid layout19- [references/TotalSalesMetricView.cs](references/TotalSalesMetricView.cs) -- MetricView with trend and goal20- [references/OrdersMetricView.cs](references/OrdersMetricView.cs) -- MetricView with count aggregation21- [references/CustomerRetentionRateMetricView.cs](references/CustomerRetentionRateMetricView.cs) -- MetricView with rate calculation22- [references/SalesByDayLineChartView.cs](references/SalesByDayLineChartView.cs) -- line chart pattern (daily granularity)23- [references/OrdersByChannelPieChartView.cs](references/OrdersByChannelPieChartView.cs) -- pie chart pattern24- [references/SalesByCategoryBarChartView.cs](references/SalesByCategoryBarChartView.cs) -- bar chart pattern25- [references/SalesByStoreTypeAreaChartView.cs](references/SalesByStoreTypeAreaChartView.cs) -- area chart pattern2627## Workflow2829This skill guides you through creating a complete dashboard application:30311. **Plan** - Analyze the data models and propose metrics + charts322. **Review** - Present the plan for user approval (accept / request changes / cancel)333. **Implement** - Generate all dashboard files following reference patterns3435## Step 1: Plan the Dashboard3637If the user has specified a database connection, read the connection context using `ivy cli explain connections/{ConnectionName}`. If not, ask the user which connection to use.3839Analyze the data models and suggest approximately 6 metrics (numeric KPIs) and 6 charts.4041### Metric Guidelines42- At least one metric should be a "North Star Metric" - the single most important KPI capturing core value43- All metrics must be numerical (not categorical). Avoid metrics better represented as charts (e.g., "Sales by Region")44- The dashboard automatically compares metrics with the previous period - factor this into calculation descriptions4546### Chart Guidelines47- Prefer Line charts unless another type clearly fits better48- Line chart granularity should be daily49- Verify all data models and fields exist before suggesting metrics/charts5051### Plan Format5253Present the plan using this markdown structure:5455```56# Dashboard Plan5758**Connection**: `{ConnectionName}`59**Icon**: `LayoutDashboard`6061## Metrics6263### Metric: [Title]6465**Icon**: `[LucideIcon]`66**File**: `Apps/Dashboard/[ClassName]MetricView.cs`67**Namespace**: `{ProjectNamespace}.Apps.Dashboard`68**Calculation**: `[description of how to calculate, including comparison to previous period]`6970## Charts7172### Chart: [Title] ([ChartType])7374**File**: `Apps/Dashboard/[ClassName][ChartType]ChartView.cs`75**Namespace**: `{ProjectNamespace}.Apps.Dashboard`76**Calculation**: `[description including dimensions and measures]`77```7879### Chrome Decision80- If the dashboard is the **only app** in the project and no multi-app navigation is needed, add a `### Update Program.cs` section that replaces `server.UseAppShell(...)` with `server.UseDefaultApp(typeof(DashboardApp));`.81- If the project has **multiple apps** or the user explicitly wants sidebar navigation, add a `### Update Program.cs` section that ensures `server.UseAppShell(...)` is present.8283Present the plan to the user and ask them to **Accept**, **Request Changes**, or **Cancel**.8485## Step 2: Handle Changes8687If the user requests changes, apply them to the plan and present the updated plan again.8889## Step 3: Implement9091Once approved, implement all dashboard files following the reference patterns exactly.9293### Project Structure9495```96Apps/97 DashboardApp.cs # Namespace: {ProjectNamespace}.Apps98 Dashboard/99 {ClassName}MetricView.cs # Namespace: {ProjectNamespace}.Apps.Dashboard100 {ClassName}{ChartType}ChartView.cs # Namespace: {ProjectNamespace}.Apps.Dashboard101```102103### Required Using Directives104105Every generated `.cs` file must include explicit `using` statements. Do NOT rely on global usings.106107**Connection usings:**108- `using {ProjectNamespace}.Connections.{ConnectionName};` -- for context factory109- `using {ProjectNamespace}.Connections.{ConnectionName}.Models;` -- for entity classes (only if the project uses a Models subfolder; check the connection context)110- `using Microsoft.EntityFrameworkCore;` -- for ToListAsync, SumAsync, CountAsync, etc.111112**Dashboard app:** `Ivy`, `Ivy.Apps`, `Ivy.Core.Hooks`, `Ivy.Hooks`, `Ivy.Shared`, `Ivy.Views`, `Ivy.Views.Dashboards`113**Metric views:** `Ivy`, `Ivy.Core.Hooks`, `Ivy.Hooks`, `Ivy.Shared`, `Ivy.Views`, `Ivy.Views.Dashboards`114**Chart views:** `Ivy`, `Ivy.Core.Hooks`, `Ivy.Hooks`, `Ivy.Shared`, `Ivy.Views`, `Ivy.Views.Charts`115116### Program.cs Chrome Configuration117118Check if the approved plan includes a `### Update Program.cs` section. If it does:119- If it specifies `UseDefaultApp`: Open `Program.cs` and replace the `server.UseAppShell(...)` line with `server.UseDefaultApp(typeof(DashboardApp));`. Remove the `UseAppShell` line entirely. Do NOT keep both.120- If it specifies `UseAppShell`: Ensure `server.UseAppShell(...)` is present in `Program.cs`.121- Follow the approved plan exactly.122123### Implementation Instructions1241251. Read the reference files listed above for exact code patterns.1262. Create `Apps/DashboardApp.cs`:127 - Namespace: `{ProjectNamespace}.Apps`128 - Using: `{ProjectNamespace}.Apps.Dashboard`129 - Attribute: `[App(icon: Icons.LayoutDashboard, group: ["Apps"])]`130 - Follow the DashboardApp reference exactly (date range selector, grid layout, HeaderLayout, etc.)1313. For each metric in the plan, create `Apps/Dashboard/{ClassName}.cs`:132 - Namespace: `{ProjectNamespace}.Apps.Dashboard`133 - Follow the metric reference patterns (MetricView, UseQuery, trend calculation, goals)134 - Constructor: `(DateTime fromDate, DateTime toDate)`1354. For each chart in the plan, create `Apps/Dashboard/{ClassName}.cs`:136 - Namespace: `{ProjectNamespace}.Apps.Dashboard`137 - Follow the chart reference patterns for the specific chart type138 - Constructor: `(DateTime fromDate, DateTime toDate)`1395. Use the correct ContextFactory name based on the connection.1406. Keep all numbers as double to avoid conversion issues.1417. After writing all files, summarize what was created.142143### Common Pitfalls144145These are critical rules for generating correct dashboard code:146147#### EF Core Limitations148- Do NOT use `Split()`, `Join()`, `Reverse()`, `Last()`, `LastOrDefault()`, or custom methods in LINQ queries - they cannot be translated to SQL.149- Use `Substring()` and `IndexOf()` instead of `Split()` and `Last()`.150- **IMPORTANT**: Never use positional record constructors (`new ChartData(...)`) inside EF Core LINQ expressions (`.Select()`, `.GroupBy().Select()`, etc.). EF Core/SQLite cannot translate them to SQL. Instead:151 1. Use anonymous types in the server-side query: `.Select(x => new { x.Name, Total = x.Sum(...) })`152 2. Materialize with `.ToArrayAsync()` / `.ToListAsync()`153 3. Project to record types client-side: `raw.Select(x => new ChartData(x.Name, x.Total)).ToArray()`154155#### Nullable Types156- `DateTime?` does not have `.Date` - use `.Value.Date` or filter nulls with `.Where(x => x.Date.HasValue)` first.157- For `UseState` with nullable types, use explicit cast: `(object?)null`, not just `null`.158- Call `.Value.ToString("N2")` on nullable types, not `.ToString("N2")` directly.159- Only use null-coalescing `??` with actually nullable types.160161#### GroupBy162- Always use **named types** (not anonymous types) when using GroupBy followed by aggregation.163164#### Aggregation165- Chart measures MUST use aggregation functions (`.Sum()`, `.Count()`, `.Average()`), never direct property access - even on pre-aggregated data.166- Check `.Any()` before calling `.Average()` to avoid exceptions on empty collections.167- `Include()` navigation properties before referencing foreign key relationships.168169#### Junction Tables170- Junction/bridge tables often lack `CreatedAt`/`UpdatedAt` fields. Verify before filtering by date - use related entity timestamps instead.171172#### Status Fields173- Always verify the actual type of status ID fields (`int`, `int?`, `string`) before comparisons.174- Use actual database seed values, not undefined constants.175176#### Date Fields177- Check entity definitions to determine if date fields are `DateTime` or `string`. If `string`, use `DateTime.Parse()`.178179#### ViewBase Inheritance180- **All metric and chart view classes MUST extend `ViewBase`** and use `public override object? Build()`.181- Plain classes without `: ViewBase` will render as their `ToString()` output when used with the `|` layout operator.182183## Post-run: Evaluate and Improve184185After completing the task:1861871. **Evaluate**: Did the build succeed? Were there compilation errors, unexpected behavior, or manual corrections needed during this run?1882. **Update learnings**: If anything required correction or was surprising, append a concise entry to `.ivy/learnings/ivy-create-dashboard.md` (create the file and `.ivy/learnings/` directory if they don't exist). Each entry should note: the date, what went wrong, why, and what to do differently next time.1893. **Skip if clean**: If everything succeeded without issues, do not update the learnings file.