ワンクリックで
migrate-grid
Migrate data grids from legacy MVC to Angular using neptune-grid and ag-Grid. Ensures complete column parity with legacy.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Migrate data grids from legacy MVC to Angular using neptune-grid and ag-Grid. Ensures complete column parity with legacy.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | migrate-grid |
| description | Migrate data grids from legacy MVC to Angular using neptune-grid and ag-Grid. Ensures complete column parity with legacy. |
| allowed-tools | ["Read","Glob","Grep","Edit","Write","Bash(dotnet build:*)","Bash(npm run gen-model:*)"] |
| argument-hint | <EntityName> <GridName> |
When the user invokes /migrate-grid <EntityName> <GridName>:
This skill guides the migration of data grids from legacy MVC views to Angular using the neptune-grid component, ensuring complete column parity with the legacy implementation.
First, thoroughly examine the legacy MVC grid:
Neptune.WebMvc/Views/{Entity}/Index.cshtmlNeptune.WebMvc/Views/{Entity}/Detail.cshtmlNeptune.WebMvc/Views/{Entity}/*Grid*.cshtmlNeptune.WebMvc/Views/Shared/*Grid*.cshtmlNote: Neptune's legacy grids use DhtmlxGrid. Look for grid initialization patterns in the views.
Create a column inventory table:
| # | Header | Field/Expression | Type | Link? | Filter? | Notes |
|---|---|---|---|---|---|---|
| 1 | Name | TreatmentBMPName | Text | Yes, to detail | Yes | - |
| 2 | Status | StatusName | Text | No | Dropdown | - |
| 3 | Date | CreatedDate | Date | No | Date range | Format: M/d/yyyy |
| 4 | Area (ac) | DelineationArea | Decimal | No | Number | 2 decimals |
| 5 | Actions | - | Actions | Yes | No | Edit, Delete |
{Entity}GridDto{Entity}{Context}GridDtoTreatmentBMPGridDto — main BMP gridProjectTreatmentBMPGridDto — BMPs on project detail page// In Neptune.Models/DataTransferObjects/{Entity}GridDto.cs
namespace Neptune.Models.DataTransferObjects;
public class EntityGridDto
{
// Primary key for row identification
public int EntityID { get; set; }
// Simple text fields
public string Name { get; set; }
public string Description { get; set; }
// Related entity names (denormalized for grid display)
public string? JurisdictionName { get; set; }
public string? StatusName { get; set; }
// Formatted/calculated fields
public decimal? TotalArea { get; set; }
public DateTime? CreatedDate { get; set; }
// Boolean fields
public bool IsActive { get; set; }
}
The AsGridDto() extension method is defined in Neptune.EFModels/Entities/Generated/ExtensionMethods/:
public static EntityGridDto AsGridDto(this Entity entity)
{
return new EntityGridDto
{
EntityID = entity.EntityID,
Name = entity.Name,
Description = entity.Description,
JurisdictionName = entity.StormwaterJurisdiction?.Organization?.OrganizationName,
StatusName = entity.Status?.StatusDisplayName,
TotalArea = entity.DelineationArea,
CreatedDate = entity.CreateDate,
IsActive = entity.IsActive ?? false
};
}
// In Neptune.EFModels/Entities/{PluralEntity}.cs
public static class Entities
{
public static List<EntityGridDto> ListAsGridDto(NeptuneDbContext dbContext)
{
return dbContext.Entities
.AsNoTracking()
.Include(x => x.StormwaterJurisdiction)
.ThenInclude(j => j.Organization)
.Include(x => x.Status)
.Select(x => x.AsGridDto())
.ToList();
}
// For filtered grids (e.g., entities for a specific parent)
public static List<EntityGridDto> ListByParentIDAsGridDto(
NeptuneDbContext dbContext, int parentID)
{
return dbContext.Entities
.AsNoTracking()
.Where(x => x.ParentID == parentID)
.Include(x => x.StormwaterJurisdiction)
.ThenInclude(j => j.Organization)
.Select(x => x.AsGridDto())
.ToList();
}
}
// In Neptune.API/Controllers/{Entity}Controller.cs
[HttpGet]
[UserViewFeature]
public ActionResult<List<EntityGridDto>> List()
{
var entities = Entities.ListAsGridDto(DbContext);
return Ok(entities);
}
// For child grids on parent detail pages
[HttpGet("{parentID}/entities")]
[UserViewFeature]
public ActionResult<List<EntityGridDto>> ListByParent([FromRoute] int parentID)
{
var entities = Entities.ListByParentIDAsGridDto(DbContext, parentID);
return Ok(entities);
}
import { AgGridHelper } from "src/app/shared/helpers/ag-grid-helper";
import { ColDef } from "ag-grid-community";
import { EntityGridDto } from "src/app/shared/generated/model/entity-grid-dto";
public columnDefs: ColDef<EntityGridDto>[] = [];
ngOnInit(): void {
this.columnDefs = this.createColumnDefs();
}
| Method | Use Case | Example |
|---|---|---|
createBasicColumnDef | Text, nested object fields | Name, Description |
createLinkColumnDef | Single link to another entity | BMP Name -> BMP Detail |
createMultiLinkColumnDef | Array of links | Tags, Programs |
createDateColumnDef | Dates with format | Created Date |
createDecimalColumnDef | Numbers with decimals | Area (2 decimal places) |
createCurrencyColumnDef | Money values | Amount ($X,XXX) |
createBooleanColumnDef | Yes/No values | Is Active |
createActionsColumnDef | Edit/Delete buttons | Row actions |
private createColumnDefs(): ColDef<EntityGridDto>[] {
return [
// Link column
AgGridHelper.createLinkColumnDef("Name", "Name", "EntityID", {
InRouterLink: "/entities/"
}),
// Basic text column
AgGridHelper.createBasicColumnDef("Jurisdiction", "JurisdictionName", {
CustomDropdownFilterField: "JurisdictionName"
}),
// Date column
AgGridHelper.createDateColumnDef("Start Date", "StartDate", "M/d/yyyy"),
// Decimal column
AgGridHelper.createDecimalColumnDef("Area (ac)", "TotalArea", {
MaxDecimalPlacesToDisplay: 2
}),
// Boolean column with dropdown filter
AgGridHelper.createBooleanColumnDef("Active", "IsActive", {
CustomDropdownFilterField: "IsActive",
}),
// Actions column
AgGridHelper.createActionsColumnDef((params) => ({
items: [
{
name: "Edit",
icon: "Edit",
callback: () => this.openEditModal(params.data)
},
{
name: "Delete",
icon: "Delete",
callback: () => this.confirmDelete(params.data)
}
]
}))
];
}
Always use CustomDropdownFilterField for columns with a fixed set of values:
| Column Type | Use Dropdown Filter? |
|---|---|
| Boolean (Yes/No) | Yes |
| Status/Stage | Yes |
| Type/Category | Yes |
| Linked entity name | Yes |
| Free-form text | No |
| Numbers | No |
| Dates | No |
Right-aligned columns (handled automatically by helper methods):
Left-aligned (default): text columns
<div class="card">
<div class="card-header"><span class="card-title">Entities</span></div>
<div class="card-body">
<neptune-grid
[rowData]="entities$ | async"
[columnDefs]="columnDefs"
[downloadFileName]="'entities'">
</neptune-grid>
</div>
</div>
<neptune-grid
[rowData]="entities$ | async"
[columnDefs]="columnDefs"
[height]="'400px'"
[downloadFileName]="'entities'">
</neptune-grid>
| Input | Type | Default | Description |
|---|---|---|---|
rowData | any[] | - | Grid data array |
columnDefs | ColDef[] | - | Column definitions |
height | string | '500px' | Grid height |
downloadFileName | string | 'grid-data' | CSV export filename |
hideDownloadButton | boolean | false | Hide CSV download button |
hideGlobalFilter | boolean | false | Hide search box |
sizeColumnsToFitGrid | boolean | false | Fit columns to grid width |
pagination | boolean | false | Enable pagination |
paginationPageSize | number | 100 | Rows per page |
public bmpColumnDefs: ColDef<TreatmentBMPGridDto>[] = [];
public projectColumnDefs: ColDef<ProjectGridDto>[] = [];
ngOnInit(): void {
this.bmpColumnDefs = this.createBMPColumnDefs();
this.projectColumnDefs = this.createProjectColumnDefs();
}
private refreshData$ = new Subject<void>();
this.entities$ = combineLatest([this.entityID$, this.refreshData$.pipe(startWith(undefined))]).pipe(
switchMap(([id]) => this.entityService.listByParent(id)),
shareReplay({ bufferSize: 1, refCount: true })
);
refreshGrid(): void {
this.refreshData$.next();
}
Before considering migration complete, verify:
AsGridDto)dotnet build Neptune.API to generate swagger.jsonnpm run gen-model to generate TypeScript modelsCreate or flesh out a Jira story with structured sections for POs, Devs, and Claude. Accepts an optional Jira key to update an existing card.
Export Water Quality Management Plans for one jurisdiction from the local Neptune database to an Esri File Geodatabase in native projection. Use when a client requests WQMP spatial data for a specific city/jurisdiction.
Extract rework items from a Jira card's Acceptance Criteria and produce a fix plan. Auto-detects issue key from branch or accepts one as argument.
Fetch a Jira card by key (e.g. NPT-100) and produce a detailed implementation plan. Use this when starting work on a new story.
Build the SQL Server DACPAC and scaffold EF Core entities. Run this after finishing all SQL schema edits in Neptune.Database/.
Add a scrollspy Table of Contents sidebar to a page component with signal-based scroll tracking.