Script Canvas, replace the text replacement system to a JSON file based one (#5228)
It is now possible to right click on nodes on the node palette to navigate to the file that holds the text data for any given node, this way it is easy to update and improve the naming of titles, subtitles, categories, tool tips and slots.
This commit is contained in:
+26
-18
@@ -91,17 +91,19 @@ namespace GraphCanvas
|
||||
|
||||
}
|
||||
|
||||
void GeneralNodeTitleComponent::SetTitle(const AZStd::string& title)
|
||||
void GeneralNodeTitleComponent::SetDetails(const AZStd::string& title, const AZStd::string& subtitle)
|
||||
{
|
||||
m_title.SetFallback(title);
|
||||
m_title = title;
|
||||
m_subTitle = subtitle;
|
||||
|
||||
if (m_generalNodeTitleWidget)
|
||||
{
|
||||
m_generalNodeTitleWidget->SetTitle(title);
|
||||
m_generalNodeTitleWidget->SetDetails(title, subtitle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GeneralNodeTitleComponent::SetTranslationKeyedTitle(const TranslationKeyedString& title)
|
||||
void GeneralNodeTitleComponent::SetTitle(const AZStd::string& title)
|
||||
{
|
||||
m_title = title;
|
||||
|
||||
@@ -113,20 +115,10 @@ namespace GraphCanvas
|
||||
|
||||
AZStd::string GeneralNodeTitleComponent::GetTitle() const
|
||||
{
|
||||
return m_title.GetDisplayString();
|
||||
return m_title;
|
||||
}
|
||||
|
||||
void GeneralNodeTitleComponent::SetSubTitle(const AZStd::string& subtitle)
|
||||
{
|
||||
m_subTitle.SetFallback(subtitle);
|
||||
|
||||
if (m_generalNodeTitleWidget)
|
||||
{
|
||||
m_generalNodeTitleWidget->SetSubTitle(subtitle);
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralNodeTitleComponent::SetTranslationKeyedSubTitle(const TranslationKeyedString& subtitle)
|
||||
{
|
||||
m_subTitle = subtitle;
|
||||
|
||||
@@ -138,7 +130,7 @@ namespace GraphCanvas
|
||||
|
||||
AZStd::string GeneralNodeTitleComponent::GetSubTitle() const
|
||||
{
|
||||
return m_subTitle.GetDisplayString();
|
||||
return m_subTitle;
|
||||
}
|
||||
|
||||
QGraphicsWidget* GeneralNodeTitleComponent::GetGraphicsWidget()
|
||||
@@ -270,7 +262,23 @@ namespace GraphCanvas
|
||||
SceneNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void GeneralNodeTitleGraphicsWidget::SetTitle(const TranslationKeyedString& title)
|
||||
void GeneralNodeTitleGraphicsWidget::SetDetails(const AZStd::string& title, const AZStd::string& subtitle)
|
||||
{
|
||||
bool updateLayout = false;
|
||||
if (m_titleWidget)
|
||||
{
|
||||
m_titleWidget->SetLabel(title);
|
||||
updateLayout = true;
|
||||
}
|
||||
|
||||
if (m_subTitleWidget)
|
||||
{
|
||||
m_subTitleWidget->SetLabel(subtitle);
|
||||
updateLayout = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralNodeTitleGraphicsWidget::SetTitle(const AZStd::string& title)
|
||||
{
|
||||
if (m_titleWidget)
|
||||
{
|
||||
@@ -279,7 +287,7 @@ namespace GraphCanvas
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralNodeTitleGraphicsWidget::SetSubTitle(const TranslationKeyedString& subtitle)
|
||||
void GeneralNodeTitleGraphicsWidget::SetSubTitle(const AZStd::string& subtitle)
|
||||
{
|
||||
if (m_subTitleWidget)
|
||||
{
|
||||
|
||||
@@ -68,12 +68,11 @@ namespace GraphCanvas
|
||||
////
|
||||
|
||||
// NodeTitleRequestBus
|
||||
void SetDetails(const AZStd::string& title, const AZStd::string& subtitle) override;
|
||||
void SetTitle(const AZStd::string& title) override;
|
||||
void SetTranslationKeyedTitle(const TranslationKeyedString& title) override;
|
||||
AZStd::string GetTitle() const override;
|
||||
|
||||
void SetSubTitle(const AZStd::string& subtitle) override;
|
||||
void SetTranslationKeyedSubTitle(const TranslationKeyedString& subtitle) override;
|
||||
AZStd::string GetSubTitle() const override;
|
||||
|
||||
QGraphicsWidget* GetGraphicsWidget() override;
|
||||
@@ -96,8 +95,8 @@ namespace GraphCanvas
|
||||
private:
|
||||
GeneralNodeTitleComponent(const GeneralNodeTitleComponent&) = delete;
|
||||
|
||||
TranslationKeyedString m_title;
|
||||
TranslationKeyedString m_subTitle;
|
||||
AZStd::string m_title;
|
||||
AZStd::string m_subTitle;
|
||||
|
||||
AZStd::string m_basePalette;
|
||||
|
||||
@@ -123,9 +122,10 @@ namespace GraphCanvas
|
||||
|
||||
void Activate();
|
||||
void Deactivate();
|
||||
|
||||
void SetTitle(const TranslationKeyedString& title);
|
||||
void SetSubTitle(const TranslationKeyedString& subtitle);
|
||||
|
||||
void SetDetails(const AZStd::string& title, const AZStd::string& subtitle);
|
||||
void SetTitle(const AZStd::string& title);
|
||||
void SetSubTitle(const AZStd::string& subtitle);
|
||||
|
||||
void SetPaletteOverride(AZStd::string_view paletteOverride);
|
||||
void SetPaletteOverride(const AZ::Uuid& uuid);
|
||||
|
||||
@@ -1007,20 +1007,16 @@ namespace GraphCanvas
|
||||
{
|
||||
if (!configuration.m_name.empty())
|
||||
{
|
||||
cloneConfiguration->m_name.Clear();
|
||||
cloneConfiguration->m_name.SetFallback(configuration.m_name);
|
||||
cloneConfiguration->m_name = configuration.m_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZStd::string nodeTitle;
|
||||
NodeTitleRequestBus::EventResult(nodeTitle, configuration.m_targetEndpoint.GetNodeId(), &NodeTitleRequests::GetTitle);
|
||||
|
||||
AZStd::string displayName = AZStd::string::format("%s:%s", nodeTitle.c_str(), cloneConfiguration->m_name.GetDisplayString().c_str());
|
||||
AZStd::string displayName = AZStd::string::format("%s:%s", nodeTitle.c_str(), cloneConfiguration->m_name.c_str());
|
||||
|
||||
// Gain some context. Lost the ability to refresh the strings.
|
||||
// Should be fixable once we get an actual use case for this setup.
|
||||
cloneConfiguration->m_name.Clear();
|
||||
cloneConfiguration->m_name.SetFallback(displayName);
|
||||
cloneConfiguration->m_name = displayName;
|
||||
}
|
||||
|
||||
AZ::Entity* slotEntity = nullptr;
|
||||
|
||||
@@ -315,12 +315,6 @@ namespace GraphCanvas
|
||||
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnTooltipChanged, m_configuration.GetTooltip());
|
||||
}
|
||||
|
||||
void NodeComponent::SetTranslationKeyedTooltip(const TranslationKeyedString& tooltip)
|
||||
{
|
||||
m_configuration.SetTooltip(tooltip.GetDisplayString());
|
||||
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnTooltipChanged, m_configuration.GetTooltip());
|
||||
}
|
||||
|
||||
void NodeComponent::AddSlot(const AZ::EntityId& slotId)
|
||||
{
|
||||
AZ_Assert(slotId.IsValid(), "Slot entity (ID: %s) is not valid!", slotId.ToString().data());
|
||||
|
||||
@@ -106,7 +106,6 @@ namespace GraphCanvas
|
||||
|
||||
// NodeRequestBus
|
||||
void SetTooltip(const AZStd::string& tooltip) override;
|
||||
void SetTranslationKeyedTooltip(const TranslationKeyedString& tooltip) override;
|
||||
const AZStd::string GetTooltip() const override { return m_configuration.GetTooltip(); }
|
||||
|
||||
void SetShowInOutliner(bool showInOutliner) override { m_configuration.SetShowInOutliner(showInOutliner); }
|
||||
|
||||
@@ -337,12 +337,9 @@ namespace GraphCanvas
|
||||
{
|
||||
m_connectionType = slotRequests->GetConnectionType();
|
||||
|
||||
TranslationKeyedString slotName = slotRequests->GetTranslationKeyedName();
|
||||
m_slotText->SetLabel(slotRequests->GetName());
|
||||
|
||||
m_slotText->SetLabel(slotName);
|
||||
|
||||
TranslationKeyedString toolTip = slotRequests->GetTranslationKeyedTooltip();
|
||||
OnTooltipChanged(toolTip);
|
||||
OnTooltipChanged(slotRequests->GetTooltip());
|
||||
|
||||
const SlotConfiguration& configuration = slotRequests->GetSlotConfiguration();
|
||||
|
||||
@@ -393,12 +390,12 @@ namespace GraphCanvas
|
||||
AZ::SystemTickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void DataSlotLayout::OnNameChanged(const TranslationKeyedString& name)
|
||||
void DataSlotLayout::OnNameChanged(const AZStd::string& name)
|
||||
{
|
||||
m_slotText->SetLabel(name);
|
||||
}
|
||||
|
||||
void DataSlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
|
||||
void DataSlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
|
||||
{
|
||||
AZ::Uuid dataType;
|
||||
DataSlotRequestBus::EventResult(dataType, m_owner.GetEntityId(), &DataSlotRequests::GetDataTypeId);
|
||||
@@ -406,7 +403,7 @@ namespace GraphCanvas
|
||||
AZStd::string typeString;
|
||||
GraphModelRequestBus::EventResult(typeString, GetSceneId(), &GraphModelRequests::GetDataTypeString, dataType);
|
||||
|
||||
AZStd::string displayText = tooltip.GetDisplayString();
|
||||
AZStd::string displayText = tooltip;
|
||||
|
||||
if (!typeString.empty())
|
||||
{
|
||||
@@ -486,7 +483,7 @@ namespace GraphCanvas
|
||||
if (!iconPath.empty())
|
||||
{
|
||||
m_textDecoration = new GraphCanvasLabel();
|
||||
m_textDecoration->SetLabel(iconPath, "", "");
|
||||
m_textDecoration->SetLabel(iconPath);
|
||||
m_textDecoration->setToolTip(toolTip.c_str());
|
||||
|
||||
ApplyTextStyle(m_textDecoration);
|
||||
|
||||
@@ -120,8 +120,8 @@ namespace GraphCanvas
|
||||
// SlotNotificationBus
|
||||
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
|
||||
|
||||
void OnNameChanged(const TranslationKeyedString&) override;
|
||||
void OnTooltipChanged(const TranslationKeyedString&) override;
|
||||
void OnNameChanged(const AZStd::string&) override;
|
||||
void OnTooltipChanged(const AZStd::string&) override;
|
||||
////
|
||||
|
||||
// StyleNotificationBus
|
||||
|
||||
+7
-14
@@ -58,13 +58,8 @@ namespace GraphCanvas
|
||||
{
|
||||
m_connectionType = slotRequests->GetConnectionType();
|
||||
|
||||
TranslationKeyedString slotName = slotRequests->GetTranslationKeyedName();
|
||||
|
||||
m_slotText->SetLabel(slotName);
|
||||
|
||||
TranslationKeyedString toolTip = slotRequests->GetTranslationKeyedTooltip();
|
||||
|
||||
OnTooltipChanged(toolTip);
|
||||
m_slotText->SetLabel(slotRequests->GetName());
|
||||
OnTooltipChanged(slotRequests->GetTooltip());
|
||||
|
||||
const SlotConfiguration& configuration = slotRequests->GetSlotConfiguration();
|
||||
|
||||
@@ -88,17 +83,15 @@ namespace GraphCanvas
|
||||
OnStyleChanged();
|
||||
}
|
||||
|
||||
void ExecutionSlotLayout::OnNameChanged(const TranslationKeyedString& name)
|
||||
void ExecutionSlotLayout::OnNameChanged(const AZStd::string& name)
|
||||
{
|
||||
m_slotText->SetLabel(name);
|
||||
}
|
||||
|
||||
void ExecutionSlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
|
||||
void ExecutionSlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
|
||||
{
|
||||
AZStd::string displayText = tooltip.GetDisplayString();
|
||||
|
||||
m_slotConnectionPin->setToolTip(displayText.c_str());
|
||||
m_slotText->setToolTip(displayText.c_str());
|
||||
m_slotConnectionPin->setToolTip(tooltip.c_str());
|
||||
m_slotText->setToolTip(tooltip.c_str());
|
||||
}
|
||||
|
||||
void ExecutionSlotLayout::OnStyleChanged()
|
||||
@@ -132,7 +125,7 @@ namespace GraphCanvas
|
||||
if (!textDecoration.empty())
|
||||
{
|
||||
m_textDecoration = new GraphCanvasLabel();
|
||||
m_textDecoration->SetLabel(textDecoration, "", "");
|
||||
m_textDecoration->SetLabel(textDecoration);
|
||||
m_textDecoration->setToolTip(toolTip.c_str());
|
||||
|
||||
ApplyTextStyle(m_textDecoration);
|
||||
|
||||
+2
-2
@@ -46,8 +46,8 @@ namespace GraphCanvas
|
||||
// SlotNotificationBus
|
||||
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
|
||||
|
||||
void OnNameChanged(const TranslationKeyedString& name) override;
|
||||
void OnTooltipChanged(const TranslationKeyedString& tooltip) override;
|
||||
void OnNameChanged(const AZStd::string& name) override;
|
||||
void OnTooltipChanged(const AZStd::string& tooltip) override;
|
||||
////
|
||||
|
||||
// StyleNotificationBus
|
||||
|
||||
+8
-10
@@ -119,13 +119,13 @@ namespace GraphCanvas
|
||||
{
|
||||
SlotRequestBus::EventResult(m_connectionType, m_owner.GetEntityId(), &SlotRequests::GetConnectionType);
|
||||
|
||||
TranslationKeyedString slotName;
|
||||
SlotRequestBus::EventResult(slotName, m_owner.GetEntityId(), &SlotRequests::GetTranslationKeyedName);
|
||||
AZStd::string slotName;
|
||||
SlotRequestBus::EventResult(slotName, m_owner.GetEntityId(), &SlotRequests::GetName);
|
||||
|
||||
m_slotText->SetLabel(slotName);
|
||||
|
||||
TranslationKeyedString toolTip;
|
||||
SlotRequestBus::EventResult(toolTip, m_owner.GetEntityId(), &SlotRequests::GetTranslationKeyedTooltip);
|
||||
AZStd::string toolTip;
|
||||
SlotRequestBus::EventResult(toolTip, m_owner.GetEntityId(), &SlotRequests::GetTooltip);
|
||||
|
||||
OnTooltipChanged(toolTip);
|
||||
|
||||
@@ -151,17 +151,15 @@ namespace GraphCanvas
|
||||
OnStyleChanged();
|
||||
}
|
||||
|
||||
void ExtenderSlotLayout::OnNameChanged(const TranslationKeyedString& name)
|
||||
void ExtenderSlotLayout::OnNameChanged(const AZStd::string& name)
|
||||
{
|
||||
m_slotText->SetLabel(name);
|
||||
}
|
||||
|
||||
void ExtenderSlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
|
||||
void ExtenderSlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
|
||||
{
|
||||
AZStd::string displayText = tooltip.GetDisplayString();
|
||||
|
||||
m_slotConnectionPin->setToolTip(displayText.c_str());
|
||||
m_slotText->setToolTip(displayText.c_str());
|
||||
m_slotConnectionPin->setToolTip(tooltip.c_str());
|
||||
m_slotText->setToolTip(tooltip.c_str());
|
||||
}
|
||||
|
||||
void ExtenderSlotLayout::OnStyleChanged()
|
||||
|
||||
+2
-2
@@ -48,8 +48,8 @@ namespace GraphCanvas
|
||||
// SlotNotificationBus
|
||||
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
|
||||
|
||||
void OnNameChanged(const TranslationKeyedString& name) override;
|
||||
void OnTooltipChanged(const TranslationKeyedString& tooltip) override;
|
||||
void OnNameChanged(const AZStd::string& name) override;
|
||||
void OnTooltipChanged(const AZStd::string& tooltip) override;
|
||||
////
|
||||
|
||||
// StyleNotificationBus
|
||||
|
||||
+3
-3
@@ -90,10 +90,10 @@ namespace GraphCanvas
|
||||
TryAndSetupSlot();
|
||||
}
|
||||
|
||||
void PropertySlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
|
||||
void PropertySlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
|
||||
{
|
||||
m_slotText->setToolTip(Tools::qStringFromUtf8(tooltip.GetDisplayString()));
|
||||
m_nodePropertyDisplay->setToolTip(Tools::qStringFromUtf8(tooltip.GetDisplayString()));
|
||||
m_slotText->setToolTip(Tools::qStringFromUtf8(tooltip));
|
||||
m_nodePropertyDisplay->setToolTip(Tools::qStringFromUtf8(tooltip));
|
||||
}
|
||||
|
||||
void PropertySlotLayout::OnStyleChanged()
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ namespace GraphCanvas
|
||||
// SlotNotificationBus
|
||||
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
|
||||
|
||||
void OnTooltipChanged(const TranslationKeyedString& tooltip) override;
|
||||
void OnTooltipChanged(const AZStd::string& tooltip) override;
|
||||
////
|
||||
|
||||
// StyleNotificationBus
|
||||
|
||||
@@ -91,14 +91,6 @@ namespace GraphCanvas
|
||||
|
||||
void SlotComponent::Activate()
|
||||
{
|
||||
SetTranslationKeyedName(m_slotConfiguration.m_name);
|
||||
|
||||
// Default tooltip.
|
||||
if (m_slotConfiguration.m_tooltip.empty())
|
||||
{
|
||||
SetTranslationKeyedTooltip(m_slotConfiguration.m_name);
|
||||
}
|
||||
|
||||
SlotRequestBus::Handler::BusConnect(GetEntityId());
|
||||
SceneMemberRequestBus::Handler::BusConnect(GetEntityId());
|
||||
}
|
||||
@@ -171,24 +163,6 @@ namespace GraphCanvas
|
||||
}
|
||||
|
||||
void SlotComponent::SetName(const AZStd::string& name)
|
||||
{
|
||||
if (name == m_slotConfiguration.m_name.GetDisplayString())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_slotConfiguration.m_name.SetFallback(name);
|
||||
|
||||
// Default tooltip.
|
||||
if (m_slotConfiguration.m_tooltip.empty())
|
||||
{
|
||||
m_slotConfiguration.m_tooltip = m_slotConfiguration.m_name;
|
||||
}
|
||||
|
||||
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
|
||||
}
|
||||
|
||||
void SlotComponent::SetTranslationKeyedName(const TranslationKeyedString& name)
|
||||
{
|
||||
if (name == m_slotConfiguration.m_name)
|
||||
{
|
||||
@@ -206,25 +180,22 @@ namespace GraphCanvas
|
||||
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
|
||||
}
|
||||
|
||||
void SlotComponent::SetTooltip(const AZStd::string& tooltip)
|
||||
void SlotComponent::SetDetails(const AZStd::string& name, const AZStd::string& tooltip)
|
||||
{
|
||||
if (tooltip == m_slotConfiguration.m_tooltip.GetDisplayString())
|
||||
if (name != m_slotConfiguration.m_name)
|
||||
{
|
||||
return;
|
||||
m_slotConfiguration.m_name = name;
|
||||
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
|
||||
}
|
||||
|
||||
m_slotConfiguration.m_tooltip.SetFallback(tooltip);
|
||||
|
||||
// Default tooltip.
|
||||
if (m_slotConfiguration.m_tooltip.empty())
|
||||
if (tooltip != m_slotConfiguration.m_tooltip)
|
||||
{
|
||||
m_slotConfiguration.m_tooltip = m_slotConfiguration.m_name;
|
||||
m_slotConfiguration.m_tooltip = tooltip;
|
||||
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnTooltipChanged, m_slotConfiguration.m_tooltip);
|
||||
}
|
||||
|
||||
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnTooltipChanged, m_slotConfiguration.m_tooltip);
|
||||
}
|
||||
|
||||
void SlotComponent::SetTranslationKeyedTooltip(const TranslationKeyedString& tooltip)
|
||||
void SlotComponent::SetTooltip(const AZStd::string& tooltip)
|
||||
{
|
||||
if (tooltip == m_slotConfiguration.m_tooltip)
|
||||
{
|
||||
@@ -521,8 +492,8 @@ namespace GraphCanvas
|
||||
{
|
||||
slotConfiguration.m_connectionType = GetConnectionType();
|
||||
|
||||
slotConfiguration.m_name = GetTranslationKeyedName();
|
||||
slotConfiguration.m_tooltip = GetTranslationKeyedTooltip();
|
||||
slotConfiguration.m_name = m_slotConfiguration.m_name;
|
||||
slotConfiguration.m_tooltip = m_slotConfiguration.m_tooltip;
|
||||
|
||||
slotConfiguration.m_slotGroup = GetSlotGroup();
|
||||
}
|
||||
|
||||
@@ -74,18 +74,14 @@ namespace GraphCanvas
|
||||
|
||||
Endpoint GetEndpoint() const override;
|
||||
|
||||
const AZStd::string GetName() const override { return m_slotConfiguration.m_name.GetDisplayString(); }
|
||||
const AZStd::string GetName() const override { return m_slotConfiguration.m_name; }
|
||||
void SetName(const AZStd::string& name) override;
|
||||
|
||||
TranslationKeyedString GetTranslationKeyedName() const override { return m_slotConfiguration.m_name; }
|
||||
void SetTranslationKeyedName(const TranslationKeyedString&) override;
|
||||
void SetDetails(const AZStd::string& name, const AZStd::string& tooltip) override;
|
||||
|
||||
const AZStd::string GetTooltip() const override { return m_slotConfiguration.m_tooltip.GetDisplayString(); }
|
||||
const AZStd::string GetTooltip() const override { return m_slotConfiguration.m_tooltip; }
|
||||
void SetTooltip(const AZStd::string& tooltip) override;
|
||||
|
||||
TranslationKeyedString GetTranslationKeyedTooltip() const override { return m_slotConfiguration.m_tooltip; }
|
||||
void SetTranslationKeyedTooltip(const TranslationKeyedString&) override;
|
||||
|
||||
void DisplayProposedConnection(const AZ::EntityId& connectionId, const Endpoint& endpoint) override;
|
||||
void RemoveProposedConnection(const AZ::EntityId& connectionId, const Endpoint& endpoint) override;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user