diff --git a/.idea/.idea.PSCHelpdesk/.idea/avalonia.xml b/.idea/.idea.PSCHelpdesk/.idea/avalonia.xml
index 9ebf1d8..e15ef08 100644
--- a/.idea/.idea.PSCHelpdesk/.idea/avalonia.xml
+++ b/.idea/.idea.PSCHelpdesk/.idea/avalonia.xml
@@ -14,8 +14,9 @@
+
-
+
diff --git a/.idea/.idea.PSCHelpdesk/.idea/workspace.xml b/.idea/.idea.PSCHelpdesk/.idea/workspace.xml
index 8d5a2b3..13b9f93 100644
--- a/.idea/.idea.PSCHelpdesk/.idea/workspace.xml
+++ b/.idea/.idea.PSCHelpdesk/.idea/workspace.xml
@@ -11,21 +11,26 @@
+
-
+
-
+
+
-
+
+
+
+
+
-
@@ -39,24 +44,19 @@
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
@@ -85,7 +85,7 @@
+
@@ -227,99 +228,41 @@
file://$PROJECT_DIR$/HetznerServer/Menu/MainMenu.cs
13
-
+
+
+
+
+
+
+
+
- file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs
- 93
-
+ file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/SettingsViewModel.cs
+ 38
+
-
+
-
+
-
+
- file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs
- 94
-
+ file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/SettingsViewModel.cs
+ 36
+
-
+
-
+
-
-
-
- file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs
- 25
-
-
-
-
-
-
-
-
-
-
-
- file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs
- 27
-
-
-
-
-
-
-
-
-
-
-
- file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs
- 113
-
-
-
-
-
-
-
-
-
-
-
- file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs
- 86
-
-
-
-
-
-
-
-
-
-
-
- file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs
- 107
-
-
-
-
-
-
-
-
-
+
diff --git a/HetznerServer/HetznerServer.cs b/HetznerServer/HetznerServer.cs
index 1bde1a3..7b07e20 100644
--- a/HetznerServer/HetznerServer.cs
+++ b/HetznerServer/HetznerServer.cs
@@ -18,24 +18,28 @@ public class HetznerServer : Contract
return "HetznerServerPlugin";
}
- public Item addMenu()
+ public void Configure()
{
- //var menuService = Ioc.Default.GetService();
+ var menuService = Ioc.Default.GetRequiredService();
var serverTab = new Item()
{
Header = "Server",
+ CommandParameter = new ServerViewModel()
};
- //menuService.AddMenuItem(serverTab);
- return serverTab;
+ menuService.AddMenuItem(serverTab);
+
+ var settingsService = Ioc.Default.GetRequiredService();
+ var hetznerSettings = new Shared.Setting.Item()
+ {
+ Header = "HetznerSettings",
+ CommandParameter = new HetznerSettingsViewModel()
+ };
+ settingsService.AddSetting(hetznerSettings);
}
- public UserControl LoadView()
+ public List LoadViews()
{
- return new ServerView();
+ return [new ServerView(), new HetznerSettingsView()];
}
- public object LoadViewModel()
- {
- return new ServerViewModel();
- }
}
\ No newline at end of file
diff --git a/HetznerServer/HetznerServer.csproj b/HetznerServer/HetznerServer.csproj
index e7b6027..a1dffd4 100644
--- a/HetznerServer/HetznerServer.csproj
+++ b/HetznerServer/HetznerServer.csproj
@@ -23,26 +23,26 @@
-
+
..\..\..\.nuget\packages\avalonia\11.2.0\ref\net8.0\Avalonia.Controls.dll
-
+
..\..\..\.nuget\packages\avalonia.controls.datagrid\11.2.0\lib\net8.0\Avalonia.Controls.DataGrid.dll
-
+
..\..\..\.nuget\packages\communitytoolkit.mvvm\8.2.1\lib\net6.0\CommunityToolkit.Mvvm.dll
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/HetznerServer/HetznerServerBootstrap.cs b/HetznerServer/HetznerServerBootstrap.cs
index 6bd1b1b..f3756e0 100644
--- a/HetznerServer/HetznerServerBootstrap.cs
+++ b/HetznerServer/HetznerServerBootstrap.cs
@@ -6,17 +6,15 @@ using Prise.Plugin;
namespace PSCHelpdesk.Plugins.HetznerServer;
-[PluginBootstrapper(PluginType = typeof(HetznerServer))]
+
public class HetznerServerBootstrap : IPluginBootstrapper
{
- [BootstrapperService(ServiceType = typeof(IMenuService), ProxyType = typeof(MenuService))]
private readonly IMenuService menuService;
public IServiceCollection Bootstrap(IServiceCollection services)
{
services.AddSingleton(this.menuService);
services.AddTransient();
- Ioc.Default.ConfigureServices(services.BuildServiceProvider());
return services;
}
}
diff --git a/HetznerServer/Models/Settings.cs b/HetznerServer/Models/Settings.cs
new file mode 100644
index 0000000..51381a3
--- /dev/null
+++ b/HetznerServer/Models/Settings.cs
@@ -0,0 +1,6 @@
+namespace PSCHelpdesk.Plugins.HetznerServer.Models;
+
+public class Settings
+{
+
+}
\ No newline at end of file
diff --git a/HetznerServer/ViewModels/HetznerSettingsViewModel.cs b/HetznerServer/ViewModels/HetznerSettingsViewModel.cs
new file mode 100644
index 0000000..310f270
--- /dev/null
+++ b/HetznerServer/ViewModels/HetznerSettingsViewModel.cs
@@ -0,0 +1,26 @@
+using System.Collections.ObjectModel;
+using Avalonia.Controls;
+using CommunityToolkit.Mvvm.Input;
+using HetznerCloudApi;
+using PSCHelpdesk.Plugins.HetznerServer.Models;
+using PSCHelpdesk.Plugins.HetznerServer.Views;
+using PSCHelpdesk.Shared.ViewModels;
+
+namespace PSCHelpdesk.Plugins.HetznerServer.ViewModels;
+
+public partial class HetznerSettingsViewModel : ViewModelBase, IViewModelBase
+{
+ private string _apiKey;
+ public HetznerSettingsViewModel()
+ {
+ LocalSetting settings = new LocalSetting();
+ settings.Load();
+
+ }
+
+ public string ApiKey
+ {
+ get => _apiKey;
+ set => SetAndRaisePropertyChanged(ref _apiKey, value);
+ }
+}
\ No newline at end of file
diff --git a/HetznerServer/Views/HetznerSettingsView.axaml b/HetznerServer/Views/HetznerSettingsView.axaml
new file mode 100644
index 0000000..021800d
--- /dev/null
+++ b/HetznerServer/Views/HetznerSettingsView.axaml
@@ -0,0 +1,8 @@
+
+ Welcome to settings hetzner!
+
diff --git a/HetznerServer/Views/HetznerSettingsView.axaml.cs b/HetznerServer/Views/HetznerSettingsView.axaml.cs
new file mode 100644
index 0000000..d468b39
--- /dev/null
+++ b/HetznerServer/Views/HetznerSettingsView.axaml.cs
@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace PSCHelpdesk.Plugins.HetznerServer.Views;
+
+public partial class HetznerSettingsView : UserControl
+{
+ public HetznerSettingsView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/PSCHelpdesk.sln.DotSettings.user b/PSCHelpdesk.sln.DotSettings.user
index 77fab93..b831f9c 100644
--- a/PSCHelpdesk.sln.DotSettings.user
+++ b/PSCHelpdesk.sln.DotSettings.user
@@ -45,6 +45,7 @@
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
diff --git a/PSCHelpdesk/PSCHelpdesk/Models/GlobalSetting.cs b/PSCHelpdesk/PSCHelpdesk/Models/GlobalSetting.cs
deleted file mode 100644
index 46c4378..0000000
--- a/PSCHelpdesk/PSCHelpdesk/Models/GlobalSetting.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using Nucs.JsonSettings;
-
-namespace PSCHelpdesk.Models;
-
-public class GlobalSetting: JsonSettings
-{
- public string HetznerApiKey { get; set; }
-
- public override string FileName { get; set; }
-}
\ No newline at end of file
diff --git a/PSCHelpdesk/PSCHelpdesk/Services/MenuService.cs b/PSCHelpdesk/PSCHelpdesk/Services/MenuService.cs
index 42ea187..a797756 100644
--- a/PSCHelpdesk/PSCHelpdesk/Services/MenuService.cs
+++ b/PSCHelpdesk/PSCHelpdesk/Services/MenuService.cs
@@ -47,7 +47,7 @@ public class MenuService: ReactiveObject, IMenuService
var testTab = new Item()
{
Header = "Plugins T",
- ViewModel = typeof(TestViewModel),
+ CommandParameter = new TestViewModel(),
};
/*var settingsTab = new MenuItem()
{
diff --git a/PSCHelpdesk/PSCHelpdesk/Services/PluginService.cs b/PSCHelpdesk/PSCHelpdesk/Services/PluginService.cs
index 453583d..0faa163 100644
--- a/PSCHelpdesk/PSCHelpdesk/Services/PluginService.cs
+++ b/PSCHelpdesk/PSCHelpdesk/Services/PluginService.cs
@@ -1,4 +1,5 @@
using System.Linq;
+using Avalonia.Controls;
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using PSCHelpdesk.Shared.Menu;
@@ -18,6 +19,7 @@ public class PluginService
private List toLoadPlugins = new List();
private Dictionary loadedPlugins = new Dictionary();
private Dictionary foundPlugins = new Dictionary();
+ private Dictionary controls = new Dictionary();
public PluginService()
{
@@ -60,9 +62,9 @@ public class PluginService
var pluginLoader = Ioc.Default.GetService(typeof(IPluginLoader)) as IPluginLoader;
var menuService = Ioc.Default.GetRequiredService();
+ var settingsService = Ioc.Default.GetRequiredService();
var testService = Ioc.Default.GetRequiredService();
var appService = Ioc.Default.GetService(typeof(AppService)) as AppService;
- //var settingsService = Ioc.Default.GetService();
var pluginAssemblies = await pluginLoader.FindPlugins(getPluginPath());
var pluginToEnable = pluginAssemblies.FirstOrDefault(p => Path.GetFileNameWithoutExtension(p.AssemblyName) == pluginName);
@@ -75,6 +77,7 @@ public class PluginService
.AddHostTypes(new[] {typeof(Application), typeof(Item)})
.AddRemoteTypes(new []{typeof(Item)})
.AddHostService(menuService)
+ .AddHostService(settingsService)
.AddHostService(testService)
//.AddHostService(settingsService)
@@ -85,13 +88,26 @@ public class PluginService
if (!this.loadedPlugins.ContainsKey(pluginName))
{
loadedPlugins.Add(plugin.GetName(), plugin);
- var item = plugin.addMenu();
- item.GetView = plugin.LoadView();
- item.ViewModel = plugin.LoadViewModel();
- menuService.AddMenuItem(item);
+ plugin.Configure();
+ var items = plugin.LoadViews();
+ foreach (var item in items)
+ {
+ this.controls.Add(item.GetType().FullName, item);
+ }
+
appService.AppIsStarted();
}
}
}
+ public UserControl GetView(string viewName)
+ {
+ return this.controls[viewName];
+ }
+
+ public bool ViewExists(string viewName)
+ {
+ return this.controls.ContainsKey(viewName);
+ }
+
}
diff --git a/PSCHelpdesk/PSCHelpdesk/Services/SettingsService.cs b/PSCHelpdesk/PSCHelpdesk/Services/SettingsService.cs
new file mode 100644
index 0000000..5513a7c
--- /dev/null
+++ b/PSCHelpdesk/PSCHelpdesk/Services/SettingsService.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using CommunityToolkit.Mvvm.DependencyInjection;
+using PSCHelpdesk.Shared.Setting;
+using PSCHelpdesk.Shared.Service;
+using PSCHelpdesk.ViewModels;
+using ReactiveUI;
+
+namespace PSCHelpdesk.Services;
+
+public class SettingsService: ReactiveObject, ISettingsService
+ {
+ private List- _settings = new List
- ();
+
+ public event EventHandler MenuChanged;
+
+ public List
- Settings
+ {
+ get => this._settings;
+ private set => this.RaiseAndSetIfChanged(ref this._settings, value);
+ }
+
+ public SettingsService()
+ {
+ this.Settings.Clear();
+ this.Settings.Clear();
+
+ var globalSettings = new Item()
+ {
+ Header = "Global",
+ CommandParameter = new SettingsGlobalViewModel(),
+ };
+
+ this.Settings.Add(globalSettings);
+ }
+
+ public void AddSetting(Item item)
+ {
+ this.Settings.Add(item);
+ OnMenuChanged(EventArgs.Empty);
+ }
+
+ protected virtual void OnMenuChanged(EventArgs e)
+ {
+ MenuChanged?.Invoke(this, e);
+ }
+
+ public Item GetMenuOptionByLabel(string coreSettingsActiveMenuItem)
+ {
+ foreach (var setting in this._settings)
+ {
+ if (setting.Header == coreSettingsActiveMenuItem)
+ {
+ return setting;
+ }
+ }
+
+ return null;
+ }
+ }
\ No newline at end of file
diff --git a/PSCHelpdesk/PSCHelpdesk/Startup.cs b/PSCHelpdesk/PSCHelpdesk/Startup.cs
index 1f6e658..99546a7 100644
--- a/PSCHelpdesk/PSCHelpdesk/Startup.cs
+++ b/PSCHelpdesk/PSCHelpdesk/Startup.cs
@@ -14,12 +14,14 @@ class Startup
public static void RegisterServices()
{
var menuService = new MenuService();
+ var settingsService = new SettingsService();
var te = new ServiceCollection()
.AddPrise()
.AddFactory(()=> new AvaloniaPluginResultConverter())
.AddSingleton()
.AddSingleton(menuService)
+ .AddSingleton(settingsService)
.AddSingleton(new TestService())
.AddSingleton()
.AddTransient();
diff --git a/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs b/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs
index 3d37fcc..d365e1b 100644
--- a/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs
+++ b/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs
@@ -24,6 +24,11 @@ public class ViewLocator : IDataTemplate
var name = data.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);
+
+ if (_pluginService.ViewExists(name))
+ {
+ return _pluginService.GetView(name);
+ }
if (type != null)
{
@@ -36,7 +41,6 @@ public class ViewLocator : IDataTemplate
public bool Match(object data)
{
var l = data is IViewModelBase;
- Console.WriteLine($"[{l}:{data}]");
return l;
}
}
\ No newline at end of file
diff --git a/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs b/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs
index c24e549..4853255 100644
--- a/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs
+++ b/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs
@@ -50,21 +50,29 @@ public class MainWindowViewModel : ViewModelBase
{
foreach (var menuServiceMenuItem in MenuService.MenuItems)
{
- menuServiceMenuItem.Command = this.ClickMenu;
- this.MenuItems.Add(menuServiceMenuItem);
+ if (!this.MenuItems.Contains(menuServiceMenuItem))
+ {
+ menuServiceMenuItem.Command = this.ClickMenu;
+ this.MenuItems.Add(menuServiceMenuItem);
+ }
+
}
foreach (var menuServiceMenuItem in MenuService.MenuOptionItems)
{
- menuServiceMenuItem.Command = this.ClickMenu;
- this.MenuItems.Add(menuServiceMenuItem);
+ if (!this.MenuItems.Contains(menuServiceMenuItem))
+ {
+ menuServiceMenuItem.Command = this.ClickMenu;
+ this.MenuItems.Add(menuServiceMenuItem);
+ }
}
};
this.InitializeClient();
this.SelectedItem = MenuService.MenuItems.Last();
-
+ this.ContentDisplay = this.SelectedItem.CommandParameter;
+
}
private List
- _menuItems;
@@ -84,16 +92,6 @@ public class MainWindowViewModel : ViewModelBase
{
get
{
- if (SelectedItem.GetView != null)
- {
- var vm = SelectedItem.GetView;
- return vm;
- }
- if (SelectedItem.ViewModel != null)
- {
- var vm = SelectedItem.ViewModel;
- return vm;
- }
return this.SelectedItem?.CommandParameter;
}
}
@@ -105,18 +103,7 @@ public class MainWindowViewModel : ViewModelBase
if (obj != null)
{
this.SelectedItem = obj;
- if (SelectedItem.GetView != null)
- {
- this.ContentDisplay = SelectedItem.GetView;
- }
- if (obj.ViewModel != null)
- {
- this.ContentDisplay = obj.ViewModel;
- }
- else
- {
- this.ContentDisplay = obj.CommandParameter;
- }
+ this.ContentDisplay = obj.CommandParameter;
}
}
}
\ No newline at end of file
diff --git a/PSCHelpdesk/PSCHelpdesk/ViewModels/PluginListViewModel.cs b/PSCHelpdesk/PSCHelpdesk/ViewModels/PluginListViewModel.cs
index 7ebe678..cec9db3 100644
--- a/PSCHelpdesk/PSCHelpdesk/ViewModels/PluginListViewModel.cs
+++ b/PSCHelpdesk/PSCHelpdesk/ViewModels/PluginListViewModel.cs
@@ -6,7 +6,7 @@ using PSCHelpdesk.Shared.ViewModels;
namespace PSCHelpdesk.ViewModels;
-class PluginListViewModel : ViewModelBase
+class PluginListViewModel : ViewModelBase, IViewModelBase
{
public RelayCommand
diff --git a/PSCHelpdesk/PSCHelpdesk/Views/SettingsView.axaml.cs b/PSCHelpdesk/PSCHelpdesk/Views/SettingsView.axaml.cs
index ae8f950..ec66cc1 100644
--- a/PSCHelpdesk/PSCHelpdesk/Views/SettingsView.axaml.cs
+++ b/PSCHelpdesk/PSCHelpdesk/Views/SettingsView.axaml.cs
@@ -17,90 +17,4 @@ public partial class SettingsView : UserControl
{
InitializeComponent();
}
-
- private async void ChooseGlobalSettingsFile_OnClick(object? sender, RoutedEventArgs e)
- {
- var topLevel = TopLevel.GetTopLevel(this);
-
- // Start async operation to open the dialog.
- var file = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
- {
- Title = "Choose File",
- AllowMultiple = false
- });
-
- if (file is not null && file.Count > 0)
- {
- SettingsViewModel model = (SettingsViewModel)this.DataContext;
- model.GlobalConfigFilePath = file[0].Path.ToString();
- }
- }
-
- private void SaveSettings_OnClick(object? sender, RoutedEventArgs e)
- {
- LocalSetting settings = new LocalSetting();
- Directory.CreateDirectory(Path.GetDirectoryName(settings.FileName));
- SettingsViewModel model = (SettingsViewModel)this.DataContext;
- settings.GlobalConfigFilePath = model.GlobalConfigFilePath;
- settings.SCPClientExecutable = model.ScpClientPath;
- settings.SSHClientExecutable = model.SshClientPath;
- settings.SCPClientExecutableArgs = model.ScpClientPathArgs;
- settings.SSHClientExecutableArgs = model.SshClientPathArgs;
- settings.PrivateSSHKeyPath = model.PrivateSSHKeyPath;
- settings.Save();
- }
-
- private async void ChooseSshClientFile_OnClick(object? sender, RoutedEventArgs e)
- {
- var topLevel = TopLevel.GetTopLevel(this);
-
- // Start async operation to open the dialog.
- var file = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
- {
- Title = "Choose File",
- AllowMultiple = false
- });
-
- if (file is not null && file.Count > 0)
- {
- SettingsViewModel model = (SettingsViewModel)this.DataContext;
- model.SshClientPath = file[0].Path.ToString();
- }
- }
-
- private async void ChooseScpClientFile_OnClick(object? sender, RoutedEventArgs e)
- {
- var topLevel = TopLevel.GetTopLevel(this);
-
- // Start async operation to open the dialog.
- var file = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
- {
- Title = "Choose File",
- AllowMultiple = false
- });
-
- if (file is not null && file.Count > 0)
- {
- SettingsViewModel model = (SettingsViewModel)this.DataContext;
- model.ScpClientPath = file[0].Path.ToString();
- }
- }
-
- private async void ChoosePrivateSshFile_OnClick(object? sender, RoutedEventArgs e)
- {
- var topLevel = TopLevel.GetTopLevel(this);
-
- // Start async operation to open the dialog.
- var file = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
- {
- Title = "Choose File",
- AllowMultiple = false
- });
-
- if (file is not null && file.Count > 0)
- {
- SettingsViewModel model = (SettingsViewModel)this.DataContext;
- model.PrivateSSHKeyPath = file[0].Path.ToString();
- }
- }
}
\ No newline at end of file
diff --git a/Shared/Menu/Item.cs b/Shared/Menu/Item.cs
index 27c7d6b..b2e6a69 100644
--- a/Shared/Menu/Item.cs
+++ b/Shared/Menu/Item.cs
@@ -7,14 +7,9 @@ namespace PSCHelpdesk.Shared.Menu;
public class Item
{
public string Icon { get; set; }
-
public string Header { get; set; }
public ICommand Command { get; set; }
-
public object CommandParameter { get; set; }
- public object ViewModel { get; set; }
-
- public UserControl GetView { get; set; }
public IList- Items { get; set; }
}
\ No newline at end of file
diff --git a/Shared/Plugin/Contract.cs b/Shared/Plugin/Contract.cs
index cb9596c..02aeb20 100644
--- a/Shared/Plugin/Contract.cs
+++ b/Shared/Plugin/Contract.cs
@@ -8,9 +8,8 @@ public interface Contract
{
string GetName();
- Item addMenu();
-
- UserControl LoadView();
- object LoadViewModel();
+ void Configure();
+ List LoadViews();
+
}
\ No newline at end of file
diff --git a/Shared/Service/ISettingsService.cs b/Shared/Service/ISettingsService.cs
new file mode 100644
index 0000000..ed4db66
--- /dev/null
+++ b/Shared/Service/ISettingsService.cs
@@ -0,0 +1,8 @@
+using PSCHelpdesk.Shared.Setting;
+
+namespace PSCHelpdesk.Shared.Service;
+
+public interface ISettingsService
+{
+ public void AddSetting(Item item);
+}
diff --git a/Shared/Setting/Item.cs b/Shared/Setting/Item.cs
new file mode 100644
index 0000000..8a4c5de
--- /dev/null
+++ b/Shared/Setting/Item.cs
@@ -0,0 +1,7 @@
+namespace PSCHelpdesk.Shared.Setting;
+
+public class Item
+{
+ public string Header { get; set; }
+ public object CommandParameter { get; set; }
+}
\ No newline at end of file