RSS Git Download  Clone
Raw Blame History 11kB 232 lines
HTML rendered
@if (loading && !data) {
    <div class="p3xr-analysis-loading">
        <mat-icon>hourglass_empty</mat-icon>
        <span>{{ s().running || 'Analyzing...' }}</span>
    </div>
}

@if (!loading && !data) {
    <div class="p3xr-analysis-loading">
        <mat-icon>analytics</mat-icon>
        <span>{{ s().noData || 'No data. Click Run Analysis to start.' }}</span>
    </div>
}

@if (data) {
    <!-- Controls + Server Info -->
    <p3xr-ng-accordion [title]="s().title || 'Memory Analysis'" accordionKey="analysis-controls">
        <div actions>
            <p3xr-ng-button
                (click)="runAnalysis(); $event.stopPropagation()"
                [label]="loading ? (s().running || 'Analyzing...') : (s().runAnalysis || 'Run Analysis')"
                [mdIcon]="loading ? 'hourglass_empty' : 'play_arrow'"
                [disabled]="loading">
            </p3xr-ng-button>
            <p3xr-ng-button
                (click)="exportOverview(); $event.stopPropagation()"
                [label]="strings().intention?.export || 'Export'"
                mdIcon="download">
            </p3xr-ng-button>
        </div>
        <div content>
            <mat-list>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().keysScanned || 'Keys Scanned' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ data.totalScanned | number }} / {{ data.dbSize | number }}</div>
                    </div>
                </mat-list-item>
                <mat-divider></mat-divider>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().topN || 'Top N' }}</div>
                        <div class="p3xr-settings-row-value">
                            <p3xr-ng-input type="number" [(ngModel)]="topN" min="5" max="100"></p3xr-ng-input>
                        </div>
                    </div>
                </mat-list-item>
                <mat-divider></mat-divider>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().maxScanKeys || 'Max Scan Keys' }}</div>
                        <div class="p3xr-settings-row-value">
                            <p3xr-ng-input type="number" [(ngModel)]="maxScanKeys" min="100" max="100000" step="1000"></p3xr-ng-input>
                        </div>
                    </div>
                </mat-list-item>
            </mat-list>
        </div>
    </p3xr-ng-accordion>

    <br />

    <!-- Memory Breakdown -->
    <p3xr-ng-accordion [title]="s().memoryBreakdown || 'Memory Breakdown'" accordionKey="analysis-memory-info">
        <div actions>
            <p3xr-ng-button
                (click)="exportMemoryBreakdown(); $event.stopPropagation()"
                [label]="strings().intention?.export || 'Export'"
                mdIcon="download">
            </p3xr-ng-button>
        </div>
        <div content>
            <mat-list>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().totalMemory || 'Total Memory' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ data.memoryInfo.usedHuman }}</div>
                    </div>
                </mat-list-item>
                <mat-divider></mat-divider>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().rssMemory || 'RSS Memory' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ data.memoryInfo.rssHuman }}</div>
                    </div>
                </mat-list-item>
                <mat-divider></mat-divider>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().peakMemory || 'Peak Memory' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ data.memoryInfo.peakHuman }}</div>
                    </div>
                </mat-list-item>
                <mat-divider></mat-divider>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().overheadMemory || 'Overhead' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ formatBytes(data.memoryInfo.overhead) }}</div>
                    </div>
                </mat-list-item>
                <mat-divider></mat-divider>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().datasetMemory || 'Dataset' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ formatBytes(data.memoryInfo.dataset) }}</div>
                    </div>
                </mat-list-item>
                <mat-divider></mat-divider>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().luaMemory || 'Lua Memory' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ formatBytes(data.memoryInfo.lua) }}</div>
                    </div>
                </mat-list-item>
                <mat-divider></mat-divider>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().fragmentation || 'Fragmentation' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ data.memoryInfo.fragRatio }}x</div>
                    </div>
                </mat-list-item>
                <mat-divider></mat-divider>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().allocator || 'Allocator' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ data.memoryInfo.allocator }}</div>
                    </div>
                </mat-list-item>
            </mat-list>
        </div>
    </p3xr-ng-accordion>

    <br />

    <!-- Type Distribution -->
    <p3xr-ng-accordion [title]="s().typeDistribution || 'Type Distribution'" accordionKey="analysis-type-dist">
        <div actions>
            <p3xr-ng-button
                (click)="exportChart(typeChartRef, 'type-distribution'); $event.stopPropagation()"
                [label]="strings().intention?.export || 'Export'"
                mdIcon="download">
            </p3xr-ng-button>
        </div>
        <div content>
            <div #typeChart class="p3xr-analysis-chart"></div>
            <mat-list>
                @for (item of typeEntries; track item.type) {
                    <mat-list-item>
                        <div class="p3xr-settings-pair-row">
                            <div class="p3xr-settings-row-label">
                                <span style="font-weight: 500;">{{ item.type }}</span>
                                <span class="p3xr-analysis-sub">{{ item.count }} keys</span>
                            </div>
                            <div class="p3xr-settings-row-value p3xr-mono">{{ formatBytes(item.bytes) }}</div>
                        </div>
                    </mat-list-item>
                    <mat-divider></mat-divider>
                }
            </mat-list>
        </div>
    </p3xr-ng-accordion>

    <br />

    <!-- Memory by Prefix -->
    <p3xr-ng-accordion [title]="s().prefixMemory || 'Memory by Prefix'" accordionKey="analysis-prefix-mem">
        <div actions>
            <p3xr-ng-button
                (click)="exportChart(prefixChartRef, 'memory-by-prefix'); $event.stopPropagation()"
                [label]="strings().intention?.export || 'Export'"
                mdIcon="download">
            </p3xr-ng-button>
        </div>
        <div content>
            <div #prefixChart class="p3xr-analysis-chart"></div>
            <mat-list>
                @for (item of data.prefixMemory; track item.prefix; let i = $index) {
                    <mat-list-item>
                        <div class="p3xr-settings-pair-row">
                            <div class="p3xr-settings-row-label">
                                <span style="opacity: 0.4; margin-right: 8px;">#{{ i + 1 }}</span>
                                <span class="p3xr-mono" style="font-size: 13px;">{{ item.prefix }}</span>
                                <span class="p3xr-analysis-sub">{{ item.keyCount }} keys</span>
                            </div>
                            <div class="p3xr-settings-row-value p3xr-mono">{{ formatBytes(item.totalBytes) }}</div>
                        </div>
                    </mat-list-item>
                    <mat-divider></mat-divider>
                }
            </mat-list>
        </div>
    </p3xr-ng-accordion>

    <br />

    <!-- Key Expiration Overview -->
    <p3xr-ng-accordion [title]="s().expirationOverview || 'Key Expiration'" accordionKey="analysis-expiration">
        <div actions>
            <p3xr-ng-button
                (click)="exportExpiration(); $event.stopPropagation()"
                [label]="strings().intention?.export || 'Export'"
                mdIcon="download">
            </p3xr-ng-button>
        </div>
        <div content>
            <mat-list>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().withTTL || 'With TTL' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ data.expirationOverview.withTTL | number }}</div>
                    </div>
                </mat-list-item>
                <mat-divider></mat-divider>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().persistent || 'Persistent' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ data.expirationOverview.persistent | number }}</div>
                    </div>
                </mat-list-item>
                <mat-divider></mat-divider>
                <mat-list-item>
                    <div class="p3xr-settings-pair-row">
                        <div class="p3xr-settings-row-label">{{ s().avgTTL || 'Average TTL' }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ formatTTL(data.expirationOverview.avgTTL) }}</div>
                    </div>
                </mat-list-item>
            </mat-list>
        </div>
    </p3xr-ng-accordion>
}