Beautiful, modern, rich dashboard Advice & Chat

Hello to the knack community

I have a working application and I’m trying to make it look good.
To do this, I’d like to get a front page in the form of a dashboard. I’d like to be able to display kpi linked to data present in the data, but also additional information, such as a twitter feed with news from the field I’m working in.

As appearance is 'quite’everything these days, I’d like to have something ‘beautiful’, which I can’t quite manage to do at the moment. For example :

Have you already set up such pages, and if so, do you have any techniques to recommend? Rich text, Iframe, other?

I’m calling on the community :wink:
Thanks for the advice

2 Likes

I had a team member build a great dynamic dashboard for an integrated business management system in Local Government. We leveraged Knack’s awesome way that you can present and report on data related to the logged in user. To make it work, we set up the data so that all the tasks, projects, actions being linked to both the employee and their supervisor and manager, and in the front end that is achieved through position based management.

In terms of displaying that on the dashboard - we started by just using Knack’s in built pivot tables and graphs. The pivot tables calculate totals (e.g. number of overdue actions). We then wanted to display dynamic notifications so that staff can see what is due and overdue, but hide them when the values are 0. And, we also wanted the built in Knack graphs to be better displayed next to these values. So we used the following components:

  1. Loaded the full bootstrap library for html components in our custom CSS - we may have been able to use the built in Knack components but it didn’t have everything we wanted, and bootstrap enables device independence. This was a pretty complex step because some of the components conflicted with knack’s built in components, so the library item names all needed to be modified. But now that it’s in we can use the components throughout.
  2. Wrote custom html and put it into a Rich Text view to create the dashboard built on Bootstrap components
  3. Added native Knack views on the same page with all the pivot tables and graphs we want in the dashboard - about 30 views!
  4. Wrote javascript that runs on page load to read the Knack pivot tables and graphs and do a mix of inserting values, moving graphs and doing calculations to populate the custom html elements. And, along the way, this code hides elements that should not be shown (e.g. 0 value notifications).

We could enhance it further with custom graphs, but for the most part, the overdue/view notifications is where the true value for us lies - and that part works awesome.

Here is the finished result:


and here it is when it’s loading before the javascript moves the data and hides 0 elements:

Sometimes I wish there was 4 columns instead of three.

Here is a sample of ours:

Thanks a lot @GrantSchuster and @IAmAKnacker

Obviously this is the example that great dashboards can be done with Knack.
I will work on this !

Of course, you could use an external dashboard service, link data to Google sheets etc and embed like this.

https://wasabi.knack.com/wasabi-digital#kpi/

Use API to push your data to any cloud service eg Google Sheets.

Could you share an example of the code for #4? I’d love to add dynamic notifications to our app but need an example that I can run with to get started…

Hi Leah,

Here are a couple of key extracts of the HTML and the javascript that create some placeholders with tags to display the values and links, and the JS to replace those with values from pivot table views:

HTML extract:

				<a class="_summary-head px-2 mr-auto text-light rounded-top d-block text-decoration-none" href="#my-approvals-and-collaboration/">
				<span class="_fa-icon align-baseline fa fa-check"></span>
				My Approvals and Collaboration
				</a>
				<div class="_summary rounded-bottom">
					<div class="row">
						<div class="_column-div col-sm">
							<div class="_column bg-light shadow m-2 p-2 rounded-lg">
								<div class="_column-head font-weight-light mr-auto text-nowrap">APPROVE
								</div>
								<div class="_column-info d-sm-flex">
									<a class="_link _info-div d-flex flex-sm-column text-decoration-none text-reset pr-sm-4 mr-sm-2 py-2 py-sm-0">
									<div class="mr-auto _text-warning text-nowrap">
										<span class="_fa-icon align-baseline fa fa-clock-o"></span>
										due
									</div>
									<div id="not-approvecollab-approve-due-val">loading...
									</div>
									</a>
									<a class="_link _info-div d-flex flex-sm-column text-decoration-none text-reset pr-sm-4 mr-sm-2 py-2 py-sm-0">
									<div class="mr-auto text-danger text-nowrap">
										<span class="_fa-icon align-baseline fa fa-exclamation-triangle"></span>
										overdue
									</div>
									<div id="not-approvecollab-approve-overdue-val">loading...
									</div>
									</a>
								</div>
							</div>
						</div>
						<div class="_column-div col-sm">
							<div class="_column bg-light shadow m-2 p-2 rounded-lg">
								<div class="_column-head font-weight-light mr-auto text-nowrap">ENDORSE
								</div>
								<div class="_column-info d-sm-flex">
									<a class="_link _info-div d-flex flex-sm-column text-decoration-none text-reset pr-sm-4 mr-sm-2 py-2 py-sm-0">
									<div class="mr-auto _text-warning text-nowrap">
										<span class="_fa-icon align-baseline fa fa-clock-o"></span>
										due
									</div>
									<div id="not-approvecollab-endorse-due-val">loading...
									</div>
									</a>
									<a class="_link _info-div d-flex flex-sm-column text-decoration-none text-reset pr-sm-4 mr-sm-2 py-2 py-sm-0">
									<div class="mr-auto text-danger text-nowrap">
										<span class="_fa-icon align-baseline fa fa-exclamation-triangle"></span>
										overdue
									</div>
									<div id="not-approvecollab-endorse-overdue-val">loading...
									</div>
									</a>
								</div>
							</div>
						</div>
						<div class="_column-div col-sm">
							<div class="_column bg-light shadow m-2 p-2 rounded-lg">
								<div class="_column-head font-weight-light mr-auto text-nowrap">CONSULT
								</div>
								<div class="_column-info d-sm-flex">
									<a class="_link _info-div d-flex flex-sm-column text-decoration-none text-reset pr-sm-4 mr-sm-2 py-2 py-sm-0">
									<div class="mr-auto _text-warning text-nowrap">
										<span class="_fa-icon align-baseline fa fa-clock-o"></span>
										due
									</div>
									<div id="not-approvecollab-consult-due-val">loading...
									</div>
									</a>
									<a class="_link _info-div d-flex flex-sm-column text-decoration-none text-reset pr-sm-4 mr-sm-2 py-2 py-sm-0">
									<div class="mr-auto text-danger text-nowrap">
										<span class="_fa-icon align-baseline fa fa-exclamation-triangle"></span>
										overdue
									</div>
									<div id="not-approvecollab-consult-overdue-val">loading...
									</div>
									</a>
								</div>
							</div>
						</div>
					</div>
				</div>
			</div>

Javascript:

function replaceValueOnDashboard(fromTagSelector, toTagSelector){
var val = $(fromTagSelector).text();
// if string
if(isNaN(val)){
$(toTagSelector).text(val);
return val;
}
// if number
else {
if(val > 0){
$(toTagSelector).text(val).closest(“a”).click(function() {
$(fromTagSelector).click();
});
}
else {
// even though we are hiding, let’s copy that value
$(toTagSelector).text(val).closest(“a”).click(function() {
$(fromTagSelector).click();
});
$(toTagSelector).closest(“._info-div”).removeClass(“d-flex”).hide();
}
return val;
}
}

var dashboardScenes = [“scene_1335”, /“scene_1532”, “scene_1548”,/ “scene_1736”]
for (var scene of dashboardScenes){
$(document).on(‘knack-scene-render.’ + scene, updateDashboard);
}

function updateDashboard(event, scene) {
var userView = null;
var faqView = null;
var carView = null;
var projectView = null;
var milestoneView = null;
var taskView = null;
var libraryView = null;
var performanceView = null;
var approvalsView = null;
var userPageAccessView = null;
var commView = null;
var returnsView = null;

// my own

if(scene.key == “scene_1335”){
userView = “view_4261”;
faqView = “view_3963”;
carView = “view_4206”;
projectView = “view_6490”;
milestoneView = “view_6523”;
taskView = “view_6521”;
// libraryView = “view_4208”;
libraryView = “view_5791”;
performanceView = “view_4552”;
userPageAccessView = “view_4616”;
questionsView = “view_4955”;
approvalsView = “view_5222”;
commView = “view_5432”;
returnsView = “view_6548”;
}

// APPROVE NUMBERS
// due
replaceValueOnDashboard(“#kn-report-” + approvalsView + “-1 td:eq(1)”, “#not-approvecollab-approve-due-val”);

// overdue
replaceValueOnDashboard(“#kn-report-” + approvalsView + “-1 td:eq(2)”, “#not-approvecollab-approve-overdue-val”);

// CONSULT NUMBERS
// due
replaceValueOnDashboard(“#kn-report-” + approvalsView + “-1 td:eq(4)”, “#not-approvecollab-consult-due-val”);

// overdue
replaceValueOnDashboard(“#kn-report-” + approvalsView + “-1 td:eq(5)”, “#not-approvecollab-consult-overdue-val”);

// ENDORSE NUMBERS
// due
replaceValueOnDashboard(“#kn-report-” + approvalsView + “-1 td:eq(7)”, “#not-approvecollab-endorse-due-val”);

// overdue
replaceValueOnDashboard(“#kn-report-” + approvalsView + “-1 td:eq(8)”, “#not-approvecollab-endorse-overdue-val”);