RSS Git Download  Clone
Raw Blame History 12kB 267 lines
HTML rendered
<!-- Memory Doctor -->
<p3xr-ng-accordion [title]="s().memoryDoctor" accordionKey="analysis-doctor">
    <div actions>
        <p3xr-ng-button
            (click)="toggleAutoDoctor(); $event.stopPropagation()"
            [label]="strings().label?.autoRefresh"
            [mdIcon]="autoRefreshDoctor ? 'check_box' : 'check_box_outline_blank'">
        </p3xr-ng-button>
        @if (!autoRefreshDoctor) {
            <p3xr-ng-button
                (click)="runDoctor(); $event.stopPropagation()"
                [label]="doctorLoading ? (strings().label?.loading) : (strings().intention?.refresh)"
                [mdIcon]="doctorLoading ? 'hourglass_empty' : 'refresh'"
                [disabled]="doctorLoading">
            </p3xr-ng-button>
        }
        <p3xr-ng-button
            (click)="exportDoctor(); $event.stopPropagation()"
            [label]="strings().intention?.export"
            mdIcon="download">
        </p3xr-ng-button>
    </div>
    <div content>
        @if (!doctorText) {
            <div style="padding: 12px 16px; opacity: 0.6;">
                {{ s().doctorNoData }}
            </div>
        } @else {
            <pre style="white-space: pre-wrap; font-family: 'Roboto Mono', monospace; font-size: 13px; padding: 12px 16px; margin: 0;">{{ doctorText }}</pre>
        }
    </div>
</p3xr-ng-accordion>

<br />

@if (loading && !data) {
    <div class="p3xr-analysis-loading">
        <mat-icon>hourglass_empty</mat-icon>
        <span>{{ s().running }}</span>
    </div>
}

@if (!loading && !data) {
    <div class="p3xr-analysis-loading">
        <mat-icon>analytics</mat-icon>
        <span>{{ s().noData }}</span>
    </div>
}

@if (data) {
    <!-- Controls + Server Info -->
    <p3xr-ng-accordion [title]="s().title" accordionKey="analysis-controls">
        <div actions>
            <p3xr-ng-button
                (click)="runAnalysis(); $event.stopPropagation()"
                [label]="loading ? (s().running) : (s().runAnalysis)"
                [mdIcon]="loading ? 'hourglass_empty' : 'play_arrow'"
                [disabled]="loading">
            </p3xr-ng-button>
            <p3xr-ng-button
                (click)="exportOverview(); $event.stopPropagation()"
                [label]="strings().intention?.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 }}</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 }}</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 }}</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" accordionKey="analysis-memory-info">
        <div actions>
            <p3xr-ng-button
                (click)="exportMemoryBreakdown(); $event.stopPropagation()"
                [label]="strings().intention?.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 }}</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 }}</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 }}</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 }}</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 }}</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 }}</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 }}</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 }}</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" accordionKey="analysis-type-dist">
        <div actions>
            <p3xr-ng-button
                (click)="exportChart(typeChartRef, 'type-distribution'); $event.stopPropagation()"
                [label]="strings().intention?.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" accordionKey="analysis-prefix-mem">
        <div actions>
            <p3xr-ng-button
                (click)="exportChart(prefixChartRef, 'memory-by-prefix'); $event.stopPropagation()"
                [label]="strings().intention?.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" accordionKey="analysis-expiration">
        <div actions>
            <p3xr-ng-button
                (click)="exportExpiration(); $event.stopPropagation()"
                [label]="strings().intention?.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 }}</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 }}</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 }}</div>
                        <div class="p3xr-settings-row-value p3xr-mono">{{ formatTTL(data.expirationOverview.avgTTL) }}</div>
                    </div>
                </mat-list-item>
            </mat-list>
        </div>
    </p3xr-ng-accordion>
}