Разделены страницы
This commit is contained in:
8
SQLVision/Models/ITreeNode.cs
Normal file
8
SQLVision/Models/ITreeNode.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace SQLVision.Models
|
||||
{
|
||||
public interface ITreeNode
|
||||
{
|
||||
bool IsFolder { get; }
|
||||
string Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace SQLVision.Models;
|
||||
|
||||
public sealed class ScriptTreeNode
|
||||
public sealed class ScriptTreeNode : ITreeNode
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public string? FilePath { get; set; }
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<ItemGroup>
|
||||
<None Remove="Views\ConnectionPage.xaml" />
|
||||
<None Remove="Views\HelpWindow.xaml" />
|
||||
<None Remove="Views\Scripts\ScriptsPage.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -48,6 +49,9 @@
|
||||
<None Update="Scripts\ServerInfo.sql">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Page Update="Views\Scripts\ScriptsPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="Views\ConnectionPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
|
||||
18
SQLVision/Selectors/TreeItemTemplateSelector.cs
Normal file
18
SQLVision/Selectors/TreeItemTemplateSelector.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,7 @@ namespace SQLVision.Services;
|
||||
|
||||
public sealed class SqlExecutor
|
||||
{
|
||||
private string _connectionString;
|
||||
|
||||
public SqlExecutor(string connectionString)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
}
|
||||
private string _connectionString = "";
|
||||
|
||||
public void SetConnect(string connectionString)
|
||||
{
|
||||
|
||||
@@ -7,9 +7,9 @@ namespace SQLVision.Services;
|
||||
|
||||
public sealed class TableDataProvider
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
private string _connectionString = "";
|
||||
|
||||
public TableDataProvider(string connectionString)
|
||||
public void SetConnect(string connectionString)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,16 @@ public sealed class ParameterViewModel : BaseViewModel
|
||||
public ParameterViewModel(ParameterDefinition 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
328
SQLVision/ViewModels/ScriptsViewModel.cs
Normal file
328
SQLVision/ViewModels/ScriptsViewModel.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -9,223 +9,46 @@
|
||||
|
||||
<!-- Fluent Mica -->
|
||||
<Window.SystemBackdrop>
|
||||
<MicaBackdrop Kind="BaseAlt"/>
|
||||
<MicaBackdrop Kind="Base"/>
|
||||
</Window.SystemBackdrop>
|
||||
|
||||
<Grid x:Name="RootGrid">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</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=""/>
|
||||
</TitleBar.IconSource>
|
||||
</TitleBar>
|
||||
|
||||
<!-- Выполнить -->
|
||||
<AppBarButton
|
||||
Label="Выполнить"
|
||||
Command="{Binding ExecuteCommand}"
|
||||
Style="{StaticResource AccentButtonStyle}">
|
||||
<AppBarButton.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</AppBarButton.Icon>
|
||||
</AppBarButton>
|
||||
|
||||
<!-- Экспорт -->
|
||||
<AppBarButton
|
||||
Label="Экспорт"
|
||||
Command="{Binding ExportToExcelCommand}">
|
||||
<AppBarButton.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</AppBarButton.Icon>
|
||||
</AppBarButton>
|
||||
|
||||
<!-- Help -->
|
||||
<AppBarButton
|
||||
Label="Help"
|
||||
Command="{Binding ShowHelpCommand}">
|
||||
<AppBarButton.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</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
|
||||
<NavigationView x:Name="nvMain"
|
||||
IsSettingsVisible="True"
|
||||
IsBackButtonVisible="Collapsed"
|
||||
SelectionChanged="nvMain_SelectionChanged"
|
||||
Grid.Row="1"
|
||||
TabItemsSource="{Binding Outputs}"
|
||||
Margin="0,16,0,0"
|
||||
CanDragTabs="False"
|
||||
IsAddTabButtonVisible="False"
|
||||
CanReorderTabs="False">
|
||||
|
||||
<mui:TabView.TabItemTemplate>
|
||||
<DataTemplate x:DataType="vm:OutputViewModel">
|
||||
|
||||
<mui:TabViewItem IsClosable="False">
|
||||
|
||||
<mui:TabViewItem.Header>
|
||||
<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>
|
||||
PaneDisplayMode="LeftCompact"
|
||||
IsPaneToggleButtonVisible="False">
|
||||
<NavigationView.MenuItems>
|
||||
<NavigationViewItem Content="Скрипты" Tag="ScriptsTag">
|
||||
<NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</NavigationViewItem.Icon>
|
||||
</NavigationViewItem>
|
||||
</NavigationView.MenuItems>
|
||||
<NavigationView.FooterMenuItems>
|
||||
<NavigationViewItem Content="Помощь" Tag="HelpTag" Icon="Help" />
|
||||
</NavigationView.FooterMenuItems>
|
||||
|
||||
<Frame x:Name="contentFrame"/>
|
||||
</NavigationView>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,59 +1,44 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using SQLVision.Services;
|
||||
using SQLVision.ViewModels;
|
||||
using SQLVision.Views.Scripts;
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
|
||||
namespace SQLVision.Views;
|
||||
|
||||
public sealed partial class MainWindow : Window
|
||||
{
|
||||
public MainViewModel ViewModel { get; }
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
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;
|
||||
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}]")
|
||||
}
|
||||
});
|
||||
//contentFrame.Navigate(typeof(SampleSettingsPage));
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
218
SQLVision/Views/Scripts/ScriptsPage.xaml
Normal file
218
SQLVision/Views/Scripts/ScriptsPage.xaml
Normal 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="" />
|
||||
<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="" />
|
||||
<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="" Foreground="{ThemeResource SystemControlHighlightAccentBrush}"/>
|
||||
</AppBarButton.Icon>
|
||||
</AppBarButton>
|
||||
|
||||
<!-- Экспорт -->
|
||||
<AppBarButton Label="Экспорт" Command="{x:Bind ViewModel.ExportToExcelCommand}">
|
||||
<AppBarButton.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="F4" />
|
||||
</AppBarButton.KeyboardAccelerators>
|
||||
<AppBarButton.Icon>
|
||||
<FontIcon Glyph="" 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>
|
||||
54
SQLVision/Views/Scripts/ScriptsPage.xaml.cs
Normal file
54
SQLVision/Views/Scripts/ScriptsPage.xaml.cs
Normal 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}]")
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user