tweaks before iamges

This commit is contained in:
Admin 2025-12-26 09:20:31 -05:00
parent bd4085dfce
commit 7fe250a411
4 changed files with 387 additions and 10 deletions

View File

@ -10,6 +10,10 @@
Text="Clear" Text="Clear"
Order="Secondary" Order="Secondary"
Clicked="OnClearClicked" /> Clicked="OnClearClicked" />
<ToolbarItem x:Name="CopyForAIToolbarItem"
Text="Copy for AI"
Order="Primary"
Clicked="OnCopyForAIClicked" />
<ToolbarItem x:Name="ShareToolbarItem" <ToolbarItem x:Name="ShareToolbarItem"
Text="Share" Text="Share"
Order="Primary" Order="Primary"

View File

@ -108,6 +108,25 @@ public partial class AppLogView : ContentPage
set => SetValue(ShowClearButtonProperty, value); set => SetValue(ShowClearButtonProperty, value);
} }
/// <summary>
/// Whether to show the Copy for AI toolbar item. Default: true.
/// </summary>
public static readonly BindableProperty ShowCopyForAIButtonProperty = BindableProperty.Create(
nameof(ShowCopyForAIButton),
typeof(bool),
typeof(AppLogView),
true,
propertyChanged: (b, o, n) => ((AppLogView)b).CopyForAIToolbarItem.IsEnabled = (bool)n);
/// <summary>
/// Gets or sets whether the Copy for AI toolbar button is visible.
/// </summary>
public bool ShowCopyForAIButton
{
get => (bool)GetValue(ShowCopyForAIButtonProperty);
set => SetValue(ShowCopyForAIButtonProperty, value);
}
/// <summary> /// <summary>
/// Whether to automatically refresh when new items are added to the TelemetryClient. Default: false. /// Whether to automatically refresh when new items are added to the TelemetryClient. Default: false.
/// When enabled, polls for new items every 2 seconds. /// When enabled, polls for new items every 2 seconds.
@ -186,6 +205,11 @@ public partial class AppLogView : ContentPage
/// </summary> /// </summary>
public event EventHandler? LogsRefreshed; public event EventHandler? LogsRefreshed;
/// <summary>
/// Raised when logs are copied for AI debugging.
/// </summary>
public event EventHandler? LogsCopiedForAI;
#endregion #endregion
#region Public Methods #region Public Methods
@ -313,6 +337,123 @@ public partial class AppLogView : ContentPage
return sb.ToString(); return sb.ToString();
} }
/// <summary>
/// Export logs in a format optimized for AI debugging assistance.
/// Includes system context, environment info, and structured log data.
/// </summary>
/// <returns>AI-optimized log export string.</returns>
public string ExportLogsForAI()
{
var sb = new StringBuilder();
// Header for AI
sb.AppendLine("# Application Debug Log for AI Analysis");
sb.AppendLine();
sb.AppendLine("Please analyze the following application logs and help identify issues, root causes, and potential fixes.");
sb.AppendLine();
// System Context
sb.AppendLine("## Environment");
sb.AppendLine("```");
sb.AppendLine($"Platform: {DeviceInfo.Platform}");
sb.AppendLine($"OS Version: {DeviceInfo.VersionString}");
sb.AppendLine($"Device: {DeviceInfo.Model} ({DeviceInfo.Manufacturer})");
sb.AppendLine($"Device Type: {DeviceInfo.DeviceType}");
sb.AppendLine($"App: {AppInfo.Name} v{AppInfo.VersionString} (Build {AppInfo.BuildString})");
sb.AppendLine($"Framework: .NET MAUI");
sb.AppendLine($"Captured: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
sb.AppendLine($"Local Time: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
sb.AppendLine($"Timezone: {TimeZoneInfo.Local.DisplayName}");
sb.AppendLine("```");
sb.AppendLine();
// Summary
var exceptions = _logItems.Where(i => i.Type == "exception").ToList();
var warnings = _logItems.Where(i => i.Type == "warning").ToList();
var journeyEvents = _logItems.Where(i => i.Type.StartsWith("journey_") || i.Type.StartsWith("step_")).ToList();
sb.AppendLine("## Summary");
sb.AppendLine($"- **Total Entries:** {_logItems.Count}");
sb.AppendLine($"- **Exceptions:** {exceptions.Count}");
sb.AppendLine($"- **Warnings:** {warnings.Count}");
sb.AppendLine($"- **Journey Events:** {journeyEvents.Count}");
if (_logItems.Count > 0)
{
var oldest = _logItems.Min(i => i.Timestamp);
var newest = _logItems.Max(i => i.Timestamp);
sb.AppendLine($"- **Time Range:** {oldest:HH:mm:ss} to {newest:HH:mm:ss} UTC ({(newest - oldest).TotalSeconds:F1}s span)");
}
sb.AppendLine();
// Exceptions first (most important for debugging)
if (exceptions.Count > 0)
{
sb.AppendLine("## Exceptions");
sb.AppendLine();
foreach (var item in exceptions.OrderByDescending(i => i.Timestamp))
{
sb.AppendLine($"### {item.Title}");
sb.AppendLine($"**Time:** {item.Timestamp:yyyy-MM-dd HH:mm:ss} UTC");
if (!string.IsNullOrEmpty(item.JourneyId))
sb.AppendLine($"**Journey ID:** {item.JourneyId}");
if (!string.IsNullOrEmpty(item.UserId))
sb.AppendLine($"**User ID:** {item.UserId}");
sb.AppendLine();
sb.AppendLine("**Message:**");
sb.AppendLine($"```");
sb.AppendLine(item.Message);
sb.AppendLine($"```");
if (!string.IsNullOrEmpty(item.StackTrace))
{
sb.AppendLine();
sb.AppendLine("**Stack Trace:**");
sb.AppendLine("```");
sb.AppendLine(item.StackTrace);
sb.AppendLine("```");
}
sb.AppendLine();
}
}
// All logs in chronological order
sb.AppendLine("## Full Log (Chronological)");
sb.AppendLine();
sb.AppendLine("| Time (UTC) | Type | Title | Message |");
sb.AppendLine("|------------|------|-------|---------|");
foreach (var item in _logItems.OrderBy(i => i.Timestamp))
{
var msg = item.Message?.Replace("|", "\\|").Replace("\n", " ").Replace("\r", "") ?? "";
if (msg.Length > 100) msg = msg[..97] + "...";
var title = item.Title?.Replace("|", "\\|") ?? "";
if (title.Length > 50) title = title[..47] + "...";
sb.AppendLine($"| {item.Timestamp:HH:mm:ss.fff} | {item.TypeDisplay} | {title} | {msg} |");
}
sb.AppendLine();
// Detailed entries for non-exceptions
var otherItems = _logItems.Where(i => i.Type != "exception").OrderByDescending(i => i.Timestamp).ToList();
if (otherItems.Count > 0)
{
sb.AppendLine("## Other Log Details");
sb.AppendLine();
foreach (var item in otherItems)
{
sb.AppendLine($"### [{item.TypeDisplay}] {item.Title}");
sb.AppendLine($"**Time:** {item.Timestamp:yyyy-MM-dd HH:mm:ss.fff} UTC");
if (!string.IsNullOrEmpty(item.JourneyId))
sb.AppendLine($"**Journey ID:** {item.JourneyId}");
if (!string.IsNullOrEmpty(item.Message))
{
sb.AppendLine();
sb.AppendLine(item.Message);
}
sb.AppendLine();
}
}
return sb.ToString();
}
/// <summary> /// <summary>
/// Get the current log items as a read-only list. /// Get the current log items as a read-only list.
/// </summary> /// </summary>
@ -356,6 +497,33 @@ public partial class AppLogView : ContentPage
LogsShared?.Invoke(this, EventArgs.Empty); LogsShared?.Invoke(this, EventArgs.Empty);
} }
private async void OnCopyForAIClicked(object? sender, EventArgs e)
{
if (_logItems.Count == 0)
{
await DisplayAlert("No Logs", "There are no logs to copy.", "OK");
return;
}
var content = ExportLogsForAI();
await Clipboard.Default.SetTextAsync(content);
// Show feedback
await MainThread.InvokeOnMainThreadAsync(async () =>
{
var originalText = CountLabel.Text;
CountLabel.Text = "Copied for AI!";
CountLabel.TextColor = Colors.Green;
await Task.Delay(1500);
CountLabel.Text = originalText;
CountLabel.TextColor = Application.Current?.RequestedTheme == AppTheme.Dark
? Color.FromArgb("#9CA3AF")
: Color.FromArgb("#6B7280");
});
LogsCopiedForAI?.Invoke(this, EventArgs.Empty);
}
private async void OnLogSelected(object? sender, SelectionChangedEventArgs e) private async void OnLogSelected(object? sender, SelectionChangedEventArgs e)
{ {
if (e.CurrentSelection.FirstOrDefault() is LogItem item) if (e.CurrentSelection.FirstOrDefault() is LogItem item)

View File

@ -16,12 +16,18 @@
<RootNamespace>IronServices.Maui</RootNamespace> <RootNamespace>IronServices.Maui</RootNamespace>
<AssemblyName>IronServices.Maui</AssemblyName> <AssemblyName>IronServices.Maui</AssemblyName>
<Description>Control library library for IronServices API (IronLicensing, IronTelemetry and IronNotify)</Description> <Version>1.1.0</Version>
<Description>MAUI UI controls for IronServices - includes LoginView, LicenseActivationView, AppLogView for telemetry logs, and UserJourneyView for visualizing user journeys with Timeline, Tree, and Flow view modes.</Description>
<Authors>David H Friedel Jr</Authors> <Authors>David H Friedel Jr</Authors>
<Company>MarketAlly</Company> <Company>MarketAlly</Company>
<PackageId>IronServices.Maui</PackageId> <PackageId>IronServices.Maui</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<PackageIcon>nuget_im.png</PackageIcon> <PackageIcon>nuget_im.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageTags>maui;licensing;telemetry;error-monitoring;user-journeys;ironservices;controls;ui</PackageTags>
<RepositoryType>git</RepositoryType>
<Copyright>Copyright (c) 2025 MarketAlly</Copyright>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>

217
README.md
View File

@ -2,6 +2,9 @@
MAUI controls and services for IronServices (IronLicensing, IronNotify, IronTelemetry). MAUI controls and services for IronServices (IronLicensing, IronNotify, IronTelemetry).
[![NuGet](https://img.shields.io/nuget/v/IronServices.Maui.svg)](https://www.nuget.org/packages/IronServices.Maui/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
## Installation ## Installation
```xml ```xml
@ -37,6 +40,15 @@ builder.Services.AddIronServices(options =>
## Controls ## Controls
| Control | Type | Description |
|---------|------|-------------|
| [`LoginView`](#loginview) | ContentView | Drop-in login form |
| [`LicenseActivationView`](#licenseactivationview) | ContentView | License key entry and activation |
| [`AppLogView`](#applogview) | ContentPage | Exception and telemetry log viewer |
| [`UserJourneyView`](#userjourneyview) | ContentPage | User journey visualization with Timeline/Tree/Flow modes |
---
### LoginView ### LoginView
A drop-in login form for IronServices authentication. A drop-in login form for IronServices authentication.
@ -154,6 +166,7 @@ A full-page log viewer for exceptions and telemetry events. Shows queued items f
| `Title` | `string` | `"App Logs"` | Page title (shown in navigation bar). | | `Title` | `string` | `"App Logs"` | Page title (shown in navigation bar). |
| `ShowShareButton` | `bool` | `true` | Enable Share toolbar button. | | `ShowShareButton` | `bool` | `true` | Enable Share toolbar button. |
| `ShowClearButton` | `bool` | `true` | Enable Clear toolbar button. | | `ShowClearButton` | `bool` | `true` | Enable Clear toolbar button. |
| `EnableLiveUpdates` | `bool` | `false` | Auto-refresh when new items are added (polls every 2s). |
#### Events #### Events
@ -182,12 +195,15 @@ A full-page log viewer for exceptions and telemetry events. Shows queued items f
| Property | Type | Description | | Property | Type | Description |
|----------|------|-------------| |----------|------|-------------|
| `Timestamp` | `DateTime` | UTC timestamp. | | `Timestamp` | `DateTime` | UTC timestamp. |
| `Type` | `string` | `"exception"`, `"message"`, `"info"`, `"warning"`, etc. | | `Type` | `string` | `"exception"`, `"message"`, `"journey_start"`, `"step_start"`, etc. |
| `Title` | `string` | Exception type name or message title. | | `Title` | `string` | Exception type name or message title. |
| `Message` | `string` | Log message. | | `Message` | `string` | Log message. |
| `StackTrace` | `string?` | Stack trace for exceptions. | | `StackTrace` | `string?` | Stack trace for exceptions. |
| `JourneyId` | `string?` | Associated user journey ID. | | `JourneyId` | `string?` | Associated user journey ID. |
| `UserId` | `string?` | Associated user ID. | | `UserId` | `string?` | Associated user ID. |
| `TypeDisplay` | `string` | Short type label: `"ERROR"`, `"MSG"`, `"START"`, etc. |
| `TypeColor` | `Color` | Color for type badge. |
| `TimestampDisplay` | `string` | Formatted local time (HH:mm:ss). |
#### Example #### Example
@ -196,7 +212,8 @@ A full-page log viewer for exceptions and telemetry events. Shows queued items f
await Navigation.PushAsync(new AppLogView await Navigation.PushAsync(new AppLogView
{ {
TelemetryClient = _telemetryClient, TelemetryClient = _telemetryClient,
Title = "Error Logs" Title = "Error Logs",
EnableLiveUpdates = true
}); });
// With event handling // With event handling
@ -213,9 +230,176 @@ logView.AddLog("warning", "Network Issue", "Connection timeout after 30s");
#### Toolbar #### Toolbar
- **Refresh** (in header): Reloads from queue.
- **Share** (Primary): Exports logs as text and opens system share sheet. - **Share** (Primary): Exports logs as text and opens system share sheet.
- **Clear** (Secondary/overflow menu): Clears displayed logs. - **Clear** (Secondary/overflow): Clears displayed logs.
- **Refresh** button in summary bar: Reloads from queue.
---
### UserJourneyView
A full-page user journey viewer with multiple visualization modes. Reconstructs journeys from `TelemetryClient` log items and displays steps, breadcrumbs, exceptions, and metadata.
**Type:** `ContentPage` (standalone page, use with NavigationPage)
#### View Modes
| Mode | Description |
|------|-------------|
| `Timeline` | Vertical list with nested steps shown with indentation (default). |
| `Tree` | Expandable tree hierarchy with collapsible journey/step nodes. |
| `Flow` | Horizontal flowchart-style diagram showing step progression. |
#### Properties
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `TelemetryClient` | `TelemetryClient` | `null` | Client to pull journey data from. Auto-refreshes on set. |
| `Title` | `string` | `"User Journeys"` | Page title. |
| `ViewMode` | `JourneyViewMode` | `Timeline` | Current visualization mode. |
| `EnableLiveUpdates` | `bool` | `false` | Auto-refresh when new items are added (polls every 2s). |
| `ShowShareButton` | `bool` | `true` | Enable Share toolbar button. |
| `ShowClearButton` | `bool` | `true` | Enable Clear toolbar button. |
| `UserIdFilter` | `string?` | `null` | Filter to show only journeys for a specific user. |
#### Events
| Event | Args | Description |
|-------|------|-------------|
| `JourneySelected` | `JourneyItem` | User selected a journey from the list. |
| `StepSelected` | `StepItem` | User selected a step in the detail panel. |
| `JourneysRefreshed` | `EventArgs` | Journey list was refreshed. |
| `JourneysCleared` | `EventArgs` | Journeys were cleared. |
| `JourneysShared` | `EventArgs` | Journeys were exported/shared. |
#### Methods
| Method | Returns | Description |
|--------|---------|-------------|
| `RefreshJourneys()` | `void` | Reload journeys from TelemetryClient. |
| `ClearJourneys()` | `void` | Clear displayed journeys. |
| `ClearAllJourneys()` | `void` | Clear displayed journeys AND the TelemetryClient queue. |
| `ExportJourneys()` | `string` | Export all journeys as formatted text. |
| `GetJourneys()` | `IReadOnlyList<JourneyItem>` | Get current journey items. |
| `JourneyCount` | `int` | Number of journeys. |
#### JourneyItem Properties
| Property | Type | Description |
|----------|------|-------------|
| `JourneyId` | `string` | Unique journey identifier. |
| `Name` | `string` | Journey name (e.g., "Checkout Flow"). |
| `UserId` | `string?` | Associated user ID. |
| `UserEmail` | `string?` | Associated user email. |
| `Status` | `JourneyDisplayStatus` | `InProgress`, `Completed`, `Failed`, `Abandoned`. |
| `StartTime` | `DateTime` | When the journey started. |
| `EndTime` | `DateTime?` | When the journey ended (null if in progress). |
| `DurationMs` | `double?` | Duration in milliseconds. |
| `DurationDisplay` | `string` | Formatted duration: `"125ms"`, `"2.3s"`, `"1.5m"`. |
| `TimeAgo` | `string` | Relative time: `"just now"`, `"5m ago"`, `"2h ago"`. |
| `StatusDisplay` | `string` | Human-readable status text. |
| `StatusColor` | `Color` | Color for status badge (Blue/Green/Red/Gray). |
| `StatusIcon` | `string` | Icon text: `"..."`, `"OK"`, `"X"`, `"-"`. |
| `Steps` | `ObservableCollection<StepItem>` | Top-level steps in this journey. |
| `Breadcrumbs` | `List<BreadcrumbItem>` | Breadcrumbs captured during journey. |
| `Exceptions` | `List<ExceptionItem>` | Exceptions captured during journey. |
| `Metadata` | `Dictionary<string, object>` | Custom metadata. |
| `StepCount` | `int` | Total steps (including nested). |
| `FailedStepCount` | `int` | Number of failed steps. |
| `HasFailedSteps` | `bool` | Whether any steps failed. |
| `HasExceptions` | `bool` | Whether any exceptions occurred. |
| `HasUser` | `bool` | Whether a user is associated. |
#### StepItem Properties
| Property | Type | Description |
|----------|------|-------------|
| `StepId` | `string` | Unique step identifier. |
| `ParentStepId` | `string?` | Parent step ID for nested steps. |
| `Name` | `string` | Step name (e.g., "Process Payment"). |
| `Category` | `string?` | Category: `"business"`, `"technical"`, `"navigation"`. |
| `Status` | `StepDisplayStatus` | `InProgress`, `Completed`, `Failed`, `Skipped`. |
| `FailureReason` | `string?` | Reason for failure. |
| `StartTime` | `DateTime` | When the step started. |
| `EndTime` | `DateTime?` | When the step ended. |
| `DurationMs` | `double?` | Duration in milliseconds. |
| `DurationDisplay` | `string` | Formatted duration. |
| `StatusColor` | `Color` | Color for status indicator. |
| `StatusIcon` | `string` | Icon text. |
| `ChildSteps` | `ObservableCollection<StepItem>` | Nested child steps. |
| `NestingLevel` | `int` | Depth level for indentation. |
| `IndentMargin` | `Thickness` | Calculated margin for indentation. |
#### BreadcrumbItem Properties
| Property | Type | Description |
|----------|------|-------------|
| `Timestamp` | `DateTime` | When captured. |
| `Category` | `string` | Breadcrumb category. |
| `Message` | `string` | Breadcrumb message. |
| `Level` | `string` | Log level: `"info"`, `"warning"`, `"error"`, `"debug"`. |
| `LevelColor` | `Color` | Color based on level. |
| `Data` | `Dictionary<string, object>?` | Additional data. |
#### ExceptionItem Properties
| Property | Type | Description |
|----------|------|-------------|
| `Timestamp` | `DateTime` | When captured. |
| `ExceptionType` | `string` | Exception type name. |
| `Message` | `string` | Exception message. |
| `StackTrace` | `string?` | Stack trace. |
| `StepId` | `string?` | Step ID where exception occurred. |
| `HasStackTrace` | `bool` | Whether stack trace is available. |
#### Example
```csharp
// Basic usage
await Navigation.PushAsync(new UserJourneyView
{
TelemetryClient = _telemetryClient,
EnableLiveUpdates = true
});
// With view mode and filtering
var journeyView = new UserJourneyView
{
TelemetryClient = _telemetryClient,
ViewMode = JourneyViewMode.Tree,
UserIdFilter = currentUser.Id
};
await Navigation.PushAsync(journeyView);
// Event handling
var journeyView = new UserJourneyView { TelemetryClient = _telemetryClient };
journeyView.JourneySelected += (s, journey) =>
{
Debug.WriteLine($"Selected: {journey.Name} ({journey.StepCount} steps)");
};
journeyView.StepSelected += (s, step) =>
{
Debug.WriteLine($"Step: {step.Name} - {step.StatusDisplay}");
};
await Navigation.PushAsync(journeyView);
```
#### Detail Panel
When a journey is selected, a detail panel shows:
- **Status, Duration, User** - Summary info
- **Steps** - List of steps with status indicators and timing
- **Breadcrumbs** - Timestamped breadcrumb trail
- **Exceptions** - Exception details (tap to copy)
- **Metadata** - Key-value pairs
- **Copy to Clipboard** - Export journey details
#### Toolbar
- **Timeline/Tree/Flow** buttons - Switch view modes
- **Share** (Primary) - Export journeys as text
- **Clear** (Secondary) - Clear displayed journeys
- **Refresh** - Reload from TelemetryClient
--- ---
@ -310,7 +494,20 @@ private async void OnViewLogsClicked(object sender, EventArgs e)
var telemetry = Handler.MauiContext.Services.GetService<TelemetryClient>(); var telemetry = Handler.MauiContext.Services.GetService<TelemetryClient>();
await Navigation.PushAsync(new AppLogView await Navigation.PushAsync(new AppLogView
{ {
TelemetryClient = telemetry TelemetryClient = telemetry,
EnableLiveUpdates = true
});
}
// SettingsPage.xaml.cs - Navigate to journeys
private async void OnViewJourneysClicked(object sender, EventArgs e)
{
var telemetry = Handler.MauiContext.Services.GetService<TelemetryClient>();
await Navigation.PushAsync(new UserJourneyView
{
TelemetryClient = telemetry,
EnableLiveUpdates = true,
ViewMode = JourneyViewMode.Timeline
}); });
} }
``` ```
@ -329,6 +526,8 @@ All controls use MAUI resource dictionaries. Override these colors in your `App.
<Color x:Key="Gray400">#919191</Color> <Color x:Key="Gray400">#919191</Color>
<Color x:Key="Gray500">#6E6E6E</Color> <Color x:Key="Gray500">#6E6E6E</Color>
<Color x:Key="Gray600">#404040</Color> <Color x:Key="Gray600">#404040</Color>
<Color x:Key="Gray700">#374151</Color>
<Color x:Key="Gray800">#1F2937</Color>
<Color x:Key="Gray900">#212121</Color> <Color x:Key="Gray900">#212121</Color>
<Color x:Key="White">#FFFFFF</Color> <Color x:Key="White">#FFFFFF</Color>
``` ```
@ -342,8 +541,8 @@ Controls support light/dark themes via `AppThemeBinding`.
| Platform | Minimum Version | | Platform | Minimum Version |
|----------|-----------------| |----------|-----------------|
| Android | API 21 (5.0) | | Android | API 21 (5.0) |
| iOS | 14.0 | | iOS | 15.0 |
| macOS | 11.0 | | macOS | 15.0 |
| Windows | 10.0.17763.0 | | Windows | 10.0.17763.0 |
--- ---
@ -352,11 +551,11 @@ Controls support light/dark themes via `AppThemeBinding`.
- `IronServices.Client` - Core API client - `IronServices.Client` - Core API client
- `IronLicensing.Client` - License validation - `IronLicensing.Client` - License validation
- `IronTelemetry.Client` - Telemetry and logging - `IronTelemetry.Client` - Telemetry, journeys, and logging
- `Microsoft.Maui.Controls` - MAUI framework - `Microsoft.Maui.Controls` - MAUI framework
--- ---
## License ## License
Proprietary. See LICENSE file. MIT License - see [LICENSE](LICENSE) file.