jj: first pass of entitydesigner
This commit is contained in:
50
EDMI_ClientSuite/EntityDesigner/ClassControlBuilder.vb
Normal file
50
EDMI_ClientSuite/EntityDesigner/ClassControlBuilder.vb
Normal file
@@ -0,0 +1,50 @@
|
||||
Public Class ClassControlBuilder
|
||||
#Region "State"
|
||||
Private _DesignMode As Boolean
|
||||
#End Region
|
||||
|
||||
#Region "Constants"
|
||||
Private DEFAULT_SIZE As Size = New Size(200, 27)
|
||||
|
||||
Private DEFAULT_TEXT As String = "Unnamed Control"
|
||||
#End Region
|
||||
|
||||
Public Sub New(DesignMode As Boolean)
|
||||
_DesignMode = DesignMode
|
||||
End Sub
|
||||
|
||||
Private Function GetRandomControlName(Name As String)
|
||||
Return $"{Name}-{ClassUtils.ShortGUID()}"
|
||||
End Function
|
||||
|
||||
Public Function CreateLabel() As Label
|
||||
Dim Metadata As New ClassControlUtils.ControlMetadata() With {
|
||||
.Id = 4711
|
||||
}
|
||||
|
||||
Dim oLabel As New Label() With {
|
||||
.Name = GetRandomControlName("Label"),
|
||||
.Text = DEFAULT_TEXT,
|
||||
.AutoSize = False,
|
||||
.Size = DEFAULT_SIZE,
|
||||
.Tag = Metadata
|
||||
}
|
||||
|
||||
Return oLabel
|
||||
End Function
|
||||
|
||||
Public Function CreateTextbox() As TextBox
|
||||
Dim Metadata As New ClassControlUtils.ControlMetadata() With {
|
||||
.Id = 4711
|
||||
}
|
||||
|
||||
Dim oTextbox As New TextBox() With {
|
||||
.Name = GetRandomControlName("Textbox"),
|
||||
.Size = DEFAULT_SIZE,
|
||||
.Tag = Metadata
|
||||
}
|
||||
|
||||
Return oTextbox
|
||||
End Function
|
||||
|
||||
End Class
|
||||
10
EDMI_ClientSuite/EntityDesigner/ClassControlUtils.vb
Normal file
10
EDMI_ClientSuite/EntityDesigner/ClassControlUtils.vb
Normal file
@@ -0,0 +1,10 @@
|
||||
Public Class ClassControlUtils
|
||||
Public Enum ControlType
|
||||
Label = 0
|
||||
TextBox = 1
|
||||
End Enum
|
||||
|
||||
Public Class ControlMetadata
|
||||
Public Id As Integer
|
||||
End Class
|
||||
End Class
|
||||
146
EDMI_ClientSuite/EntityDesigner/frmEntityDesigner.Designer.vb
generated
Normal file
146
EDMI_ClientSuite/EntityDesigner/frmEntityDesigner.Designer.vb
generated
Normal file
@@ -0,0 +1,146 @@
|
||||
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
|
||||
Partial Class frmEntityDesigner
|
||||
Inherits DevExpress.XtraEditors.XtraForm
|
||||
|
||||
'Das Formular überschreibt den Löschvorgang, um die Komponentenliste zu bereinigen.
|
||||
<System.Diagnostics.DebuggerNonUserCode()>
|
||||
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
|
||||
Try
|
||||
If disposing AndAlso components IsNot Nothing Then
|
||||
components.Dispose()
|
||||
End If
|
||||
Finally
|
||||
MyBase.Dispose(disposing)
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
'Wird vom Windows Form-Designer benötigt.
|
||||
Private components As System.ComponentModel.IContainer
|
||||
|
||||
'Hinweis: Die folgende Prozedur ist für den Windows Form-Designer erforderlich.
|
||||
'Das Bearbeiten ist mit dem Windows Form-Designer möglich.
|
||||
'Das Bearbeiten mit dem Code-Editor ist nicht möglich.
|
||||
<System.Diagnostics.DebuggerStepThrough()>
|
||||
Private Sub InitializeComponent()
|
||||
Me.SplitContainerMain = New DevExpress.XtraEditors.SplitContainerControl()
|
||||
Me.PanelMain = New EDMI_ClientSuite.SnapPanel()
|
||||
Me.TabControlDetail = New DevExpress.XtraTab.XtraTabControl()
|
||||
Me.TabPageProperties = New DevExpress.XtraTab.XtraTabPage()
|
||||
Me.PropertyGridControl1 = New DevExpress.XtraVerticalGrid.PropertyGridControl()
|
||||
Me.TabPageControls = New DevExpress.XtraTab.XtraTabPage()
|
||||
Me.btnTextbox = New System.Windows.Forms.Button()
|
||||
Me.btnLabel = New System.Windows.Forms.Button()
|
||||
CType(Me.SplitContainerMain, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
Me.SplitContainerMain.SuspendLayout()
|
||||
CType(Me.TabControlDetail, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
Me.TabControlDetail.SuspendLayout()
|
||||
Me.TabPageProperties.SuspendLayout()
|
||||
CType(Me.PropertyGridControl1, System.ComponentModel.ISupportInitialize).BeginInit()
|
||||
Me.TabPageControls.SuspendLayout()
|
||||
Me.SuspendLayout()
|
||||
'
|
||||
'SplitContainerMain
|
||||
'
|
||||
Me.SplitContainerMain.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.SplitContainerMain.Location = New System.Drawing.Point(0, 0)
|
||||
Me.SplitContainerMain.Name = "SplitContainerMain"
|
||||
Me.SplitContainerMain.Panel1.Controls.Add(Me.PanelMain)
|
||||
Me.SplitContainerMain.Panel1.Text = "Panel1"
|
||||
Me.SplitContainerMain.Panel2.Controls.Add(Me.TabControlDetail)
|
||||
Me.SplitContainerMain.Panel2.Text = "Panel2"
|
||||
Me.SplitContainerMain.Size = New System.Drawing.Size(800, 450)
|
||||
Me.SplitContainerMain.SplitterPosition = 583
|
||||
Me.SplitContainerMain.TabIndex = 0
|
||||
Me.SplitContainerMain.Text = "SplitContainerControl1"
|
||||
'
|
||||
'PanelMain
|
||||
'
|
||||
Me.PanelMain.AllowDrop = True
|
||||
Me.PanelMain.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.PanelMain.GridSize = 8
|
||||
Me.PanelMain.Location = New System.Drawing.Point(0, 0)
|
||||
Me.PanelMain.Name = "PanelMain"
|
||||
Me.PanelMain.ShowGrid = True
|
||||
Me.PanelMain.Size = New System.Drawing.Size(583, 450)
|
||||
Me.PanelMain.TabIndex = 0
|
||||
'
|
||||
'TabControlDetail
|
||||
'
|
||||
Me.TabControlDetail.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.TabControlDetail.Location = New System.Drawing.Point(0, 0)
|
||||
Me.TabControlDetail.Name = "TabControlDetail"
|
||||
Me.TabControlDetail.SelectedTabPage = Me.TabPageProperties
|
||||
Me.TabControlDetail.Size = New System.Drawing.Size(205, 450)
|
||||
Me.TabControlDetail.TabIndex = 1
|
||||
Me.TabControlDetail.TabPages.AddRange(New DevExpress.XtraTab.XtraTabPage() {Me.TabPageControls, Me.TabPageProperties})
|
||||
'
|
||||
'TabPageProperties
|
||||
'
|
||||
Me.TabPageProperties.Controls.Add(Me.PropertyGridControl1)
|
||||
Me.TabPageProperties.Name = "TabPageProperties"
|
||||
Me.TabPageProperties.Size = New System.Drawing.Size(203, 425)
|
||||
Me.TabPageProperties.Text = "Properties"
|
||||
'
|
||||
'PropertyGridControl1
|
||||
'
|
||||
Me.PropertyGridControl1.Cursor = System.Windows.Forms.Cursors.Hand
|
||||
Me.PropertyGridControl1.Dock = System.Windows.Forms.DockStyle.Fill
|
||||
Me.PropertyGridControl1.Location = New System.Drawing.Point(0, 0)
|
||||
Me.PropertyGridControl1.Name = "PropertyGridControl1"
|
||||
Me.PropertyGridControl1.Size = New System.Drawing.Size(203, 425)
|
||||
Me.PropertyGridControl1.TabIndex = 0
|
||||
'
|
||||
'TabPageControls
|
||||
'
|
||||
Me.TabPageControls.Controls.Add(Me.btnTextbox)
|
||||
Me.TabPageControls.Controls.Add(Me.btnLabel)
|
||||
Me.TabPageControls.Name = "TabPageControls"
|
||||
Me.TabPageControls.Size = New System.Drawing.Size(262, 425)
|
||||
Me.TabPageControls.Text = "Controls"
|
||||
'
|
||||
'btnTextbox
|
||||
'
|
||||
Me.btnTextbox.Location = New System.Drawing.Point(15, 48)
|
||||
Me.btnTextbox.Name = "btnTextbox"
|
||||
Me.btnTextbox.Size = New System.Drawing.Size(122, 23)
|
||||
Me.btnTextbox.TabIndex = 1
|
||||
Me.btnTextbox.Text = "Textbox"
|
||||
Me.btnTextbox.UseVisualStyleBackColor = True
|
||||
'
|
||||
'btnLabel
|
||||
'
|
||||
Me.btnLabel.Location = New System.Drawing.Point(15, 19)
|
||||
Me.btnLabel.Name = "btnLabel"
|
||||
Me.btnLabel.Size = New System.Drawing.Size(122, 23)
|
||||
Me.btnLabel.TabIndex = 0
|
||||
Me.btnLabel.Text = "Label"
|
||||
Me.btnLabel.UseVisualStyleBackColor = True
|
||||
'
|
||||
'frmEntityDesigner
|
||||
'
|
||||
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
|
||||
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
|
||||
Me.ClientSize = New System.Drawing.Size(800, 450)
|
||||
Me.Controls.Add(Me.SplitContainerMain)
|
||||
Me.Name = "frmEntityDesigner"
|
||||
Me.Text = "Entitäten Designer"
|
||||
CType(Me.SplitContainerMain, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
Me.SplitContainerMain.ResumeLayout(False)
|
||||
CType(Me.TabControlDetail, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
Me.TabControlDetail.ResumeLayout(False)
|
||||
Me.TabPageProperties.ResumeLayout(False)
|
||||
CType(Me.PropertyGridControl1, System.ComponentModel.ISupportInitialize).EndInit()
|
||||
Me.TabPageControls.ResumeLayout(False)
|
||||
Me.ResumeLayout(False)
|
||||
|
||||
End Sub
|
||||
|
||||
Friend WithEvents SplitContainerMain As DevExpress.XtraEditors.SplitContainerControl
|
||||
Friend WithEvents TabControlDetail As DevExpress.XtraTab.XtraTabControl
|
||||
Friend WithEvents TabPageProperties As DevExpress.XtraTab.XtraTabPage
|
||||
Friend WithEvents PropertyGridControl1 As DevExpress.XtraVerticalGrid.PropertyGridControl
|
||||
Friend WithEvents TabPageControls As DevExpress.XtraTab.XtraTabPage
|
||||
Friend WithEvents PanelMain As SnapPanel
|
||||
Friend WithEvents btnTextbox As Button
|
||||
Friend WithEvents btnLabel As Button
|
||||
End Class
|
||||
120
EDMI_ClientSuite/EntityDesigner/frmEntityDesigner.resx
Normal file
120
EDMI_ClientSuite/EntityDesigner/frmEntityDesigner.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
128
EDMI_ClientSuite/EntityDesigner/frmEntityDesigner.vb
Normal file
128
EDMI_ClientSuite/EntityDesigner/frmEntityDesigner.vb
Normal file
@@ -0,0 +1,128 @@
|
||||
|
||||
|
||||
Public Class frmEntityDesigner
|
||||
Private _IsMouseDown As Boolean = False
|
||||
Private _IsMouseMoving As Boolean = False
|
||||
|
||||
Private _BeginPosition As Point = Nothing
|
||||
Private _EndPosition As Point = Nothing
|
||||
Private _LastCursorPosition As Point = Nothing
|
||||
|
||||
Private _CurrentControl As Control = Nothing
|
||||
Private _ControlBuilder As ClassControlBuilder = Nothing
|
||||
|
||||
Private Sub frmEntityDesigner_Load(sender As Object, e As EventArgs) Handles Me.Load
|
||||
' Assign Control Types to DragDrop Buttons
|
||||
btnLabel.Tag = ClassControlUtils.ControlType.Label
|
||||
btnTextbox.Tag = ClassControlUtils.ControlType.TextBox
|
||||
|
||||
|
||||
_ControlBuilder = New ClassControlBuilder(DesignMode:=True)
|
||||
End Sub
|
||||
|
||||
|
||||
#Region "Control Buttons Events"
|
||||
Private Sub btnControl_MouseDown(sender As Object, e As MouseEventArgs) Handles btnLabel.MouseDown, btnTextbox.MouseDown
|
||||
_IsMouseDown = True
|
||||
End Sub
|
||||
|
||||
Private Sub btnControl_MouseMove(sender As Button, e As MouseEventArgs) Handles btnLabel.MouseMove, btnTextbox.MouseMove
|
||||
If _IsMouseDown Then
|
||||
Dim oButton = sender
|
||||
Dim oType As ClassControlUtils.ControlType = oButton.Tag
|
||||
|
||||
oButton.DoDragDrop(oType.ToString, DragDropEffects.Copy)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub SnapPanelMain_DragEnter(sender As Object, e As DragEventArgs) Handles PanelMain.DragEnter
|
||||
If (e.Data.GetDataPresent(DataFormats.Text)) Then
|
||||
e.Effect = DragDropEffects.Copy
|
||||
Else
|
||||
e.Effect = DragDropEffects.None
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub SnapPanelMain_DragDrop(sender As Object, e As DragEventArgs) Handles PanelMain.DragDrop
|
||||
Dim data As String = e.Data.GetData(DataFormats.Text)
|
||||
Dim type = ClassUtils.ToEnum(Of ClassControlUtils.ControlType)(data)
|
||||
|
||||
HandleDragDrop(type)
|
||||
End Sub
|
||||
#End Region
|
||||
|
||||
#Region "Control Events"
|
||||
Private Sub Control_MouseDown(sender As Control, e As MouseEventArgs)
|
||||
If e.Button = MouseButtons.Left Then
|
||||
_CurrentControl = sender
|
||||
_BeginPosition = e.Location
|
||||
|
||||
' Set the mode flag to signal the MouseMove event handler that it
|
||||
' needs to now calculate new positions for our control
|
||||
_IsMouseMoving = True
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub Control_MouseMove(sender As Control, e As MouseEventArgs)
|
||||
If _CurrentControl Is Nothing Or Not _IsMouseMoving Then
|
||||
Exit Sub
|
||||
End If
|
||||
|
||||
Cursor = Cursors.Hand
|
||||
|
||||
Dim oControl = sender
|
||||
Dim oCursorPosition As Point = PanelMain.PointToClient(Cursor.Position)
|
||||
Dim oNewPosition As New Point(oCursorPosition.X - _BeginPosition.X, oCursorPosition.Y - _BeginPosition.Y)
|
||||
|
||||
' If control will be moved out the of bounds of the panel at TOP/LEFT side, exit.
|
||||
If oNewPosition.X < 0 Or oNewPosition.Y < 0 Then
|
||||
Exit Sub
|
||||
End If
|
||||
|
||||
oControl.Location = oNewPosition
|
||||
End Sub
|
||||
|
||||
Private Sub Control_MouseUp(sender As Object, e As MouseEventArgs)
|
||||
If Not _IsMouseMoving Then
|
||||
Exit Sub
|
||||
End If
|
||||
|
||||
_IsMouseMoving = False
|
||||
_EndPosition = e.Location
|
||||
|
||||
Cursor = Cursors.Default
|
||||
End Sub
|
||||
|
||||
Private Sub SetEventHandlers(Control As Control)
|
||||
AddHandler Control.MouseDown, AddressOf Control_MouseDown
|
||||
AddHandler Control.MouseMove, AddressOf Control_MouseMove
|
||||
AddHandler Control.MouseUp, AddressOf Control_MouseUp
|
||||
End Sub
|
||||
#End Region
|
||||
|
||||
Private Sub HandleDragDrop(type As ClassControlUtils.ControlType)
|
||||
Dim oCursorPosition As Point = PanelMain.PointToClient(Cursor.Position)
|
||||
Dim oControl As Control = Nothing
|
||||
|
||||
Select Case type
|
||||
Case ClassControlUtils.ControlType.Label
|
||||
oControl = _ControlBuilder.CreateLabel()
|
||||
Case ClassControlUtils.ControlType.TextBox
|
||||
oControl = _ControlBuilder.CreateTextbox()
|
||||
Case Else
|
||||
MsgBox($"Unknown Control Type {type.ToString}")
|
||||
Exit Sub
|
||||
End Select
|
||||
|
||||
' Set Location to current cursor position
|
||||
oControl.Location = oCursorPosition
|
||||
|
||||
' Attach Eventhandlers
|
||||
SetEventHandlers(oControl)
|
||||
|
||||
' Add the control to the panel
|
||||
PanelMain.Controls.Add(oControl)
|
||||
End Sub
|
||||
|
||||
|
||||
End Class
|
||||
Reference in New Issue
Block a user