-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathConfigurationWindow.xaml.cs
311 lines (256 loc) · 10.4 KB
/
ConfigurationWindow.xaml.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/* *******************************************************************************************************************
* Application: ChatGPTExtension
*
* Autor: Daniel Liedke
*
* Copyright © Daniel Liedke 2024
* Usage and reproduction in any manner whatsoever without the written permission of Daniel Liedke is strictly forbidden.
*
* Purpose: User control to configure custom actions for GPT
*
* *******************************************************************************************************************/
using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.ComponentModel;
using System.Windows.Controls;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Newtonsoft.Json;
namespace ChatGPTExtension
{
public partial class ConfigurationWindow : Window
{
#region Class Variables
private const string _configurationFileName = "actions.json";
private static readonly string _appDataPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "ChatGPTExtension", "Actions");
private static readonly string _fullConfigPath = System.IO.Path.Combine(_appDataPath, _configurationFileName);
public static bool _dataChanged = false;
#endregion
#region Properties
/// <summary>
/// List of actions to be displayed and manipulated on the UI.
/// </summary>
public ObservableCollection<ActionItem> ActionItems { get; set; } = new ObservableCollection<ActionItem>();
#endregion
#region Constructor
public ConfigurationWindow()
{
InitializeComponent();
DataContext = this;
LoadConfiguration();
new ListViewDragDropManager<ActionItem>(this.ActionListView);
}
#endregion
#region Load/Save configuration
/// <summary>
/// Load existing configurations or default ones if none exists.
/// </summary>
private void LoadConfiguration()
{
var configurations = LoadConfigurationFromFile();
foreach (var config in configurations)
{
AddActionItem(config);
}
}
/// <summary>
/// Load configurations from a JSON file. If the file doesn't exist, create one with default actions.
/// </summary>
private List<ActionItem> LoadConfigurationFromFile()
{
try
{
if (!File.Exists(_fullConfigPath))
{
var defaultActions = GetDefaultActions();
SaveConfigurationToFile(defaultActions);
_dataChanged = true;
return defaultActions;
}
var json = File.ReadAllText(_fullConfigPath);
var configuration = JsonConvert.DeserializeObject<List<ActionItem>>(json);
_dataChanged = false;
return configuration;
}
catch
{
// Old configurations will not work, load default actions
var defaultActions = GetDefaultActions();
SaveConfigurationToFile(defaultActions);
return defaultActions;
}
}
/// <summary>
/// Save the current configurations to the JSON file.
/// </summary>
private void SaveConfiguration()
{
SaveConfigurationToFile(ActionItems.ToList());
_dataChanged = false;
}
/// <summary>
/// Write configurations to a JSON file.
/// </summary>
private void SaveConfigurationToFile(List<ActionItem> actions)
{
if (!Directory.Exists(_appDataPath))
{
Directory.CreateDirectory(_appDataPath);
}
var json = JsonConvert.SerializeObject(actions, Formatting.Indented);
File.WriteAllText(_fullConfigPath, json);
}
private List<ActionItem> GetDefaultActions()
{
// Return default initial actions for this extension
return new List<ActionItem> {
new ActionItem { Name = "Error Handling", Prompt = "Please add error handling to the following {languageCode} code:" },
new ActionItem { Name = "Optimize", Prompt = "Please optimize the following {languageCode} code for performance:" },
new ActionItem { Name = "Comment", Prompt = "Please add comments to the following {languageCode} code:" },
new ActionItem { Name = "Unit Tests", Prompt = "Please create unit tests for the following {languageCode} code:" },
new ActionItem { Name = "Security Issues", Prompt = "Please identify and fix security issues in the following {languageCode} code:" },
new ActionItem { Name = "Thread-safe", Prompt = "Please make the following {languageCode} code thread-safe:" },
new ActionItem { Name = "Explain", Prompt = "Please help me understand the following {languageCode} code:" }
};
}
#endregion
#region Save Click / Cancel Click
private void OnSaveClick(object sender, RoutedEventArgs e)
{
SaveConfiguration();
DialogResult = true;
Close();
}
private void OnCancelClick(object sender, RoutedEventArgs e)
{
Close();
}
#endregion
#region Move Up/Down/Delete/Add
private void MoveUpButton_Click(object sender, RoutedEventArgs e)
{
// Find the ListViewItem that contains the clicked button
var button = (Button)sender;
ListViewItem item = FindListViewItem(button);
if (item != null)
{
var actionToMove = (ActionItem)item.DataContext;
int index = ActionItems.IndexOf(actionToMove);
if (index > 0)
{
ActionItems.Move(index, index - 1);
}
}
_dataChanged = true;
}
private void MoveDownButton_Click(object sender, RoutedEventArgs e)
{
// Find the ListViewItem that contains the clicked button
var button = (Button)sender;
ListViewItem item = FindListViewItem(button);
if (item != null)
{
var actionToMove = (ActionItem)item.DataContext;
int index = ActionItems.IndexOf(actionToMove);
if (index < ActionItems.Count - 1)
{
ActionItems.Move(index, index + 1);
}
}
_dataChanged = true;
}
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
// Find the ListViewItem that contains the clicked button
var button = (Button)sender;
ListViewItem item = FindListViewItem(button);
if (item != null)
{
var actionToDelete = (ActionItem)item.DataContext;
RemoveActionItem(actionToDelete);
}
}
private ListViewItem FindListViewItem(DependencyObject child)
{
while (child != null && !(child is ListViewItem))
{
child = VisualTreeHelper.GetParent(child);
}
return child as ListViewItem;
}
private void AddButton_Click(object sender, RoutedEventArgs e)
{
// Max 20
if (ActionItems.Count >= 20)
{
MessageBox.Show("Maxium of 20 custom actions can be added!", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// Create a new empty ActionItem
var newAction = new ActionItem { Name = "New Action", Prompt = "Enter prompt here" };
// Add it to the ObservableCollection
ActionItems.Add(newAction);
// Set the new item as the selected one in the ListView
ActionListView.SelectedItem = newAction;
// Scroll the ListView to the newly added item
ActionListView.ScrollIntoView(newAction);
_dataChanged = true;
}
private void AddActionItem(ActionItem item)
{
// Add the item to the ObservableCollection
item.PropertyChanged += ActionItem_PropertyChanged;
ActionItems.Add(item);
}
private void RemoveActionItem(ActionItem item)
{
// Remove the item from the ObservableCollection
item.PropertyChanged -= ActionItem_PropertyChanged;
ActionItems.Remove(item);
_dataChanged = true;
}
#endregion
#region Data Change detection / Closing Window
private void ActionItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// Configuration was updated
_dataChanged = true;
}
private void ConfigurationWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// If we have changed the config, ask if user wants to save it
if (_dataChanged)
{
MessageBoxResult result = MessageBox.Show("Do you want to save changes?", "Confirmation", MessageBoxButton.YesNo, MessageBoxImage.Question);
switch (result)
{
case MessageBoxResult.Yes:
SaveConfiguration();
break;
case MessageBoxResult.No:
break;
}
}
}
private void ActionTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
// Configuration was updated
_dataChanged = true;
}
#endregion
#region GPT Wide Button
private void ConfigureGPTWideButton_Click(object sender, RoutedEventArgs e)
{
// Show GPT wide script configuration screen
var gptWideWindow = new GPTWideWindow
{
Owner = this
};
gptWideWindow.ShowDialog();
}
#endregion
}
}