ironservices-maui/Controls/UserJourneyView.xaml

389 lines
22 KiB
XML

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:IronServices.Maui.Controls"
x:Class="IronServices.Maui.Controls.UserJourneyView"
x:DataType="controls:UserJourneyView"
Title="User Journeys">
<ContentPage.Resources>
<ResourceDictionary>
<controls:IsGreaterThanZeroConverter x:Key="IsGreaterThanZero" />
<controls:StringToBoolConverter x:Key="StringToBool" />
<controls:NestingLevelToMarginConverter x:Key="NestingToMargin" />
<controls:DictionaryToStringConverter x:Key="DictToString" />
<controls:CountToVisibilityConverter x:Key="CountToVisibility" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.ToolbarItems>
<ToolbarItem x:Name="RefreshToolbarItem"
Text="Refresh"
Order="Primary"
Clicked="OnRefreshClicked" />
<ToolbarItem x:Name="ShareToolbarItem"
Text="Share"
Order="Primary"
Clicked="OnShareClicked" />
<ToolbarItem x:Name="ClearToolbarItem"
Text="Clear"
Order="Secondary"
Clicked="OnClearClicked" />
</ContentPage.ToolbarItems>
<Grid RowDefinitions="Auto,*,Auto">
<!-- Header Bar with Summary and View Mode Toggle -->
<Border Grid.Row="0"
Padding="16,12"
BackgroundColor="{AppThemeBinding Light={StaticResource Gray100}, Dark={StaticResource Gray800}}"
StrokeThickness="0">
<Grid ColumnDefinitions="*,Auto,Auto">
<!-- Count Label -->
<Label x:Name="CountLabel"
Text="0 journeys"
FontSize="14"
TextColor="{AppThemeBinding Light={StaticResource Gray600}, Dark={StaticResource Gray400}}"
VerticalOptions="Center" />
<!-- View Mode Selector -->
<HorizontalStackLayout Grid.Column="1" Spacing="4" Margin="0,0,12,0">
<Button x:Name="TimelineBtn"
Text="Timeline"
Clicked="OnTimelineSelected"
BackgroundColor="{StaticResource Primary}"
TextColor="White"
FontSize="11"
Padding="8,4"
CornerRadius="4"
HeightRequest="28" />
<Button x:Name="TreeBtn"
Text="Tree"
Clicked="OnTreeSelected"
BackgroundColor="Transparent"
TextColor="{StaticResource Primary}"
FontSize="11"
Padding="8,4"
CornerRadius="4"
HeightRequest="28" />
<Button x:Name="FlowBtn"
Text="Flow"
Clicked="OnFlowSelected"
BackgroundColor="Transparent"
TextColor="{StaticResource Primary}"
FontSize="11"
Padding="8,4"
CornerRadius="4"
HeightRequest="28" />
</HorizontalStackLayout>
<!-- Live Updates Indicator -->
<HorizontalStackLayout Grid.Column="2" Spacing="4" IsVisible="{Binding EnableLiveUpdates}">
<Ellipse WidthRequest="8" HeightRequest="8" Fill="Green" VerticalOptions="Center" />
<Label Text="Live" FontSize="11" TextColor="Green" VerticalOptions="Center" />
</HorizontalStackLayout>
</Grid>
</Border>
<!-- Main Content Area -->
<Grid x:Name="ContentArea" Grid.Row="1">
<!-- Timeline View (default) -->
<CollectionView x:Name="JourneyList"
SelectionMode="Single"
SelectionChanged="OnJourneySelected">
<CollectionView.EmptyView>
<VerticalStackLayout VerticalOptions="Center" HorizontalOptions="Center" Padding="32">
<Label Text="No journeys captured"
FontSize="18"
TextColor="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}"
HorizontalOptions="Center" />
<Label Text="User journeys will appear here when tracked"
FontSize="14"
TextColor="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}"
HorizontalOptions="Center"
Margin="0,8,0,0" />
</VerticalStackLayout>
</CollectionView.EmptyView>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="controls:JourneyItem">
<Border Padding="12"
Margin="8,4"
BackgroundColor="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray900}}"
Stroke="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray700}}"
StrokeShape="RoundRectangle 8">
<Grid RowDefinitions="Auto,Auto,Auto" ColumnDefinitions="Auto,*,Auto">
<!-- Status Badge -->
<Border Grid.Row="0" Grid.Column="0"
Padding="6,2"
StrokeThickness="0"
BackgroundColor="{Binding StatusColor}"
StrokeShape="RoundRectangle 4"
VerticalOptions="Start"
Margin="0,0,8,0">
<Label Text="{Binding StatusIcon}"
FontSize="10"
TextColor="White"
FontAttributes="Bold" />
</Border>
<!-- Journey Name -->
<Label Grid.Row="0" Grid.Column="1"
Text="{Binding Name}"
FontSize="14"
FontAttributes="Bold"
LineBreakMode="TailTruncation"
MaxLines="1"
VerticalOptions="Center" />
<!-- Duration and Time -->
<VerticalStackLayout Grid.Row="0" Grid.Column="2" Spacing="2">
<Label Text="{Binding DurationDisplay}"
FontSize="12"
FontAttributes="Bold"
TextColor="{AppThemeBinding Light={StaticResource Gray700}, Dark={StaticResource Gray300}}"
HorizontalOptions="End" />
<Label Text="{Binding TimeAgo}"
FontSize="10"
TextColor="{AppThemeBinding Light={StaticResource Gray500}, Dark={StaticResource Gray400}}"
HorizontalOptions="End" />
</VerticalStackLayout>
<!-- Journey Details Row -->
<HorizontalStackLayout Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3"
Spacing="12" Margin="0,8,0,0">
<Label Text="{Binding StepCount, StringFormat='{0} steps'}"
FontSize="12"
TextColor="{AppThemeBinding Light={StaticResource Gray600}, Dark={StaticResource Gray400}}" />
<Label Text="{Binding FailedStepCount, StringFormat='{0} failed'}"
FontSize="12"
TextColor="Red"
IsVisible="{Binding HasFailedSteps}" />
<Label Text="{Binding Exceptions.Count, StringFormat='{0} errors'}"
FontSize="12"
TextColor="Red"
IsVisible="{Binding HasExceptions}" />
</HorizontalStackLayout>
<!-- User Info Row -->
<HorizontalStackLayout Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3"
Spacing="8" Margin="0,4,0,0"
IsVisible="{Binding HasUser}">
<Label Text="User:"
FontSize="11"
TextColor="{AppThemeBinding Light={StaticResource Gray500}, Dark={StaticResource Gray400}}" />
<Label Text="{Binding UserId}"
FontSize="11"
TextColor="{StaticResource Primary}"
LineBreakMode="TailTruncation"
MaxLines="1" />
</HorizontalStackLayout>
</Grid>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<!-- Tree View (shown when ViewMode = Tree) -->
<ScrollView x:Name="TreeViewContainer" IsVisible="False">
<VerticalStackLayout x:Name="TreeViewContent" Padding="8" Spacing="4">
<!-- Tree nodes will be built programmatically -->
</VerticalStackLayout>
</ScrollView>
<!-- Flow View (shown when ViewMode = Flow) -->
<ScrollView x:Name="FlowViewContainer" IsVisible="False" Orientation="Both">
<GraphicsView x:Name="FlowGraphicsView"
WidthRequest="800"
HeightRequest="400" />
</ScrollView>
</Grid>
<!-- Detail Panel (shows when journey selected) -->
<Border x:Name="DetailPanel"
Grid.Row="2"
IsVisible="False"
Padding="16"
BackgroundColor="{AppThemeBinding Light={StaticResource Gray100}, Dark={StaticResource Gray800}}"
Stroke="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"
StrokeShape="Rectangle"
MaximumHeightRequest="400">
<ScrollView>
<VerticalStackLayout Spacing="12">
<!-- Header with Close Button -->
<Grid ColumnDefinitions="*,Auto">
<Label x:Name="DetailTitle"
FontSize="16"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
<Button Grid.Column="1"
Text="Close"
Clicked="OnCloseDetailClicked"
BackgroundColor="Transparent"
TextColor="{StaticResource Primary}"
FontSize="12"
Padding="8,4" />
</Grid>
<!-- Status, Duration, User -->
<HorizontalStackLayout Spacing="16">
<HorizontalStackLayout Spacing="4">
<Label Text="Status:" FontSize="12" TextColor="{AppThemeBinding Light={StaticResource Gray500}, Dark={StaticResource Gray400}}" />
<Label x:Name="DetailStatus" FontSize="12" FontAttributes="Bold" />
</HorizontalStackLayout>
<HorizontalStackLayout Spacing="4">
<Label Text="Duration:" FontSize="12" TextColor="{AppThemeBinding Light={StaticResource Gray500}, Dark={StaticResource Gray400}}" />
<Label x:Name="DetailDuration" FontSize="12" FontAttributes="Bold" />
</HorizontalStackLayout>
<HorizontalStackLayout x:Name="DetailUserContainer" Spacing="4" IsVisible="False">
<Label Text="User:" FontSize="12" TextColor="{AppThemeBinding Light={StaticResource Gray500}, Dark={StaticResource Gray400}}" />
<Label x:Name="DetailUser" FontSize="12" TextColor="{StaticResource Primary}" />
</HorizontalStackLayout>
</HorizontalStackLayout>
<!-- Steps Section -->
<VerticalStackLayout x:Name="StepsSection" Spacing="4">
<Label Text="Steps" FontSize="14" FontAttributes="Bold" />
<CollectionView x:Name="StepsList"
MaximumHeightRequest="150"
SelectionMode="Single"
SelectionChanged="OnStepSelected">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="controls:StepItem">
<Grid Margin="{Binding IndentMargin}" Padding="8,4" ColumnDefinitions="Auto,*,Auto">
<!-- Status Indicator -->
<Border Padding="4,2"
StrokeThickness="0"
BackgroundColor="{Binding StatusColor}"
StrokeShape="RoundRectangle 2"
VerticalOptions="Center"
Margin="0,0,8,0">
<Label Text="{Binding StatusIcon}"
FontSize="9"
TextColor="White"
FontAttributes="Bold" />
</Border>
<!-- Step Name -->
<VerticalStackLayout Grid.Column="1" VerticalOptions="Center">
<Label Text="{Binding Name}"
FontSize="12"
LineBreakMode="TailTruncation" />
<Label Text="{Binding FailureReason}"
FontSize="10"
TextColor="Red"
IsVisible="{Binding HasFailureReason}"
LineBreakMode="TailTruncation" />
</VerticalStackLayout>
<!-- Duration -->
<Label Grid.Column="2"
Text="{Binding DurationDisplay}"
FontSize="11"
TextColor="{AppThemeBinding Light={StaticResource Gray500}, Dark={StaticResource Gray400}}"
VerticalOptions="Center" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
<!-- Breadcrumbs Section -->
<VerticalStackLayout x:Name="BreadcrumbsSection" Spacing="4" IsVisible="False">
<Label Text="Breadcrumbs" FontSize="14" FontAttributes="Bold" />
<CollectionView x:Name="BreadcrumbsList" MaximumHeightRequest="100">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="controls:BreadcrumbItem">
<Grid Padding="4" ColumnDefinitions="Auto,Auto,*">
<Label Text="{Binding TimestampDisplay}"
FontSize="10"
TextColor="{AppThemeBinding Light={StaticResource Gray500}, Dark={StaticResource Gray400}}"
VerticalOptions="Center"
Margin="0,0,8,0" />
<Border Grid.Column="1"
Padding="4,1"
StrokeThickness="0"
BackgroundColor="{Binding LevelColor}"
StrokeShape="RoundRectangle 2"
VerticalOptions="Center"
Margin="0,0,8,0">
<Label Text="{Binding Category}"
FontSize="9"
TextColor="White" />
</Border>
<Label Grid.Column="2"
Text="{Binding Message}"
FontSize="11"
LineBreakMode="TailTruncation"
VerticalOptions="Center" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
<!-- Exceptions Section -->
<VerticalStackLayout x:Name="ExceptionsSection" Spacing="4" IsVisible="False">
<Label Text="Exceptions" FontSize="14" FontAttributes="Bold" TextColor="Red" />
<CollectionView x:Name="ExceptionsList"
MaximumHeightRequest="120"
SelectionMode="Single"
SelectionChanged="OnExceptionSelected">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="controls:ExceptionItem">
<Border Padding="8" Margin="0,2"
BackgroundColor="{AppThemeBinding Light=#FEE2E2, Dark=#7F1D1D}"
Stroke="Transparent"
StrokeShape="RoundRectangle 4">
<VerticalStackLayout Spacing="2">
<HorizontalStackLayout Spacing="8">
<Label Text="{Binding TimestampDisplay}"
FontSize="10"
TextColor="{AppThemeBinding Light={StaticResource Gray500}, Dark={StaticResource Gray300}}" />
<Label Text="{Binding ExceptionType}"
FontSize="11"
FontAttributes="Bold"
TextColor="Red" />
</HorizontalStackLayout>
<Label Text="{Binding Message}"
FontSize="11"
LineBreakMode="TailTruncation"
MaxLines="2" />
</VerticalStackLayout>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
<!-- Metadata Section -->
<VerticalStackLayout x:Name="MetadataSection" Spacing="4" IsVisible="False">
<Label Text="Metadata" FontSize="14" FontAttributes="Bold" />
<Label x:Name="MetadataLabel"
FontFamily="Consolas"
FontSize="11"
TextColor="{AppThemeBinding Light={StaticResource Gray600}, Dark={StaticResource Gray400}}" />
</VerticalStackLayout>
<!-- Copy Button -->
<Button x:Name="CopyButton"
Text="Copy to Clipboard"
Clicked="OnCopyClicked"
BackgroundColor="{StaticResource Primary}"
TextColor="White"
FontSize="12"
Padding="12,8"
CornerRadius="4"
HorizontalOptions="Start" />
</VerticalStackLayout>
</ScrollView>
</Border>
</Grid>
</ContentPage>