Разделены страницы

This commit is contained in:
2026-01-05 06:31:54 +03:00
parent d0653c2098
commit 9f9107362d
12 changed files with 701 additions and 258 deletions

View File

@@ -0,0 +1,8 @@
namespace SQLVision.Models
{
public interface ITreeNode
{
bool IsFolder { get; }
string Name { get; set; }
}
}

View File

@@ -2,7 +2,7 @@
namespace SQLVision.Models; namespace SQLVision.Models;
public sealed class ScriptTreeNode public sealed class ScriptTreeNode : ITreeNode
{ {
public string Name { get; set; } = ""; public string Name { get; set; } = "";
public string? FilePath { get; set; } public string? FilePath { get; set; }

View File

@@ -17,6 +17,7 @@
<ItemGroup> <ItemGroup>
<None Remove="Views\ConnectionPage.xaml" /> <None Remove="Views\ConnectionPage.xaml" />
<None Remove="Views\HelpWindow.xaml" /> <None Remove="Views\HelpWindow.xaml" />
<None Remove="Views\Scripts\ScriptsPage.xaml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -48,6 +49,9 @@
<None Update="Scripts\ServerInfo.sql"> <None Update="Scripts\ServerInfo.sql">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<Page Update="Views\Scripts\ScriptsPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="Views\ConnectionPage.xaml"> <Page Update="Views\ConnectionPage.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>

View File

@@ -0,0 +1,18 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using SQLVision.Models;
namespace SQLVision.Selectors;
class TreeItemTemplateSelector : DataTemplateSelector
{
public DataTemplate FolderTemplate { get; set; }
public DataTemplate FileTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
var explorerItem = (ITreeNode)item;
return explorerItem.IsFolder ? FolderTemplate : FileTemplate;
}
}

View File

@@ -10,12 +10,7 @@ namespace SQLVision.Services;
public sealed class SqlExecutor public sealed class SqlExecutor
{ {
private string _connectionString; private string _connectionString = "";
public SqlExecutor(string connectionString)
{
_connectionString = connectionString;
}
public void SetConnect(string connectionString) public void SetConnect(string connectionString)
{ {

View File

@@ -7,9 +7,9 @@ namespace SQLVision.Services;
public sealed class TableDataProvider public sealed class TableDataProvider
{ {
private readonly string _connectionString; private string _connectionString = "";
public TableDataProvider(string connectionString) public void SetConnect(string connectionString)
{ {
_connectionString = connectionString; _connectionString = connectionString;
} }

View File

@@ -41,6 +41,16 @@ public sealed class ParameterViewModel : BaseViewModel
public ParameterViewModel(ParameterDefinition definition) public ParameterViewModel(ParameterDefinition definition)
{ {
Definition = definition; Definition = definition;
Value = definition.DefaultValue;
if (definition.DefaultValue is not null)
{
Value = definition.Type switch
{
ParameterType.Bool => definition.DefaultValue.Equals("true", System.StringComparison.OrdinalIgnoreCase) || definition.DefaultValue.Equals("1", System.StringComparison.OrdinalIgnoreCase),
ParameterType.Int => int.TryParse(definition.DefaultValue, out var i) ? i : null,
ParameterType.String => definition.DefaultValue,
_ => definition.DefaultValue,
};
}
} }
} }

View File

@@ -0,0 +1,328 @@
using Microsoft.UI.Xaml;
using SQLVision.Models;
using SQLVision.Services;
using SQLVision.Views;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows.Input;
namespace SQLVision.ViewModels;
public sealed partial class ScriptsViewModel : BaseViewModel
{
private readonly SqlCommentParser _parser;
private readonly SqlExecutor _executor;
private readonly ParameterResolver _parameterResolver;
private readonly TableDataProvider _tableDataProvider;
private readonly ExcelExportService _excelExportService;
// -----------------------------
// Подключения
// -----------------------------
private readonly ConnectionStorageService _storage;
public ObservableCollection<ConnectionProfile> SavedConnections { get; } = new();
private ConnectionProfile? _selectedConnection;
public ConnectionProfile? SelectedConnection
{
get => _selectedConnection;
set
{
if (SetProperty(ref _selectedConnection, value))
{
if (value != null)
ConnectionString = value.ConnectionString;
}
}
}
private string _connectionString = "";
public string ConnectionString
{
get => _connectionString;
set => SetProperty(ref _connectionString, value);
}
// -----------------------------
// Скрипты, дерево и параметры
// -----------------------------
public ObservableCollection<ScriptMetadata> Scripts { get; } = new();
// Дерево скриптов для TreeView
public ObservableCollection<ScriptTreeNode> ScriptTree { get; } = new();
private ScriptTreeNode? _selectedScriptNode;
public ScriptTreeNode? SelectedScriptNode
{
get => _selectedScriptNode;
set
{
if (SetProperty(ref _selectedScriptNode, value))
{
if (value?.FilePath is not null)
{
// Находим ScriptMetadata по пути файла
var meta = Scripts.FirstOrDefault(s =>
string.Equals(s.FilePath, value.FilePath, StringComparison.OrdinalIgnoreCase));
if (meta is not null)
SelectedScript = meta;
}
}
}
}
public ObservableCollection<ParameterViewModel> Parameters { get; } = new();
public ObservableCollection<OutputViewModel> Outputs { get; } = new();
private ScriptMetadata? _selectedScript;
public ScriptMetadata? SelectedScript
{
get => _selectedScript;
set
{
if (SetProperty(ref _selectedScript, value))
{
(ExecuteCommand as RelayCommand)?.RaiseCanExecuteChanged();
_ = LoadParametersForSelectedScriptAsync();
}
}
}
private ExecutionResult? _lastResult;
public ExecutionResult? LastResult
{
get => _lastResult;
set
{
if (SetProperty(ref _lastResult, value))
{
(ExportToExcelCommand as RelayCommand)?.RaiseCanExecuteChanged();
_ = LoadParametersForSelectedScriptAsync();
}
}
}
// -----------------------------
// Команды
// -----------------------------
public ICommand ExecuteCommand { get; }
public ICommand ExportToExcelCommand { get; }
public ICommand OpenConnectionCommand { get; }
// -----------------------------
// Конструктор
// -----------------------------
public ScriptsViewModel(
SqlCommentParser parser,
SqlExecutor executor,
ParameterResolver parameterResolver,
TableDataProvider tableDataProvider,
ExcelExportService excelExportService)
{
_parser = parser;
_executor = executor;
_parameterResolver = parameterResolver;
_tableDataProvider = tableDataProvider;
_excelExportService = excelExportService;
ExecuteCommand = new RelayCommand(async _ => await ExecuteAsync(), _ => SelectedScript is not null);
ExportToExcelCommand = new RelayCommand(_ => ExportToExcel(), _ => LastResult is not null);
OpenConnectionCommand = new RelayCommand(_ => OpenConnection());
_storage = new ConnectionStorageService();
foreach (var p in _storage.Load())
SavedConnections.Add(p);
SelectedConnection = SavedConnections.FirstOrDefault();
}
// -----------------------------
// Окно подключения
// -----------------------------
private void OpenConnection()
{
var vm = new ConnectionViewModel();
var page = new ConnectionPage { DataContext = vm };
vm.ConnectionSaved += profile =>
{
var existing = SavedConnections.FirstOrDefault(p => p.Name == profile.Name);
if (existing is not null)
SavedConnections.Remove(existing);
SavedConnections.Add(profile);
_storage.Save(SavedConnections.ToList());
SelectedConnection = profile;
};
var window = new Window
{
Content = page
};
window.Activate();
}
// -----------------------------
// Загрузка скриптов и построение дерева
// -----------------------------
public void LoadScripts(string scriptsFolder)
{
Scripts.Clear();
ScriptTree.Clear();
if (!Directory.Exists(scriptsFolder))
return;
// Строим дерево по корневой папке
var rootNode = BuildScriptTree(scriptsFolder);
ScriptTree.Add(rootNode);
}
private ScriptTreeNode BuildScriptTree(string folderPath)
{
var folderNode = new ScriptTreeNode
{
Name = Path.GetFileName(folderPath),
FilePath = null
};
// Подпапки
foreach (var dir in Directory.GetDirectories(folderPath))
{
var subNode = BuildScriptTree(dir);
folderNode.Children.Add(subNode);
}
// Файлы .sql
foreach (var file in Directory.GetFiles(folderPath, "*.sql"))
{
var meta = _parser.Parse(file);
Scripts.Add(meta);
var fileNode = new ScriptTreeNode
{
Name = Path.GetFileName(file),
FilePath = file
};
folderNode.Children.Add(fileNode);
}
return folderNode;
}
// -----------------------------
// Параметры
// -----------------------------
private async Task LoadParametersForSelectedScriptAsync()
{
Parameters.Clear();
Outputs.Clear();
if (SelectedScript is null)
return;
foreach (var p in SelectedScript.Parameters)
{
var vm = new ParameterViewModel(p);
Parameters.Add(vm);
if (p.TableQuery is not null)
{
var table = await _tableDataProvider.LoadTableAsync(p.TableQuery);
vm.LookupTable = table;
}
}
foreach (var o in SelectedScript.Outputs)
Outputs.Add(new OutputViewModel(o));
}
// -----------------------------
// Выполнение SQL
// -----------------------------
private async Task ExecuteAsync()
{
if (SelectedScript is null)
return;
if (string.IsNullOrWhiteSpace(ConnectionString))
{
// TODO: вывести ContentDialog "Подключение не выбрано"
return;
}
var sqlText = await File.ReadAllTextAsync(SelectedScript.FilePath);
var paramValues = Parameters.ToDictionary(
p => p.Definition,
p => p.Value);
// Если SqlExecutor умеет менять строку подключения динамически — здесь можно прокинуть ConnectionString
_executor.SetConnect(ConnectionString);
var result = await _executor.ExecuteAsync(SelectedScript, sqlText, paramValues);
for (int i = 0; i < Outputs.Count; i++)
{
result.Tables[i].TableName = Outputs[i].Definition.Title;
Outputs[i].Table = result.Tables[i];
}
LastResult = result;
RaisePropertyChanged(nameof(Outputs));
SaveParameterValues(SelectedScript.FilePath, paramValues);
}
// -----------------------------
// Экспорт
// -----------------------------
private void ExportToExcel()
{
if (LastResult is null || LastResult.Tables.Count == 0)
return;
var directory = Path.Combine(AppContext.BaseDirectory, "Export");
Directory.CreateDirectory(directory);
var fileName = $"{LastResult.ScriptName}_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx";
var fullPath = Path.Combine(directory, fileName);
_excelExportService.ExportTablesToExcel(LastResult.Tables, fullPath);
}
// -----------------------------
// Сохранение параметров
// -----------------------------
private void SaveParameterValues(string scriptPath, Dictionary<ParameterDefinition, object?> values)
{
var directory = Path.Combine(AppContext.BaseDirectory, "Config", "Parameters");
Directory.CreateDirectory(directory);
var fileName = Path.GetFileNameWithoutExtension(scriptPath) + ".json";
var fullPath = Path.Combine(directory, fileName);
var payload = new ParameterValueSet
{
ScriptFilePath = scriptPath,
Values = values.ToDictionary(t => t.Key.Name, t => t.Value),
};
var json = JsonSerializer.Serialize(payload, new JsonSerializerOptions
{
WriteIndented = true
});
File.WriteAllText(fullPath, json);
}
}

View File

@@ -9,223 +9,46 @@
<!-- Fluent Mica --> <!-- Fluent Mica -->
<Window.SystemBackdrop> <Window.SystemBackdrop>
<MicaBackdrop Kind="BaseAlt"/> <MicaBackdrop Kind="Base"/>
</Window.SystemBackdrop> </Window.SystemBackdrop>
<Grid x:Name="RootGrid"> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto" />
<RowDefinition Height="*"/> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- ========================= -->
<!-- TOP COMMAND BAR -->
<!-- ========================= -->
<CommandBar
Background="{ThemeResource MicaBaseAltFillColorDefaultBrush}"
Padding="12"
CornerRadius="0"
DefaultLabelPosition="Right">
<CommandBar.PrimaryCommands> <TitleBar Title="SQLVision"
Subtitle="Preview"
IsBackButtonVisible="False"
IsPaneToggleButtonVisible="True"
PaneToggleRequested="TitleBar_PaneToggleRequested"
>
<TitleBar.IconSource>
<FontIconSource Glyph="&#xF4AA;"/>
</TitleBar.IconSource>
</TitleBar>
<!-- Выполнить --> <NavigationView x:Name="nvMain"
<AppBarButton IsSettingsVisible="True"
Label="Выполнить" IsBackButtonVisible="Collapsed"
Command="{Binding ExecuteCommand}" SelectionChanged="nvMain_SelectionChanged"
Style="{StaticResource AccentButtonStyle}">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE768;" />
</AppBarButton.Icon>
</AppBarButton>
<!-- Экспорт -->
<AppBarButton
Label="Экспорт"
Command="{Binding ExportToExcelCommand}">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE74E;" />
</AppBarButton.Icon>
</AppBarButton>
<!-- Help -->
<AppBarButton
Label="Help"
Command="{Binding ShowHelpCommand}">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE897;" />
</AppBarButton.Icon>
</AppBarButton>
<AppBarSeparator/>
<!-- Подключения -->
<mui:AppBarElementContainer>
<StackPanel Orientation="Horizontal" Spacing="8">
<ComboBox
ItemsSource="{Binding SavedConnections}"
SelectedItem="{Binding SelectedConnection, Mode=TwoWay}"
DisplayMemberPath="Name"
Width="220"
PlaceholderText="Подключение"
Style="{StaticResource DefaultComboBoxStyle}"/>
<Button
Content="Новое"
Command="{Binding OpenConnectionCommand}"
Style="{StaticResource AccentButtonStyle}"/>
</StackPanel>
</mui:AppBarElementContainer>
</CommandBar.PrimaryCommands>
</CommandBar>
<!-- ========================= -->
<!-- MAIN CONTENT -->
<!-- ========================= -->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="260"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- LEFT PANEL -->
<Border
Background="{ThemeResource LayerFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="0,0,1,0">
<TreeView
ItemsSource="{Binding ScriptTree}"
SelectionMode="Single"
SelectedItem="{Binding SelectedScriptNode, Mode=TwoWay}"
Margin="12">
<TreeView.ItemTemplate>
<DataTemplate x:DataType="m:ScriptTreeNode">
<TreeViewItem
Content="{Binding Name}"
IsExpanded="True"
ItemsSource="{Binding Children}"/>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Border>
<!-- RIGHT PANEL -->
<Grid Grid.Column="1" Padding="20" RowSpacing="16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Параметры -->
<StackPanel Spacing="12">
<TextBlock
Text="Параметры"
Style="{StaticResource SubtitleTextBlockStyle}"/>
<ItemsControl ItemsSource="{Binding Parameters}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Spacing="6" Margin="0,0,0,16">
<TextBlock
Text="{Binding Definition.DisplayName}"
Style="{StaticResource BodyStrongTextBlockStyle}"/>
<TextBox
Text="{Binding Value, Mode=TwoWay}"
Style="{StaticResource DefaultTextBoxStyle}"
Visibility="{Binding Definition.Type,
Converter={StaticResource ParameterTypeToVisibilityConverter},
ConverterParameter=Text}"/>
<DatePicker
Date="{Binding Value, Mode=TwoWay, Converter={StaticResource ObjectToDateTimeOffsetConverter}}"
Visibility="{Binding Definition.Type,
Converter={StaticResource ParameterTypeToVisibilityConverter},
ConverterParameter=Date}"/>
<CheckBox
IsChecked="{Binding Value, Mode=TwoWay, Converter={StaticResource ObjectToNullableBoolConverter}}"
Content="Да / Нет"
Visibility="{Binding Definition.Type,
Converter={StaticResource ParameterTypeToVisibilityConverter},
ConverterParameter=Bool}"/>
<ComboBox
ItemsSource="{Binding LookupTable}"
SelectedValuePath="Id"
DisplayMemberPath="Name"
SelectedValue="{Binding Value, Mode=TwoWay}"
Style="{StaticResource DefaultComboBoxStyle}"
Visibility="{Binding Definition.Type,
Converter={StaticResource ParameterTypeToVisibilityConverter},
ConverterParameter=Table}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<!-- ВЫВОДЫ -->
<mui:TabView
Grid.Row="1" Grid.Row="1"
TabItemsSource="{Binding Outputs}" PaneDisplayMode="LeftCompact"
Margin="0,16,0,0" IsPaneToggleButtonVisible="False">
CanDragTabs="False" <NavigationView.MenuItems>
IsAddTabButtonVisible="False" <NavigationViewItem Content="Скрипты" Tag="ScriptsTag">
CanReorderTabs="False"> <NavigationViewItem.Icon>
<FontIcon Glyph="&#xE9F9;" />
<mui:TabView.TabItemTemplate> </NavigationViewItem.Icon>
<DataTemplate x:DataType="vm:OutputViewModel"> </NavigationViewItem>
</NavigationView.MenuItems>
<mui:TabViewItem IsClosable="False"> <NavigationView.FooterMenuItems>
<NavigationViewItem Content="Помощь" Tag="HelpTag" Icon="Help" />
<mui:TabViewItem.Header> </NavigationView.FooterMenuItems>
<TextBlock Text="{Binding Definition.Title}"/>
</mui:TabViewItem.Header>
<mui:TabViewItem.Content>
<Grid Padding="8">
<toolkit:DataGrid
AutoGenerateColumns="False"
ItemsSource="{Binding Table.DefaultView}"
GridLinesVisibility="None"
HeadersVisibility="Column"
BorderThickness="0"
RowHeight="32"
Loaded="DataGrid_Loaded"
Visibility="{Binding Definition.Type,
Converter={StaticResource OutputTypeToVisibilityConverter},
ConverterParameter=Table}"/>
</Grid>
</mui:TabViewItem.Content>
</mui:TabViewItem>
</DataTemplate>
</mui:TabView.TabItemTemplate>
</mui:TabView>
</Grid>
</Grid>
<Frame x:Name="contentFrame"/>
</NavigationView>
</Grid> </Grid>
</Window> </Window>

View File

@@ -1,59 +1,44 @@
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using SQLVision.Services; using SQLVision.Views.Scripts;
using SQLVision.ViewModels;
using System; using System;
using System.Data;
using System.IO;
namespace SQLVision.Views; namespace SQLVision.Views;
public sealed partial class MainWindow : Window public sealed partial class MainWindow : Window
{ {
public MainViewModel ViewModel { get; }
public MainWindow() public MainWindow()
{ {
InitializeComponent(); // òåïåðü íàéä¸òñÿ, åñëè x:Class ñîâïàäàåò InitializeComponent(); // òåïåðü íàéä¸òñÿ, åñëè x:Class ñîâïàäàåò
const string connectionString =
"Server=...;Database=...;Trusted_Connection=True;TrustServerCertificate=True;";
var parser = new SqlCommentParser();
var executor = new SqlExecutor(connectionString);
var paramResolver = new ParameterResolver();
var tableDataProvider = new TableDataProvider(connectionString);
var excelExport = new ExcelExportService();
ViewModel = new MainViewModel(parser, executor, paramResolver, tableDataProvider, excelExport);
// Â WinUI 3 DataContext íåò ó Window — ñòàâèì íà êîðíåâîé Grid
RootGrid.DataContext = ViewModel;
var scriptsFolder = Path.Combine(AppContext.BaseDirectory, "Scripts");
ViewModel.LoadScripts(scriptsFolder);
} }
private void DataGrid_Loaded(object sender, RoutedEventArgs e) private void nvMain_SelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args)
{ {
if (sender is CommunityToolkit.WinUI.UI.Controls.DataGrid grid) if (args.IsSettingsSelected)
{ {
var x = grid.DataContext; //contentFrame.Navigate(typeof(SampleSettingsPage));
if (grid.ItemsSource is DataView dv && dv.Table is not null)
{
foreach (System.Data.DataColumn column in dv.Table.Columns)
{
grid.Columns.Add(new CommunityToolkit.WinUI.UI.Controls.DataGridTextColumn
{
Header = column.ColumnName,
// Èñïîëüçóåì ñèíòàêñèñ èíäåêñàòîðà äëÿ DataRowView
Binding = new Microsoft.UI.Xaml.Data.Binding
{
Path = new Microsoft.UI.Xaml.PropertyPath($"[{column.ColumnName}]")
}
});
} }
else
{
var selectedItem = (Microsoft.UI.Xaml.Controls.NavigationViewItem)args.SelectedItem;
if (selectedItem != null)
{
string selectedItemTag = ((string)selectedItem.Tag);
Type? page = selectedItemTag switch
{
"ScriptsTag" => typeof(ScriptsPage),
_ => null,
};
if (page is null) return;
contentFrame.Navigate(page);
} }
} }
} }
private void TitleBar_PaneToggleRequested(Microsoft.UI.Xaml.Controls.TitleBar sender, object args)
{
nvMain.IsPaneOpen = !nvMain.IsPaneOpen;
}
} }

View File

@@ -0,0 +1,218 @@
<?xml version="1.0" encoding="utf-8"?>
<Page
x:Class="SQLVision.Views.Scripts.ScriptsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SQLVision.Views.Scripts"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="using:CommunityToolkit.WinUI.UI.Controls"
xmlns:vm="using:SQLVision.ViewModels"
xmlns:m="using:SQLVision.Models"
xmlns:s="using:SQLVision.Selectors"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="FolderTemplate" x:DataType="m:ScriptTreeNode">
<TreeViewItem AutomationProperties.Name="{x:Bind Name}"
ItemsSource="{x:Bind Children}"
IsExpanded="True">
<StackPanel Orientation="Horizontal">
<FontIcon Glyph="&#xE8B7;" />
<TextBlock Margin="0,0,10,0"/>
<TextBlock Text="{x:Bind Name}" />
</StackPanel>
</TreeViewItem>
</DataTemplate>
<DataTemplate x:Key="FileTemplate" x:DataType="m:ScriptTreeNode">
<TreeViewItem AutomationProperties.Name="{x:Bind Name}">
<StackPanel Orientation="Horizontal">
<FontIcon Glyph="&#xE8A5;" />
<TextBlock Margin="0,0,10,0"/>
<TextBlock Text="{x:Bind Name}"/>
</StackPanel>
</TreeViewItem>
</DataTemplate>
<s:TreeItemTemplateSelector x:Key="ExplorerItemTemplateSelector"
FolderTemplate="{StaticResource FolderTemplate}"
FileTemplate="{StaticResource FileTemplate}" />
</Page.Resources>
<Grid x:Name="RootGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="260"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- LEFT PANEL -->
<TreeView
ItemsSource="{x:Bind ViewModel.ScriptTree}"
Background="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}"
SelectionMode="Single"
ItemTemplateSelector = "{StaticResource ExplorerItemTemplateSelector}"
SelectedItem="{x:Bind ViewModel.SelectedScriptNode, Mode=TwoWay}"
>
</TreeView>
<!-- ========================= -->
<!-- MAIN CONTENT -->
<!-- ========================= -->
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- ========================= -->
<!-- TOP COMMAND BAR -->
<!-- ========================= -->
<CommandBar Grid.Row="0" Background="Transparent" DefaultLabelPosition="Right" HorizontalAlignment="Left">
<!-- Подключения -->
<AppBarElementContainer Margin="8">
<ComboBox ItemsSource="{x:Bind ViewModel.SavedConnections}"
SelectedItem="{x:Bind ViewModel.SelectedConnection, Mode=TwoWay}"
DisplayMemberPath="Name"
Width="220"
PlaceholderText="Подключение"
/>
</AppBarElementContainer>
<AppBarButton Label="Новое подключение" Command="{x:Bind ViewModel.OpenConnectionCommand}" LabelPosition="Collapsed" Width="40">
<AppBarButton.KeyboardAccelerators>
<KeyboardAccelerator Key="N" Modifiers="Control"/>
</AppBarButton.KeyboardAccelerators>
<AppBarButton.Icon>
<SymbolIcon Symbol="Add" />
</AppBarButton.Icon>
</AppBarButton>
<AppBarSeparator/>
<!-- Выполнить -->
<AppBarButton Label="Выполнить" Command="{x:Bind ViewModel.ExecuteCommand}" >
<AppBarButton.KeyboardAccelerators>
<KeyboardAccelerator Key="F5" />
</AppBarButton.KeyboardAccelerators>
<AppBarButton.Icon>
<FontIcon Glyph="&#xE768;" Foreground="{ThemeResource SystemControlHighlightAccentBrush}"/>
</AppBarButton.Icon>
</AppBarButton>
<!-- Экспорт -->
<AppBarButton Label="Экспорт" Command="{x:Bind ViewModel.ExportToExcelCommand}">
<AppBarButton.KeyboardAccelerators>
<KeyboardAccelerator Key="F4" />
</AppBarButton.KeyboardAccelerators>
<AppBarButton.Icon>
<FontIcon Glyph="&#xE74E;" Foreground="{ThemeResource SystemControlHighlightAccentBrush}"/>
</AppBarButton.Icon>
</AppBarButton>
</CommandBar>
<!-- RIGHT PANEL -->
<Grid Grid.Row="1" Padding="20" RowSpacing="16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Параметры -->
<StackPanel Spacing="12">
<TextBlock Text="Параметры"/>
<ItemsControl ItemsSource="{x:Bind ViewModel.Parameters}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:ParameterViewModel">
<StackPanel Spacing="6" Margin="0,0,0,16">
<TextBlock
Text="{x:Bind Definition.DisplayName}"
/>
<TextBox
Text="{x:Bind Value, Mode=TwoWay}"
Visibility="{x:Bind Definition.Type, Converter={StaticResource ParameterTypeToVisibilityConverter}, ConverterParameter=Text}"
/>
<DatePicker
Date="{x:Bind Value, Mode=TwoWay, Converter={StaticResource ObjectToDateTimeOffsetConverter}}"
Visibility="{x:Bind Definition.Type, Converter={StaticResource ParameterTypeToVisibilityConverter}, ConverterParameter=Date}"
/>
<CheckBox
IsChecked="{x:Bind Value, Mode=TwoWay, Converter={StaticResource ObjectToNullableBoolConverter}}"
Content="Да / Нет"
Visibility="{x:Bind Definition.Type, Converter={StaticResource ParameterTypeToVisibilityConverter}, ConverterParameter=Bool}"
/>
<ComboBox
ItemsSource="{x:Bind LookupTable}"
SelectedValuePath="Id"
DisplayMemberPath="Name"
SelectedValue="{x:Bind Value, Mode=TwoWay}"
Visibility="{x:Bind Definition.Type, Converter={StaticResource ParameterTypeToVisibilityConverter}, ConverterParameter=Table}"
/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<!-- ВЫВОДЫ -->
<TabView
Grid.Row="1"
TabItemsSource="{x:Bind ViewModel.Outputs}"
Margin="0,16,0,0"
CanDragTabs="False"
IsAddTabButtonVisible="False"
CanReorderTabs="False">
<TabView.TabItemTemplate>
<DataTemplate x:DataType="vm:OutputViewModel">
<TabViewItem IsClosable="False">
<TabViewItem.Header>
<TextBlock Text="{x:Bind Definition.Title}"/>
</TabViewItem.Header>
<TabViewItem.Content>
<Grid Padding="8">
<toolkit:DataGrid
AutoGenerateColumns="False"
ItemsSource="{x:Bind Table.DefaultView}"
GridLinesVisibility="None"
HeadersVisibility="Column"
BorderThickness="0"
RowHeight="32"
Loaded="DataGrid_Loaded"
Visibility="{x:Bind Definition.Type, Converter={StaticResource OutputTypeToVisibilityConverter}, ConverterParameter=Table}"/>
</Grid>
</TabViewItem.Content>
</TabViewItem>
</DataTemplate>
</TabView.TabItemTemplate>
</TabView>
</Grid>
</Grid>
</Grid>
</Page>

View File

@@ -0,0 +1,54 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using SQLVision.Services;
using SQLVision.ViewModels;
using System;
using System.Data;
using System.IO;
namespace SQLVision.Views.Scripts;
public sealed partial class ScriptsPage : Page
{
public ScriptsViewModel ViewModel { get; }
public ScriptsPage()
{
InitializeComponent();
var parser = new SqlCommentParser();
var executor = new SqlExecutor();
var paramResolver = new ParameterResolver();
var tableDataProvider = new TableDataProvider();
var excelExport = new ExcelExportService();
ViewModel = new ScriptsViewModel(parser, executor, paramResolver, tableDataProvider, excelExport);
var scriptsFolder = Path.Combine(AppContext.BaseDirectory, "Scripts");
ViewModel.LoadScripts(scriptsFolder);
this.DataContext = this;
}
private void DataGrid_Loaded(object sender, RoutedEventArgs e)
{
if (sender is CommunityToolkit.WinUI.UI.Controls.DataGrid grid)
{
var x = grid.DataContext;
if (grid.ItemsSource is DataView dv && dv.Table is not null)
{
foreach (System.Data.DataColumn column in dv.Table.Columns)
{
grid.Columns.Add(new CommunityToolkit.WinUI.UI.Controls.DataGridTextColumn
{
Header = column.ColumnName,
// Èñïîëüçóåì ñèíòàêñèñ èíäåêñàòîðà äëÿ DataRowView
Binding = new Microsoft.UI.Xaml.Data.Binding
{
Path = new Microsoft.UI.Xaml.PropertyPath($"[{column.ColumnName}]")
}
});
}
}
}
}
}