aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ReportIssueView.xaml
blob: aac712f59580d08e8c086b7b64fb1fdc31140b89 (plain)
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
<UserControl x:Class="Tango.MachineStudio.UI.Views.ReportIssueView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls"
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:autoComplete="clr-namespace:Tango.AutoComplete.Editors;assembly=Tango.AutoComplete"
             xmlns:integration="clr-namespace:Tango.Integration.ExternalBridge;assembly=Tango.Integration"
             xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI"
             xmlns:vm="clr-namespace:Tango.MachineStudio.UI.ViewModels"
             xmlns:tfs="clr-namespace:Tango.TFS;assembly=Tango.TFS"
             xmlns:tfss="clr-namespace:Tango.MachineStudio.UI.TFS"
             xmlns:local="clr-namespace:Tango.MachineStudio.UI.Views"
             mc:Ignorable="d" Width="530" Height="660" Background="{StaticResource Dialog.Background}" d:DataContext="{d:DesignInstance Type=vm:ReportIssueViewVM, IsDesignTimeCreatable=False}" Foreground="{StaticResource MainWindow.Foreground}">

    <UserControl.Resources>
        <converters:EnumToItemsSourceConverter x:Key="EnumToItemsSourceConverter" />
        <tfss:TeamMembersProvider x:Key="TeamMembersProvider" />
        <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    </UserControl.Resources>

    <Grid>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="90"/>
                <RowDefinition Height="377*"/>
                <RowDefinition Height="70"/>
            </Grid.RowDefinitions>

            <Grid>
                <StackPanel Orientation="Horizontal">
                    <Image Source="/Images/bug.png" Width="48" RenderOptions.BitmapScalingMode="Fant"></Image>
                    <TextBlock VerticalAlignment="Center" Margin="10 0 0 0" FontSize="20">Report Issue</TextBlock>
                </StackPanel>
            </Grid>

            <Grid Grid.Row="1" Focusable="True">
                <DockPanel>
                    <StackPanel DockPanel.Dock="Top">
                        <DockPanel>
                            <materialDesign:PackIcon Kind="Pencil" Width="24" Height="24" VerticalAlignment="Center" Margin="0 0 10 0" />
                            <TextBox x:Name="txt_title" materialDesign:HintAssist.Hint="Title" materialDesign:HintAssist.IsFloating="True" FontSize="16" Text="{Binding WorkItem.Title}"></TextBox>
                        </DockPanel>

                        <DockPanel Margin="0 10 0 0">
                            <materialDesign:PackIcon Kind="Account" Width="24" Height="24" VerticalAlignment="Center" Margin="0 0 10 0" />
                            <autoComplete:AutoCompleteTextBox Provider="{StaticResource TeamMembersProvider}" SelectedItem="{Binding WorkItem.AssignedTo,Mode=TwoWay}" DisplayMember="DisplayName" materialDesign:HintAssist.Hint="Assigned To" materialDesign:HintAssist.IsFloating="True"></autoComplete:AutoCompleteTextBox>
                        </DockPanel>

                        <DockPanel Margin="0 10 0 0">
                            <materialDesign:PackIcon Kind="Star" Width="24" Height="24" VerticalAlignment="Center" Margin="0 0 10 0" />
                            <Grid>
                                <TextBox IsReadOnly="True" materialDesign:HintAssist.Hint="Area" materialDesign:HintAssist.IsFloating="True"  Text="{Binding WorkItem.Area.Name}" VerticalAlignment="Bottom" Margin="0 0 0 3"></TextBox>
                                <ToggleButton x:Name="toggleArea">
                                    <ToggleButton.Template>
                                        <ControlTemplate TargetType="ToggleButton">
                                            <Grid Background="Transparent">
                                                <Popup Height="200" AllowsTransparency="True" Width="{TemplateBinding ActualWidth}" PopupAnimation="Slide" IsOpen="{Binding IsChecked, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
                                                    <Border Background="{StaticResource MainWindow.Background}" Margin="0 2 0 0" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" CornerRadius="3">
                                                        <TreeView Loaded="TreeView_Loaded" ItemsSource="{Binding Project.Areas}" SelectedItemChanged="TreeView_SelectedItemChanged">
                                                            <TreeView.ItemTemplate>
                                                                <HierarchicalDataTemplate ItemsSource="{Binding SubAreas}">
                                                                    <TextBlock Text="{Binding Name}" />
                                                                </HierarchicalDataTemplate>
                                                            </TreeView.ItemTemplate>
                                                        </TreeView>
                                                    </Border>
                                                </Popup>
                                            </Grid>
                                        </ControlTemplate>
                                    </ToggleButton.Template>
                                </ToggleButton>
                            </Grid>
                        </DockPanel>

                        <DockPanel Margin="0 10 0 0">
                            <materialDesign:PackIcon Kind="CommentAlertOutline" Width="24" Height="24" VerticalAlignment="Center" Margin="0 0 10 0" />
                            <ComboBox materialDesign:HintAssist.Hint="Severity" materialDesign:HintAssist.IsFloating="True" ItemsSource="{Binding Source={x:Type tfs:Severity},Converter={StaticResource EnumToItemsSourceConverter}}" SelectedValue="{Binding WorkItem.Severity}" SelectedValuePath="Value" DisplayMemberPath="DisplayName"></ComboBox>
                        </DockPanel>

                        <DockPanel Margin="0 20 0 0">
                            <materialDesign:PackIcon Kind="Tag" Width="24" Height="24" VerticalAlignment="Center" Margin="0 0 10 0" />
                            <TextBlock VerticalAlignment="Center"><Run>Tags</Run> <Run FontSize="10" Foreground="Gray">(highlight selected tags)</Run></TextBlock>
                        </DockPanel>
                        <ScrollViewer Margin="30 0 0 0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Height="120">
                            <ItemsControl ItemsSource="{Binding SelectedTags}">
                                <ItemsControl.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <WrapPanel IsItemsHost="True" Orientation="Horizontal" />
                                    </ItemsPanelTemplate>
                                </ItemsControl.ItemsPanel>
                                <ItemsControl.ItemTemplate>
                                    <DataTemplate>
                                        <ToggleButton Style="{StaticResource emptyToggleButton}" IsChecked="{Binding IsSelected}" Cursor="Hand">
                                            <Border CornerRadius="5" Margin="0 5 5 5" Padding="5" BorderThickness="1" BorderBrush="DimGray">
                                                <Border.Style>
                                                    <Style TargetType="Border">
                                                        <Setter Property="Background" Value="{StaticResource borderBrush}"></Setter>
                                                        <Style.Triggers>
                                                            <DataTrigger Binding="{Binding IsSelected}" Value="True">
                                                                <Setter Property="Background" Value="{StaticResource AccentColorBrush}"></Setter>
                                                                <Setter Property="TextElement.Foreground" Value="{StaticResource MainWindow.Foreground}"></Setter>
                                                            </DataTrigger>
                                                        </Style.Triggers>
                                                    </Style>
                                                </Border.Style>
                                                <TextBlock Text="{Binding Data.Name}" FontSize="11"></TextBlock>
                                            </Border>
                                        </ToggleButton>
                                    </DataTemplate>
                                </ItemsControl.ItemTemplate>
                            </ItemsControl>
                        </ScrollViewer>

                        <DockPanel Margin="0 20 0 0">
                            <materialDesign:PackIcon Kind="FileImage" Width="24" Height="24" VerticalAlignment="Center" Margin="0 0 10 0" />
                            <TextBlock VerticalAlignment="Center"><Run>Attach Image</Run></TextBlock>
                        </DockPanel>
                        <DockPanel Margin="30 0 0 0">
                            <Button DockPanel.Dock="Right" Margin="10 0 0 0" Style="{StaticResource MaterialDesignFlatButton}" Command="{Binding BrowseImageCommand}">BROWSE</Button>
                            <TextBox IsReadOnly="True" Text="{Binding ImageFile}"></TextBox>
                        </DockPanel>
                    </StackPanel>


                    <Grid>
                        <DockPanel>
                            <DockPanel Margin="0 20 0 0" DockPanel.Dock="Top">
                                <materialDesign:PackIcon Kind="ChartTimeline" Width="24" Height="24" VerticalAlignment="Center" Margin="0 0 10 0" />
                                <TextBlock VerticalAlignment="Center">Steps To Reproduce</TextBlock>
                            </DockPanel>

                            <Grid Margin="30 0 0 0">
                                <TextBox Margin="0 5 0 0" Style="{x:Null}" BorderBrush="{StaticResource borderBrush}" AcceptsReturn="True" TextWrapping="Wrap" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Text="{Binding WorkItem.StepsToReproduce}"></TextBox>
                            </Grid>
                        </DockPanel>
                    </Grid>
                </DockPanel>
            </Grid>

            <Grid Grid.Row="2">
                <Button HorizontalAlignment="Right" Height="40" Width="140" Command="{Binding OKCommand}" Background="{StaticResource RedBrush100}" BorderBrush="{StaticResource RedBrush100}" IsDefault="True">SUBMIT</Button>

                <ItemsControl ItemsSource="{Binding ValidationErrors}" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Center" Visibility="Visible">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Foreground="{StaticResource RedBrush100}" Margin="0 2 0 0"><Run>*</Run> <Run Text="{Binding Path=.,Mode=OneWay}"></Run></TextBlock>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Grid>
        </Grid>
    </Grid>
</UserControl>
ass="p">; } private void TeamFoundationServiceExtendedClient_CurrentUserChanged(object sender, User user) { if (user != null) { user_email = user.Email; Task.Factory.StartNew(async () => { Thread.Sleep(5000); await UpdateCurrentUserResolvedWorkItems(); }); } } public Task<WorkItem> UploadWorkItem(WorkItem workItem) { return UploadWorkItem(Project, workItem); } public async Task UpdateCurrentUserResolvedWorkItems() { try { if (Project != null) { IStudioApplicationManager app = TangoIOC.Default.GetInstance<IStudioApplicationManager>(); var member = GetUserTeamMember(); if (member != null) { var items = await GetWorkItemsCreatedBy(Project, member); items.Where(x => x.StepsToReproduce != null).ToList().ForEach(x => x.StepsToReproduce = x.StepsToReproduce.Replace("<div style=\"white-space:pre;\">", "").Replace("</div>", "")); ResolvedWorkItems = items.Where(x => x.State == State.Resolved && x.ResolvedReason == ResolvedReason.Fixed && x.IsBuildVersionValid && x.FoundInBuildVersion < app.Version).ToObservableCollection(); } else { LogManager.Default.Log($"User '{user_email}' is not part of the VSTS team.", LogCategory.Warning); } } } catch (Exception ex) { LogManager.Log(ex, "Error getting the current user resolved work items."); } } public async Task<WorkItem> CloseWorkItem(WorkItem workItem) { await SetWorkItemState(Project, workItem, State.Closed); var updated = await AddWorkItemComment(Project, workItem, GetUserTeamMember(), "Bug has been verified and closed by " + GetUserTeamMember().DisplayName + " (via Machine Studio)."); ResolvedWorkItems.Remove(workItem); return updated; } public async Task<WorkItem> ReactivateWorkItem(WorkItem workItem) { await SetWorkItemState(Project, workItem, State.New); var updated = await AddWorkItemComment(Project, workItem, GetUserTeamMember(), "Bug has been reactivated by " + GetUserTeamMember().DisplayName + " (via Machine Studio)."); updated = await SetWorkItemAssignment(Project, updated, workItem.ResolvedBy); ResolvedWorkItems.Remove(workItem); return updated; } public void Initialize() { Task.Factory.StartNew(() => { if (!IsInitialized) { try { Project = GetProject("Tango").Result; IsInitialized = true; } catch (Exception ex) { LogManager.Log(ex, "Error initializing the Team Foundation Service client."); } } }); } public WorkItem CreateBug() { WorkItem item = new WorkItem(); IAuthenticationProvider auth = TangoIOC.Default.GetInstance<IAuthenticationProvider>(); IStudioApplicationManager app = TangoIOC.Default.GetInstance<IStudioApplicationManager>(); item.Area = Project.Areas.FirstOrDefault(); item.Iteration = Project.Iterations.FirstOrDefault(); TeamMember currentUser = GetUserTeamMember(); if (currentUser == null) { throw LogManager.Default.Log(new AuthenticationException($"User '{user_email}' is not part of the Tango VSTS team. Please contact your administrator.")); } item.CreatedBy = currentUser; item.ChangedBy = currentUser; item.AuthorizedAs = currentUser; item.FoundInBuild = app.Version.ToString(); item.Priority = Priority.Priority3; item.Severity = Severity.Medium; item.State = State.New; item.Type = WorkItemType.Bug; item.Environment = SettingsManager.Default.GetOrCreate<MachineStudioSettings>().DeploymentSlot.ToDescription(); foreach (var window in Application.Current.Windows.OfType<Window>().Where(x => !String.IsNullOrWhiteSpace(x.Title))) { var bitmap = UIHelper.TakeSnapshot(window); if (!_tempFolder.Exists()) { _tempFolder = TemporaryManager.CreateFolder(); } var tempFile = _tempFolder.CreateFile(); bitmap.SaveJpeg(tempFile.Path, 30); String title = window.Title; item.Attachments.Add(new Attachment() { Description = title + " Screen Capture", FilePath = tempFile.Path, Name = $"{title}.jpg", }); } return item; } private string[] GetLogFiles(FileLogger logger) { string[] fileEntries = new string[1]; fileEntries[0] = logger.LogFile; string fileName = Path.GetFileNameWithoutExtension(logger.LogFile); int indexPos = fileName.IndexOf(FileLogger.FILE_SET_EXTENSION); if (indexPos > 0) { string extension = Path.GetExtension(logger.LogFile); fileName = fileName.Substring(0, indexPos); fileEntries = Directory.GetFiles(logger.Folder, $"{fileName}*{extension}").Where(x => Path.GetFileName(x).StartsWith(logger.Tag)).OrderBy(x => x.Length).ThenBy(x => x).ToArray(); } return fileEntries; } public void FinalizeBug(WorkItem item) { IAuthenticationProvider auth = TangoIOC.Default.GetInstance<IAuthenticationProvider>(); IStudioApplicationManager app = TangoIOC.Default.GetInstance<IStudioApplicationManager>(); FileLogger appFileLogger = LogManager.Default.RegisteredLoggers.FirstOrDefault(x => x.GetType() == typeof(FileLogger)) as FileLogger; FileLogger embeddedFileLogger = MachineOperator.EmbeddedLogManager.RegisteredLoggers.FirstOrDefault(x => x.GetType() == typeof(FileLogger)) as FileLogger; if (appFileLogger != null) { string[] logFiles = GetLogFiles(appFileLogger); foreach( string file in logFiles) { var appLogFile = _tempFolder.CreateImaginaryFile(); File.Copy(file, appLogFile.Path); item.Attachments.Add(new Attachment() { Description = "Application Log File", FilePath = appLogFile.Path, Name = Path.GetFileName(file), }); } } if (embeddedFileLogger != null && File.Exists(embeddedFileLogger.LogFile)) { string[] logFiles = GetLogFiles(embeddedFileLogger); foreach (string file in logFiles) { var embeddedLogFile = _tempFolder.CreateImaginaryFile(); File.Copy(file, embeddedLogFile.Path); item.Attachments.Add(new Attachment() { Description = "Embedded Log File", FilePath = embeddedLogFile.Path, Name = Path.GetFileName(file), }); } } //Add session log file.. if (MachineOperator.EnableSessionLogFile) { var file = MachineOperator.SessionLogger.LogFile; if (file != null && File.Exists(file)) { var sessionLogFile = _tempFolder.CreateImaginaryFile(); File.Copy(file, sessionLogFile.Path); item.Attachments.Add(new Attachment() { Description = "Session Log File", FilePath = sessionLogFile.Path, Name = Path.GetFileName(file), }); } } SystemInformationModel sysModel = new SystemInformationModel(); sysModel.ApplicationVersion = app.Version.ToString(); sysModel.EmbeddedVersion = "N/A"; sysModel.HostName = Environment.MachineName; sysModel.UserName = auth.CurrentUser.Contact.FullName; if (app.ConnectedMachine != null) { Machine machine = app.Machine; sysModel.Machine = machine; sysModel.EmbeddedVersion = app.ConnectedMachine.DeviceInformation.Version; sysModel.ConfigurationString = machine.Configuration.Clone().ToJsonString(); if (app.ConnectedMachine.CurrentProcessParameters != null) { sysModel.LoadedProcessParametersString = app.ConnectedMachine.CurrentProcessParameters.ToJsonString(nameof(ProcessParametersTable.ProcessParametersTablesGroup)); } if (app.ConnectedMachine.CurrentHardwareConfiguration != null) { sysModel.LoadedHardwareConfigurationString = app.ConnectedMachine.CurrentHardwareConfiguration.ToJsonString(); } } if (app.Machine != null && app.ConnectedMachine != null && app.ConnectedMachine.DeviceInformation != null) { item.EmbeddedVersion = app.ConnectedMachine.DeviceInformation.Version; item.MachineSerialNumber = app.Machine.SerialNumber; } String html = String.Empty; using (var stream = EmbeddedResourceHelper.GetEmbeddedResourceStream("Tango.MachineStudio.UI.TFS.SystemInformationTemplate.cshtml")) { StreamReader reader = new StreamReader(stream); html = reader.ReadToEnd(); } item.SystemInformation = CodeGeneration.Helper.Parse(html, sysModel); item.StepsToReproduce = String.Format("<div style=\"white-space:pre\">{0}</div>", item.StepsToReproduce); } private TeamMember GetUserTeamMember() { IAuthenticationProvider auth = TangoIOC.Default.GetInstance<IAuthenticationProvider>(); TeamMember currentUser = Project.Members.SingleOrDefault(x => x.UniqueName.ToLower().Contains(auth.CurrentUser.Email.ToLower())); return currentUser; } } }