using AIStudio.Settings.DataModel;
using AIStudio.Tools.PluginSystem;
namespace AIStudio.Tools.Services;
///
/// Counts documents, whatever a document is for the kind of data source: a file for a folder, a
/// mail for a mailbox. Which word the user reads is the business of the page showing it.
///
/// CurrentDocumentBlock and CurrentDocumentPage are null rather than zero while nothing is known
/// about them: a document which is only about to start has no first block, and not every kind of
/// document has pages to count. Block numbers start at one, the way the page states them.
///
/// VectorStoreUnreadable says why a data source failed, not only that it did. The UI needs that
/// difference to offer the repair for this one case, and it is carried as its own flag so nothing
/// has to read it back out of the message in LastError. Attention does the same for what the user
/// has to decide, and PendingRemovalCount is the number a held back removal asks about: agreeing to
/// it hands that very number back, cf. ApprovePendingMailRemovalAsync.
///
/// LastSyncUtc is when the data source was last worked through as a whole, for those which are
/// synced rather than watched, such as mailboxes. It stays null for the others.
///
public sealed record DataSourceEmbeddingStatus(
string DataSourceId,
string DataSourceName,
DataSourceType DataSourceType,
DataSourceEmbeddingState State,
int TotalDocuments,
int IndexedDocuments,
int FailedDocuments,
string CurrentDocument,
string LastError,
IReadOnlyList Failures,
int PermanentlySkippedDocuments = 0,
int? CurrentDocumentBlock = null,
int? CurrentDocumentPage = null,
bool VectorStoreUnreadable = false,
DataSourceAttention Attention = DataSourceAttention.NONE,
int? PendingRemovalCount = null,
DateTimeOffset? LastSyncUtc = null)
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(DataSourceEmbeddingStatus).Namespace, nameof(DataSourceEmbeddingStatus));
///
/// Documents which were skipped for good are done, even though nothing was indexed of them.
/// Leaving them out would keep the bar short of the end for a data source which has nothing
/// left to do.
///
public int ProgressPercent => this.TotalDocuments <= 0 ? 0 : Math.Clamp((int)Math.Round((this.IndexedDocuments + this.PermanentlySkippedDocuments) * 100d / this.TotalDocuments), 0, 100);
public string StateLabel => this.State switch
{
DataSourceEmbeddingState.QUEUED => TB("Queued"),
DataSourceEmbeddingState.RUNNING => TB("Running"),
DataSourceEmbeddingState.COMPLETED => TB("Completed"),
DataSourceEmbeddingState.FAILED => TB("Needs attention"),
_ => TB("Idle")
};
public int SortOrder => this.State switch
{
DataSourceEmbeddingState.RUNNING => 0,
DataSourceEmbeddingState.QUEUED => 1,
DataSourceEmbeddingState.FAILED => 2,
DataSourceEmbeddingState.COMPLETED => 3,
_ => 4,
};
}