Files
OTSSignsOrchestrator/OTSSignsOrchestrator.Desktop/Views/CreateInstanceView.axaml
Matt Batchelder 90eb649940 feat: Implement container logs functionality in InstancesViewModel
- Added properties for managing container logs, including log entries, service filters, and auto-refresh options.
- Introduced commands for refreshing logs, toggling auto-refresh, and closing the logs panel.
- Implemented log fetching logic with error handling and status messages.
- Integrated log display in the InstancesView with a dedicated logs panel.

feat: Enhance navigation to Instances page with auto-selection

- Added method to navigate to the Instances page and auto-select an instance based on abbreviation.

feat: Update SettingsViewModel to load and save Bitwarden configuration

- Integrated Bitwarden configuration loading from IOptions and saving to appsettings.json.
- Added properties for Bitwarden instance project ID and connection status.
- Updated UI to reflect Bitwarden settings and connection status.

feat: Add advanced options for instance creation

- Introduced a new expander in CreateInstanceView for advanced options, including purging stale volumes.

feat: Improve InstanceDetailsWindow with pending setup banner

- Added a banner to indicate pending setup for Xibo OAuth credentials, with editable fields for client ID and secret.

fix: Update appsettings.json to include Bitwarden configuration structure

- Added Bitwarden section to appsettings.json for storing configuration values.

chore: Update Docker Compose template with health checks

- Added health check configuration for web service in template.yml to ensure service availability.

refactor: Drop AppSettings table from database

- Removed AppSettings table and related migration files as part of database cleanup.

feat: Create ServiceLogEntry DTO for log management

- Added ServiceLogEntry class to represent individual log entries from Docker services.
2026-02-25 17:39:17 -05:00

219 lines
14 KiB
XML

<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:OTSSignsOrchestrator.Desktop.ViewModels"
x:Class="OTSSignsOrchestrator.Desktop.Views.CreateInstanceView"
x:DataType="vm:CreateInstanceViewModel">
<ScrollViewer>
<Grid ColumnDefinitions="1*,20,1*" Margin="0,0,8,16">
<!-- ══ LEFT COLUMN — inputs ══ -->
<StackPanel Grid.Column="0" Spacing="10">
<TextBlock Text="Create New Instance" Classes="pageTitle" />
<TextBlock Text="Deploy a new CMS stack to a Docker Swarm host" Classes="pageSubtitle" />
<!-- SSH Host -->
<Border Classes="card">
<StackPanel Spacing="8">
<TextBlock Text="Target Host" FontSize="13" FontWeight="SemiBold"
Foreground="{StaticResource AccentBrush}" />
<ComboBox ItemsSource="{Binding AvailableHosts}"
SelectedItem="{Binding SelectedSshHost}"
PlaceholderText="Select SSH Host..."
HorizontalAlignment="Stretch">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Border>
<!-- Core fields -->
<Border Classes="card">
<StackPanel Spacing="8">
<TextBlock Text="Customer Details" FontSize="13" FontWeight="SemiBold"
Foreground="#60A5FA" />
<TextBlock Text="Customer Name" FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" />
<TextBox Text="{Binding CustomerName}" Watermark="e.g. Acme Corp" />
<TextBlock Text="Abbreviation (3 letters)" FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" />
<TextBox Text="{Binding CustomerAbbrev}"
Watermark="e.g. acm"
MaxLength="3" />
</StackPanel>
</Border>
<!-- Pangolin / Newt (optional) -->
<Expander Header="Pangolin / Newt credentials (optional)">
<Border Classes="card" Margin="0,8,0,0">
<StackPanel Spacing="8">
<TextBlock Text="Newt ID" FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" />
<TextBox Text="{Binding NewtId}" Watermark="(from Pangolin dashboard)" />
<TextBlock Text="Newt Secret" FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" />
<TextBox Text="{Binding NewtSecret}" PasswordChar="●" Watermark="(from Pangolin dashboard)" />
</StackPanel>
</Border>
</Expander>
<!-- NFS volume settings -->
<Expander Header="NFS volume settings">
<Border Classes="card" Margin="0,8,0,0">
<StackPanel Spacing="8">
<TextBlock Text="NFS Server" FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" />
<TextBox Text="{Binding NfsServer}" Watermark="e.g. 192.168.1.100" />
<TextBlock Text="Export Path" FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" />
<TextBox Text="{Binding NfsExport}" Watermark="e.g. /srv/nfs" />
<TextBlock Text="Export Folder (optional)" FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" />
<TextBox Text="{Binding NfsExportFolder}" Watermark="e.g. ots_cms (leave empty for export root)" />
<TextBlock Text="Extra Mount Options" FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" />
<TextBox Text="{Binding NfsExtraOptions}" Watermark="Additional options after nfsvers=4,proto=tcp" />
</StackPanel>
</Border>
</Expander>
<!-- Advanced options -->
<Expander Header="Advanced options">
<Border Classes="card" Margin="0,8,0,0">
<StackPanel Spacing="8">
<CheckBox IsChecked="{Binding PurgeStaleVolumes}">
<StackPanel Spacing="2">
<TextBlock Text="Purge stale volumes before deploying" FontSize="12" />
<TextBlock Text="Removes existing Docker volumes for this stack so fresh volumes are created. Only needed if volumes were created with wrong settings." FontSize="11" Foreground="{StaticResource TextMutedBrush}" TextWrapping="Wrap" />
</StackPanel>
</CheckBox>
</StackPanel>
</Border>
</Expander>
<!-- Deploy button + progress -->
<Button Content="Deploy Instance"
Classes="accent"
Command="{Binding DeployCommand}"
IsEnabled="{Binding !IsBusy}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Padding="14,10" FontSize="14"
Margin="0,8,0,0" />
<!-- Progress bar -->
<Grid ColumnDefinitions="*,Auto" Margin="0,4,0,0"
IsVisible="{Binding IsBusy}">
<ProgressBar Value="{Binding ProgressPercent}"
Maximum="100" Height="6"
CornerRadius="3"
Foreground="{StaticResource AccentBrush}" />
<TextBlock Grid.Column="1" Text="{Binding ProgressStep}"
FontSize="11" Foreground="{StaticResource TextMutedBrush}"
Margin="10,0,0,0" VerticalAlignment="Center" />
</Grid>
<TextBlock Text="{Binding StatusMessage}" Classes="status"
Margin="0,4,0,0" TextWrapping="Wrap" />
<!-- Deploy output -->
<TextBox Text="{Binding DeployOutput}" IsReadOnly="True"
AcceptsReturn="True" MaxHeight="260"
FontFamily="Cascadia Mono, Consolas, monospace" FontSize="11"
IsVisible="{Binding DeployOutput.Length}"
CornerRadius="8" />
</StackPanel>
<!-- ══ RIGHT COLUMN — tabbed preview ══ -->
<TabControl Grid.Column="2" VerticalAlignment="Top">
<!-- Tab 1: Resource preview -->
<TabItem Header="Resource Preview">
<Border Classes="card" Margin="0,8,0,0">
<StackPanel Spacing="6">
<TextBlock Text="Resource Preview" FontSize="14" FontWeight="SemiBold"
Foreground="{StaticResource AccentBrush}" Margin="0,0,0,10" />
<TextBlock Text="Stack" FontSize="11" Foreground="{StaticResource TextMutedBrush}" />
<TextBlock Text="{Binding PreviewStackName}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#60A5FA" Margin="0,0,0,8" />
<TextBlock Text="Services" FontSize="11" Foreground="{StaticResource TextMutedBrush}" />
<TextBlock Text="{Binding PreviewServiceWeb}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#4ADE80" />
<TextBlock Text="{Binding PreviewServiceCache}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#4ADE80" />
<TextBlock Text="{Binding PreviewServiceChart}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#4ADE80" />
<TextBlock Text="{Binding PreviewServiceNewt}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#4ADE80" Margin="0,0,0,8" />
<TextBlock Text="Network" FontSize="11" Foreground="{StaticResource TextMutedBrush}" />
<TextBlock Text="{Binding PreviewNetwork}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#2DD4BF" Margin="0,0,0,8" />
<TextBlock Text="NFS Volumes" FontSize="11" Foreground="{StaticResource TextMutedBrush}" />
<TextBlock Text="{Binding PreviewVolCustom}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#F472B6" />
<TextBlock Text="{Binding PreviewVolBackup}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#F472B6" />
<TextBlock Text="{Binding PreviewVolLibrary}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#F472B6" />
<TextBlock Text="{Binding PreviewVolUserscripts}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#F472B6" />
<TextBlock Text="{Binding PreviewVolCaCerts}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#F472B6" Margin="0,0,0,8" />
<TextBlock Text="Docker Secrets" FontSize="11" Foreground="{StaticResource TextMutedBrush}" />
<TextBlock Text="{Binding PreviewSecret}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#FBBF24" />
<TextBlock Text="{Binding PreviewSecretUser}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#FBBF24" />
<TextBlock Text="{Binding PreviewSecretHost}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#FBBF24" />
<TextBlock Text="{Binding PreviewSecretPort}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#FBBF24" Margin="0,0,0,8" />
<TextBlock Text="MySQL Database" FontSize="11" Foreground="{StaticResource TextMutedBrush}" />
<TextBlock Text="{Binding PreviewMySqlDb}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#C084FC" />
<TextBlock Text="{Binding PreviewMySqlUser}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#C084FC" Margin="0,0,0,8" />
<TextBlock Text="CMS URL" FontSize="11" Foreground="{StaticResource TextMutedBrush}" />
<TextBlock Text="{Binding PreviewCmsUrl}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#2DD4BF" />
</StackPanel>
</Border>
</TabItem>
<!-- Tab 2: Rendered compose YML -->
<TabItem Header="Compose YML">
<Border Classes="card" Margin="0,8,0,0">
<Grid RowDefinitions="Auto,*,Auto">
<!-- Load button -->
<Button Grid.Row="0"
Content="Load / Refresh YML"
Command="{Binding LoadYmlPreviewCommand}"
IsEnabled="{Binding !IsLoadingYml}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Padding="10,7"
Margin="0,0,0,10" />
<!-- YML text box -->
<TextBox Grid.Row="1"
Text="{Binding PreviewYml}"
IsReadOnly="True"
AcceptsReturn="True"
FontFamily="Cascadia Mono, Consolas, monospace"
FontSize="11"
MinHeight="320"
CornerRadius="6"
Watermark="Click 'Load / Refresh YML' to preview the rendered compose file..."
TextWrapping="NoWrap" />
<!-- Copy button -->
<Button Grid.Row="2"
Content="Copy to Clipboard"
Command="{Binding CopyYmlCommand}"
IsEnabled="{Binding HasPreviewYml}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Padding="10,7"
Margin="0,10,0,0" />
</Grid>
</Border>
</TabItem>
</TabControl>
</Grid>
</ScrollViewer>
</UserControl>