Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render HTML in a Grid? #466

Closed
jello3d opened this issue Nov 13, 2018 · 26 comments
Closed

Render HTML in a Grid? #466

jello3d opened this issue Nov 13, 2018 · 26 comments
Milestone

Comments

@jello3d
Copy link

jello3d commented Nov 13, 2018

I may just be dense, but is there any way to render html inside a new-udgrid? This would be for feeding in markup that colors the background of the cell, changed font weight, etc... preferably based on markup embedded in a custom object.

Maybe I'm overthinking it...

@adamdriscoll
Copy link
Member

You can't really customize the cells themselves at the moment. You should be able to use New-UDElement\New-UDHTML to render data within the cells.

Similar to this but with custom formatting rather than a dropdown: https://forums.universaldashboard.io/t/dropdowns-in-new-udgrid/44/3?u=adam

As mentioned in that post, there is abut in 2.1 that will prevent you from using New-UDElement from within a grid but you can use the latest AppVeyor build to play with that functionality.

@jello3d
Copy link
Author

jello3d commented Nov 15, 2018

Any idea, in this code, why the table does not populate, but the grid does?

$Page3 = New-UDPage -Name "Page3" -Icon home -Content { 
    New-UDRow {
        $Rooms = $Cache:VEStatus | Group-Object ROOM
        Foreach ($Room in $Rooms) {
            $RoomVEStatus = $Cache:VEStatus | Where {$_.ROOM -eq $Room.name} | foreach {[pscustomobject]@{NAME = $_.NAME;PING = $_.PING;WRM = $_.WRM;VMIX = $_.VMIX }}
            
            New-UDColumn -size 3 -Content {
                $VECardBack = '#888888'
                Foreach ($MachineVEStatus in $RoomVEStatus) {
                    
                    If ($MachineVEStatus.PING -eq "0" -or $MachineVEStatus.WRM -eq "0") {
                        $VECardBack = '#aa0000'
                    } 
                    ElseIf ($MachineVEStatus.VMIX -eq "1") {
                        $VECardBack = '#aaaaaa'
                    } Else {
                    $VECardBack = '#00aa00'
                    }
                }
                New-UDCard -Size small -BackgroundColor $VECardBack -Title $Room.name -Content { 
                    
                    New-UDTable -Headers @("NAME","PING","WRM","VMIX") -Endpoint {
                        $RoomVEStatus | Out-UDTableData -Property @("NAME","PING","WRM","VMIX")
                    } -AutoRefresh -RefreshInterval 30
                    New-UDGrid -Headers @("Name","PING","WRM","VMIX") -Properties @("NAME","PING","WRM","VMIX") -Endpoint {  
                        $RoomVEStatus | Out-UDGridData 
                    } -NoPaging -DefaultSortColumn "NAME" -AutoRefresh -RefreshInterval 30
                }
            }
        }
    }
    
} -AutoRefresh -RefreshInterval 10

@adamdriscoll
Copy link
Member

I'm not really sure why that wouldn't work. The only thing I can think is that we have a scoping issue with the variable for some reason. Can you verify that $RoomVEStatus is populated when you are within the UDTable Endpoint?

Throw a Wait-Debugger in there and see if it has the correct value.

New-UDTable -Headers @("NAME","PING","WRM","VMIX") -Endpoint {
Wait-Debugger
                        $RoomVEStatus | Out-UDTableData -Property @("NAME","PING","WRM","VMIX")
                    } -AutoRefresh -RefreshInterval 30

Then load your dashboard in the browser. Go back to the PS console and then run Get-Runspace and the Debug-Runspace the runspace that is InBreakpoint.

Then you should be able to just dump the variable to the console: $RoomVEStatus

@jello3d
Copy link
Author

jello3d commented Nov 15, 2018

It's null. Interestingly, with the variable named $RoomVEStatus, there is no error, but no output. I tried changing the name of the variable to $rvs and then the table displays a Cannot bind argument error. Maybe there are two issues in play...

FYI, $Cache.VEStatus works fine... the issue only effects the new variable.

@adamdriscoll
Copy link
Member

What happens if you change it to use ArgumentList rather than implicit variable scoping?

$Page3 = New-UDPage -Name "Page3" -Icon home -Content { 
    New-UDRow {
        $Rooms = $Cache:VEStatus | Group-Object ROOM
        Foreach ($Room in $Rooms) {
            $RoomVEStatus = $Cache:VEStatus | Where {$_.ROOM -eq $Room.name} | foreach {[pscustomobject]@{NAME = $_.NAME;PING = $_.PING;WRM = $_.WRM;VMIX = $_.VMIX }}
            
            New-UDColumn -size 3 -Content {
                $VECardBack = '#888888'
                Foreach ($MachineVEStatus in $RoomVEStatus) {
                    
                    If ($MachineVEStatus.PING -eq "0" -or $MachineVEStatus.WRM -eq "0") {
                        $VECardBack = '#aa0000'
                    } 
                    ElseIf ($MachineVEStatus.VMIX -eq "1") {
                        $VECardBack = '#aaaaaa'
                    } Else {
                    $VECardBack = '#00aa00'
                    }
                }
                New-UDCard -Size small -BackgroundColor $VECardBack -Title $Room.name -Content { 
                    
                    New-UDTable -Headers @("NAME","PING","WRM","VMIX") -Endpoint {
                        $ArgumentList[0] | Out-UDTableData -Property @("NAME","PING","WRM","VMIX")
                    } -AutoRefresh -RefreshInterval 30 -ArgumentList $RoomVEStatus
                    New-UDGrid -Headers @("Name","PING","WRM","VMIX") -Properties @("NAME","PING","WRM","VMIX") -Endpoint {  
                        $ArgumentList[0] | Out-UDGridData 
                    } -NoPaging -DefaultSortColumn "NAME" -AutoRefresh -RefreshInterval 30 -ArgumentList $RoomVEStatus
                }
            }
        }
    }
    
} -AutoRefresh -RefreshInterval 10

@jello3d
Copy link
Author

jello3d commented Nov 15, 2018

My UDTable does not allow -ArgumentList, so that just errors out

The Grid, however, now shows the this.state.events.map is not a function

I suppose that brings up another (probably dumb) question... how does one properly install the appveyor versions?

@adamdriscoll
Copy link
Member

Ah, crap. That needs to be fixed. I will get a build put together with that change. See below. It needs to be updated here:

https://github.com/ironmansoftware/universal-dashboard/blob/master/src/UniversalDashboard/Controls/src/table.ps1#L54

From AppVeyor, if you go to the Artifacts tab, you can then download the ZIP and either unzip it to your PSModulePath or unzip it to a folder where you directly import the the PSD1. You will need to make sure to unblock the files: dir -recurse | Unblock-File

https://ci.appveyor.com/project/adamdriscoll/universal-dashboard/build/artifacts

If we get lucky, should be able to just add ArgumentList to New-UDTable and pass it onto the New-UDElement call.

function New-UDTable {
	param(
		[Parameter()]
	    [string]$Id = (New-Guid),
		[Parameter()]
	    [string]$Title,
	    [Parameter(Mandatory = $true)]
	    [string[]]$Headers,
		[Parameter()]
		[UniversalDashboard.Models.DashboardColor]$BackgroundColor,
		[Parameter()]
		[UniversalDashboard.Models.DashboardColor]$FontColor,
		[Parameter()]
		[ValidateSet("bordered", "striped", "highlight", "centered", "responsive-table")]
		[string]$Style,
	    [Parameter()]
		[UniversalDashboard.Models.Link[]] $Links,
		[Parameter(Mandatory = $true)]
		[object]$Endpoint,
		[Parameter()]
		[Switch]$AutoRefresh,
		[Parameter()]
		[int]$RefreshInterval = 5,
                [Parameter()]
                $ArgumentList
	)

	$Actions = $null
	if ($Links -ne $null) {
		$Actions = New-UDElement -Tag 'div' -Content {
			$Links
		} -Attributes @{
			className = 'card-action'
		}
	}

	New-UDElement -Tag "div" -Id $Id -Attributes @{
		className = 'card ud-table' 
		style = @{
			backgroundColor = $BackgroundColor.HtmlColor
			color = $FontColor.HtmlColor
		}
	} -Content {
		New-UDElement -Tag "div" -Attributes @{
			className = 'card-content'
		} -Content {
			New-UDElement -Tag 'span' -Content { $Title }
			New-UDElement -Tag 'table' -Content {
				New-UDElement -Tag 'thead' -Content {
					New-UDElement -Tag 'tr' -Content {
						foreach($header in $Headers) {
							New-UDElement -Tag 'th' -Content { $header }
						}
					}
				}
				New-UDElement -Tag 'tbody' -Endpoint $Endpoint -AutoRefresh:$AutoRefresh -RefreshInterval $RefreshInterval -ArgumentList $ArgumentList
			} -Attributes @{ className = $Style }
		}
		$Actions
	}
}

@jello3d
Copy link
Author

jello3d commented Nov 15, 2018

I downloaded the file, expanded it, unblocked it, gave it a name, put it in a folder, edited the controls pms1 with what you have above, then ipmo'd the psd1 form the file location. get-module shows 2.2.0

-argumentlist was still not an option.

Do I have to uninstall 2.1.0 entirely? I tried just unloading it... then impo'ing the new build.

@jello3d
Copy link
Author

jello3d commented Nov 15, 2018

Ah, #479 was just borked... I've got argumentlist working with #476 with UDTable

@adamdriscoll
Copy link
Member

Ack. I'll have to look at what's going on with the latest build.

@jello3d
Copy link
Author

jello3d commented Nov 15, 2018

Well, it sort of works in #476. The Sch Endpoint that gathers the data doesn't seem to be updating at all. And if I have the -autorefresh turned on on the udtable, some of the tables will refresh with nothing populated and some will. Randomly. If I then refresh the page in the browser over and over, randomly some tables will be populated, others will not. Without the autorefresh enabled, they all populate (refreshint is set to 10 sec).

Probably just a buggy build, but at least I can confirm that the argumentlist works nicely. :)

@adamdriscoll
Copy link
Member

lol....

Yeah seems problematic. I'll throw together a test case that matches this scenario so that we can make sure it's right.

This would include:

  • Scheduled endpoint providing the data
  • Tables in a loop fed by the scheduled endpoint's data
  • Tables use ArgumentList\Endpoint
  • Tables AutoRefresh

Right?

@jello3d
Copy link
Author

jello3d commented Nov 15, 2018

Sounds right. Not that it should matter, but note that the scheduled endpoint is using a pssqlite query. However, it has been working fine under 2.1.0 to continuously query.

$EPVEStatusSCH = New-UDEndpointSchedule -Every 15 -Second
$EPVEStatus = New-UDEndpoint -Schedule $EPVEStatusSCH -Endpoint {
    $Cache:VEStatus = Invoke-SqliteQuery -DataSource "C:\Data\ve.db" -Query "SELECT * FROM STATUS"
}

That db is fed from another script running from scheduled tasks.

This is the latest page code I am using. Perhaps I am gumming something up trying to dynamically change the Title of the table? (it would be nice if the title could be refreshed on both grids and tables from within the new-udtable/new-udgrid, and/or accept the $ArgumentList object). I have not been able to get the grid title to update even on a page refresh, but the table does seem to.

$Page3 = New-UDPage -Name "Page3" -Icon home -Content { 
    New-UDRow {
        $Rooms = $Cache:VEStatus | Group-Object ROOM
        Foreach ($Room in $Rooms) {
            $RoomVEStatus = $Cache:VEStatus | Where {$_.ROOM -eq $Room.name}
            
            New-UDColumn -size 3 -Content {
                $VECardBack = '#00aa00'
                Foreach ($MachineVEStatus in $RoomVEStatus) {
                    
                    If ($MachineVEStatus.PING -eq "0" -or $MachineVEStatus.WRM -eq "0") {
                        $VECardBack = '#aa0000'
                    } 
                    ElseIf ($MachineVEStatus.VMIX -eq "1") {
                        $VECardBack = '#aaaaaa'
                    } Else {
                    
                    }
                }
                New-UDCard -Size small -BackgroundColor $VECardBack -Title $Room.name -Content { 
                    $InUse = If ($RoomVEStatus[0].VMIX -eq "1") {"IN USE"} else {"Available"}
                    $Title = $RoomVEStatus[0].ROOM + " - " + $InUse
                    New-UDTable -Title $Title -Headers @("NAME","PING","WRM","VMIX") -Endpoint {
                    
                        $ArgumentList | foreach {[pscustomobject]@{NAME = $_.NAME;PING = $_.PING;WRM = $_.WRM;VMIX = New-UDElement -Tag 'div' -Attributes @{style=@{color='blue'}} -Content {$_.VMIX.tostring()}}} | Out-UDTableData -Property @("NAME","PING","WRM","VMIX")
                    } -AutoRefresh -RefreshInterval 10 -ArgumentList $RoomVEStatus
                    #New-UDGrid -Headers @("Name","PING","WRM","VMIX") -Properties @("NAME","PING","WRM","VMIX") -Endpoint {  
                    #    $ArgumentList[0] | Out-UDGridData 
                    #} -NoPaging -DefaultSortColumn "NAME" -AutoRefresh -RefreshInterval 30 -ArgumentList $RoomVEStatus
                } 
            }
        }
    }
    
    #New-UDGrid -Title "Video Express Status" -Headers @("Room","Name","IP","PING","WRM","VMIX") -Properties @("ROOM","NAME","IP","PING","WRM","VMIX") -Endpoint {  
    #$Cache:VEStatus | Out-UDGridData 
    #} -NoPaging -DefaultSortColumn "NAME" -AutoRefresh -RefreshInterval 30
        
} -AutoRefresh -RefreshInterval 30



@jello3d
Copy link
Author

jello3d commented Nov 15, 2018

PS - Ideally all that should work in Grids too, fwiw.

@jello3d
Copy link
Author

jello3d commented Nov 16, 2018

PPS... after further testing I believe the scheduled endpoint continues working normally.

  • A vanilla Grid with -autorefresh and -argument list passing the cached variable will update.
  • A vanilla Table with the same will not.

In either case, if I dynamically generate a bunch of tables or grids as I am doing above, they will not refresh.... even if directly passing the cached variable into -argumentlist. Pretty much as soon as I add a foreach, it seems to kill the refresh.

Oh, and lastly... I cannot seem pass New-UDElement into a UDGrid cell in the latest .305. UDTable, yes, UDGrid, no.

@adamdriscoll
Copy link
Member

Ok. Thanks for the follow up. Glad that the scheduled endpoints are working.

@jello3d
Copy link
Author

jello3d commented Nov 16, 2018

I think what's going on is that Page Autorefresh and Table autorefresh don't work. Grid autorefresh does. BUT, if a grid is using a variable that is set elsewhere in the page, it does not "appear" to refresh because page Autorefresh doesn't work.

I've been playing a schedule endpoint that just caches the time... then I'm trying to use that in different ways in a page/table/grid, secondary variable, etc.... The above description seems to explain what I am seeing. Everything else appears to be a symptom.

@adamdriscoll
Copy link
Member

I think I have a handle on this issue. Here's the breakdown.

UDPage auto-refresh was indeed broken. When using the -Content parameter of any component, that will never auto-refresh. I fixed it so that you can use -Endpoint with the -Name parameter of New-UDPage.

$Page = New-UDPage -Name 'Autoreload' -Endpoint {
} -AutoRefresh -RefreshInterval 1

Another thing I realized is that, due to the nature of how variables work with endpoints, the value of the variables were actually being cache and even though auto-refresh was running, it was just getting the same data over and over again.

So in this example, when the table and grid are created, they get the value of $Status. When they autorefresh, they are just getting the same value of status again that is stored with the endpoint. It's not executing all the code surrounding the New-UDTable\New-UDGrid, just what's in the Endpoint script block.

            $MyItems = $Cache:Items | Group-Object Name
            foreach($Item in $MyItems) {

                $Status = $Cache:Items | Where { $_.Name -eq $Item.Name }

                New-UDTable -Title $Item.Name -Headers @("NAME", "PING", "VMIX", "WRM") -Endpoint {
                    $Status | Out-UDTableData -Property @("NAME", "PING", "VMIX", "WRM")
                } -AutoReload

                New-UDGrid -Title $Item.Name -Headers @("NAME", "PING", "VMIX", "WRM") -Properties @("NAME", "PING", "VMIX", "WRM") -Endpoint {
                    $ArgumentList | Out-UDGridData
                } -ArgumentList $Status -NoPaging -DefaultSortColumn "NAME" -AutoReload
            }

So after fixing that, I also realized that there were some issues with the client-side JavaScript React code that was preventing it from re-rendering even if it did get new data.

Here's a working sample that I added to the integration tests. Rather than auto-refreshing the table\grid themselves, I'm just autorefreshing the entire page.

Notice that I added a -Content parameter to New-UDTable. It doesn't make another call back to the server when loading the page since it's just static data at that point anyways.

$Schedule = New-UDEndpointSchedule -Every 1 -Second
        $ScheduledEndpoint = New-UDEndpoint -Schedule $Schedule -Endpoint {
            $Item1 = [PSCustomObject]@{ PING = 100; VMIX = (New-UDButton -Text (Get-Date).Second); WRM = 1; NAME = "ITEM1" }
            $Item2 = [PSCustomObject]@{ PING = 200; VMIX = (New-UDButton -Text (Get-Date).Second); WRM = 1; NAME = "ITEM1" }
            $Item3 = [PSCustomObject]@{ PING = 300; VMIX = (New-UDButton -Text (Get-Date).Second); WRM = 1; NAME = "ITEM2" }
            $Item4 = [PSCustomObject]@{ PING = 400; VMIX = (New-UDButton -Text (Get-Date).Second); WRM = 1; NAME = "ITEM2" }
    
            $Cache:Items = @($Item1, $Item2, $Item3, $Item4)
        }

        $Page = New-UDPage -Name 'Autoreload' -Endpoint {

            New-UDCard -Title "Hi $((Get-Date).Second)" -Content {} -Id 'card'

            $MyItems = $Cache:Items | Group-Object Name
            foreach($Item in $MyItems) {

                $Status = $Cache:Items | Where { $_.Name -eq $Item.Name }

                New-UDTable -Title $Item.Name -Headers @("NAME", "PING", "VMIX", "WRM") -Content {
                    $Status | Out-UDTableData -Property @("NAME", "PING", "VMIX", "WRM")
                } 

                New-UDGrid -Title $Item.Name -Headers @("NAME", "PING", "VMIX", "WRM") -Properties @("NAME", "PING", "VMIX", "WRM") -Endpoint {
                    $ArgumentList | Out-UDGridData
                } -ArgumentList $Status -NoPaging -DefaultSortColumn "NAME"
            }
        } -AutoRefresh -RefreshInterval 1

        $Dashboard = New-UDDashboard -Title "Dashboard" -Pages $Page
        $Server = Start-UDDashboard -Port 10001 -Dashboard $Dashboard -Endpoint $ScheduledEndpoint

Let me know how build 308 works for you.

https://ci.appveyor.com/project/adamdriscoll/universal-dashboard/builds/20374299

@adamdriscoll adamdriscoll added this to the 2.2.0 milestone Nov 17, 2018
@jello3d
Copy link
Author

jello3d commented Nov 17, 2018

Seems to be erroring out on the UDPage -Endpoint (object ref not set to an instance...etc)

@jello3d
Copy link
Author

jello3d commented Nov 17, 2018

I should ask... is it ok to load both 2.1.0 (Enterprise) and the appveyor builds at the same time? Seems to work so far in giving me the login page, plus the new features in community... but I don't know if that's "sanitary".... I need to keep the ent features running.

I've been starting my dash with this to keep it as clean as possible:

get-module universaldashboard* | remove-module
ipmo universaldashboard
ipmo "C:\UD\ud2.2.0.308\UniversalDashboard.Community.psd1"

Is that an alright method?

@adamdriscoll
Copy link
Member

Hmmm that might be the problem. Since UD is a binary module, doing a Remove-Module doesn't actually remove the assemblies from PowerShell which means the enterprise version is still loaded in more.

I have a test for this scenario here:

https://github.com/ironmansoftware/universal-dashboard/blob/466/src/UniversalDashboard.UITest/Integration/Scenarios.Tests.ps1#L23

It's passing on the builder and on my machine.

https://ci.appveyor.com/project/adamdriscoll/universal-dashboard/builds/20374599#L1061

I will have to get this PR into the enterprise fork and get you a build.

@adamdriscoll
Copy link
Member

Can you please try the beta1 version? https://www.powershellgallery.com/packages/UniversalDashboard/2.2.0-beta1

@jello3d
Copy link
Author

jello3d commented Nov 20, 2018

So far so good. Haven't test a grid yet, but Elements and Tables are updating the way I expected. The hardest part about all this, honestly, is the scoping of variables between one component and another... bit of mental gymnastics, but I am figuring it out.

image

@jello3d
Copy link
Author

jello3d commented Nov 20, 2018

Well... it works for a while anyways. At some point things stop updating and refreshing the page just spins until it fails. I'll see what I can learn about that. Works for about an hour or so

@adamdriscoll
Copy link
Member

I would suggest checking in the Network tab of the developer tools in your browser to see if it's giving errors there. Otherwise, Enable-UDLogging should be helpful.

@alaaelmahdy
Copy link

So far so good. Haven't test a grid yet, but Elements and Tables are updating the way I expected. The hardest part about all this, honestly, is the scoping of variables between one component and another... bit of mental gymnastics, but I am figuring it out.

image

i know it have been a while but i am working in a similar project , appreciate if you can share the code of this dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants