View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0005167 | NoesisGUI | Unity | public | 2026-08-12 20:24 | 2026-08-13 18:41 |
| Reporter | stonstad | Assigned To | jsantos | ||
| Priority | normal | Severity | block | ||
| Status | feedback | Resolution | open | ||
| Product Version | 4.0 | ||||
| Summary | 0005167: 4.0 RC1. GatherDependenciesFromSourceFile. ArgumentException: The specified path is not of a legal form | ||||
| Description | I'm unable to load or view any XAML files in 4.0 RC1. Every XAML control and screen errors out. ArgumentException: The specified path is not of a legal form (empty). | ||||
| Attached Files | BorderControlBorderless.cs (8,636 bytes)
using Noesis;
using NoesisGUIExtensions;
using StellarConquest.Model.Universe;
namespace StellarConquest.Presentation.Unity.UI
{
public partial class BorderControlBorderless : ContentControl
{
private Path _PanelBlur;
private Path _PanelColor;
private Path _DecorTop;
private Path _DecorBottom;
public event EventHandler Ready;
private float _ContentWidth = 0;
private float _ContentHeight = 0;
public static readonly DependencyProperty PanelFillBrushProperty = DependencyProperty.Register("PanelFillBrush", typeof(Brush), typeof(BorderControlBorderless));
public static readonly DependencyProperty PanelStrokeBrushProperty = DependencyProperty.Register("PanelStrokeBrush", typeof(Brush), typeof(BorderControlBorderless));
public static readonly DependencyProperty BlurLayerProperty = DependencyProperty.Register("BlurLayer", typeof(FrameworkElement), typeof(BorderControlBorderless), new PropertyMetadata(null));
private bool _TemplateApplied = false;
public Brush PanelFillBrush
{
get { return GetValue(PanelFillBrushProperty) as Brush; }
set { SetValue(PanelFillBrushProperty, value); }
}
public Brush PanelStrokeBrush
{
get { return GetValue(PanelStrokeBrushProperty) as Brush; }
set { SetValue(PanelStrokeBrushProperty, value); }
}
public FrameworkElement BlurLayer
{
get { return (FrameworkElement)GetValue(BlurLayerProperty); }
set { SetValue(BlurLayerProperty, value); }
}
public BorderControlBorderless()
{
Style = FindResource("BorderControlBorderless") as Style;
Loaded += (sender, e) => Build();
SizeChanged += (sender, e) => Build();
PanelFillBrush = FindResource("DefaultUI.Brush.Bottom.Gradient") as Brush;
PanelStrokeBrush = FindResource("DefaultUI.Brush.Border") as Brush;
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (Template != null)
{
_PanelBlur = GetTemplateChild("_PanelBlur") as Path;
_PanelColor = GetTemplateChild("_PanelColor") as Path;
_DecorTop = GetTemplateChild("_DecorTop") as Path;
_DecorBottom = GetTemplateChild("_DecorBottom") as Path;
_TemplateApplied = true;
}
}
public void Resize()
{
if (_TemplateApplied && Parent != null && View != null)
{
_ContentWidth = 0;
_ContentHeight = 0;
_PanelBlur.Data = null;
_PanelColor.Data = null;
UpdateLayout();
Build();
}
}
private void Build()
{
if (!_TemplateApplied)
return;
FrameworkElement content = (FrameworkElement)Content;
float contentWidth;
float contentHeight;
if (content != null)
{
contentWidth = content.ActualWidth + content.Margin.Left + content.Margin.Right - 2;
contentHeight = content.ActualHeight + content.Margin.Top + content.Margin.Bottom - 2;
}
else
{
contentWidth = Width;
contentHeight = Height;
}
// we should compare via equals. But here we do a less than comparison due to rounding
// errors in the path data. The ideal solution is to recreate the path using integer values
// to eliminate rounding errors
if (contentWidth <= _ContentWidth && contentHeight <= _ContentHeight)
return;
// Noesis Bug FIX. Noesis sometimes resets ResourcesCommon which
// affects TopBlurRadius and BottomBlurRadius. To prevent a zero value
// from affecting background effects, here, we reapply the values.
PlayerPreferences.Instance.ApplyBackgroundBlur();
_ContentWidth = contentWidth;
_ContentHeight = contentHeight;
// primary dimensions
float width = _ContentWidth;
float height = _ContentHeight;
// main panel
float bevelSize = 10.0f;
StreamGeometry geometry = new StreamGeometry();
using (StreamGeometryContext ctx = geometry.Open())
{
// Top Left Bevel
ctx.BeginFigure(new Point(bevelSize, 0.0f), true, true);
ctx.LineTo(new Point(width - bevelSize, 0.0f), true, false); // Top Edge
// Top Right Bevel
ctx.LineTo(new Point(width, bevelSize), true, false);
ctx.LineTo(new Point(width, height - bevelSize), true, false); // Right Edge
// Bottom Right Bevel
ctx.LineTo(new Point(width - bevelSize, height), true, false);
ctx.LineTo(new Point(bevelSize, height), true, false); // Bottom Edge
// Bottom Left Bevel
ctx.LineTo(new Point(0.0f, height - bevelSize), true, false);
ctx.LineTo(new Point(0.0f, bevelSize), true, false); // Left Edge
ctx.Close();
}
_PanelBlur.Data = geometry;
_PanelColor.Data = geometry;
// top decor
float thickness = 1.5f;
StreamGeometry topGeometry = new StreamGeometry();
using (StreamGeometryContext ctx = topGeometry.Open())
{
ctx.BeginFigure(new Point(0f, bevelSize), true, true);
ctx.LineTo(new Point(bevelSize, 0f), true, false);
ctx.LineTo(new Point(width - bevelSize, 0f), true, false);
ctx.LineTo(new Point(width, bevelSize), true, false);
ctx.LineTo(new Point(width - bevelSize, thickness), true, false);
ctx.LineTo(new Point(bevelSize, thickness), true, false);
ctx.Close();
}
_DecorTop.Data = topGeometry;
// bottom decor
StreamGeometry bottomGeometry = new StreamGeometry();
using (StreamGeometryContext ctx = bottomGeometry.Open())
{
ctx.BeginFigure(new Point(0f, thickness - bevelSize), true, true);
ctx.LineTo(new Point(bevelSize, thickness), true, false);
ctx.LineTo(new Point(width - bevelSize, thickness), true, false);
ctx.LineTo(new Point(width, thickness - bevelSize), true, false);
ctx.LineTo(new Point(width - bevelSize, 0f), true, false);
ctx.LineTo(new Point(bevelSize, 0f), true, false);
ctx.Close();
}
_DecorBottom.Data = bottomGeometry;
Ready?.Invoke(this, EventArgs.Empty);
}
public Geometry ContentGeometry
{
get { return _PanelColor.Data; }
}
public void SetAlertLevel(AlertLevelType value)
{
switch (value)
{
case AlertLevelType.Nominal:
PanelFillBrush = FindResource("DefaultUI.Brush.Bottom.Gradient") as Brush;
PanelStrokeBrush = FindResource("DefaultUI.Brush.Border") as Brush;
//DecorFillBrush = FindResource("DefaultUI.Brush.Decor.Gradient") as Brush;
break;
case AlertLevelType.Medium:
PanelFillBrush = FindResource("DefaultUI.Brush.Bottom.Gradient.HighAlert") as Brush;
PanelStrokeBrush = FindResource("DefaultUI.Brush.Border.HighAlert") as Brush;
//DecorFillBrush = FindResource("DefaultUI.Brush.Decor.Gradient.HighAlert") as Brush;
break;
case AlertLevelType.High:
PanelFillBrush = FindResource("DefaultUI.Brush.Bottom.Gradient.HighAlert") as Brush;
PanelStrokeBrush = FindResource("DefaultUI.Brush.Border.HighAlert") as Brush;
//DecorFillBrush = FindResource("DefaultUI.Brush.Decor.Gradient.HighAlert") as Brush;
break;
default:
break;
}
}
}
}
| ||||
| Platform | Any | ||||
|
Full file path is E:\Source\StellarConquest\StellarConquest.Presentation.Unity\Assets\User Interface\Controls\Border Control Borderless\BorderControlBorderless.cs InvalidOperationException: Resource not found 'BorderControlBorderless' |
|
|
|
|
|
There are a few errors that I have detected in our new Xaml importer. Please, try replace the following file. Apart from this, there is something new in v4.0, that is still not documented (Unity and Unreal tutorials hasn't been updated yet). In your classes, if you have dependencies to assets (for example, UserControl loading a XAML), they attribute AssetDependency must be used to make this dependency explicit. For example:
Do you have many usercontrols (or shaders) in your project? NoesisXamlImporter.cs (16,248 bytes)
//#define DEBUG_IMPORTER
using UnityEditor;
using UnityEngine;
using UnityEditor.AssetImporters;
using UnityEngine.Video;
using System;
using System.Linq;
using System.IO;
using System.Collections.Generic;
[ScriptedImporter(2, "xaml")]
class NoesisXamlImporter : ScriptedImporter
{
[UnityEditor.InitializeOnLoadMethod]
static void RegisterApplicationResourcesHash()
{
string projectPath = System.IO.Path.GetDirectoryName(Application.dataPath);
string filename = System.IO.Path.Combine(projectPath, "Library", "Noesis", "ApplicationResources_Hash");
if (File.Exists(filename))
{
try
{
string hash = File.ReadAllText(filename);
AssetDatabase.RegisterCustomDependency("Noesis_ApplicationResources", Hash128.Parse(hash));
}
catch (Exception e)
{
Debug.LogException(e);
}
}
}
[Serializable]
struct Dependencies
{
public string hash;
public long timestamp;
public List<string> items;
}
static string HashFile(string path)
{
var hash = new Hash128();
hash.Append(File.ReadAllText(path));
return hash.ToString();
}
static string HashStr(string str)
{
var hash = new Hash128();
hash.Append(str);
return hash.ToString();
}
static string DependenciesPath()
{
string projectPath = System.IO.Path.GetDirectoryName(Application.dataPath);
return System.IO.Path.Combine(projectPath, "Library", "Noesis", "Dependencies2");
}
static bool LoadDependencies(string path, ref Dependencies deps)
{
string folder = DependenciesPath();
string filename = Path.Combine(folder, HashStr(path));
if (File.Exists(filename))
{
try
{
string json = File.ReadAllText(filename);
deps = JsonUtility.FromJson<Dependencies>(json);
return true;
}
catch (Exception e)
{
Debug.LogException(e);
}
}
return false;
}
static void SaveDependencies(string path, Dependencies deps)
{
try
{
string folder = DependenciesPath();
System.IO.Directory.CreateDirectory(folder);
string json = JsonUtility.ToJson(deps);
File.WriteAllText(Path.Combine(folder, HashStr(path)), json);
}
catch (Exception e)
{
Debug.LogException(e);
}
}
static IEnumerable<string> FindFonts(string uri)
{
int index = uri.IndexOf('#');
if (index != -1)
{
string folder = uri.Substring(0, index);
if (Directory.Exists(folder))
{
string family = uri.Substring(index + 1);
var files = Directory.EnumerateFiles(folder).Where(s => IsFont(s));
foreach (var font in files)
{
using (FileStream file = File.Open(font, FileMode.Open, FileAccess.Read, FileShare.Read))
{
if (NoesisUnity.HasFamily(file, family))
{
yield return font;
}
}
}
}
}
}
static Dependencies GetCachedDependencies(string path)
{
Dependencies deps = new Dependencies();
bool cached = LoadDependencies(path, ref deps);
long timestamp = 0;
try
{
timestamp = File.GetLastWriteTime(path).Ticks;
}
catch (Exception e)
{
Debug.LogException(e);
}
if (cached)
{
if (timestamp == deps.timestamp)
{
return deps;
}
deps.timestamp = timestamp;
string hash = HashFile(path);
if (hash == deps.hash)
{
SaveDependencies(path, deps);
return deps;
}
deps.hash = hash;
}
else
{
deps.timestamp = timestamp;
deps.hash = HashFile(path);
}
#if DEBUG_IMPORTER
Debug.Log($"=> Dependencies {path}");
#endif
deps.items = new List<string>();
bool typesWithAttributeRequested = false;
TypeCache.TypeCollection typesWithAttribute;
using (FileStream file = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Noesis.GUI.GetXamlDependencies(file, path, (uri_, type) =>
{
try
{
string assembly = Noesis.UriHelper.GetAssembly(uri_);
string uri = Noesis.UriHelper.GetPath(uri_);
if (assembly == "Noesis.GUI.Extensions")
{
uri = $"Packages/com.noesis.noesisgui/{uri}";
}
if (type == Noesis.XamlDependencyType.Filename)
{
deps.items.Add(uri);
}
else if (type == Noesis.XamlDependencyType.Font)
{
foreach (var font in FindFonts(uri))
{
if (!deps.items.Contains(font))
{
deps.items.Add(font);
}
}
}
else if (type == Noesis.XamlDependencyType.Class)
{
if (!typesWithAttributeRequested)
{
typesWithAttributeRequested = true;
typesWithAttribute = TypeCache.GetTypesWithAttribute<Noesis.AssetDependencyAttribute>();
}
foreach (var cachedType in typesWithAttribute)
{
if (cachedType.FullName == uri)
{
object[] attributes = cachedType.GetCustomAttributes(typeof(Noesis.AssetDependencyAttribute), false);
foreach (Noesis.AssetDependencyAttribute attribute in attributes)
{
if (String.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(attribute.AssetPath)))
{
Debug.LogWarning($"[{cachedType.FullName}] Invalid AssetDependency '{attribute.AssetPath}'");
}
else
{
deps.items.Add(attribute.AssetPath);
}
}
}
}
}
}
catch (Exception e)
{
Debug.LogException(e);
}
});
}
SaveDependencies(path, deps);
return deps;
}
static string[] GatherDependenciesFromSourceFile(string path)
{
NoesisUnity.InitCore();
List<string> deps = new List<string>();
try
{
foreach (var dep in GetCachedDependencies(path).items)
{
if (File.Exists(dep))
{
deps.Add(dep);
}
}
}
catch (Exception e)
{
Debug.LogException(e);
}
return deps.ToArray();
}
static bool AddFont(string uri, ref List<NoesisFont> fonts)
{
NoesisFont font = AssetDatabase.LoadAssetAtPath<NoesisFont>(uri);
if (font != null)
{
fonts.Add(font);
return true;
}
return false;
}
static bool AddTexture(string uri, ref List<Texture> textures, ref List<Sprite> sprites)
{
if (AssetImporter.GetAtPath(uri) is TextureImporter textureImporter)
{
if (!AssetDatabase.GetLabels(textureImporter).Contains("Noesis"))
{
Debug.LogWarning($"{uri} is missing Noesis label");
}
if (textureImporter.textureType == TextureImporterType.Sprite &&
textureImporter.spriteImportMode == SpriteImportMode.Single)
{
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(uri);
if (sprite != null)
{
sprites.Add(sprite);
return true;
}
}
else
{
Texture texture = AssetDatabase.LoadAssetAtPath<Texture>(uri);
if (texture != null)
{
textures.Add(texture);
return true;
}
}
}
return false;
}
static bool AddAudio(string uri, ref List<AudioClip> audios)
{
AudioClip audio = AssetDatabase.LoadAssetAtPath<AudioClip>(uri);
if (audio != null)
{
audios.Add(audio);
return true;
}
return false;
}
static bool AddVideo(string uri, ref List<VideoClip> videos)
{
VideoClip video = AssetDatabase.LoadAssetAtPath<VideoClip>(uri);
if (video != null)
{
videos.Add(video);
return true;
}
return false;
}
static bool AddRive(string uri, ref List<NoesisRive> rives)
{
NoesisRive rive = AssetDatabase.LoadAssetAtPath<NoesisRive>(uri);
if (rive != null)
{
rives.Add(rive);
return true;
}
return false;
}
static bool AddXaml(string uri, ref List<NoesisXaml> xamls)
{
NoesisXaml xaml = AssetDatabase.LoadAssetAtPath<NoesisXaml>(uri);
if (xaml != null)
{
xamls.Add(xaml);
return true;
}
return false;
}
static bool AddShader(string uri, ref List<NoesisShader> shaders)
{
NoesisShader shader = AssetDatabase.LoadAssetAtPath<NoesisShader>(uri);
if (shader != null)
{
shaders.Add(shader);
return true;
}
return false;
}
static void ScanDependencies(AssetImportContext ctx,
out List<NoesisFont> fonts_, out List<Texture> textures_, out List<Sprite> sprites_,
out List<AudioClip> audios_, out List<VideoClip> videos_, out List<NoesisRive> rives_,
out List<NoesisXaml> xamls_, out List<NoesisShader> shaders_)
{
List<NoesisFont> fonts = new List<NoesisFont>();
List<Texture> textures = new List<Texture>();
List<Sprite> sprites = new List<Sprite>();
List<AudioClip> audios = new List<AudioClip>();
List<VideoClip> videos = new List<VideoClip>();
List<NoesisRive> rives = new List<NoesisRive>();
List<NoesisXaml> xamls = new List<NoesisXaml>();
List<NoesisShader> shaders = new List<NoesisShader>();
string filename = ctx.assetPath;
try
{
if (HasExtension(filename, ".xaml"))
{
// Add dependency to code-behind, just the source, we don't need the artifact
// Even if the file doesn't exist we add it to get a reimport first time code-behind is created
ctx.DependsOnSourceAsset(filename + ".cs");
}
var dependencies = GetCachedDependencies(filename);
foreach (var dep in dependencies.items)
{
// Register the dependency even if it doesn't currently exist.
// This ensures we are re-evaluated if it is imported later.
ctx.DependsOnArtifact(dep);
if (!String.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(dep)))
{
if (!AddXaml(dep, ref xamls))
{
if (!AddTexture(dep, ref textures, ref sprites))
{
if (!AddFont(dep, ref fonts))
{
if (!AddAudio(dep, ref audios))
{
if (!AddVideo(dep, ref videos))
{
if (!AddShader(dep, ref shaders))
{
AddRive(dep, ref rives);
}
}
}
}
}
}
}
}
}
catch (Exception e)
{
Debug.LogException(e);
}
fonts_ = fonts;
textures_ = textures;
sprites_ = sprites;
audios_ = audios;
videos_ = videos;
rives_ = rives;
xamls_ = xamls;
shaders_ = shaders;
}
public override void OnImportAsset(AssetImportContext ctx)
{
NoesisUnity.InitCore();
#if DEBUG_IMPORTER
Debug.Log($"=> Import {ctx.assetPath}");
#endif
NoesisXaml xaml = (NoesisXaml)ScriptableObject.CreateInstance<NoesisXaml>();
xaml.uri = ctx.assetPath;
xaml.content = System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(ctx.assetPath));
// Add dependencies
List<NoesisFont> fonts;
List<Texture> textures;
List<Sprite> sprites;
List<AudioClip> audios;
List<VideoClip> videos;
List<NoesisRive> rives;
List<NoesisXaml> xamls;
List<NoesisShader> shaders;
ScanDependencies(ctx, out fonts, out textures, out sprites, out audios, out videos, out rives, out xamls, out shaders);
xaml.xamls = xamls.Select(x => new NoesisXaml.Xaml { uri = AssetDatabase.GetAssetPath(x), xaml = x }).ToArray();
xaml.textures = textures.Select(x => new NoesisXaml.Texture { uri = AssetDatabase.GetAssetPath(x), texture = x }).ToArray();
xaml.sprites = sprites.Select(x => new NoesisXaml.Sprite { uri = AssetDatabase.GetAssetPath(x), sprite = x }).ToArray();
xaml.audios = audios.Select(x => new NoesisXaml.Audio { uri = AssetDatabase.GetAssetPath(x), audio = x }).ToArray();
xaml.videos = videos.Select(x => new NoesisXaml.Video { uri = AssetDatabase.GetAssetPath(x), video = x }).ToArray();
xaml.rives = rives.Select(x => new NoesisXaml.Rive { uri = AssetDatabase.GetAssetPath(x), rive = x }).ToArray();
xaml.fonts = fonts.Select(x => new NoesisXaml.Font { uri = AssetDatabase.GetAssetPath(x), font = x }).ToArray();
xaml.shaders = shaders.Select(x => new NoesisXaml.Shader { uri = AssetDatabase.GetAssetPath(x), shader = x} ).ToArray();
// Depends on global dictionary
ctx.DependsOnCustomDependency("Noesis_ApplicationResources");
ctx.AddObjectToAsset("XAML", xaml);
ctx.SetMainObject(xaml);
}
static bool HasExtension(string filename, string extension)
{
return filename.EndsWith(extension, StringComparison.OrdinalIgnoreCase);
}
static bool IsFont(string filename)
{
return HasExtension(filename, ".ttf") || HasExtension(filename, ".otf") || HasExtension(filename, ".ttc");
}
}
|
|
|
The The main issue with We are still investigating whether this can be improved |
|
|
I'll retry with the updated file. I do not have any shader effects, but I do have plenty of user controls. It isn't clear to me what dependencies my customer user controls might have because they are very simple. They inherit from UserControl. |
|
|
Thanks! If for example, your UserControl loads a XAML, you have a dependency to that asset. Are your UserControls loading XAMLs? |
|
|
I uninstalled 3.2.12. NoesisGUI v4.0.0-rc1 successfully installed I now have 15 Noesis errors instead of 999: Assets/User Interface/Screens/Game/Overlay/Spedometer/SpedometerControl.xaml(15,9): Xaml not found 'Assets/User Interface/Controls/Radial Range Control/RadialRangeControl.xaml' I'll apply the patch and try dependencies. |
|
Here is how I am implemented AssetDependency. Is this correct?
Is there a significant cost to do a FIle.Exists for a XAML file of the same name beside the CS file? ** I haven't applied the patch yet because things are working, and I was thinking it is diagnostically useful to show what works and doesn't incrementally. |
|
|
OK, so the class definition now needs the same thing as the XAML file? Or can I just reference the XAML file and declared dependencies are used? Example, see below: |
|
|
I am definitely able to get further with the upgrade! I can see other users being impacted by stale data in \library\noesis -- the errors thrown are definitely confusing. I started working through the dependencies. If I am understanding the scope of the change, it is a significant body of work. I have to roll back the upgrade to complete other work. I'll try again when I have a large block of time to address the dependencies requirement. OK to close issue. |
|
|
You don't need the The problem is the following. Imagine we have this XAML:
When we parse that XAML, we need to analyze all its dependencies. For example, in this case, the dependency on In 3.2, this process was automatic, but it was very slow because it searched for files everywhere, not only in /Assets, but also inside each package. It also has many restrictions and conventions rules. That's why we added the new That said, you're right: I could simplify this and bring back automatic dependency detection as a fallback, like before, but make it more efficient. I'll try to have something ready for the next version. |
|
Yes, the same uri string is duplicated. You could unify it. So at the end, it is just finding all yours But wait a bit, let me see if we can auto-detect simple scenarios as said in my previous comment. |
|
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-08-12 20:24 | stonstad | New Issue | |
| 2026-08-12 20:24 | stonstad | File Added: image.png | |
| 2026-08-12 20:24 | stonstad | File Added: BorderControlBorderless.cs | |
| 2026-08-12 20:27 | stonstad | Note Added: 0012487 | |
| 2026-08-12 20:29 | stonstad | Note Added: 0012488 | |
| 2026-08-12 20:29 | stonstad | File Added: image-2.png | |
| 2026-08-13 01:50 | jsantos | Relationship added | related to 0005166 |
| 2026-08-13 01:50 | jsantos | Assigned To | => jsantos |
| 2026-08-13 01:50 | jsantos | Status | new => assigned |
| 2026-08-13 01:53 | jsantos | Note Added: 0012495 | |
| 2026-08-13 01:53 | jsantos | File Added: NoesisXamlImporter.cs | |
| 2026-08-13 01:54 | jsantos | Status | assigned => feedback |
| 2026-08-13 02:29 | jsantos | Note Added: 0012498 | |
| 2026-08-13 15:00 | stonstad | Note Added: 0012501 | |
| 2026-08-13 15:00 | stonstad | Status | feedback => assigned |
| 2026-08-13 15:25 | jsantos | Note Added: 0012503 | |
| 2026-08-13 15:25 | jsantos | Status | assigned => feedback |
| 2026-08-13 15:31 | stonstad | Note Added: 0012505 | |
| 2026-08-13 15:31 | stonstad | Status | feedback => assigned |
| 2026-08-13 15:36 | stonstad | Note Added: 0012506 | |
| 2026-08-13 15:41 | stonstad | Note Added: 0012507 | |
| 2026-08-13 15:50 | stonstad | Note Added: 0012508 | |
| 2026-08-13 15:51 | stonstad | Note Edited: 0012507 | |
| 2026-08-13 18:28 | jsantos | Note Edited: 0012506 | |
| 2026-08-13 18:28 | jsantos | Note Edited: 0012507 | |
| 2026-08-13 18:39 | jsantos | Note Added: 0012512 | |
| 2026-08-13 18:40 | jsantos | Note Added: 0012513 | |
| 2026-08-13 18:41 | jsantos | Status | assigned => feedback |