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
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"metadata": {
"description": "Claude skills for Dynamicweb 10 — organized by task domain, bundled by role.",
"version": "5.8.8"
"version": "5.8.9"
},
"plugins": [
{
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
All notable changes to the Dynamicweb Skills plugin are recorded here. The
`version` field in `.claude-plugin/marketplace.json` tracks these entries.

## [5.8.9]

- **`dw-demo-pim` `screen-authoring.md`: one layout, one tab per product type.** A tab whose editors the
product lacks is not rendered, so one `ProductEditScreen` layout with a tab per category shows each
product type its own tab. Unplaced editors go to the `IsCatchAll` group and vanish silently without one;
group names must be unique across the layout. Saves renumber `Order`, `ScreenLayoutDelete` cascades,
writes apply on the next load.
- **`dw-demo-pim` `screen-authoring.md`: query list presets render headers but blank cells.** Row data comes
from the user's own default `ProductListScreen` preset, not the query's `ListScreenViewPresetId`; give each
worklist user a default list preset covering every query column (platform defect, DW 10.29.6).
- **Translation worklist that opens side by side.** Query edit-screen languages plus *Open product in edit
mode* open Multi Edit; the hidden `ProductQueryListWidget` is added by system name and has product-aware
rows. Recipe in `dw-demo-pim` `localization.md`, widget row in `dw-pim-completeness` `rules-and-dashboards.md`.

## [5.8.8]

- **`dw-pim-completeness`: per-language completeness works with the "Completeness feature" flag on.**
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": 2,
"generatedAt": "2026-10-07T10:22:42.391Z",
"generatedAt": "2026-10-07T10:25:34.190Z",
"worksOn": {
"dw": {
"ring": "R1",
Expand Down
23 changes: 23 additions & 0 deletions skills/dw-demo-pim/references/localization.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,29 @@ The demo deltas on top of that sequence:
3. **Translate the hero products' name + short description.** Skip custom-field translation in a first pass; the fallback handles it.
4. This recipe fits between **Step 3 (languages)** and **Step 4 (manufacturers)** of [`canonical-setup-order.md`](canonical-setup-order.md); the first `EcomLanguage` row is set up there, additional languages follow this doc.

## Translation worklist that opens side by side

A translation dashboard whose rows open the product in the side-by-side language view is native, and
no widget setting carries it: the query does [dw 10.29.6].

1. **The query**: a translation-gap predicate (with the Completeness feature flag on, a per-language
`CompletionRule|<id> < 100` query; see
[`../../dw-pim-localization/SKILL.md`](../../dw-pim-localization/SKILL.md) "Per-language completeness"),
*Edit screen languages* set to every language to compare (MCP `editScreenLanguageIds`), an edit preset
(`editScreenViewPresetId`), and *Open product in edit mode* on.
2. When those languages resolve to more than one language the product has, a row click opens
`/Admin/UI/Products/MultiEdit?...&Type=MultiEditByQuery` with the languages side by side and the edit
preset applied. Any product-aware row inherits this from the query.
3. **The widget**: `Dynamicweb.Products.UI.Dashboard.Widgets.ProductQueryListWidget` renders the query's
rows as product list rows, so a click opens Multi Edit. It is `[AddInActive(false)]` and absent from
the Add widget picker, but `add_widgets_to_dashboards` with that system name (parameters `Query`,
`TitleField`, `HintField`, `RightField`) adds it and it renders. It cannot be re-added from the picker
once removed. `RepositoryGridWidget` rows are not product-aware and open the plain editor. A
`RepositoryCountWidget` tile opens the query list, whose rows then open Multi Edit.

Validate by clicking a widget row: the URL is `MultiEdit` with one model identifier per configured
language.

## Demo philosophy

PIM localization sells the "single product master, multiple market storefronts" story — high-leverage. But:
Expand Down
41 changes: 40 additions & 1 deletion skills/dw-demo-pim/references/screen-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
- [The entity chain](#the-entity-chain)
- [`ScreenType` is a fully-qualified .NET type name](#screentype-is-a-fully-qualified-net-type-name)
- [Three column grammars, and only the platform picker lists them](#three-column-grammars-and-only-the-platform-picker-lists-them)
- [One layout, one tab per product type, and the catch-all group](#one-layout-one-tab-per-product-type-and-the-catch-all-group)
- [Screen presets: create, audience, default](#screen-presets-create-audience-default)
- [Query list presets: headers render, cells come from the user's default](#query-list-presets-headers-render-cells-come-from-the-users-default)
- ["No tab strip" has two causes and one discriminator](#no-tab-strip-has-two-causes-and-one-discriminator)
- [Grid edit and Bulk update have no Management API surface](#grid-edit-and-bulk-update-have-no-management-api-surface)
- [Bulk update writes an EMPTY value when the dual list is untouched](#bulk-update-writes-an-empty-value-when-the-dual-list-is-untouched)
Expand Down Expand Up @@ -70,7 +72,9 @@ tab from the strip** with no error, no log line and no clue: 4 of 5 configured t
missing tab's 3 groups and 30 editors are all correct in the database, and deleting, recreating,
recycling and renaming all change nothing. Tabs that mix in at least one bare product property
survive and mask the problem. Diagnostic: **if a whole tab is missing from the strip while its rows
are correct, its editors are all unresolvable. Check the `CategoryFields|` prefix first.**
are correct, its editors are all unresolvable. Check the `CategoryFields|` prefix first.** The same rule drops a tab whose
correctly named editors the product simply does not carry, which is what makes per-product-type tabs
work (next section).

`ScreenPresetSave` has the same hole: it accepts any string in `ConfigurableColumns` and answers
`status: ok`, so a wrong column name is indistinguishable from a right one until the grid renders
Expand All @@ -93,6 +97,26 @@ the worklist grid rendering the named headers.

**Local installs only** for the `SELECT`: on a hosted install, the rendered worklist grid is the check.

## One layout, one tab per product type, and the catch-all group

`ScreenLayout` exists once per screen type, not per data model, yet one layout can still show each
product type its own editor [dw 10.29.6]. The edit screen builds every tab and group of the layout and
then places only the editors the product renders; a tab left with no editors is not rendered. So:

1. One `ProductEditScreen` layout, with **one tab per category**, its editors named
`CategoryFields|ProductCategory|<cat>|<field>`. A product shows the general tabs plus its own
category's tab; a variant shows only the tabs that hold variant-level fields.
2. **Always one group flagged `IsCatchAll`.** Editors not placed in any group land there. **With no
catch-all group they are dropped from the editor silently**: price, stock and SEO vanish.
3. **Group names unique across the whole layout.** Groups are identified by name (`screenType|tab|group`)
and the catch-all is found by group name across every tab.
4. Narrow further per worklist with an edit preset on the query; the preset filters the layout's editors
(see "No tab strip" below).

Tab, group and editor saves renumber `Order` from 1, so read the order back rather than writing gaps.
`ScreenLayoutDelete` cascades to tabs, groups and editors. Layout writes apply on the next screen load,
without a recycle.

## Screen presets: create, audience, default

**Sweep `ScreenPresetAccessUserRelation` before creating the first preset.** `ScreenPresetDelete` does
Expand All @@ -118,6 +142,21 @@ screen type's default untouched, and it leaves `ScreenPresetAccessUserRelation`
(the preset stays granted to the user). `ScreenPresetDelete` is not the alternative: it removes the
preset for everyone.

## Query list presets: headers render, cells come from the user's default

**A query's list preset renders its column headers, but the row cells come from the signed-in user's
own `ProductListScreen` preset** [dw 10.29.6]. The query's `ListScreenViewPresetId` (set by
`create_or_update_product_queries` or in Manage query) sets the headers. The row data is mapped earlier
by `MappingContextHelper.GetMappingContextForScreen`, which reads only the user's temporary or default
list preset (`GetUserSpecifiedOrDefault`) and ignores the query's. Every cell outside that preset is
blank: a nine-column worklist preset showed values only for Name, Number and Completeness, with workflow
state, manufacturer, translated names and every category column empty. This is a platform defect.

**Workaround: give each worklist user a default list preset that covers every column the query presets
use**, with `ScreenPresetSetAsDefault` on `ProductListScreen`. One `CustomFields|` column maps all custom
fields, but each `CategoryFields|` column must be listed on its own. Side effect: "All products" shows
that preset for the user. Read the result on a rendered worklist row, not on the headers.

## "No tab strip" has two causes and one discriminator

A product editor rendering two unlabelled cards (Identity, Classification) and **no tab strip** is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ A PIM governance dashboard lives or dies on the "click the count, land on the of
| `Dynamicweb.Application.UI.Dashboard.Widgets.RepositoryCountWidget` | **Yes** — clicking the count opens the filtered product list from the backing query | Per-rule / per-blocker counts |
| `Dynamicweb.Application.UI.Dashboard.Widgets.RepositoryGridWidget` | **Yes** — each row links to the product | "Offender list" surface — show the exact SKUs that are failing |
| `Dynamicweb.Application.UI.Dashboard.Widgets.RepositoryListWidget` | **Yes** | Title / hint pairs from a query |
| `Dynamicweb.Products.UI.Dashboard.Widgets.ProductQueryListWidget` | **Yes, product-aware**: a row click honours the query's edit languages and edit preset, so it can open the side-by-side Multi Edit view | Translation worklists. Hidden from the Add widget picker (`[AddInActive(false)]`); add it with `add_widgets_to_dashboards` by system name, parameters `Query`, `TitleField`, `HintField`, `RightField` [dw 10.29.6]. `RepositoryGridWidget` rows are not product-aware |
| `Dynamicweb.Application.UI.Dashboard.Widgets.RepositoryFacetWidget` | **Yes** — facet filters are clickable | Catalog-by-category breakdowns |
| `Dynamicweb.Products.UI.Dashboard.Widgets.LastChangedProductsWidget` | **Yes** | Recent edits |
| `Dynamicweb.Insights.UI.Dashboard.Widgets.ScalarSqlCountWidget` | **NO — dead end** | Avoid for governance dashboards. It renders a bare number with NO drill-through. Only use when there's no queryable surrogate (e.g. counting rows in a non-product table). |
Expand Down
Loading