Pushing Podio

Fun Experiments pushing Citrix Podio to the limit so you can get more done.
... with a little help from GlobiFlow, ProcFu, and other friends ...

Creating Custom Dashboards for Podio

- Posted in Uncategorized by

A dashboard is really just a collection of tiles with some data in them. ProcFu website widgets come in really handy in creating the tile content.

For this example, we're going to create a simple dashboard like this one:

This is just for example purposes. The possibilities are really endless and you can build anything you want into your dashboard. Using the code presented here would provide a good starting point.

To help us with the layout, we're using Bootstrap 4 (for tiles, tables, progress bars, etc), and Charts.js for pretty graphs.

Progress Widget

The progress widget is taken from a simple report widget in Podio (the kind that just returns a single number):

Our code block in ProcFu has a little function to retrieve this value and create the HTML required:

function widget_1_progress () {
    $pct = call_pf_script("report_get_single.pf", ["widget_id" => 80325645]);
    $html = '<h4 class="card-title">Lorem Ipsum</h4>';
    $html .= '<p class="card-text">Some Metric</p>';
    $html .= '<div class="progress" id="prg1">';
    $html .= '<div class="progress-bar progress-bar-striped bg-primary" role="progressbar" style="width: '.$pct.'%" aria-valuenow="'.$pct.'" aria-valuemin="0" aria-valuemax="100">'.$pct.'%</div>';
    $html .= '</div>';
    return $html;
}

And the rendered HTML looks something like this:

Counter Widget

Similar to the Progress Widget, we have another report widget in Podio that returns a single number, and we want to represent it as a counter tile.

The function we built looks like this:

function widget_2_counter() {
    $num = call_pf_script("report_get_single.pf", ["widget_id" => 80325685]);
    $html = '<h4 class="card-title">Another Metric</h4>';
    $html .= '<div class="float-left"><h1>';
    // font-awesome icon
    $html .= '<i class="fa fa-bar-chart" aria-hidden="true" style="color: rgba(54, 162, 235, 0.5)"></i>';
    $html .= '</h1></div>';
    $html .= '<div class="float-right">';
    $html .= '<h1 class="card-title font-weight-bold text-right mb-0">'.$num.'</h1>';
    $html .= '</div><div class="clearfix"></div><p class="" style="color: #888">Lorem Ipsum dolor</p>';
    return $html;
}

And the rendered HTML like this:

A Simple Gauge

To incorporate Google Static Image Charts, we can do something similar, and in this case we're just re-using our existing report tile from above:

function widget_3_gauge() {
    $pct = call_pf_script("report_get_single.pf", ["widget_id" => 80325645]);
    $html = '<h4 class="card-title">Google Gauge</h4>';
    $html .= '<p class="card-text text-center">';
    $html .= '<img src="https://chart.googleapis.com/chart?chs=175x85&cht=gom&chd=t:'.$pct.'&chco=00FF00,FFFF00,FF0000">';
    $html .= '</p>';
    return $html;
}

Which renders:

A Nice Bar Chart

Charts start getting a little more complex, but are still easy-enough to acomplish if you use a library like charts.js.

Using a view in Podio:

We get the tabular data, and massage it a little and create a chart with this function:

function widget_5_barchart() {
    $view = json_decode(call_pf_script("podio_view_get.pf", ["app_id" => 20894955, "view_id" => 38147362, "raw" => 0]), true);
    $data = [
        "labels" => array_column($view, "title"),
        "datasets" =>  [[
            "data" => array_column($view, "progress"),
            "backgroundColor" => ["red", "blue", "green", "grey", "orange", "purple"],
        ]]
    ];
    $options = [
        "scales" => [ "yAxes" => [ "ticks" => [ "beginAtZero" => true ] ] ],
        "legend" =>  [ "display" => false ],
        "elements" => [ "point" =>  [ "radius" =>  0 ] ]
    ];
    $html = '<h4 class="card-title">Bar chart</h4>';
    $html .= '<canvas id="barChart" style="height:230px"></canvas>';
    $html .= '<script>';
    $html .= 'var data = ' . json_encode($data) . ';' . "\n";
    $html .= 'var options = ' . json_encode($options) . ';' . "\n";
    $html .= 'if ($("#barChart").length) { ';
    $html .= 'var barChartCanvas = $("#barChart").get(0).getContext("2d");' . "\n";
    $html .= 'var barChart = new Chart(barChartCanvas, {type: "bar", data: data, options: options});' . "\n";
    $html .= '}';
    $html .= '</script>';
    return $html;
}

Which gives us:

Tabular Data

Building tables is also very straight forward. We just need to get a view from Podio, and massage the data a little bit:

function widget_7_table() {
    $view = json_decode(call_pf_script("podio_view_get.pf", ["app_id" => 20894955, "view_id" => 38147362, "raw" => 0]), true);
    $html = '<h4 class="card-title">Bordered table</h4>';
    $html = '<table class="table table-bordered"><thead><tr><th>Name</th><th>Progress</th><th class="text-right">Amount</th><th class="text-center">Due Date</th></tr></thead><tbody>';
    $cnt = intval(rand(2, 9));
    foreach ( $view as $row ) {
        $barclass = "bg-success";
        if ( $row['progress'] < 80 ) $barclass="bg-primary";
        if ( $row['progress'] < 60 ) $barclass="bg-warning";
        if ( $row['progress'] < 40 ) $barclass="bg-info";
        if ( $row['progress'] < 20 ) $barclass="bg-danger";
        $bar = '<div class="progress-bar '.$barclass.'" role="progressbar" style="width: '.$row['progress'].'%" aria-valuenow="'.$row['progress'].'" aria-valuemin="0" aria-valuemax="100">'.$row['progress'].'%</div>';
        $html .= '<tr><td>' . $row['title'] . '</td><td>' . 
            $bar . '</td><td class="text-right">$ ' . number_format($row['amount'], 0, '.', ',') . 
            '</td><td class="text-center">'.$row['due-date'].'</td></tr>';
    }
    $html .= '</tbody></table>';
    return $html;
}

Which renders as:

Putting it all Togather

We need a little bit of plumbing to make this work nicely.

Since we have all the functions in the same code block, we need a way to call individual ones, so we'll use a URL parameter called widget.

In our code block, we now just need to get the widget value and run the corresponding function:

$widget = json_decode($pf_payload, true)["GET"]['widget'];
if ( $widget == 1 ) return widget_1_progress();
if ( $widget == 2 ) return widget_2_counter();
if ( $widget == 3 ) return widget_3_gauge();
if ( $widget == 4 ) return widget_4_text();
if ( $widget == 5 ) return widget_5_barchart();
if ( $widget == 6 ) return widget_6_linechart();
if ( $widget == 7 ) return widget_7_table();

We also need an HTML page which has all the required libraries included, like Bootstrap4, JQuery, and Charts.js, as well as placeholders for each tile:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>PF Bootstrap Dashboard Test</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="Refresh" content="600">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
</head>
<body> 

<div class="container">
<br>
    <h2>Test Dashboard</h2>
    <div class="card-deck">
        <div class="card">
            <div class="card-body" id="w1">
            </div>
        </div>
        <div class="card">
            <div class="card-body" id="w2">
            </div>
        </div>
        <div class="card">
            <div class="card-body" id="w3">
            </div>
        </div>
        <div class="card">
            <div class="card-body" id="w4">
            </div>
        </div>
    </div>
<br>
    <div class="card-deck">
        <div class="card">
            <div class="card-body" id="w5">
            </div>
        </div>
        <div class="card">
            <div class="card-body" id="w6">
            </div>
        </div>
    </div>
<br>
    <div class="card-deck">
        <div class="card-body" id="w7">
        </div>
    </div>
</div>

We next need is to create a Website Widget in ProcFu using the code block with our code in it so that we can call it from the web page:

With the ID of the PF widget, we can simply use JQuery to populate each tile with the results of our code block in ProcFu.

To prevent PF from sending over html head sections we also include the "pfajax" url parameter just to be safe.

<script>
// tile 1 progress
$("#w1").load("https://procfuwidgets.b-cdn.net/html/m6yMkKywwWsS?pfajax&widget=1");
// tile 2 counter
$("#w2").load("https://procfuwidgets.b-cdn.net/html/m6yMkKywwWsS?pfajax&widget=2");
// tile 3 google gauge
$("#w3").load("https://procfuwidgets.b-cdn.net/html/m6yMkKywwWsS?pfajax&widget=3");
// tile 4 text
$("#w4").load("https://procfuwidgets.b-cdn.net/html/m6yMkKywwWsS?pfajax&widget=4");
// tile 5 bar chart
$("#w5").load("https://procfuwidgets.b-cdn.net/html/m6yMkKywwWsS?pfajax&widget=5");
// tile 6 line chart
$("#w6").load("https://procfuwidgets.b-cdn.net/html/m6yMkKywwWsS?pfajax&widget=6");
// tile 7 table
$("#w7").load("https://procfuwidgets.b-cdn.net/html/m6yMkKywwWsS?pfajax&widget=7");
</script>

The Result

The result is pretty neat:

For your reference, here are:

Happy Dashing :-)

Comments