Files
SharepointToolbox-Web/Components/Shared/SitePicker.razor
T

107 lines
4.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@inject ISiteDiscoveryService SiteDiscovery
<div class="site-picker">
<div class="flex-row" style="gap:8px;align-items:flex-end">
<div class="form-group" style="flex:1">
<label class="form-label">Sites</label>
<input class="form-input" @bind="_filter" @bind:event="oninput" placeholder="Filter loaded sites by name or URL…" />
</div>
<button class="btn btn-secondary" @onclick="LoadSites" disabled="@_loading">
@(_loading ? "Loading…" : (_all.Count > 0 ? "Reload sites" : "Load sites"))
</button>
</div>
@if (!string.IsNullOrEmpty(_error))
{
<div class="alert alert-error mt-8">@_error</div>
}
@if (_all.Count > 0)
{
<div class="flex-row mt-8" style="gap:12px;align-items:center">
<button class="btn btn-link btn-sm" @onclick="SelectAllFiltered">Select all (@Filtered.Count())</button>
<button class="btn btn-link btn-sm" @onclick="ClearSelection">Clear</button>
<span class="spacer"></span>
<span class="count-badge">@SelectedSites.Count selected</span>
</div>
<div class="site-picker-list" style="max-height:240px;overflow:auto;border:1px solid var(--border);border-radius:4px;padding:4px;margin-top:6px">
@foreach (var s in Filtered)
{
<label style="display:flex;align-items:center;gap:8px;padding:3px 6px;cursor:pointer">
<input type="checkbox" checked="@IsSelected(s)" @onchange="e => Toggle(s, (bool)(e.Value ?? false))" />
<span>@s.Title</span>
<span class="text-muted" style="font-size:11px">@s.Url</span>
</label>
}
@if (!Filtered.Any())
{
<div class="text-muted" style="padding:6px">No sites match the filter.</div>
}
</div>
}
else if (!_loading)
{
<div class="text-muted mt-8" style="font-size:12px">Click “Load sites” to list the tenants SharePoint sites, then tick the ones to scan.</div>
}
</div>
@code {
[Parameter] public TenantProfile Profile { get; set; } = default!;
[Parameter] public List<SiteInfo> SelectedSites { get; set; } = new();
[Parameter] public EventCallback<List<SiteInfo>> SelectedSitesChanged { get; set; }
[Parameter] public bool Disabled { get; set; }
private List<SiteInfo> _all = new();
private string _filter = string.Empty;
private bool _loading;
private string _error = string.Empty;
private IEnumerable<SiteInfo> Filtered =>
string.IsNullOrWhiteSpace(_filter)
? _all
: _all.Where(s =>
s.Title.Contains(_filter, StringComparison.OrdinalIgnoreCase) ||
s.Url.Contains(_filter, StringComparison.OrdinalIgnoreCase));
private bool IsSelected(SiteInfo s) =>
SelectedSites.Any(x => string.Equals(x.Url, s.Url, StringComparison.OrdinalIgnoreCase));
private async Task LoadSites()
{
_loading = true; _error = string.Empty;
try
{
_all = (await SiteDiscovery.SearchSitesAsync(Profile)).ToList();
if (_all.Count == 0) _error = "No sites returned. The account may lack Sites.Read.All.";
}
catch (Exception ex) { _error = ex.Message; }
finally { _loading = false; }
}
private async Task Toggle(SiteInfo s, bool on)
{
if (on)
{
if (!IsSelected(s)) SelectedSites.Add(s);
}
else
{
SelectedSites.RemoveAll(x => string.Equals(x.Url, s.Url, StringComparison.OrdinalIgnoreCase));
}
await SelectedSitesChanged.InvokeAsync(SelectedSites);
}
private async Task SelectAllFiltered()
{
foreach (var s in Filtered)
if (!IsSelected(s)) SelectedSites.Add(s);
await SelectedSitesChanged.InvokeAsync(SelectedSites);
}
private async Task ClearSelection()
{
SelectedSites.Clear();
await SelectedSitesChanged.InvokeAsync(SelectedSites);
}
}