Compare commits

...
Author SHA1 Message Date
7b842a9fe9
user the CommandBar
All checks were successful
Dotnet build and test / build (pull_request) Successful in 9m17s
2026-09-07 20:53:23 +01:00
b75d0add7d
db testing 2026-09-07 20:02:56 +01:00
4 changed files with 158 additions and 116 deletions

View file

@ -12,118 +12,132 @@
x:DataType="vm:BlogsViewModel" x:DataType="vm:BlogsViewModel"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"> VerticalAlignment="Stretch">
<Design.DataContext> <Design.DataContext>
<vm:BlogsViewModel /> <vm:BlogsViewModel />
</Design.DataContext> </Design.DataContext>
<Grid Margin="12" RowSpacing="12" <Grid Margin="12" RowSpacing="12"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"> VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0" HorizontalAlignment="Stretch">
<TextBlock Text="Blog Posts" FontSize="22" FontWeight="SemiBold" />
<TextBox Text="{Binding SearchText, Mode=TwoWay}" PlaceholderText="Filter by title or author..." />
<CommandBar IsDynamicOverflowEnabled="True">
<CommandBar.PrimaryCommands>
<CommandBarButton Label="Filter" Command="{Binding SearchAsync}">
<CommandBarButton.Icon>
<PathIcon Data="{StaticResource FilterIcon}" />
</CommandBarButton.Icon>
</CommandBarButton>
<CommandBarButton Label="Refresh" Command="{Binding RefreshAsync}">
<CommandBarButton.Icon>
<PathIcon Data="{StaticResource RefreshIcon}" />
</CommandBarButton.Icon>
</CommandBarButton>
<CommandBarButton Label="Save" Command="{Binding SaveAsync}">
<CommandBarButton.Icon>
<PathIcon Data="{StaticResource SaveIcon}" />
</CommandBarButton.Icon>
</CommandBarButton>
<CommandBarButton Label="Delete" Command="{Binding DeleteAsync}">
<CommandBarButton.Icon>
<PathIcon Data="{StaticResource DeleteIcon}" />
</CommandBarButton.Icon>
</CommandBarButton>
<CommandBarButton Label="Ajouter fichiers" Click="AddAttachment_Click"
x:Name="AddAttachmentButton">
<CommandBarButton.Icon>
<PathIcon Data="{StaticResource AddIcon}" />
</CommandBarButton.Icon>
</CommandBarButton>
<CommandBarButton x:Name="ManageAclButton"
Label="ACL" Command="{Binding ManageAclAsync}">
<CommandBarButton.Icon>
<PathIcon Data="{StaticResource AclIcon}" />
</CommandBarButton.Icon>
</CommandBarButton>
<CommandBarButton x:Name="OpenCirclesButton"
Label="Mes cercles" Command="{Binding OpenCirclesAsync}">
<CommandBarButton.Icon>
<PathIcon Data="{StaticResource CircleIcon}" />
</CommandBarButton.Icon>
</CommandBarButton>
<CommandBarToggleButton Label="Publié"
IsChecked="{Binding DraftIsPublished, Mode=TwoWay}">
<CommandBarToggleButton.Icon>
<PathIcon Data="{StaticResource PublishedIcon}" />
</CommandBarToggleButton.Icon>
</CommandBarToggleButton>
<CommandBarButton x:Name="OpenSignatureDevButton"
Label="[DEV] Signature" Command="{Binding OpenSignatureDevAsync}">
<CommandBarButton.Icon>
<PathIcon Data="{StaticResource SignIcon}" />
</CommandBarButton.Icon>
</CommandBarButton>
</CommandBar.PrimaryCommands>
</CommandBar>
</WrapPanel>
<Border Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Padding="8">
<ListBox ItemsSource="{Binding FilteredPosts}" SelectedItem="{Binding SelectedPost, Mode=TwoWay}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinHeight="40">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="models:BlogPostDto">
<StackPanel Spacing="4">
<TextBlock Text="{Binding Title}" FontWeight="SemiBold" />
<TextBlock Text="{Binding DateModified, StringFormat='Updated: {0:yyyy-MM-dd HH:mm}'}" FontSize="10" Foreground="Gray" />
<TextBlock Text="{Binding AuthorId}" FontSize="10" Foreground="DarkSlateGray" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
<Border Grid.Row="2" BorderBrush="Gray" BorderThickness="1" Padding="8">
<Grid RowSpacing="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Row="0" <TextBlock Grid.Row="0" Text="Post detail" FontWeight="SemiBold" />
HorizontalAlignment="Stretch" <TextBox Grid.Row="1" Text="{Binding DraftTitle, Mode=TwoWay}" PlaceholderText="Title" />
VerticalAlignment="Top" <TextBox Grid.Row="2" PlaceholderText="Write something here !"
Padding="0"> Text="{Binding DraftArticle, Mode=TwoWay}"
<WrapPanel Orientation="Horizontal"> MinHeight="320"
<Button Command="{Binding RefreshAsync}" Content="🗘 Refresh" /> HorizontalAlignment="Stretch"
<Button Command="{Binding SearchAsync}" Content="🔍 Filter" /> VerticalAlignment="Stretch" />
<Button Command="{Binding SaveAsync}" Content="Save" />
<Button Command="{Binding DeleteAsync}" Content="Delete" /> <Border Grid.Row="3" BorderBrush="LightGray" BorderThickness="1" Padding="8">
<Button x:Name="AddAttachmentButton" <StackPanel Spacing="4">
Content="Ajouter fichiers" <TextBlock Text="Pièces jointes" FontWeight="SemiBold" />
Click="AddAttachment_Click" /> <ItemsControl ItemsSource="{Binding DraftAttachments}">
<Button x:Name="ManageAclButton" <ItemsControl.ItemTemplate>
Command="{Binding ManageAclAsync}" <DataTemplate>
Content="ACL" /> <TextBlock Text="{Binding FileName}" />
<Button x:Name="OpenCirclesButton" </DataTemplate>
Command="{Binding OpenCirclesAsync}" </ItemsControl.ItemTemplate>
Content="Mes cercles" /> </ItemsControl>
<!-- Publication toggle: a CheckBox wired to </StackPanel>
DraftIsPublished. Clicking it fires
TogglePublishCommand, which pushes the
new state to /api/blog/{id}/publish.
The CheckBox is the canonical
AvaloniaXaml 'toggle' surface; binding
IsChecked TwoWay keeps the visual state
and the buffer in sync. -->
<CheckBox Content="Publié"
IsChecked="{Binding DraftIsPublished, Mode=TwoWay}"
Command="{Binding TogglePublishAsync}"
VerticalAlignment="Center"/>
<!--
DEV ONLY: temporary shortcut to open the signature
capture page. Production entry point is a SignalR
push from Yavsc.Org ("devis received, sign here").
Remove this button and its Click handler in
MainPage.axaml.cs once the SignalR handler lands.
-->
<Button x:Name="OpenSignatureDevButton"
Command="{Binding OpenSignatureDevAsync}"
Content="[DEV] Signature"
ToolTip.Tip="DEV ONLY — to remove when SignalR handler lands" />
</WrapPanel>
</Border> </Border>
<Border Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Padding="8"> <postitControls:StatusBar Grid.Row="4"
<ListBox ItemsSource="{Binding FilteredPosts}" SelectedItem="{Binding SelectedPost, Mode=TwoWay}" DataContext="{Binding ActionStatus}" />
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinHeight="40">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="models:BlogPostDto">
<StackPanel Spacing="4">
<TextBlock Text="{Binding Title}" FontWeight="SemiBold" />
<TextBlock Text="{Binding DateModified, StringFormat='Updated: {0:yyyy-MM-dd HH:mm}'}" FontSize="10" Foreground="Gray" />
<TextBlock Text="{Binding AuthorId}" FontSize="10" Foreground="DarkSlateGray" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
<Border Grid.Row="2" BorderBrush="Gray" BorderThickness="1" Padding="8"> </Grid>
<Grid RowSpacing="10" </Border>
HorizontalAlignment="Stretch" </Grid>
VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Text="Post detail" FontWeight="SemiBold" />
<TextBox Grid.Row="1" Text="{Binding DraftTitle, Mode=TwoWay}" PlaceholderText="Title" />
<TextBox Grid.Row="2" PlaceholderText="Write something here !"
Text="{Binding DraftArticle, Mode=TwoWay}"
MinHeight="320"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
<Border Grid.Row="3" BorderBrush="LightGray" BorderThickness="1" Padding="8">
<StackPanel Spacing="4">
<TextBlock Text="Pièces jointes" FontWeight="SemiBold" />
<ItemsControl ItemsSource="{Binding DraftAttachments}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FileName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
<postitControls:StatusBar Grid.Row="4"
DataContext="{Binding ActionStatus}" />
</Grid>
</Border>
</Grid>
</ContentPage> </ContentPage>

View file

@ -1,20 +1,22 @@
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Yavsc.Models;
namespace Yavsc.Org.Tests.Mandatory namespace Yavsc.Org.Tests.Mandatory
{ {[Collection("Database")]
[Collection("Database")]
[Trait("regression", "II")] [Trait("regression", "II")]
[Trait("dev", "wip")] [Trait("dev", "wip")]
public class Database: IClassFixture<WebServerFixture>, IDisposable public class Database: IClassFixture<WebServerFixture>, IDisposable
{ {
readonly WebServerFixture _serverFixture;
readonly ITestOutputHelper output; readonly ITestOutputHelper output;
public Database(WebServerFixture serverFixture, ITestOutputHelper output) readonly WebServerFixture _serverFixture;
public Database(ITestOutputHelper output, WebServerFixture _serverFixture)
{ {
this.output = output; this.output = output;
_serverFixture = serverFixture; this._serverFixture = _serverFixture;
} }
/// <summary> /// <summary>
@ -30,5 +32,13 @@ namespace Yavsc.Org.Tests.Mandatory
} }
} }
[Fact]
public void TestDatabaseMigration()
{
// Test logic goes here
_serverFixture.ResetAndMigrateDatabase();
}
} }
} }

View file

@ -189,6 +189,20 @@ public sealed class WebServerFixture : WebHostFixture
return app; return app;
} }
public void ResetAndMigrateDatabase()
{
using var scope = Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
db.Database.EnsureDeleted();
if (db.Database.IsRelational())
{
db.Database.Migrate();
return;
}
db.Database.EnsureCreated();
}
protected override async Task<WebApplication> ConfigurePipelineAsync(WebApplication app) protected override async Task<WebApplication> ConfigurePipelineAsync(WebApplication app)
{ {
// The MSBuild target CopyYavscOrgStaticAssets in // The MSBuild target CopyYavscOrgStaticAssets in

View file

@ -11,6 +11,10 @@ namespace Yavsc.Migrations
/// <inheritdoc /> /// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
var declarationDateDefaultSql = ActiveProvider == "Microsoft.EntityFrameworkCore.Sqlite"
? "CURRENT_TIMESTAMP"
: "LOCALTIMESTAMP";
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Activities", name: "Activities",
columns: table => new columns: table => new
@ -1484,7 +1488,7 @@ namespace Yavsc.Migrations
Platform = table.Column<string>(type: "text", nullable: true), Platform = table.Column<string>(type: "text", nullable: true),
Version = table.Column<string>(type: "text", nullable: true), Version = table.Column<string>(type: "text", nullable: true),
DeviceOwnerId = table.Column<string>(type: "text", nullable: true), DeviceOwnerId = table.Column<string>(type: "text", nullable: true),
DeclarationDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "LOCALTIMESTAMP"), DeclarationDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: declarationDateDefaultSql),
LatestActivityUpdate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true) LatestActivityUpdate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
}, },
constraints: table => constraints: table =>