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:

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

The Result

The result is pretty neat:

For your reference, here are:

Happy Dashing :-)

Comments