All files / app/features/history/pages/diff-page diff-page.component.ts

100% Statements 44/44
90.9% Branches 20/22
100% Functions 9/9
100% Lines 40/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 791x 1x 1x 1x 1x 1x 1x 1x 1x 1x       1x 1x                             1x 23x   23x 23x   23x 11x 11x 10x     23x 10x 10x         23x 11x 11x 10x 10x 2x 2x       23x 23x     1x 1x       5x 5x 5x 5x       23x 23x      
import { CmDiffViewComponent } from '../../../../shared/components/cm-diff-view/cm-diff-view.component';
import { DiffViewComponent } from '../../../../shared/components/diff-view/diff-view.component';
import { ModerationSidebarActionComponent } from '../../../../shared/components/moderation-sidebar-action/moderation-sidebar-action.component';
import { SidebarActionComponent } from '../../../../shared/components/sidebar-action/sidebar-action.component';
import { VersionLabelComponent } from '../../components/version-label/version-label.component';
import { DiffPageDataService } from '../../services/diff-page-data.service';
import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core';
import { LoggerService, StorageService } from '@drevo-web/core';
import { validateWikiContent, ValidationResult } from '@drevo-web/editor';
import { ApprovalStatus, ModerationResult, SidebarActionPriority } from '@drevo-web/shared';
 
type DiffViewType = 'cm' | 'jsdiff';
 
const STORAGE_KEY = 'diff-view-type';
const VALID_TYPES: readonly DiffViewType[] = ['cm', 'jsdiff'];
 
@Component({
    selector: 'app-diff-page',
    imports: [
        CmDiffViewComponent,
        DiffViewComponent,
        ModerationSidebarActionComponent,
        SidebarActionComponent,
        VersionLabelComponent,
    ],
    templateUrl: './diff-page.component.html',
    styleUrl: './diff-page.component.scss',
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DiffPageComponent {
    readonly data = inject(DiffPageDataService);
 
    private readonly logger = inject(LoggerService).withContext('DiffPageComponent');
    private readonly storage = inject(StorageService);
 
    readonly isModerationEnabled = computed(() => {
        const pairs = this.data.versionPairs();
        if (!pairs) return false;
        return pairs.previous.approved === ApprovalStatus.Approved;
    });
 
    readonly moderationPriority = computed<SidebarActionPriority>(() => {
        const pairs = this.data.versionPairs();
        return this.isModerationEnabled() && pairs?.current.approved === ApprovalStatus.Pending
            ? 'primary'
            : 'secondary';
    });
 
    readonly validationResult = computed<ValidationResult>(() => {
        const content = this.data.versionPairs()?.current.content;
        if (!content) return { errors: 0, warnings: 0 };
        const problems = validateWikiContent(content);
        return {
            errors: problems.filter(p => p.severity === 'error').length,
            warnings: problems.filter(p => p.severity === 'warning').length,
        };
    });
 
    private readonly _diffType = signal<DiffViewType>(this.loadDiffType());
    readonly diffType = this._diffType.asReadonly();
 
    onModerated(result: ModerationResult): void {
        this.data.updateCurrentApproval(result.approved, result.comment);
        this.logger.info('Version moderated', { versionId: result.versionId, approved: result.approved });
    }
 
    toggleDiffType(): void {
        const newType: DiffViewType = this._diffType() === 'cm' ? 'jsdiff' : 'cm';
        this._diffType.set(newType);
        this.storage.setString(STORAGE_KEY, newType);
        this.logger.info('Diff view type changed', { type: newType });
    }
 
    private loadDiffType(): DiffViewType {
        const stored = this.storage.getString(STORAGE_KEY);
        return stored && VALID_TYPES.includes(stored as DiffViewType) ? (stored as DiffViewType) : 'cm';
    }
}