spiderly 19.10.0 → 19.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -205,6 +205,8 @@ new Column({ field: 'total', name: 'Total', filterType: 'numeric',
205
205
 
206
206
  It receives a `CellClickEvent` — `{ id, field, row, value, displayValue, element, originalEvent }`, where `value` is the raw cell value and `displayValue` is the formatted text shown. Only columns that set it become clickable (they get a `cursor`/hover affordance), and the click stops propagation so it does **not** also trigger `navigateOnRowClick`. Anchor overlays with `element` — it's the clicked `<td>`, captured synchronously, so it stays valid inside an async handler (`originalEvent.currentTarget` is null once dispatch ends). Not applied to editable cells. (Reusing one popover across rows is the `show()` + `align()` case shown in the snippet above — bare `show()` swaps content but won't move an already-open panel.)
207
207
 
208
+ Style the popover's content at your component's SCSS **top level**, never nested under `:host` — PrimeNG appends the open popover to `document.body`, where `:host`-scoped rules (compiled to `[_nghost] … [_ngcontent]` descendant selectors) silently stop matching; top-level rules keep the `[_ngcontent]` scoping that travels with the moved nodes.
209
+
208
210
  ### Custom Toolbar Actions
209
211
 
210
212
  Project an `<ng-template spiderlyDataTableActions>` to add your own buttons (or any markup) to the table's toolbar, alongside the built-in Clear Filters / Export to Excel / Reload / Delete Selected buttons. Import `SpiderlyDataTableActionsDirective` in the consuming component.
@@ -31,7 +31,12 @@ Follow Spiderly's fail-loudly convention: every refused-to-start condition exits
31
31
 
32
32
  > Working tree must be clean before upgrading. Commit or stash your changes first — the upgrade will make many edits, and a clean tree is your `git restore .` safety net.
33
33
 
34
- 4. **Detect current version.** Read all `Spiderly.*` `PackageReference` `Version=` values across every csproj, plus the `"spiderly"` value in `Frontend/package.json`. They should agree. If they drift, list the values and ask the user which to treat as "current".
34
+ 4. **Detect current version.** Versions live in one of two places — check for **Central Package Management first**:
35
+
36
+ - **CPM (`Directory.Packages.props` exists next to or above the csprojs):** versions are `<PackageVersion Include="Spiderly.X" Version="..." />` there, and the csprojs carry **versionless** `<PackageReference Include="Spiderly.X" />`. Reading `Version=` off the csprojs finds nothing — don't conclude "not a Spiderly app".
37
+ - **Classic:** `Version=` on each csproj's `PackageReference`.
38
+
39
+ Read whichever applies, plus the `"spiderly"` value in `Frontend/package.json`. They should agree. If they drift, list the values and ask the user which to treat as "current". Record which layout you found — Step 6 bumps the same place.
35
40
 
36
41
  5. **Multi-solution monorepo.** If multiple Backend dirs (each with their own Spiderly refs) exist, ask the user which one to upgrade. One app per invocation.
37
42
 
@@ -39,7 +44,7 @@ Follow Spiderly's fail-loudly convention: every refused-to-start condition exits
39
44
 
40
45
  - If arg is `latest` or omitted: WebFetch `https://api.nuget.org/v3-flatcontainer/spiderly.shared/index.json`, parse the `versions` array, pick the highest stable (no `-` suffix), confirm with the user.
41
46
  - Otherwise validate the arg as `X.Y.Z` (or `X.Y.Z-preview.N` if the user is explicitly opting into a preview — warn that preview release notes are usually thin).
42
- - Reject downgrades: if target < current, exit `Downgrades are not supported. To downgrade, edit Spiderly.* PackageReference Version= attributes and the "spiderly" npm dep manually, then run dotnet restore and npm install.`
47
+ - Reject downgrades: if target < current, exit `Downgrades are not supported. To downgrade, edit the Spiderly.* versions (Directory.Packages.props under CPM, otherwise the csproj PackageReference Version= attributes) and the "spiderly" npm dep manually, then run dotnet restore and npm install.`
43
48
  - Reject no-op: if target == current, exit `Already on {version}.`
44
49
 
45
50
  ## Step 3 — Fetch what changed
@@ -94,7 +99,7 @@ Code edits (N items affect you):
94
99
  Manual steps after upgrade:
95
100
  - <step the agent can't do for you>
96
101
 
97
- Version bumps: Spiderly.* 19.5.0 → 21.2.0 (4 csproj + Frontend/package.json[ + .claude/settings.json legacy-plugin removal])
102
+ Version bumps: Spiderly.* 19.5.0 → 21.2.0 (Directory.Packages.props | 4 csproj + Frontend/package.json[ + .claude/settings.json legacy-plugin removal])
98
103
 
99
104
  After approval: apply → bump → migrate guidance + config → restore + install (parallel) → build → agent-sync. Up to 2 build-fix retries on failure.
100
105
  ```
@@ -108,7 +113,19 @@ Present the plan and ask the user explicitly. Don't proceed without a clear yes.
108
113
  In this order. A failure at any step is a hard stop until the recovery procedure in Step 7.
109
114
 
110
115
  1. **Code edits.** Apply each plan item via Edit. Read each target file first.
111
- 2. **Version bumps.** Iterate the csproj list cached in Step 1: rewrite every `<PackageReference Include="Spiderly.X" Version="OLD" />` to the new version. Rewrite `"spiderly": "OLD"` in `Frontend/package.json`. Don't re-glob.
116
+ 2. **Version bumps.** Bump the layout detected in Step 1.4:
117
+
118
+ - **CPM:** rewrite each `<PackageVersion Include="Spiderly.X" Version="OLD" />` in `Directory.Packages.props`. The csprojs need no edit — that is the point of CPM, and adding a `Version=` there is an error (`NU1008`).
119
+ - **Classic:** iterate the csproj list cached in Step 1 and rewrite every `<PackageReference Include="Spiderly.X" Version="OLD" />`.
120
+
121
+ Then rewrite `"spiderly": "OLD"` in `Frontend/package.json`. Don't re-glob.
122
+
123
+ **If the app commits `packages.lock.json` files** (`RestorePackagesWithLockFile`), the restore in item 5 updates them — but only for the current OS's resolution graph. Apps whose CI restores in `--locked-mode` on linux must regenerate the locks under the **linux SDK image**, or a macOS-only regeneration ships a lock that CI rejects. Add it to the manual steps:
124
+
125
+ ```bash
126
+ docker run --rm -v "$PWD:/src" -v <cache-volume>:/root/.nuget/packages -w /src \
127
+ mcr.microsoft.com/dotnet/sdk:<version> dotnet restore <Solution>.sln --force
128
+ ```
112
129
  3. **Migrate agent guidance off the legacy plugin.** Spiderly's AI-agent guidance now ships *inside* the `spiderly` npm package (projected by `spiderly agent-sync` in item 7 below), replacing the old `spiderly@spiderly` Claude Code plugin. If `.claude/settings.json` contains `extraKnownMarketplaces.spiderly` and/or `enabledPlugins."spiderly@spiderly"`, remove just those keys (leave any other settings intact; delete the file only if it becomes an empty `{}`). No settings file or no spiderly entries → skip.
113
130
  4. **Migrate `spiderly.json` → `.spiderly/config.json`.** Recent Spiderly moved the generator/api config out of a root `spiderly.json` into `.spiderly/config.json`. If the app has a `spiderly.json` registered via `<AdditionalFiles Include="spiderly.json" />`, `git mv` it to `.spiderly/config.json` and rewrite that csproj line to `<AdditionalFiles Include=".spiderly/config.json" />`. No `spiderly.json` → skip.
114
131
  5. **Restore packages in parallel.** Same message, two Bash calls: `dotnet restore` in Backend and `npm install` in Frontend. They share no locks. If either fails, surface the actual error and exit.
@@ -5421,6 +5421,8 @@ const unauthorizedInterceptor = (req, next) => {
5421
5421
  if (!config.production) {
5422
5422
  console.error(err);
5423
5423
  }
5424
+ // TODO: type this as an ApiError interface (TS mirror of ApiErrorDTO, next to errors/api-error-codes.ts)
5425
+ // so message/errorCode/traceId reads of the cross-language contract are compile-checked, not conventional.
5424
5426
  let errorResponse = err.error;
5425
5427
  if (request.responseType !== 'json' && typeof err.error === 'string') {
5426
5428
  try {
@@ -5430,31 +5432,36 @@ const unauthorizedInterceptor = (req, next) => {
5430
5432
  errorResponse = null;
5431
5433
  }
5432
5434
  }
5435
+ // ApiErrorDTO.traceId is present only on reportable errors, so this is a no-op everywhere else —
5436
+ // the server decides which responses carry a support reference, never this status-code chain.
5437
+ const withReference = (detail) => errorResponse?.traceId
5438
+ ? `${detail} ${translocoService.translate('ErrorReference', { traceId: errorResponse.traceId })}`
5439
+ : detail;
5433
5440
  if (err.status === 0) {
5434
5441
  // Server unreachable; defer so the message isn't lost during a shutdown/refresh race.
5435
5442
  setTimeout(() => {
5436
- messageService.warningMessage(translocoService.translate('ServerLostConnectionDetails'), translocoService.translate('ServerLostConnectionTitle'));
5443
+ messageService.warningMessage(withReference(translocoService.translate('ServerLostConnectionDetails')), translocoService.translate('ServerLostConnectionTitle'));
5437
5444
  }, 100);
5438
5445
  }
5439
5446
  else if (err.status === 400) {
5440
- messageService.warningMessage(errorResponse?.message ?? translocoService.translate('BadRequestDetails'), translocoService.translate('Warning'));
5447
+ messageService.warningMessage(withReference(errorResponse?.message ?? translocoService.translate('BadRequestDetails')), translocoService.translate('Warning'));
5441
5448
  }
5442
5449
  else if (err.status === 401) {
5443
5450
  if (errorResponse?.errorCode === ApiErrorCodes.InvalidToken) {
5444
5451
  authService.clearSession(); // expired/invalid session — drop it; guards send the user to login
5445
5452
  }
5446
5453
  else {
5447
- messageService.warningMessage(errorResponse?.message ?? translocoService.translate('LoginRequired'), translocoService.translate('Warning'));
5454
+ messageService.warningMessage(withReference(errorResponse?.message ?? translocoService.translate('LoginRequired')), translocoService.translate('Warning'));
5448
5455
  }
5449
5456
  }
5450
5457
  else if (err.status === 403) {
5451
- messageService.warningMessage(translocoService.translate('PermissionErrorDetails'), translocoService.translate('PermissionErrorTitle'));
5458
+ messageService.warningMessage(withReference(translocoService.translate('PermissionErrorDetails')), translocoService.translate('PermissionErrorTitle'));
5452
5459
  }
5453
5460
  else if (err.status === 404) {
5454
- messageService.warningMessage(translocoService.translate('NotFoundDetails'), translocoService.translate('NotFoundTitle'));
5461
+ messageService.warningMessage(withReference(translocoService.translate('NotFoundDetails')), translocoService.translate('NotFoundTitle'));
5455
5462
  }
5456
5463
  else {
5457
- messageService.errorMessage(translocoService.translate('UnexpectedErrorDetails'), translocoService.translate('UnexpectedErrorTitle'));
5464
+ messageService.errorMessage(withReference(translocoService.translate('UnexpectedErrorDetails')), translocoService.translate('UnexpectedErrorTitle'));
5458
5465
  }
5459
5466
  };
5460
5467
  return next(req).pipe(catchError((err) => {