CMS Adapter Reference
This document covers the mapping layer between the CMS document model and the WI rendering stack.
The CMS uses string-based blockCode and containerTypeCode identifiers;
the WI renderer uses ContentType and WiContainerType enums.
The adapter in projects/cms/master/contentviewer/cms-content-adapters.ts performs this translation.
Content always flows one direction: CMS → WI renderer.
grid_view Block Type Codes CmsBlock.blockCode
info
blockCode is a string constant stored in the CMS database on each CmsBlock row.
The adapter maps it to ContentType enum values used by ContentBlockRendererComponent.| blockCode | ContentType | Enum Value | contentRef format | Notes |
|---|---|---|---|---|
RICHTEXT | RichText | 0 | HTML string | propsJson.html |
IMAGE | Image | 1 | URL string | propsJson.url + optional caption |
VIDEO | Video | 2 | URL string | propsJson.url + loop + duration |
PDF | 3 | URL string | propsJson.url | |
CHECKLIST | Checklist | 4 | JSON array | propsJson.items[] |
WARNING | Warning | 5 | Level integer string | propsJson.level 1–3 |
DECISION | DecisionBranch | 6 | JSON array | propsJson.branches[] |
FILE | File | 7 | URL string | propsJson.url + label |
QRCODE | QRCode | 8 | Data string | propsJson.data to encode |
TABLE | DataTable | 9 | JSON object | propsJson.headers + rows |
BANNER | Banner | 10 | JSON object | propsJson.title, subtitle, bgColor |
view_quilt Container Type Codes CmsContainer.containerTypeCode
| containerTypeCode | WiContainerType | Enum Value | Zones | Zone name pattern |
|---|---|---|---|---|
SINGLE | Single | 0 | 1 zone | main |
TWOCOL | TwoColumn | 1 | 2 zones | left, right |
BANNER | Banner | 2 | 1 zone | banner |
ACCORDION | Accordion | 3 | N zones | section-1, section-2, … |
TAB | Tab | 4 | N zones | tab-1, tab-2, … |
Single
SINGLE
WiContainerType = 0
main
Two Column
TWOCOL
WiContainerType = 1
left
right
Banner
BANNER
WiContainerType = 2
banner
Accordion
ACCORDION
WiContainerType = 3
chevron_right section-1
chevron_right section-2
chevron_right section-3
section-N (dynamic)
Tab
TAB
WiContainerType = 4
TAB-1
TAB-2
+
active zone content
tab-N (dynamic)
data_object propsJson Schemas per Block Type
Each CmsBlock.propsJson is a JSON string. The adapter calls JSON.parse(block.propsJson) and maps fields to WiStepContent.
propsJson schema
{
"html": "<p>Content…</p>",
"plainText": "Content…"
}
Mapped to
contentRef ← propsJson.html
Write
From Library
Upload
Embed URL
propsJson schema
{
"url": "https://cdn…/img.jpg",
"caption": "Alt text",
"zoomRegion": {
"x": 0, "y": 0,
"w": 100, "h": 100
}
}
Mapped to
contentRef ← propsJson.url
Write
From Library
Upload
Embed URL
propsJson schema
{
"url": "https://cdn…/vid.mp4",
"caption": "Video caption",
"loopMedia": 0,
"displayDurationSecs": 0
}
Mapped to
contentRef ← propsJson.url · loopMedia and displayDurationSecs hoisted to block fields
Write
From Library
Upload
Embed URL
propsJson schema
{
"url": "https://cdn…/doc.pdf",
"caption": "Download PDF"
}
Mapped to
contentRef ← propsJson.url
Write
From Library
Upload
Embed URL
propsJson schema
{
"items": [
{
"id": "c1",
"label": "Verify PPE",
"checked": false,
"isOptional": false
}
]
}
Write
From Library
Upload
Embed URL
propsJson schema
{
"level": 2,
// 0=None 1=Caution 2=Warning 3=Danger
"message": "Optional extra message"
}
WarningLevel
0 = None
1 = Caution
2 = Warning
3 = Danger
Write
From Library
Upload
Embed URL
propsJson schema
{
"branches": [
{
"id": "b1",
"label": "Yes → proceed",
"description": "If condition met",
"targetStepId": 5
}
]
}
Write
From Library
Upload
Embed URL
propsJson schema
{
"url": "https://cdn…/file.xlsx",
"label": "Download Report",
"description": "Monthly summary"
}
Write
From Library
Upload
Embed URL
propsJson schema
{
"data": "https://forms.example.com/audit",
"size": "medium"
// size: "small" | "medium" | "large"
}
Mapped to
contentRef ← propsJson.data
Write
From Library
Upload
Embed URL
propsJson schema
{
"headers": ["Part", "Qty", "Unit"],
"rows": [
["Electrode", "5", "pcs"]
]
}
Write
From Library
Upload
Embed URL
propsJson schema
{
"title": "Section Title",
"subtitle": "Supporting text",
"bgColor": "#0f172a",
"bgImageUrl": ""
}
Write
From Library
Upload
Embed URL
code Adapter Code — cms-content-adapters.ts
folder_open
File location:
One-way dependency: CMS project → WI library (not the reverse).
projects/cms/master/contentviewer/cms-content-adapters.tsOne-way dependency: CMS project → WI library (not the reverse).
BLOCK_TYPE_MAP and CONTAINER_TYPE_MAP
TypeScript
import { ContentType, WiContainerType } from 'projects/wi/src/lib/models/wi.models'; export const BLOCK_TYPE_MAP: Record<string, ContentType> = { RICHTEXT: ContentType.RichText, // 0 IMAGE: ContentType.Image, // 1 VIDEO: ContentType.Video, // 2 PDF: ContentType.PDF, // 3 CHECKLIST:ContentType.Checklist, // 4 WARNING: ContentType.Warning, // 5 DECISION: ContentType.DecisionBranch, // 6 FILE: ContentType.File, // 7 QRCODE: ContentType.QRCode, // 8 TABLE: ContentType.DataTable, // 9 BANNER: ContentType.Banner, // 10 }; export const CONTAINER_TYPE_MAP: Record<string, WiContainerType> = { SINGLE: WiContainerType.Single, // 0 TWOCOL: WiContainerType.TwoColumn, // 1 BANNER: WiContainerType.Banner, // 2 ACCORDION: WiContainerType.Accordion, // 3 TAB: WiContainerType.Tab, // 4 };
cmsToContainers() function
TypeScript
export function cmsToContainers( cmsContainers: CmsContainer[] ): WiContainer[] { return cmsContainers.map((c, idx) => ({ wiContainerId: -(idx + 1), // negative = CMS-origin (read-only in WI) containerType: CONTAINER_TYPE_MAP[c.containerTypeCode] ?? WiContainerType.Single, containerLabel: c.label, slNo: idx + 1, blocks: c.blocks.map((b, bi) => mapBlock(b, bi)), })); } function mapBlock(b: CmsBlock, idx: number): WiStepContent { const props = JSON.parse(b.propsJson ?? '{}'); const contentType = BLOCK_TYPE_MAP[b.blockCode] ?? ContentType.RichText; const contentRef = resolveContentRef(contentType, props); return { wiStepContentId: -(idx + 1), wiStepId: 0, slNo: idx + 1, contentType, contentSource: ContentSource.CMS, // always CMS-sourced contentRef, mediaCaption: props.caption ?? '', displayDurationSecs: props.displayDurationSecs ?? 0, loopMedia: props.loopMedia ?? 0, zoneName: b.zoneName, blockInContainerPos: idx + 1, isActive: 1, }; } function resolveContentRef(type: ContentType, props: Record<string, unknown>): string { switch (type) { case ContentType.RichText: return (props.html as string) ?? ''; case ContentType.Warning: return String(props.level ?? 0); case ContentType.Checklist: case ContentType.DecisionBranch: case ContentType.DataTable: case ContentType.Banner: return JSON.stringify(props); case ContentType.QRCode: return (props.data as string) ?? ''; default: return (props.url as string) ?? ''; } }
schema CmsBlock & CmsContainer Interfaces
TypeScript
interface CmsBlock { cmsBlockId: number; blockCode: string; // RICHTEXT | IMAGE | VIDEO | … zoneName: string; // main | left | right | section-N | tab-N slNo: number; // sort order within zone propsJson: string; // JSON string; shape depends on blockCode sourceCode: string; // WRITE | LIBRARY | UPLOAD | URL cmsRefId: number | null; // FK to referenced CMS document (source=LIBRARY) isActive: 0 | 1; } interface CmsContainer { cmsContainerId: number; containerTypeCode: string; // SINGLE | TWOCOL | BANNER | ACCORDION | TAB label: string; // section heading slNo: number; blocks: CmsBlock[]; isActive: 0 | 1; } interface CmsDocument { cmsDocumentId: number; spaceCode: string; typeCode: string; title: string; statusCode: string; // DRAFT | REVIEW | APPROVED | PUBLISHED | ARCHIVED version: string; containers: CmsContainer[]; createdBy: number; createdDate: string; lastModifiedDate:string; }
table_chart ContentSource Matrix (CMS context)
info
In the CMS designer, sources are labelled differently from the WI designer:
Write = Inline · From Library = CMS · Upload = FileStore · Embed URL = ExternalURL
| Block Type | Write (Inline) | From Library (CMS) | Upload (FileStore) | Embed URL (External) |
|---|---|---|---|---|
| RichText | ✓ | ✓ | — | — |
| Image | ✓ | ✓ | ✓ | ✓ |
| Video | ✓ | ✓ | ✓ | ✓ |
| ✓ | ✓ | ✓ | ✓ | |
| Checklist | ✓ | ✓ | — | — |
| Warning | ✓ | — | — | — |
| DecisionBranch | ✓ | — | — | — |
| File | — | ✓ | ✓ | ✓ |
| QRCode | ✓ | — | — | ✓ |
| DataTable | ✓ | ✓ | — | — |
| Banner | ✓ | ✓ | — | — |
timeline CMS Document Lifecycle States
DRAFT
→
IN REVIEW
→
APPROVED
→
PUBLISHED
→
ARCHIVED
| statusCode | Editable | Renderable in WI/LMS | Transitions to | Notes |
|---|---|---|---|---|
| DRAFT | ✓ | — | IN_REVIEW, PUBLISHED | Default on create; visible only to author & admins |
| IN_REVIEW | Restricted | — | APPROVED, DRAFT (rejected) | Minor edits permitted; major changes require DRAFT reversion |
| APPROVED | — | Preview only | PUBLISHED | Locked; awaiting publish scheduling |
| PUBLISHED | — | ✓ | ARCHIVED, DRAFT (new version) | Renderable by WI renderer & LMS; new edit creates v+1 as DRAFT |
| ARCHIVED | — | — | DRAFT (restore) | Retained for audit; not rendered; can be restored to DRAFT |
warning
A WI step that references a CMS block with
ContentSource.CMS will fail to render if the referenced document is not in PUBLISHED state.
The WI renderer shows a placeholder block. Always verify referenced documents are published before publishing the WI.