Skip to content
Open
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
13 changes: 11 additions & 2 deletions src/lib/pushers/model-pusher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,19 @@ function modelTypeMatches(a: mgmtApi.Model, b: mgmtApi.Model): boolean {
return aType === bType;
}

/** Human-readable model kind for messages. 1 = content, 2 = component/module. */
/**
* Human-readable model kind for messages.
*
* PROD-2315: per the SDK's ContentDefinitionTypeID enum, 0 = List (a content model backing a
* container/content list — the common case) and 1 = SingleItem (a content model for a single
* item) are BOTH content models; only 2 = Component (module/component) is the other kind. This
* previously only recognized 1 as "content" and let 0 fall through to the internal `"type 0"`
* label — which fired on most real collisions, since list-backed content models (0) are far more
* common than single-item ones (1).
*/
function modelKindName(model: mgmtApi.Model): string {
const t = (model as any)?.contentDefinitionTypeID;
return t === 1 ? "content" : t === 2 ? "component/module" : `type ${t}`;
return t === 0 || t === 1 ? "content" : t === 2 ? "component/module" : `type ${t}`;
}

/**
Expand Down
18 changes: 18 additions & 0 deletions src/lib/pushers/tests/model-pusher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,24 @@ describe("pushModels — cross-kind reference-name collision (PROD-2315)", () =>
expect(result.failureDetails![0].error).toMatch(/content model with that reference name already exists/);
});

it("labels a List-type (contentDefinitionTypeID 0) collision as \"content\", not \"type 0\" (PROD-2315 wording)", async () => {
const saveModel = jest.fn();
jest.spyOn(stateModule, "getApiClient").mockReturnValue(makeApiClient(saveModel));

const { pushModels } = await import("../model-pusher");

// Source LinkCard is a List-backed content model (type 0) — the common case for real
// container-backed models — colliding with a component (type 2) on the target.
const sourceModel = makeModel({ referenceName: "LinkCard", contentDefinitionTypeID: 0 });
const targetModel = makeModel({ id: 504, referenceName: "LinkCard", contentDefinitionTypeID: 2 });

const result = await pushModels([sourceModel], [targetModel]);

expect(result.failureDetails).toHaveLength(1);
expect(result.failureDetails![0].error).toMatch(/is a content model on the source/);
expect(result.failureDetails![0].error).not.toMatch(/type 0/);
});

it("does NOT flag a same-name model when the kinds are unknown (falls back to adopt-by-reference)", async () => {
const saveModel = jest.fn();
jest.spyOn(stateModule, "getApiClient").mockReturnValue(makeApiClient(saveModel));
Expand Down
Loading