User Interface Design¶
The Stratpoint Timesheet Application uses a traditional Bootstrap-based interface built with AngularJS 1.x. The UI follows standard Bootstrap patterns with minimal custom styling, focusing on functionality over modern design aesthetics. This section covers the actual UI implementation and structure.
Actual UI Architecture¶
Design System Overview¶
The application uses a straightforward approach: - Bootstrap 3.x for base styling and components - Font Awesome for icons - Basic custom CSS for application-specific styling - Standard HTML forms and tables with Bootstrap classes
graph TB
A[UI Foundation] --> B[Bootstrap 3.x]
A --> C[Font Awesome Icons]
A --> D[Custom CSS]
B --> E[Standard Components]
E --> F[Panels]
E --> G[Forms]
E --> H[Tables]
E --> I[Buttons]
C --> J[Navigation Icons]
C --> K[Action Icons]
D --> L[Application Colors]
D --> M[Layout Adjustments]
Actual Layout Structure¶
Header Navigation¶
<!-- From /public/app/partials/header.html -->
<nav class="navbar navbar-default fixed-horizontally" ng-controller="HeaderCtrl">
<div class="container-fluid">
<div class="navbar-left">
<div class="navbar-brand">
<a href="dashboard" title="Dashboard">
<img src="app/img/timesheet_logo.png" height="40" />
</a>
</div>
</div>
<div class="navbar-right">
<ul class="nav navbar-nav navShowWhenWide" ng-if="currentUser.firstname">
<li class="dropdown" uib-dropdown>
<a href="#" class="uib-dropdown-toggle" role="button" uib-dropdown-toggle>
{{currentUser.firstname}} <b class="caret"></b>
</a>
<ul class="dropdown-menu" role="menu" uib-dropdown-menu>
<li><a href="users/profile">My Profile</a></li>
<li><a ng-click="logout()">Logout</a></li>
</ul>
</li>
</ul>
</div>
<!-- Collapsible Navigation Menu -->
<div class="navbar-collapse uib-collapse in" uib-collapse="!isCollapsed">
<ul class="nav navbar-nav">
<li class="dropdown" uib-dropdown ng-repeat-start="item in navItems" ng-if="item.children.length > 0">
<a href="#" class="uib-dropdown-toggle" uib-dropdown-toggle role="button">
{{item.title}} <b class="caret"></b>
</a>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="subitem in item.children"
ng-class="{'dropdown-submenu': subitem.children.length > 0}">
<a href="{{subitem.path}}" ng-if="!subitem.children.length > 0">
{{subitem.title}}
</a>
<!-- Support for nested dropdowns -->
<ul class="dropdown-menu" ng-if="subitem.children.length > 0">
<li ng-repeat="item in subitem.children">
<a href="{{item.path}}">{{item.title}}</a>
</li>
</ul>
</li>
</ul>
</li>
<li ng-repeat-end ng-if="item.children.length == 0">
<a href="{{item.path}}" role="button">{{item.title}}</a>
</li>
</ul>
</div>
</div>
</nav>
Main Content Structure¶
<!-- Basic application layout structure -->
<div id="mainWrapper">
<nav class="navbar"><!-- Header navigation --></nav>
<main>
<div ng-view>
<!-- Angular route content loads here -->
</div>
</main>
<footer>
<!-- Footer content -->
</footer>
</div>
Actual UI Components¶
Dashboard Panels¶
The application uses Bootstrap accordion panels for the dashboard:
<!-- From /public/app/partials/dashboard/index.html -->
<section class="row dashboard">
<h1>Dashboard</h1>
<div class="panel panel-default">
<div class="panel-body">
<uib-accordion close-others="false">
<div class="row">
<div class="col-md-6">
<uib-accordion-group ng-init="isOpen.timelogs = false"
is-open="isOpen.timelogs"
ng-if="data.panels.timelogs">
<uib-accordion-heading>
<span>My Timelogs</span>
<i class="fa" ng-class="{'fa-caret-up': isOpen.timelogs, 'fa-caret-down': !isOpen.timelogs}"></i>
</uib-accordion-heading>
<div ng-if="data.timelogs" ng-include="'app/partials/dashboard/timelogs.html'"></div>
</uib-accordion-group>
</div>
<!-- Additional accordion groups -->
</div>
</uib-accordion>
</div>
</div>
</section>
Form Components¶
Forms use standard Bootstrap form classes with Angular validation:
<!-- Typical form structure from timelog approval page -->
<form class="form" name="sForm" ng-submit="getDetailedTaskReport(sForm)" novalidate autocomplete="off">
<h3 class="panelHeader">Filter <small>(Fields with * are required)</small></h3>
<div class="row">
<div class="col-md-2">
<!-- Select dropdown -->
<div class="form-group required"
ng-class="{ 'has-error' : (submitted || !sForm.status.$pristine) && (sForm.status.$invalid || report.errors.status) }">
<label class="control-label">Status</label>
<select ng-model="report.status" class="form-control" ng-required="true">
<option ng-repeat="optionValue in statusList" value="{{optionValue}}">
{{optionValue | replace_}}
</option>
</select>
<p ng-show="(submitted || !sForm.status.$pristine) && sForm.status.$error.required"
class="help-block">Please select the status</p>
</div>
<!-- Date picker -->
<div class="form-group required"
ng-class="{ 'has-error' : (submitted || !sForm.startDate.$pristine) && (sForm.startDate.$invalid || report.errors.startDate) }">
<label class="control-label">Start Date</label>
<input type="text"
class="form-control"
placeholder="Start Date"
name="startDate"
ng-required="!initialLoadStatusPage"
uib-datepicker-popup="yyyy-MM-dd"
is-open="startDateIsOpen"
ng-model="report.startDate"
ng-click="startDateIsOpen = !startDateIsOpen"
datepicker-append-to-body="true" />
<p ng-show="(submitted || !sForm.startDate.$pristine) && (sForm.startDate.$error.required || sForm.startDate.$error.date)"
class="help-block">Please enter a valid date</p>
</div>
</div>
<div class="col-md-4">
<button class="btn btn-primary"> Submit </button>
</div>
</div>
</form>
Data Tables¶
Tables use ng-table with Bootstrap styling:
<!-- Standard data table structure -->
<div class="panel panel-default withTableRecords">
<div class="panel-heading listTableHeader">
<strong>Total Records: {{tableParams.total()}}</strong>
<a ng-click="tableParams.sorting({})" class="btn btn-default btn-sm">Clear Sorting</a>
</div>
<div class="panel-body">
<div ng-table-pagination="tableParams" template-url="'ng-table/pager.html'"></div>
<table class="table table-striped table-hover table-bordered" ng-table="tableParams" export-csv="csv">
<tbody>
<tr ng-repeat="item in $data track by item.id">
<td width="30" style="text-align: left" header="'ng-table/headers/checkbox.html'">
<input ng-if="!item.dateMadeUneditable"
type="checkbox"
value="{{item.id}}"
ng-checked="item.checked"
ng-model="item.checked" />
</td>
<td data-title="'Resource'" sortable="'resourceName'">
{{item.resourceName}}
</td>
<td data-title="'Project / Task'" sortable="'taskName'">
{{item.taskName}}
</td>
<!-- Additional table columns -->
</tr>
</tbody>
</table>
</div>
</div>
Action Buttons¶
Standard Bootstrap button groups for table actions:
<!-- Table action buttons -->
<div class="row tableMenuActions">
<div class="col-lg-12">
<button has-permission="103" type="button" class="btn btn-success" ng-click="approveBatch($event)">
<i class="fa fa-check"></i> Approve Checked Records
</button>
<button has-permission="103" type="button" class="btn btn-danger" ng-click="rejectBatch($event)">
<i class="fa fa-ban"></i> Reject Checked Records
</button>
<a class="btn btn-primary" ng-click="exportListFromBackend('Timelogs For Approval', 'csv')">
<i class="fa fa-file-excel-o"></i> Export to CSV
</a>
</div>
</div>
Actual Styling¶
Base CSS Variables and Styles¶
/* From /public/app/css/mine/style1.css */
html, body {
height: 100%;
margin: 0;
padding: 0;
background-color: #E5E5E5;
font-size: .9em;
font-family: 'Open Sans', sans-serif;
}
#mainWrapper {
box-sizing: border-box;
min-height: 100%;
padding: 0 0 35px; /* based on height of footer */
position: relative;
}
main {
padding: 0 1em;
margin-top: -30px;
}
footer {
background-color: #152630;
border-top: inset 1px #3E606F;
padding: 1em;
bottom: 0;
left: 0;
position: absolute;
width: 100%;
}
Navigation Styling¶
.navbar {
font-size: 1em;
border-radius: 0;
border: none;
background-color: #FFF;
-webkit-box-shadow: 0px 2px 10px 0px rgba(192, 192, 192, 0.75);
-moz-box-shadow: 0px 2px 10px 0px rgba(192, 192, 192, 0.75);
box-shadow: 0px 2px 10px 0px rgba(192, 192, 192, 0.75);
}
.navbar-brand {
padding-left: 0;
}
.navbar-brand img {
margin-top: -10px;
display: inline-block;
}
.navbar-default .navbar-nav > li > a {
color: #1472DC;
font-weight: bold;
border-right: solid 1px #F1F1F1;
}
.navbar-default .navbar-nav > li > a:hover {
color: #FFF;
background-color: #1472DC;
}
Table Styling¶
.table {
background: #FFF;
}
.table > thead > tr > th.text-right {
text-align: right;
}
.table > thead > tr > th.text-left {
text-align: left;
}
section.table-responsive {
width: auto;
border: none;
}
.pagination {
margin: 0;
}
Loading States¶
/* Loading container for ng-table */
.loading-container {
position: relative;
}
.loading-container .loading {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.8);
z-index: 1000;
}
Responsive Design¶
The application uses Bootstrap's responsive utilities:
/* Responsive navigation */
@media (max-width: 767px) {
.navShowWhenWide {
display: none !important;
}
.navShowWhenNarrow {
display: block !important;
}
}
@media (min-width: 768px) {
.navShowWhenWide {
display: block !important;
}
.navShowWhenNarrow {
display: none !important;
}
}
Key Characteristics¶
The Stratpoint Timesheet Application UI is characterized by:
- Traditional Bootstrap 3.x Design: Standard panels, forms, and tables
- Minimal Custom Styling: Basic color scheme and layout adjustments
- Functional Focus: Emphasis on data display and form functionality over aesthetics
- Permission-Based UI: Elements shown/hidden based on user permissions via
has-permissiondirective - Icon Usage: Font Awesome icons throughout for actions and status indicators
- Standard Navigation: Bootstrap navbar with dropdown menus
- Table-Heavy Interface: Extensive use of ng-table for data display
- Modal Dialogs: Standard Bootstrap modals for forms and confirmations
The interface prioritizes functionality and data management over modern design patterns, reflecting its enterprise-focused nature and practical requirements for timesheet and project management.