feat(project-editor): pre-publish change + validation preview
Milestone 5 of the Configuration Engine sprint. - Facade: changeSummary computed - per modified field, before/after values (schema label + stringified diff vs originalBootstrap), reusing modifiedFields from M4. - preview-section: new "changes since last publish" card ahead of the existing export/import/live-preview card - validation issue list (warning/error styled) plus a before/after change table. Reuses the existing, non-destructive ProjectEditorPreviewService.preview() call. - i18n: previewChangesTitle/NoIssues/NoChanges/ChangeField/Before/After in interface + en/ru/hy. Gate: tsc --noEmit, npm test (33/33), arch:check, build all green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,38 @@
|
||||
<app-section-card [title]="'builder.previewChangesTitle' | translate">
|
||||
@if (issues().length > 0) {
|
||||
<ul class="preview-validation" [class.has-errors]="hasBlockingIssues()">
|
||||
@for (issue of issues(); track issue.code) {
|
||||
<li [class.is-warning]="issue.severity === 'warning'" [class.is-error]="issue.severity === 'error'">{{ issue.message | translate }}</li>
|
||||
}
|
||||
</ul>
|
||||
} @else {
|
||||
<p class="preview-validation-ok">{{ 'builder.previewNoIssues' | translate }}</p>
|
||||
}
|
||||
|
||||
@if (changeSummary().length > 0) {
|
||||
<table class="preview-changes">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'builder.previewChangeField' | translate }}</th>
|
||||
<th>{{ 'builder.previewChangeBefore' | translate }}</th>
|
||||
<th>{{ 'builder.previewChangeAfter' | translate }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (row of changeSummary(); track row.fieldKey) {
|
||||
<tr>
|
||||
<td>{{ row.labelKey | translate }}</td>
|
||||
<td class="preview-before">{{ row.before || '—' }}</td>
|
||||
<td class="preview-after">{{ row.after || '—' }}</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
} @else {
|
||||
<p class="preview-validation-ok">{{ 'builder.previewNoChanges' | translate }}</p>
|
||||
}
|
||||
</app-section-card>
|
||||
|
||||
<app-section-card [title]="'builder.preview' | translate">
|
||||
<div class="editor-actions">
|
||||
<app-button variant="primary" (click)="preview()">{{ 'builder.livePreview' | translate }}</app-button>
|
||||
|
||||
@@ -18,6 +18,9 @@ export class ProjectEditorPreviewSectionComponent {
|
||||
readonly exportValue = signal('');
|
||||
readonly importValue = signal('');
|
||||
readonly importError = this.facade.importError;
|
||||
readonly changeSummary = this.facade.changeSummary;
|
||||
readonly issues = this.facade.validationIssues;
|
||||
readonly hasBlockingIssues = this.facade.hasBlockingIssues;
|
||||
|
||||
refreshExport(): void {
|
||||
this.exportValue.set(this.facade.exportBootstrap());
|
||||
|
||||
@@ -170,6 +170,57 @@ button.secondary {
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.preview-validation {
|
||||
margin: 0 0 12px;
|
||||
padding-left: 1.25rem;
|
||||
color: var(--warning-color, #b45309);
|
||||
|
||||
&.has-errors {
|
||||
color: var(--error-color, #991b1b);
|
||||
}
|
||||
|
||||
li.is-warning {
|
||||
color: var(--warning-color, #b45309);
|
||||
}
|
||||
|
||||
li.is-error {
|
||||
color: var(--error-color, #991b1b);
|
||||
}
|
||||
}
|
||||
|
||||
.preview-validation-ok {
|
||||
margin: 0 0 12px;
|
||||
color: var(--text-secondary, #5f6e6a);
|
||||
}
|
||||
|
||||
.preview-changes {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.9rem;
|
||||
|
||||
th,
|
||||
td {
|
||||
text-align: left;
|
||||
padding: 8px 10px;
|
||||
border-bottom: 1px solid var(--border-color, #d3dad9);
|
||||
}
|
||||
|
||||
th {
|
||||
color: var(--text-secondary, #5f6e6a);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.preview-before {
|
||||
color: var(--text-secondary, #5f6e6a);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.preview-after {
|
||||
color: var(--text-primary, #1e3c38);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.editor-grid.two,
|
||||
.editor-grid.three,
|
||||
|
||||
Reference in New Issue
Block a user