kavaa-dce-ui-angular
v1.1.3
Published
Angular standalone UI kit for DCE checklist workspaces.
Readme
kavaa-dce-ui-angular
Angular standalone UI kit for DCE checklist workspaces.
The package renders DCE view models provided by the host application. It does not own backend calls, auth, tenant headers, permissions, workflow transitions, routing, download URLs, antivirus scanning, audit persistence, or refresh logic. The host application stays responsible for those concerns and passes ready-to-render data to the kit.
Packages
Install both packages:
npm install kavaa-dce-viewmodels kavaa-dce-ui-angular| Package | Role |
| --- | --- |
| kavaa-dce-viewmodels | TypeScript contracts shared by the API layer and the UI kit. |
| kavaa-dce-ui-angular | Angular standalone components, styles, tokens, and schematics. |
Compatibility
| Dependency | Supported version |
| --- | --- |
| Angular core/common/forms/cdk/material | ^21.0.0 |
| Angular localize | ^21.0.0 |
| RxJS | ~7.8.0 |
| Kendo Angular Grid | ^24.1.0 |
| Kendo Data Query | ^1.7.3 |
| Kendo Default Theme | ^14.1.0 |
| kavaa-dce-viewmodels | 1.0.7 |
Installation
Use ng add when you want the kit to add the recommended style imports:
ng add kavaa-dce-ui-angularThe schematic asks:
Use Kendo Grid as the default DCE table renderer?Non-interactive usage:
ng add kavaa-dce-ui-angular --use-kendo-grid=true
ng add kavaa-dce-ui-angular --use-kendo-grid=falseIf the package is already installed:
ng generate kavaa-dce-ui-angular:ng-addnpm install only installs the packages. It does not run the schematic and does not modify angular.json or project.json.
Global Styles
Add the package styles globally in angular.json or the project configuration used by your Angular workspace.
Kendo renderer:
{
"styles": [
"node_modules/@progress/kendo-theme-default/scss/all.scss",
"node_modules/kavaa-dce-ui-angular/src/lib/tokens/dce-tokens.css",
"node_modules/kavaa-dce-ui-angular/src/styles/material-overrides.scss",
"src/styles.scss"
]
}Material-only renderer:
{
"styles": [
"node_modules/kavaa-dce-ui-angular/src/lib/tokens/dce-tokens.css",
"node_modules/kavaa-dce-ui-angular/src/styles/material-overrides.scss",
"src/styles.scss"
]
}Load Material Icons in src/index.html:
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Round"
rel="stylesheet"
/>Without Material Icons, mat-icon may render icon names as text.
Angular Configuration
Register your workspace provider with WORKSPACE_CONTEXT. The provider is the bridge between your app and the kit.
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { provideRouter } from '@angular/router';
import { WORKSPACE_CONTEXT } from 'kavaa-dce-ui-angular';
import { appRoutes } from './app.routes';
import { DceWorkspaceProvider } from './providers/dce-workspace-provider';
export const appConfig: ApplicationConfig = {
providers: [
provideBrowserGlobalErrorListeners(),
provideHttpClient(),
provideAnimationsAsync(),
provideRouter(appRoutes),
DceWorkspaceProvider,
{
provide: WORKSPACE_CONTEXT,
useExisting: DceWorkspaceProvider
}
]
};The UI kit itself does not require HttpClient. Your host provider usually does.
Workspace Provider Contract
WORKSPACE_CONTEXT expects this contract:
import type { Signal } from '@angular/core';
import type { ActorContext, ChecklistWorkspaceViewModel } from 'kavaa-dce-viewmodels';
export type WorkspaceLoadParams =
| {
dossierId: string;
processCode: string;
stepCode: string;
actorContext: ActorContext | string;
}
| {
checklistId: string;
actorContext: ActorContext | string;
};
export interface IWorkspaceContext {
workspace: Signal<ChecklistWorkspaceViewModel | null>;
loading: Signal<boolean>;
error: Signal<string | null>;
load(params: WorkspaceLoadParams): Promise<void>;
refresh(): Promise<void>;
}Minimal provider example:
import { Injectable, signal } from '@angular/core';
import type { ChecklistWorkspaceViewModel } from 'kavaa-dce-viewmodels';
import type { IWorkspaceContext, WorkspaceLoadParams } from 'kavaa-dce-ui-angular';
@Injectable()
export class DceWorkspaceProvider implements IWorkspaceContext {
readonly workspace = signal<ChecklistWorkspaceViewModel | null>(null);
readonly loading = signal(false);
readonly error = signal<string | null>(null);
private lastParams: WorkspaceLoadParams | null = null;
async load(params: WorkspaceLoadParams): Promise<void> {
this.lastParams = params;
this.loading.set(true);
this.error.set(null);
try {
const workspace = await this.fetchWorkspace(params);
this.workspace.set(workspace);
} catch (error) {
this.error.set(error instanceof Error ? error.message : 'Workspace DCE indisponible');
} finally {
this.loading.set(false);
}
}
async refresh(): Promise<void> {
if (this.lastParams) {
await this.load(this.lastParams);
}
}
private async fetchWorkspace(params: WorkspaceLoadParams): Promise<ChecklistWorkspaceViewModel> {
// Call your backend here and map the response to ChecklistWorkspaceViewModel.
throw new Error(`Not implemented for ${JSON.stringify(params)}`);
}
}The provider is also the right place to implement upload, replace, validate, approve, reject, download, audit navigation, and business-specific routing.
Main Workspace Usage
Use ChecklistWorkspaceComponent for the full DCE experience.
import { Component, OnInit, inject, signal } from '@angular/core';
import {
ActorContext,
type DecisionState,
type ItemIntentEvent,
type RejectionConfirmedEvent,
type ReplaceConfirmedEvent,
type UploadConfirmedEvent,
type UploadState
} from 'kavaa-dce-viewmodels';
import { ChecklistWorkspaceComponent } from 'kavaa-dce-ui-angular';
import { DceWorkspaceProvider } from './providers/dce-workspace-provider';
@Component({
selector: 'app-dce-page',
standalone: true,
imports: [ChecklistWorkspaceComponent],
templateUrl: './dce-page.html'
})
export class DcePage implements OnInit {
private readonly provider = inject(DceWorkspaceProvider);
readonly uploadState = signal<UploadState>('idle');
readonly decisionState = signal<DecisionState>('idle');
ngOnInit(): void {
void this.provider.load({
dossierId: 'PRJ-2025-001',
processCode: 'INVEST_DIRECT',
stepCode: 'PRE_ACCEPTANCE',
actorContext: ActorContext.Analyst
});
}
async onUploadConfirmed(event: UploadConfirmedEvent): Promise<void> {
this.uploadState.set('uploading');
try {
await this.provider.upload(event);
await this.provider.refresh();
this.uploadState.set('success');
} catch {
this.uploadState.set('error');
}
}
async onReplaceConfirmed(event: ReplaceConfirmedEvent): Promise<void> {
this.uploadState.set('uploading');
try {
await this.provider.replace(event);
await this.provider.refresh();
this.uploadState.set('success');
} catch {
this.uploadState.set('error');
}
}
async onValidationConfirmed(event: ItemIntentEvent): Promise<void> {
this.decisionState.set('submitting');
try {
await this.provider.validate(event);
await this.provider.refresh();
this.decisionState.set('idle');
} catch {
this.decisionState.set('error');
}
}
async onApprovalConfirmed(event: ItemIntentEvent): Promise<void> {
this.decisionState.set('submitting');
try {
await this.provider.approve(event);
await this.provider.refresh();
this.decisionState.set('idle');
} catch {
this.decisionState.set('error');
}
}
async onRejectionConfirmed(event: RejectionConfirmedEvent): Promise<void> {
this.decisionState.set('submitting');
try {
await this.provider.reject(event);
await this.provider.refresh();
this.decisionState.set('idle');
} catch {
this.decisionState.set('error');
}
}
}Template:
<dce-checklist-workspace
mode="analyst"
tableRenderer="kendo"
[uploadState]="uploadState()"
[decisionState]="decisionState()"
(uploadConfirmed)="onUploadConfirmed($event)"
(replaceConfirmed)="onReplaceConfirmed($event)"
(validationConfirmed)="onValidationConfirmed($event)"
(approvalConfirmed)="onApprovalConfirmed($event)"
(rejectionConfirmed)="onRejectionConfirmed($event)"
/>Render Modes
| Mode | Intended user | Behavior |
| --- | --- | --- |
| analyst | Back-office analyst | Upload, replace, L1 validation, rejection according to item actions. |
| promoter | External promoter/depositor | Upload/replace-oriented usage according to item actions. |
| validator | L2 validator | Approval/rejection-oriented usage according to item actions. |
| committee | Committee/read-only consultation | Checklist actions are read-only and committee projection is displayed when available. |
Actions are always controlled by ChecklistItemViewModel.actions. The mode only changes presentation/read-only behavior.
Table Renderer
The default renderer is Kendo Grid:
<dce-checklist-workspace tableRenderer="kendo" />Use the Material fallback:
<dce-checklist-workspace tableRenderer="material" />Grouped mode is automatic in dce-checklist-workspace: when workspace.sections has entries, the table groups items by section. In the Kendo renderer this uses native Kendo grouping with one grid, not one grid per section.
Public Components
| Component | Selector | Purpose |
| --- | --- | --- |
| ChecklistWorkspaceComponent | dce-checklist-workspace | Full workspace composition: header, gate, summary, table, upload dialog, decision panel, audit, committee view. |
| ComplianceGateBannerComponent | dce-compliance-gate-banner | Displays global compliance status and blocking reasons. |
| ChecklistSummaryComponent | dce-checklist-summary | Displays counters, progress, and status metrics. |
| ChecklistItemTableComponent | dce-checklist-item-table | Displays checklist items with Kendo or Material table renderer. |
| DocumentUploadPanelComponent | dce-document-upload-panel | Upload/replace panel with file validation. Used as a dialog by the workspace component. |
| ValidationDecisionPanelComponent | dce-validation-decision-panel | Validate, approve, and reject active document versions. |
| ChecklistAuditTimelineComponent | dce-checklist-audit-timeline | Displays recent audit events and exposes audit navigation outputs. |
| CommitteeReadOnlyPanelComponent | dce-committee-readonly-panel | Displays committee-ready read-only projection. |
All components are standalone. Import only the components you use.
dce-checklist-workspace
Composite component. It reads workspace, loading, and error from WORKSPACE_CONTEXT.
Inputs:
| Input | Type | Default | Description |
| --- | --- | --- | --- |
| mode | ChecklistRenderMode | 'analyst' | Presentation mode: analyst, promoter, validator, or committee. |
| tableRenderer | 'kendo' \| 'material' | 'kendo' | Table implementation. |
| uploadState | UploadState | 'idle' | Host-controlled state for upload/replace feedback. |
| decisionState | DecisionState | 'idle' | Host-controlled state for validate/approve/reject feedback. |
Outputs:
| Output | Payload | When emitted |
| --- | --- | --- |
| uploadConfirmed | UploadConfirmedEvent | User selected a file and confirmed deposit. |
| replaceConfirmed | ReplaceConfirmedEvent | User confirmed replacement of an active version. |
| validationConfirmed | ItemIntentEvent | User confirmed L1 validation. |
| approvalConfirmed | ItemIntentEvent | User confirmed L2 approval. |
| rejectionConfirmed | RejectionConfirmedEvent | User confirmed rejection with reason/comment. |
| downloadRequested | ItemIntentEvent | User requested download of active version. |
| openItemRequested | { itemId: string } | User opened/clicked an item. |
| historyRequested | ItemIntentEvent | User requested document version history. |
| auditRequested | ItemIntentEvent | User requested audit for one item. |
| blockingReasonSelected | { code: string } | User selected a global blocking reason. |
| sectionFocusRequested | { sectionCode: string } | Summary metric requested a section focus. |
| auditEventSelected | { eventType: string; timestamp: string } | User selected an audit timeline event. |
| openAuditRequested | void | User requested full audit. |
| openCommitteeReportRequested | void | User requested the committee report. |
| committeeConsultationRequested | void | User requested committee consultation/evidence package. |
Example:
<dce-checklist-workspace
mode="validator"
tableRenderer="kendo"
[uploadState]="uploadState()"
[decisionState]="decisionState()"
(downloadRequested)="download($event)"
(historyRequested)="openHistory($event)"
(auditRequested)="openItemAudit($event)"
/>dce-compliance-gate-banner
Inputs:
| Input | Type | Default | Description |
| --- | --- | --- | --- |
| gate | ComplianceGateViewModel \| null | null | Compliance status, completeness, and blocking reasons. |
| loading | boolean | false | Shows loading presentation. |
Outputs:
| Output | Payload | Description |
| --- | --- | --- |
| blockingReasonSelected | { code: string } | Emitted when a blocking reason is selected. |
Example:
<dce-compliance-gate-banner
[gate]="workspace.complianceGate"
(blockingReasonSelected)="filterByBlockingReason($event.code)"
/>dce-checklist-summary
Inputs:
| Input | Type | Default | Description |
| --- | --- | --- | --- |
| summary | ChecklistSummaryViewModel \| null | null | Summary counters for the workspace. |
| loading | boolean | false | Shows loading presentation. |
Outputs:
| Output | Payload | Description |
| --- | --- | --- |
| sectionFocusRequested | { sectionCode: string } | Reserved for section navigation/filtering. |
Example:
<dce-checklist-summary [summary]="workspace.summary" />dce-checklist-item-table
Inputs:
| Input | Type | Default | Description |
| --- | --- | --- | --- |
| items | ChecklistItemViewModel[] | [] | Items to render. |
| sections | ChecklistSectionViewModel[] | [] | Optional sections used for grouped rendering. |
| mode | 'flat' \| 'grouped' | 'flat' | Table grouping mode. |
| tableRenderer | 'kendo' \| 'material' | 'kendo' | Table implementation. |
| renderMode | ChecklistRenderMode | 'analyst' | UI mode used by the action bar. |
| readOnly | boolean | false | Disables actions when true. Committee mode is always read-only. |
Outputs:
| Output | Payload | Description |
| --- | --- | --- |
| itemSelected | ItemIntentEvent | Emitted when an item row/card is selected. |
| uploadRequested | { itemId: string } | Upload action requested. |
| replaceRequested | ItemIntentEvent | Replace action requested. |
| validateRequested | ItemIntentEvent | Validate action requested. |
| approveRequested | ItemIntentEvent | Approve action requested. |
| rejectRequested | ItemIntentEvent | Reject action requested. |
| historyRequested | ItemIntentEvent | History action requested. |
| auditRequested | ItemIntentEvent | Audit action requested. |
| downloadRequested | ItemIntentEvent | Download action requested. |
| openItemRequested | { itemId: string } | Item open requested. |
Example:
<dce-checklist-item-table
[items]="workspace.items"
[sections]="workspace.sections"
mode="grouped"
tableRenderer="material"
renderMode="analyst"
(uploadRequested)="openUpload($event.itemId)"
(downloadRequested)="download($event)"
/>dce-document-upload-panel
Use this component directly when you build your own layout. dce-checklist-workspace already opens it inside MatDialog.
Inputs:
| Input | Type | Default | Description |
| --- | --- | --- | --- |
| item | ChecklistItemViewModel \| null | null | Item receiving the uploaded/replacement file. |
| activeVersion | DocumentVersionViewModel \| null | null | Current active version. When present and replace is allowed, replacement mode is used. |
| visible | boolean | false | Renders the panel when true. |
| uploadState | UploadState | 'idle' | Host-controlled feedback state. |
| allowedFormats | string[] | ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'png', 'jpg', 'jpeg'] | Accepted file extensions. Dots are optional. |
| maxFileSizeMb | number | 25 | Maximum selected file size in MB. |
Outputs:
| Output | Payload | Description |
| --- | --- | --- |
| uploadConfirmed | UploadConfirmedEvent | New deposit confirmed. |
| replaceConfirmed | ReplaceConfirmedEvent | Replacement confirmed after second confirmation step. |
| cancelled | void | User cancelled. |
Payload shape:
interface UploadConfirmedEvent {
itemId: string;
file: File;
metadata?: Record<string, unknown>;
}
interface ReplaceConfirmedEvent extends UploadConfirmedEvent {
previousDocumentVersionId: string;
}Example:
<dce-document-upload-panel
[item]="selectedItem"
[activeVersion]="selectedItem?.activeVersion ?? null"
[visible]="uploadOpen"
[allowedFormats]="['pdf', 'docx']"
[maxFileSizeMb]="20"
[uploadState]="uploadState()"
(uploadConfirmed)="upload($event)"
(replaceConfirmed)="replace($event)"
(cancelled)="uploadOpen = false"
/>dce-validation-decision-panel
Inputs:
| Input | Type | Default | Description |
| --- | --- | --- | --- |
| item | ChecklistItemViewModel \| null | null | Item to validate/approve/reject. |
| activeVersion | DocumentVersionViewModel \| null | null | Active document version. Required for decision actions. |
| visible | boolean | false | Renders the panel when true. |
| decisionState | DecisionState | 'idle' | Host-controlled submit/error feedback. |
| rejectionCommentRequired | boolean | false | Requires comment before rejection. |
Outputs:
| Output | Payload | Description |
| --- | --- | --- |
| validationConfirmed | ItemIntentEvent | L1 validation confirmed. |
| approvalConfirmed | ItemIntentEvent | L2 approval confirmed. |
| rejectionConfirmed | RejectionConfirmedEvent | Rejection confirmed with reason/comment. |
| cancelled | void | User cancelled. |
Payload shape:
interface ItemIntentEvent {
itemId: string;
documentVersionId?: string;
}
interface RejectionConfirmedEvent extends ItemIntentEvent {
reason: string;
comment?: string;
}Example:
<dce-validation-decision-panel
[item]="selectedItem"
[activeVersion]="selectedItem?.activeVersion ?? null"
[visible]="decisionOpen"
[decisionState]="decisionState()"
[rejectionCommentRequired]="true"
(validationConfirmed)="validate($event)"
(approvalConfirmed)="approve($event)"
(rejectionConfirmed)="reject($event)"
(cancelled)="decisionOpen = false"
/>dce-checklist-audit-timeline
Inputs:
| Input | Type | Default | Description |
| --- | --- | --- | --- |
| auditSummary | ChecklistAuditSummaryViewModel \| null | null | Audit summary and recent events. |
| maxEvents | number | 8 | Maximum events displayed. |
Outputs:
| Output | Payload | Description |
| --- | --- | --- |
| eventSelected | { eventType: string; timestamp: string } | User selected an event. |
| fullAuditRequested | void | User requested full audit view. |
Example:
<dce-checklist-audit-timeline
[auditSummary]="workspace.auditSummary"
[maxEvents]="10"
(eventSelected)="openAuditEvent($event)"
(fullAuditRequested)="openFullAudit()"
/>dce-committee-readonly-panel
Inputs:
| Input | Type | Required | Description |
| --- | --- | --- | --- |
| committeeView | CommitteeReadOnlyViewModel | Yes | Committee projection. |
| header | ChecklistHeaderViewModel | Yes | Workspace header. |
Outputs:
| Output | Payload | Description |
| --- | --- | --- |
| reportRequested | void | User requested committee report. |
| consultationRequested | void | User requested consultation/evidence package. |
Example:
<dce-committee-readonly-panel
[committeeView]="workspace.committeeView!"
[header]="workspace.header"
(reportRequested)="openCommitteeReport()"
(consultationRequested)="openCommitteeConsultation()"
/>Data Contract Summary
The full workspace is a ChecklistWorkspaceViewModel:
interface ChecklistWorkspaceViewModel {
meta: DceMetaViewModel;
header: ChecklistHeaderViewModel;
complianceGate: ComplianceGateViewModel;
summary: ChecklistSummaryViewModel;
items: ChecklistItemViewModel[];
sections: ChecklistSectionViewModel[];
auditSummary?: ChecklistAuditSummaryViewModel | null;
committeeView?: CommitteeReadOnlyViewModel | null;
actorContext: ActorContext | string;
mode?: ChecklistRenderMode;
links?: LinkMap;
}Important item fields:
interface ChecklistItemViewModel {
itemId: string;
documentTypeCode: string;
documentTypeName: string;
category: string;
sectionCode: string;
sectionLabel: string;
required: boolean;
requiredValidationLevel: 0 | 1 | 2;
currentValidationLevel: 0 | 1 | 2;
status: ItemStatus;
statusLabel: string;
activeVersion: DocumentVersionViewModel | null;
availableVersions: DocumentVersionViewModel[];
actions: ChecklistItemActionsViewModel;
blockingReasons: BlockingReason[];
}Actions control the buttons:
interface ChecklistItemActionsViewModel {
canUpload: boolean;
canReplace: boolean;
canValidate: boolean;
canApprove: boolean;
canReject: boolean;
canDownloadActiveVersion: boolean;
canViewHistory: boolean;
canViewAudit?: boolean;
disabledReasons: Partial<Record<ChecklistItemActionCode, string>> | string[];
}Supported statuses:
| Type | Values |
| --- | --- |
| ItemStatus | MISSING, UPLOADED, VALIDATED, APPROVED, REJECTED, EXPIRED, NOT_APPLICABLE, PENDING_UPLOAD, ERROR_TECH, QUARANTINED |
| GateStatus | OK, BLOCKED, OVERRIDABLE |
| ActorContext | ANALYST, PROMOTER, VALIDATOR, COMMITTEE |
| UploadState | idle, selecting, uploading, success, error |
| DecisionState | idle, submitting, error |
API Mapping
Your backend can expose any endpoint shape. The host must map it to the view model contract before assigning workspace.
Example endpoint:
GET /kdceEngine-service/api/v1/workspace/PRJ-2025-001/dossier
?processCode=INVEST_DIRECT
&stepCode=PRE_ACCEPTANCE
&actorContext=ANALYSTEExample actor mapping:
| UI value | Backend value |
| --- | --- |
| ANALYST | ANALYSTE |
| PROMOTER | PROMOTEUR |
| VALIDATOR | VALIDATEUR |
| COMMITTEE | COMITE |
Typical host responsibilities:
| UI output | Backend action |
| --- | --- |
| uploadConfirmed | Upload File, persist metadata, refresh workspace. |
| replaceConfirmed | Replace active document version, refresh workspace. |
| validationConfirmed | Validate L1, refresh workspace. |
| approvalConfirmed | Approve L2, refresh workspace. |
| rejectionConfirmed | Reject with reason/comment, refresh workspace. |
| downloadRequested | Open signed URL, stream file, or call download endpoint. |
| historyRequested | Open document history route/dialog. |
| auditRequested | Open item audit route/dialog. |
| openAuditRequested | Open full workspace audit. |
Styling And Theme Adaptation
The kit is designed to adapt to the host application's graphic charter. Components use --dce-* tokens. dce-tokens.css maps those tokens from common host variables first, then falls back to neutral defaults.
Recognized host token families:
| Host theme family | Variables read by the kit |
| --- | --- |
| Generic applications | --app-* |
| Kavaa / SIFC applications | --Kavaa-* |
| CDC Carthage applications | --CdcCarthage-* |
| KCGE integrations | --kcge-* |
| Angular Material 3 | --mat-sys-* |
| Direct override | --dce-* |
Recommended generic mapping in the host src/styles.scss:
:root {
--app-font-sans: var(--font-family-base, 'Inter', 'Segoe UI', system-ui, sans-serif);
--app-primary: var(--brand-primary);
--app-primary-dark: var(--brand-primary-dark);
--app-primary-soft: var(--brand-primary-soft);
--app-accent: var(--brand-accent);
--app-accent-dark: var(--brand-accent-dark);
--app-accent-soft: var(--brand-accent-soft);
--app-success: var(--color-success);
--app-success-soft: var(--color-success-soft);
--app-warning: var(--color-warning);
--app-warning-soft: var(--color-warning-soft);
--app-danger: var(--color-danger);
--app-danger-soft: var(--color-danger-soft);
--app-info: var(--color-info);
--app-info-soft: var(--color-info-soft);
--app-page: var(--page-background);
--app-surface: var(--card-background);
--app-surface-alt: var(--muted-background);
--app-surface-hover: var(--hover-background);
--app-border: var(--border-color);
--app-border-light: var(--divider-color);
--app-text: var(--text-primary);
--app-text-secondary: var(--text-secondary);
--app-text-muted: var(--text-muted);
--app-on-primary: var(--text-on-primary);
--app-radius-sm: 6px;
--app-radius: 8px;
--app-radius-lg: 12px;
}Direct DCE-only override:
:root {
--dce-primary: #1e3a8a;
--dce-accent: #0f766e;
--dce-surface: #ffffff;
--dce-surface-alt: #f4f6fa;
--dce-border: #dbe3ef;
--dce-text-primary: #0f172a;
--dce-text-secondary: #475569;
--dce-text-muted: #64748b;
}Scoped dark theme example:
.dark-theme {
--app-page: #0f172a;
--app-surface: #111827;
--app-surface-alt: #1f2937;
--app-border: #334155;
--app-text: #f8fafc;
--app-text-secondary: #cbd5e1;
--app-text-muted: #94a3b8;
}material-overrides.scss is scoped to DCE selectors and DCE overlay panel classes. It should not restyle every Material component in the host app.
Overlay classes used by the kit:
| Class | Used for |
| --- | --- |
| dce-overlay-panel | Material overlay theming for DCE controls. |
| dce-upload-dialog | Upload dialog sizing, button readability, and panel styling. |
Layout Notes
dce-checklist-workspacerenders its own page section and can be placed inside any host route content.- The Material table renderer includes a mobile card layout.
- Kendo Grid needs enough horizontal space for the action column. Put the workspace inside a container that can stretch to the available route width.
- The upload panel is opened as a
MatDialogby the workspace component. - The validation decision panel is rendered inline below the table by the workspace component.
Testing Entrypoint
For tests and demos only:
import {
MockWorkspaceContext,
WORKSPACE_BLOCKED,
WORKSPACE_OK,
WORKSPACE_OVERRIDABLE
} from 'kavaa-dce-ui-angular/testing';Do not import kavaa-dce-ui-angular/testing in production code.
Local Development
npm run build:viewmodels
npm run build:ui
npm run test:ui
npm run build:cdc-dceReference app:
apps/cdc-dce-testThe reference app demonstrates:
- mock-only workspace provider wiring;
- Kendo Grid default renderer with native grouping;
- Material table fallback;
- full composite workspace;
- upload, replace, validation, approval, rejection handlers;
- host-controlled state and refresh behavior.
Publishing
Publish view models first, then UI:
npm run build:viewmodels
npm publish ./libs/dce-viewmodels --registry=https://registry.npmjs.org/ --access public --offline=false
npm run build:ui
npm publish ./dist/libs/dce-ui-angular --registry=https://registry.npmjs.org/ --access public --offline=falseIf npm requires two-factor authentication:
npm publish ./dist/libs/dce-ui-angular --registry=https://registry.npmjs.org/ --access public --offline=false --otp=123456Before publishing:
npm whoami --registry=https://registry.npmjs.org/ --offline=falsemust return your npm username.kavaa-dce-viewmodelsmust already exist at the version declared in the UI peer dependency.- bump
libs/dce-ui-angular/package.jsonwhen changing README, styles, components, or peer dependencies.
Common npm errors:
| Error | Meaning | Fix |
| --- | --- | --- |
| E401 Unauthorized | npmjs does not see a valid login/token. | Run npm login --registry=https://registry.npmjs.org/, then verify with npm whoami. |
| E404 Not Found - PUT on first publish | Often an auth/token problem hidden as 404. | Verify npm whoami; regenerate token if needed. |
| E403 Forbidden | Name exists or account cannot publish that package. | Choose another unscoped name or use an account with access. |
| EOTP | 2FA code required. | Re-run publish with --otp=<6-digit-code>. |
Design Rule
The UI kit renders the DCE contract and emits user intentions. The host owns APIs, auth, workflow, permissions, routing, audit, persistence, and refresh.
