This commit is contained in:
2026-06-02 17:39:58 +02:00
36 changed files with 2520 additions and 463 deletions
+18 -17
View File
@@ -8,9 +8,10 @@
@inject DuplicatesHtmlExportService HtmlExport
@inject WebExportService WebExport
@inject IAuditService Audit
@inject TranslationSource T
@rendermode InteractiveServer
<h1 class="page-title">Duplicate Detection</h1>
<h1 class="page-title">@T["duplicates.page.title"]</h1>
@if (!Session.HasProfile) { <NoProfilePrompt /> return; }
@@ -18,29 +19,29 @@
<SitePicker Profile="Session.CurrentProfile!" @bind-SelectedSites="_sites" />
<div class="form-row mt-8">
<div class="form-group">
<label class="form-label">Mode</label>
<label class="form-label">@T["duplicates.lbl.mode"]</label>
<select class="form-select" @bind="_mode" style="width:120px">
<option value="Files">Files</option>
<option value="Folders">Folders</option>
<option value="Files">@T["duplicates.mode.files"]</option>
<option value="Folders">@T["duplicates.mode.folders"]</option>
</select>
</div>
<LibraryPicker Profile="Session.CurrentProfile!" SiteUrl="@(_sites.FirstOrDefault()?.Url)" @bind-Library="_library" Label="Library (optional)" Placeholder="" />
<LibraryPicker Profile="Session.CurrentProfile!" SiteUrl="@(_sites.FirstOrDefault()?.Url)" @bind-Library="_library" Label="@T["duplicates.lbl.library_optional"]" Placeholder="" />
</div>
<div class="flex-row">
<label><input type="checkbox" @bind="_matchSize" /> Match size</label>
<label><input type="checkbox" @bind="_matchCreated" /> Match created</label>
<label><input type="checkbox" @bind="_matchModified" /> Match modified</label>
<label><input type="checkbox" @bind="_matchSize" /> @T["duplicates.chk.match_size"]</label>
<label><input type="checkbox" @bind="_matchCreated" /> @T["duplicates.chk.match_created"]</label>
<label><input type="checkbox" @bind="_matchModified" /> @T["duplicates.chk.match_modified"]</label>
@if (_mode == "Folders")
{
<label><input type="checkbox" @bind="_matchFolderCount" /> Match subfolder count</label>
<label><input type="checkbox" @bind="_matchFileCount" /> Match file count</label>
<label><input type="checkbox" @bind="_matchFolderCount" /> @T["duplicates.chk.match_folder_count"]</label>
<label><input type="checkbox" @bind="_matchFileCount" /> @T["duplicates.chk.match_file_count"]</label>
}
</div>
<div class="flex-row mt-8">
<button class="btn btn-primary" @onclick="RunScan" disabled="@_running">
@(_running ? "Scanning" : "Find Duplicates")
@(_running ? T["duplicates.btn.scanning"] : T["duplicates.btn.find"])
</button>
@if (_running) { <button class="btn btn-secondary" @onclick="Cancel">Cancel</button> }
@if (_running) { <button class="btn btn-secondary" @onclick="Cancel">@T["btn.cancel"]</button> }
</div>
<ProgressPanel IsRunning="_running" StatusMessage="@_status" Current="_current" Total="_total" />
</div>
@@ -51,17 +52,17 @@
{
<div class="card">
<div class="flex-row">
<div class="card-title">Duplicate Groups <span class="count-badge">@_results.Count</span></div>
<div class="card-title">@T["duplicates.results.title"] <span class="count-badge">@_results.Count</span></div>
<div class="spacer"></div>
<MergeModeSelect Value="_mergeMode" ValueChanged="v => _mergeMode = v" Visible="_bySite.Count > 1" />
<button class="btn btn-secondary btn-sm" @onclick="ExportCsv">Export CSV</button>
<button class="btn btn-secondary btn-sm" @onclick="ExportHtml">Export HTML</button>
<button class="btn btn-secondary btn-sm" @onclick="ExportCsv">@T["audit.btn.exportCsv"]</button>
<button class="btn btn-secondary btn-sm" @onclick="ExportHtml">@T["audit.btn.exportHtml"]</button>
</div>
@foreach (var g in _results.Take(100))
{
<div style="margin-bottom:8px;border:1px solid var(--border);border-radius:4px;overflow:hidden">
<div style="background:#f0f0f0;padding:6px 12px;font-weight:600;font-size:13px">
@g.Name <span class="chip chip-blue">@g.Items.Count copies</span>
@g.Name <span class="chip chip-blue">@g.Items.Count @T["report.text.copies"]</span>
</div>
@foreach (var item in g.Items)
{
@@ -72,7 +73,7 @@
}
</div>
}
@if (_results.Count > 100) { <div class="text-muted mt-8">Showing first 100 groups. Export for all.</div> }
@if (_results.Count > 100) { <div class="text-muted mt-8">@T["duplicates.results.truncated"]</div> }
</div>
}