# Ignition 8.1 PowerTable header background color

**URL:** <https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854>\
**Category:** Ignition\
**Tags:** ignition81, vision, scripting\
**Created:** [October 5, 2022, 4:41pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854 "2022-10-05T16:41:55Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![Matthew.gaitan](https://avatars.discourse-cdn.com/v4/letter/m/59ef9b/32.png) [@Matthew.gaitan](https://forum.inductiveautomation.com/u/Matthew.gaitan)\
**Post date:** [October 5, 2022, 4:41pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/1 "2022-10-05T16:41:55Z")

</div>

Is it possible to use a Vision `Client Startup Script` to change all instances of Power Table headers background to a different color?

On 8.1 it seems that the header uses the same color as the table instead of staying white like it did previously

I tried this, but it didn't work to change the header color:

```auto
from java.awt import Color
from javax.swing import UIManager

UIManager.put('TableHeader.background', Color.white)

```

Is there perhaps another `magic key` i can use that drives the background color of the power table header?

I know we can utilize the `configureHeaderStyle` extension function but we have 1800 screens and I really don't want to have to go through all of them to change this manually

```auto
def configureHeaderStyle(self, colIndex, colName):
	return { 'background': 'white' }

```

Thanks!

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [October 5, 2022, 7:15pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/2 "2022-10-05T19:15:53Z")

</div>

You're saying you have 1800 separate power tables, and you're wanting to globally change the default color?

---

<div class="post-metadata">

**Author:** ![Matthew.gaitan](https://avatars.discourse-cdn.com/v4/letter/m/59ef9b/32.png) [@Matthew.gaitan](https://forum.inductiveautomation.com/u/Matthew.gaitan)\
**Post date:** [October 5, 2022, 7:23pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/3 "2022-10-05T19:23:19Z")

</div>

We have 1800 vision windows.

I do not want to manually go through ALL of them to determine which have power tables that need their header background colors updated.

I know it's possible to use `UIManager` to set the look and feel of objects in the client, just don't know if it's possible to do for the power table header background color. I can use the same code and change `TableHeader.background` to `TableHeader.foreground` and have that apply to all power tables. Just wasn't sure if it was possible for the background color of the header 🤞

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [October 6, 2022, 1:58am UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/4 "2022-10-06T01:58:51Z")

</div>

You will probably have to go about this differently. If I'm not mistaken, the header of a power table is created via a JViewport, and in ignition 8.1, the UIManager for a JViewport is a SynthViewportUI.

Verification script:

```auto
from javax.swing import JViewport
from javax.swing import UIManager
print UIManager.getUI(JViewport())

```

Output:  
[javax.swing.plaf.synth.SynthViewportUI](https://docs.oracle.com/javase/7/docs/api/javax/swing/plaf/synth/SynthViewportUI.html)

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [October 6, 2022, 9:54am UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/5 "2022-10-06T09:54:50Z")

</div>

I don't believe anybody has tried this yet, and I would be quite interested to see if you could get it to work:

> **[Synthetica - Java Look And Feel](https://www.jyloo.com/synthetica/customize/#JViewport)**
>
> Jyloo Software is a leading Java Look and Feel and Swing component provider. Based on Java Swing technology, Jyloo, JAVASOFT software products are user friendly, come along with a modern look, provide consistency and a high grade of customizability.

---

<div class="post-metadata">

**Author:** ![Matthew.gaitan](https://avatars.discourse-cdn.com/v4/letter/m/59ef9b/32.png) [@Matthew.gaitan](https://forum.inductiveautomation.com/u/Matthew.gaitan)\
**Post date:** [October 6, 2022, 4:34pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/6 "2022-10-06T16:34:23Z")

</div>

Ok, so messing around with these settings.

None of them seem to really have any affect in the client.

If i run this in the designer, then interact with the table it makes the background of the table white, but not the background of the header:

```auto
from java.awt import Color
from javax.swing import UIManager
UIManager.put('Synthetica.viewport.dynamicBackgroundColorEnabled', False)
UIManager.put('Viewport.background', Color.white)

```

![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/9/3/9382fc4d17a1c904c3cc84f01830d3c40a2468c5.png)

Poking around the structure of the table, it seems the header uses a different type. But I'm not sure what to do with that information

```auto
table = event.source.parent.getComponent('Power Table')
print table.getComponent(3).getComponent(0).getUI()

```

prints out: `com.jidesoft.plaf.synthetica.SyntheticaAutoFilterTableHeaderUI@2530beec`

I can't find any info on that and I'm not sure what `UIManager ` key would even control the background color for it, if any ☹

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [October 6, 2022, 4:57pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/7 "2022-10-06T16:57:27Z")

</div>

Interesting. I haven't encountered that before in my own various power table diggings. I'm looking forward to exploring this.

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [October 6, 2022, 5:21pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/8 "2022-10-06T17:21:54Z")

</div>

This could be a useful resource for this type of activity:  
[List of all UIResource Elements for Predefined Look and Feel Classes](https://link.springer.com/content/pdf/bbm:978-1-4302-0033-8/1.pdf)

---

<div class="post-metadata">

**Author:** ![Matthew.gaitan](https://avatars.discourse-cdn.com/v4/letter/m/59ef9b/32.png) [@Matthew.gaitan](https://forum.inductiveautomation.com/u/Matthew.gaitan)\
**Post date:** [October 6, 2022, 9:53pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/9 "2022-10-06T21:53:41Z")

</div>

Well... based on this forum post I don't think this is possible how I want to do it ☹

> [@How to Set UI Theme in v8.1 Vision Clients](https://forum.inductiveautomation.com/t/how-to-set-ui-theme-in-v8-1-vision-clients/54929/3):
>
> The short answer is you don’t; I think I was probably the person who told you that a while back. 8.0+ is using a custom-skinned version of the Synthetica Look-And-Feel. For performance and other reasons, this LaF effectively renders and paints entire images on components, not single colors that can be easily controlled by UIManager properties. So the way to ‘theme’ a Vision application would be to obtain a Synthetica theme .jar and apply it to the Vision client - except you can’t do that, beca…

Such a bummer, but I guess I need to suck it up and go into each window / table and do it manually

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 6, 2022, 10:01pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/10 "2022-10-06T22:01:12Z")

</div>

As a middle ground, you could make a script inside the designer that opens every window, looks inside it for any power tables, and manually adds this extension function implementation; see [`ExtensibleComponent`](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.21/com/inductiveautomation/vision/api/client/components/model/ExtensibleComponent.html) and [`ExtensionFunction`](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.21/com/inductiveautomation/vision/api/client/components/model/ExtensionFunction.html). Whether scripting that together is going to be faster than doing it manually is perhaps a subject of debate.

---

<div class="post-metadata">

**Author:** ![Matthew.gaitan](https://avatars.discourse-cdn.com/v4/letter/m/59ef9b/32.png) [@Matthew.gaitan](https://forum.inductiveautomation.com/u/Matthew.gaitan)\
**Post date:** [October 6, 2022, 10:05pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/11 "2022-10-06T22:05:21Z")

</div>

We do already have code that goes through each window and pulls out all of the pertinent configuration for each screen and stores it in a database, so it might be trivial to extend upon that, I guess I would just be weary about mucking something up... but i guess that's what backups are for 😅

Thank you for the idea! That should speed things up tremendously

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [October 6, 2022, 10:42pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/12 "2022-10-06T22:42:35Z")

</div>

@paul-griffith I was hoping you would chime in at some point. It seems like you tend to have the best ideas when it comes to this sort of thing.

---

<div class="post-metadata">

**Author:** ![Matthew.gaitan](https://avatars.discourse-cdn.com/v4/letter/m/59ef9b/32.png) [@Matthew.gaitan](https://forum.inductiveautomation.com/u/Matthew.gaitan)\
**Post date:** [October 6, 2022, 11:12pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/13 "2022-10-06T23:12:13Z")

</div>

So... is it actually possible to enable extension functions programmatically?

Or do I need to call the `ExtensionFunction` constructor to rebuild it?

Something along the lines of this:

```auto
extensionFunctions = subComponent.getExtensionFunctions()
configureHeaderStyle = extensionFunctions['configureHeaderStyle'] 
			
if not configureHeaderStyle.enabled:
	newExtensionFunction = ExtensionFunction(True, configureHeaderStyle.getScript() )
	extensionFunctions = extensionFunctions.put('configureHeaderStyle', newExtensionFunction )

```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 6, 2022, 11:29pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/14 "2022-10-06T23:29:20Z")

</div>

> [@Matthew.gaitan](#):
>
> So... is it actually possible to enable extension functions programmatically?
> 
> Or do I need to call the `ExtensionFunction` constructor to rebuild it?

You would have to build a new `Map<String, ExtensionFunction>` and then reapply that onto the component.

So, from your example, probably more like this:

```python
extensionFunctions = dict(subComponent.getExtensionFunctions())

if "configureHeaderStyle" in extensionFunctions:
	configureHeaderStyle = extensionFunctions['configureHeaderStyle'] 
	if not configureHeaderStyle.enabled:
	newExtensionFunction = ExtensionFunction(True, configureHeaderStyle.script)
	extensionFunctions['configureHeaderStyle'] = newExtensionFunction

	subComponent.setExtensionFunctions(extensionFunctions)

```

Possible complications:

- I don't think it's guaranteed that you get a mutable map from `getExtensionFunctions` (hence the `dict` call).
- I think `configureHeaderStyle` might be null in certain circumstances?
- The 'script' to supply to the `ExtensionFunction` header must include the `def`, the parameters, _and the docstring_ to work properly going forward.

Also, you didn't hear about any of this from me and don't contact support if it breaks anything 😉

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [October 7, 2022, 3:51am UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/15 "2022-10-07T03:51:31Z")

</div>

Using @paul-griffith's direction, I have developed a script that will accomplish the goal of globally changing all power table header configurations from the designer. The script opens every vision window, then loops through getting all of the components from each window's root container. Then it checks each component list for power tables and nested containers. If there is a nested container, it repeats the process until there are no more nested containers.\*

\*For each power table found, if the configureHeaderStyle extension function does not exist or is not enabled, the script applies a configureHeaderStyle extension function that changes the color of the header to white. No other preexisting extension functions are altered or affected. The applied extension function string is in line three, so if a different color or additional properties are needed, this is where it will need to be changed.

_Here is the script:_

```auto
def processHeader(subComponent):
	from com.inductiveautomation.vision.api.client.components.model import ExtensionFunction
	script = 'def configureHeaderStyle(self, colIndex, colName):\n	return {\'background\': \'white\'}'
	try:
		extensionFunctions = subComponent.getExtensionFunctions()
		if "configureHeaderStyle" in extensionFunctions:
			configureHeaderStyle = extensionFunctions['configureHeaderStyle'] 
			if not configureHeaderStyle.enabled:
				updatedExtensionFunction = ExtensionFunction(True, script)
				extensionFunctions['configureHeaderStyle'] = updatedExtensionFunction
				subComponent.setExtensionFunctions(extensionFunctions)
		else:
			updatedExtensionFunction = ExtensionFunction(True, script)
			extensionFunctions['configureHeaderStyle'] = updatedExtensionFunction
			subComponent.setExtensionFunctions(extensionFunctions)
	except:
		from java.util import HashMap
		updatedExtensionFunction = ExtensionFunction(True, script)
		Map = HashMap()
		Map.put('configureHeaderStyle', ExtensionFunction(True, script))
		subComponent.setExtensionFunctions(Map)
def containerProcessor(components):
	for subComponent in components:
		if 'VisionAdvancedTable' in str(type(subComponent)):
			processHeader(subComponent)
		elif 'Container'in str(type(subComponent)):
			containerComponents = subComponent.getComponents()
			loopThroughComponents(containerComponents)
def loopThroughComponents(components):
	for subComponent in components:
		if 'VisionAdvancedTable' in str(type(subComponent)):
			processHeader(subComponent)
		elif 'Container'in str(type(subComponent)):
			containerComponents = subComponent.getComponents()
			containerProcessor(containerComponents) 
for name in system.gui.getWindowNames():
	system.nav.openWindow(name)
	components = system.gui.getWindow(name).getRootContainer().getComponents()
	loopThroughComponents(components)
	system.nav.closeWindow(name)

```

Edit: Everything in the above script now works correctly. The initial version seemed to work, but when I attempted to save the changes, the designer threw an exception due to unhashable dictionaries. This was fixed by removing all dictionary casts and methods, and by setting up exception handling that creates a hashmap for power tables that return a null value during the getExtensionFunctions method because they have never had any extension functions enabled.

Subsequent Edit: It occurred to me that opening 1800 windows in the designer would probably be a bad idea. I added a line of code to close each window upon edit completion.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 7, 2022, 2:26pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/16 "2022-10-07T14:26:56Z")

</div>

Good stuff!

You could replace the string type checks with imports; should just need [BasicContainer](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.21/com/inductiveautomation/factorypmi/application/components/BasicContainer.html) and [VisionAdvancedTable](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.21/com/inductiveautomation/factorypmi/application/components/VisionAdvancedTable.html). Because of Vision's serialized nature, these classpaths are stable and have been for more-or-less a decade.

---

<div class="post-metadata">

**Author:** ![Matthew.gaitan](https://avatars.discourse-cdn.com/v4/letter/m/59ef9b/32.png) [@Matthew.gaitan](https://forum.inductiveautomation.com/u/Matthew.gaitan)\
**Post date:** [October 7, 2022, 8:41pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/17 "2022-10-07T20:41:27Z")

</div>

Well...

I couldn't let @justinedwards.jle have all the fun!

here is my implementation:

```auto
from com.inductiveautomation.factorypmi.application.components import VisionAdvancedTable
from com.inductiveautomation.vision.api.client.components.model import ExtensionFunction
from java.util import HashMap

# Config
writeResultsToTags = True
baseTagPath = '[default]PowerTableSetHeaderColor'
tags = ['changedTablesOnTheseWindows', 'checkTheseWindowsManually']
batchSize = 400
batchNo = 0
baseWindowPath = 'Main Windows'
pathExclusions = [
	'dev_',
	'Popups'
]

# Filter our windows list (must start with baseWindowPath and all pathExclusion conditions must be met
windows = [win for win in system.gui.getWindowNames() if win[:len(baseWindowPath)] == baseWindowPath and all([exclusion.lower() not in win.lower() for exclusion in pathExclusions])] # 2014
windowCount = len(windows)

# Grab the current batch of windows
if batchNo == 0:
	windows = windows[:batchSize]
	print 0, batchSize
else:
	start = batchSize*batchNo
	end = start+batchSize 
	end = end if end < windowCount else windowCount
	print start, end
	windows = windows[start:end]

scriptToAdd = '''def configureHeaderStyle(self, colIndex, colName):
	"""
	Provides a chance to configure the style of each column header. Return a
	dictionary of name-value pairs with the desired attributes. Available
	attributes include: 'background', 'border', 'font', 'foreground',
	'horizontalAlignment', 'toolTipText', 'verticalAlignment'

	Arguments:
		self: A reference to the component that is invoking this function.
		colIndex: The index of the column in the underlying dataset
		colName: The name of the column in the underlying dataset
	"""
	from javax.swing.border import MatteBorder
	from java.awt import Color
	return { 'background' : Color.white, 'border': MatteBorder(0, 0, 1, 1, Color(164, 168, 172)) }'''

changedTablesOnTheseWindows = []
checkTheseWindowsManually = []
def searchThroughWindow(windowPath, component):
	for subComponent in component.getComponents():
		if isinstance(subComponent, VisionAdvancedTable):			
			extensionFunctions = subComponent.getExtensionFunctions()
			
			# Sometimes extensionFunctions is `None` if no extension functions are set on a table
			extensionFunctions = dict(extensionFunctions) if extensionFunctions else {}
			
			# Only apply this to tables where configureHeaderStyle exists but isn't enabled
			# or tables without configureHeaderStyle setup all together
			configureHeaderStyle = extensionFunctions.get('configureHeaderStyle')
			if (configureHeaderStyle and not configureHeaderStyle.enabled) or not configureHeaderStyle:
				extensionFunctions['configureHeaderStyle'] = ExtensionFunction(True, scriptToAdd) 
				
				# Convert our `extensionFuncitons` dict back into a HashMap
				# writing our dict back to the component will throw an error 
				# becaues the new value (a map) isn't serializable
				newExtensionFunctionsMap = HashMap()
				for key, value in extensionFunctions.iteritems():
					newExtensionFunctionsMap.put(key, value)
				subComponent.setExtensionFunctions(newExtensionFunctionsMap)
				
				changedTablesOnTheseWindows.append([windowPath, subComponent.name])
			# Keep a record of WindowPath + Table Name for manually applying these changes to 
			# Tables that already have a `configureHeaderStyle` extension function
			else:
				checkTheseWindowsManually.append([windowPath, subComponent.name])
		
		# Dig deeper into window	
		searchThroughWindow(windowPath, subComponent)

for win in windows:
	windowReference = system.nav.openWindow(win)	
	searchThroughWindow(win, windowReference)	
	system.nav.closeWindow(win)

if writeResultsToTags:
	batchFolderPath = '{}/{}'.format(baseTagPath, batchNo)
	fullTagPaths = ['{}/{}'.format(batchFolderPath, tag) for tag in tags]
	
	# Create current batch folder if it doesn't exist
	if not system.tag.exists(batchFolderPath):
		system.tag.configure(baseTagPath, {'name': batchNo, 'tagType': 'Folder'})
	
	# Create tags if they don't exist
	for idx, tag in enumerate(fullTagPaths):
		if not system.tag.exists(tag):
			system.tag.configure( batchFolderPath, { 'name': tags[idx], 'valueSource': 'memory', 'tagType': 'AtomicTag','dataType': 'DataSet' } )
	
	# Write results to tags		
	headers = ['windowPath', 'tableName']
	system.tag.writeBlocking( 
		fullTagPaths, 
		[
			system.dataset.toDataSet(headers, changedTablesOnTheseWindows), 
			system.dataset.toDataSet(headers, checkTheseWindowsManually)
		]
)

```

It supports window filtering, batching, and writing the results to tags.  
My work laptop is horrible and is screaming while doing this so the batching was a must. Even doing batches of 400 windows at a time is still taking upwards of 30-40 minutes per batch ☹  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/1/f/1f8f93bb5c9e66b90dd4bd043d8cff0c3d589bc2.png)

Thank you both for all of the help. I can get by doing these in small batches. It's still much faster than having to do this manually like some barbarian

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [October 7, 2022, 9:26pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/18 "2022-10-07T21:26:45Z")

</div>

> [@Matthew.gaitan](#):
>
> batching was a must. Even doing batches of 400 windows at a time is still taking upwards of 30-40 minutes

I've set up a virtual machine that I do my playing around on, and it isn't fast, but the sandbox Vision instanced I created to test this script only had 4 windows with various nested power tables, so the script completed almost instantly. Nevertheless, I was at some point pondering the scale of your undertaking, and I had imagined that adding some sort of batching method would be desirable. Especially after I decided to make sure the script result still worked outside of the designer, and I discovered the dictionary hashing error. I imagine that it would be terrible to have processed 1800 windows only to discover that none of the work was savable! In any case, I'm glad we were able to figure this problem out; I'm sure that this work will come in handy elsewhere in the future.

---

<div class="post-metadata">

**Author:** ![Matthew.gaitan](https://avatars.discourse-cdn.com/v4/letter/m/59ef9b/32.png) [@Matthew.gaitan](https://forum.inductiveautomation.com/u/Matthew.gaitan)\
**Post date:** [October 7, 2022, 9:36pm UTC](https://forum.inductiveautomation.com/t/ignition-8-1-powertable-header-background-color/64854/19 "2022-10-07T21:36:50Z")

</div>

> [@justinedwards.jle](#):
>
> I imagine that it would be terrible to have processed 1800 hundred windows only to discover that none of work was savable!

heh I'm sure glad I implemented it too because my first batch resulted in failure because of the aforementioned hashing error 😅

> [@justinedwards.jle](#):
>
> I'm sure that this work will come in handy elsewhere in the future.

Yes! I already can see using this again in the future to validate our non-templatized components (multi-state indicators 🤮) are all setup the same way and fix the outliers
