Merge branch 'release-1.0.0_rc1'
This commit is contained in:
21
README.md
Executable file
21
README.md
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
StatusBoard
|
||||||
|
=============
|
||||||
|
|
||||||
|
StatusBoard is a simple PHP web-based tool for displaying the status of services. Administrators can manually record incidents and provide estimated end times and simple descriptions. This tool is suitable for exposing status information to customers or other third parties and does not need to be connected to internal systems.
|
||||||
|
|
||||||
|
Features
|
||||||
|
-------
|
||||||
|
|
||||||
|
* Customisable list of Services and Sites.
|
||||||
|
* Manual reporting and status changes for Incidents.
|
||||||
|
* Multiple severity levels.
|
||||||
|
* Full admin UI.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
* PHP
|
||||||
|
* MYSQL
|
||||||
|
* Smarty
|
||||||
|
* sihnon-php-lib: https://github.com/optiz0r/sihnon-php-lib
|
||||||
|
|
||||||
106
build/schema/mysql.demo.sql
Normal file
106
build/schema/mysql.demo.sql
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
-- phpMyAdmin SQL Dump
|
||||||
|
-- version 3.1.4
|
||||||
|
-- http://www.phpmyadmin.net
|
||||||
|
--
|
||||||
|
-- Host: localhost:3306
|
||||||
|
-- Generation Time: Dec 16, 2011 at 01:27 AM
|
||||||
|
-- Server version: 5.1.53
|
||||||
|
-- PHP Version: 5.3.6-pl1-gentoo
|
||||||
|
|
||||||
|
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Database: `status-board`
|
||||||
|
--
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `settings`
|
||||||
|
--
|
||||||
|
|
||||||
|
UPDATE `settings` SET `value`='Example Status Board' WHERE `name`='site.title';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `service`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `service` (`id`, `name`, `description`) VALUES
|
||||||
|
(1, 'Internet', 'Shared Internet connection.'),
|
||||||
|
(2, 'Web', 'Hosted web servers'),
|
||||||
|
(3, 'Email', 'Hosted email services'),
|
||||||
|
(4, 'DNS', 'Hosted DNS services'),
|
||||||
|
(5, 'LDAP', 'Hosted directory services');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `site`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `site` (`id`, `service`, `name`, `description`) VALUES
|
||||||
|
(1, 1, 'Local', 'Local Internet access'),
|
||||||
|
(2, 2, 'Offsite', 'Offsite web services'),
|
||||||
|
(3, 3, 'Offsite', 'Offsite email services'),
|
||||||
|
(4, 4, 'Local', 'Primary DNS services'),
|
||||||
|
(5, 4, 'Offsite', 'Backup DNS services'),
|
||||||
|
(6, 5, 'Local', 'Local LDAP services'),
|
||||||
|
(7, 5, 'Offsite', 'Offsite LDAP services');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `incident`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `incident` (`id`, `site`, `reference`, `description`, `start_time`, `estimated_end_time`, `actual_end_time`) VALUES
|
||||||
|
(1, 1, 'UK:0001', 'Intermittent packetloss on primary internet connection', 1324079805, 1324079805, NULL),
|
||||||
|
(2, 1, 'UK:0002', 'Full outage', 1324079805, 1324079805, NULL),
|
||||||
|
(3, 4, 'UK:0003', 'DNS zone maintenance', 1324082411, 1324082411, NULL);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `incidentstatus`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `incidentstatus` (`id`, `incident`, `status`, `description`, `ctime`) VALUES
|
||||||
|
(1, 1, 2, 'Initial classification', 1324079864),
|
||||||
|
(2, 2, 4, 'Initial classification', 1324079864),
|
||||||
|
(3, 1, 3, 'Status upgraded due to increasing impact from the ongoing issue.', 1324080307),
|
||||||
|
(4, 3, 1, 'Initial classification', 1324082426);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `user`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `user` (`id`, `username`, `password`, `fullname`, `email`, `last_login`, `last_password_change`) VALUES
|
||||||
|
(2, 'guest', '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', 'Guest', NULL, NULL, 1324211553);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `group`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `group` (`id`, `name`, `description`) VALUES
|
||||||
|
(2, 'readonly', 'Basic group with read only access to the status boards.');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `usergroup`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `usergroup` (`id`, `user`, `group`, `added`) VALUES
|
||||||
|
(2, 2, 2, 1324211572);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `permission`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `permission` (`id`, `name`, `description`) VALUES
|
||||||
|
(2, 'Update Status Boards', 'Permission to add/edit/delete any service or site.'),
|
||||||
|
(3, 'Update Incidents', 'Permission to create and update the status of any incident.'),
|
||||||
|
(4, 'View Status Boards', 'Permission to view the status of all services and sites, and details of any incident.');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `grouppermission`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `grouppermission` (`id`, `group`, `permission`, `added`) VALUES
|
||||||
|
(2, 1, 2, 1324211935),
|
||||||
|
(3, 1, 3, 1324211935),
|
||||||
|
(4, 1, 4, 1324211935),
|
||||||
|
(5, 2, 4, 1324211935);
|
||||||
|
|
||||||
@@ -18,11 +18,6 @@ SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
|
|||||||
--
|
--
|
||||||
-- Table structure for table `settings`
|
-- Table structure for table `settings`
|
||||||
--
|
--
|
||||||
-- Creation: Sep 24, 2010 at 07:22 PM
|
|
||||||
-- Last update: Dec 04, 2011 at 01:19 PM
|
|
||||||
-- Last check: Aug 20, 2011 at 10:32 PM
|
|
||||||
--
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `settings`;
|
DROP TABLE IF EXISTS `settings`;
|
||||||
CREATE TABLE IF NOT EXISTS `settings` (
|
CREATE TABLE IF NOT EXISTS `settings` (
|
||||||
`name` varchar(255) NOT NULL,
|
`name` varchar(255) NOT NULL,
|
||||||
@@ -34,10 +29,10 @@ CREATE TABLE IF NOT EXISTS `settings` (
|
|||||||
--
|
--
|
||||||
-- Dumping data for table `settings`
|
-- Dumping data for table `settings`
|
||||||
--
|
--
|
||||||
|
|
||||||
INSERT INTO `settings` (`name`, `value`, `type`) VALUES
|
INSERT INTO `settings` (`name`, `value`, `type`) VALUES
|
||||||
('debug.display_exceptions', '1', 'bool'),
|
('debug.display_exceptions', '1', 'bool'),
|
||||||
('cache.base_dir', '/dev/shm/status-board/', 'string'),
|
('cache.base_dir', '/dev/shm/status-board/', 'string'),
|
||||||
|
('auth', 'Database', 'string'),
|
||||||
('logging.plugins', 'Database\nFlatFile', 'array(string)'),
|
('logging.plugins', 'Database\nFlatFile', 'array(string)'),
|
||||||
('logging.Database', 'webui', 'array(string)'),
|
('logging.Database', 'webui', 'array(string)'),
|
||||||
('logging.Database.webui.table', 'log', 'string'),
|
('logging.Database.webui.table', 'log', 'string'),
|
||||||
@@ -48,14 +43,14 @@ INSERT INTO `settings` (`name`, `value`, `type`) VALUES
|
|||||||
('logging.FlatFile.tmp.format', '%timestamp% %hostname%:%pid% %progname%:%file%[%line%] %message%', 'string'),
|
('logging.FlatFile.tmp.format', '%timestamp% %hostname%:%pid% %progname%:%file%[%line%] %message%', 'string'),
|
||||||
('logging.FlatFile.tmp.severity', 'debug\ninfo\nwarning\nerror', 'array(string)'),
|
('logging.FlatFile.tmp.severity', 'debug\ninfo\nwarning\nerror', 'array(string)'),
|
||||||
('logging.FlatFile.tmp.category', 'webui\ndefault', 'array(string)'),
|
('logging.FlatFile.tmp.category', 'webui\ndefault', 'array(string)'),
|
||||||
('templates.tmp_path', '/var/tmp/status-board/', 'string');
|
('templates.tmp_path', '/var/tmp/status-board/', 'string'),
|
||||||
|
('site.title', 'Status Board', 'string'),
|
||||||
|
('sessions', 1, 'bool'),
|
||||||
|
('sessions.path', '/', 'string');
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `log`
|
-- Table structure for table `log`
|
||||||
--
|
--
|
||||||
-- Creation: Aug 20, 2011 at 10:32 PM
|
|
||||||
--
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `log`;
|
DROP TABLE IF EXISTS `log`;
|
||||||
CREATE TABLE IF NOT EXISTS `log` (
|
CREATE TABLE IF NOT EXISTS `log` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
@@ -71,3 +66,307 @@ CREATE TABLE IF NOT EXISTS `log` (
|
|||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `service`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `service`;
|
||||||
|
CREATE TABLE IF NOT EXISTS `service` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(32) NOT NULL,
|
||||||
|
`description` text NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `service`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `site`;
|
||||||
|
CREATE TABLE IF NOT EXISTS `site` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`service` int(10) unsigned NOT NULL,
|
||||||
|
`name` varchar(32) NOT NULL,
|
||||||
|
`description` text NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `service` (`service`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `incident`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `incident`;
|
||||||
|
CREATE TABLE IF NOT EXISTS `incident` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`site` int(10) unsigned NOT NULL,
|
||||||
|
`reference` varchar(32) NOT NULL,
|
||||||
|
`description` text NOT NULL,
|
||||||
|
`start_time` int(10) NOT NULL,
|
||||||
|
`estimated_end_time` int(10) NULL,
|
||||||
|
`actual_end_time` int(10) NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `site` (`site`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `incidentstatus`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `incidentstatus`;
|
||||||
|
CREATE TABLE IF NOT EXISTS `incidentstatus` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`incident` int(10) unsigned NOT NULL,
|
||||||
|
`status` int(10) unsigned NOT NULL,
|
||||||
|
`description` text NOT NULL,
|
||||||
|
`ctime` int(10) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `incident` (`incident`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for view `incidentstatus_current_int`
|
||||||
|
--
|
||||||
|
DROP VIEW IF EXISTS `incidentstatus_current_int`;
|
||||||
|
CREATE VIEW `incidentstatus_current_int` AS (
|
||||||
|
SELECT
|
||||||
|
`incidentstatus`.`incident` AS `incident`,
|
||||||
|
MAX(`incidentstatus`.`id`) AS `latest`
|
||||||
|
FROM
|
||||||
|
`incidentstatus`
|
||||||
|
GROUP BY
|
||||||
|
`incidentstatus`.`incident`
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for view `incidentstatus_current`
|
||||||
|
--
|
||||||
|
DROP VIEW IF EXISTS `incidentstatus_current`;
|
||||||
|
CREATE VIEW `incidentstatus_current` AS (
|
||||||
|
SELECT
|
||||||
|
`is`.`id` AS `id`,
|
||||||
|
`is`.`incident` AS `incident`,
|
||||||
|
`is`.`status` AS `status`,
|
||||||
|
`is`.`ctime` AS `ctime`
|
||||||
|
FROM (
|
||||||
|
`incidentstatus` AS `is`
|
||||||
|
JOIN `incidentstatus_current_int` AS `isci`
|
||||||
|
)
|
||||||
|
WHERE (
|
||||||
|
(`isci`.`incident` = `is`.`incident`)
|
||||||
|
AND (`is`.`id` = `isci`.`latest`)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for view `incident_open`
|
||||||
|
--
|
||||||
|
DROP VIEW IF EXISTS `incident_open`;
|
||||||
|
CREATE VIEW `incident_open` AS (
|
||||||
|
SELECT
|
||||||
|
`i`.*,
|
||||||
|
`isc`.`ctime`
|
||||||
|
FROM
|
||||||
|
`incident` AS `i`
|
||||||
|
JOIN `incidentstatus_current` AS `isc`
|
||||||
|
ON `i`.`id` = `isc`.`incident`
|
||||||
|
WHERE
|
||||||
|
`isc`.`status` IN (1,2,3,4)
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for view `incident_closedtime`
|
||||||
|
--
|
||||||
|
DROP VIEW IF EXISTS `incident_closedtime`;
|
||||||
|
CREATE VIEW `incident_closedtime` AS (
|
||||||
|
SELECT
|
||||||
|
`incident` AS `incident`,
|
||||||
|
`ctime` AS `ctime`
|
||||||
|
FROM
|
||||||
|
`incidentstatus`
|
||||||
|
WHERE
|
||||||
|
`status` = 0
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for view `incident_opentimes`
|
||||||
|
--
|
||||||
|
DROP VIEW IF EXISTS `incident_opentimes`;
|
||||||
|
CREATE VIEW `incident_opentimes` AS (
|
||||||
|
SELECT
|
||||||
|
`i`.*,
|
||||||
|
IFNULL(`t`.`ctime`, 0xffffffff+0) AS `ctime`
|
||||||
|
FROM
|
||||||
|
`incident` as `i`
|
||||||
|
LEFT JOIN `incident_closedtime` AS `t` ON `i`.`id`=`t`.`incident`
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `user`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `user`;
|
||||||
|
CREATE TABLE IF NOT EXISTS `user` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`username` varchar(255) NOT NULL,
|
||||||
|
`password` char(40) NOT NULL,
|
||||||
|
`fullname` varchar(255) NULL,
|
||||||
|
`email` varchar(255) NULL,
|
||||||
|
`last_login` int(10) NULL,
|
||||||
|
`last_password_change` int(10) NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `user`
|
||||||
|
--
|
||||||
|
INSERT INTO `user` (`id`, `username`, `password`, `fullname`, `email`, `last_login`, `last_password_change`) VALUES
|
||||||
|
(1, 'admin', '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', 'Administrator', NULL, NULL, 1324211456);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `group`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `group`;
|
||||||
|
CREATE TABLE IF NOT EXISTS `group` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(255) NOT NULL,
|
||||||
|
`description` text NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `group`
|
||||||
|
--
|
||||||
|
INSERT INTO `group` (`id`, `name`, `description`) VALUES
|
||||||
|
(1, 'admins', 'Administrative users will full control over the status boards.');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `usergroup`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `usergroup`;
|
||||||
|
CREATE TABLE IF NOT EXISTS `usergroup` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`user` int(10) unsigned NOT NULL,
|
||||||
|
`group` int(10) unsigned NOT NULL,
|
||||||
|
`added` int(10) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `user` (`user`,`group`),
|
||||||
|
KEY `group` (`group`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `usergroup`
|
||||||
|
--
|
||||||
|
INSERT INTO `usergroup` (`id`, `user`, `group`, `added`) VALUES
|
||||||
|
(1, 1, 1, 1324211572);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for view `groups_by_user`
|
||||||
|
--
|
||||||
|
DROP VIEW IF EXISTS `groups_by_user`;
|
||||||
|
CREATE VIEW `groups_by_user` AS (
|
||||||
|
SELECT
|
||||||
|
`u`.`id` AS `user`,
|
||||||
|
`g`.*
|
||||||
|
FROM
|
||||||
|
`usergroup` as `ug`
|
||||||
|
LEFT JOIN `user` AS `u` ON `ug`.`user`=`u`.`id`
|
||||||
|
LEFT JOIN `group` AS `g` ON `ug`.`group`=`g`.`id`
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `permission`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `permission`;
|
||||||
|
CREATE TABLE IF NOT EXISTS `permission` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(255) NOT NULL,
|
||||||
|
`description` text NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `permission`
|
||||||
|
--
|
||||||
|
INSERT INTO `permission` (`id`, `name`, `description`) VALUES
|
||||||
|
(1, 'Administrator', 'Full administrative rights.');
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `grouppermission`
|
||||||
|
--
|
||||||
|
DROP TABLE IF EXISTS `grouppermission`;
|
||||||
|
CREATE TABLE IF NOT EXISTS `grouppermission` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`group` int(10) unsigned NOT NULL,
|
||||||
|
`permission` int(10) unsigned NOT NULL,
|
||||||
|
`added` int(10) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `group` (`group`,`permission`),
|
||||||
|
KEY `permission` (`permission`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `grouppermission`
|
||||||
|
--
|
||||||
|
INSERT INTO `grouppermission` (`id`, `group`, `permission`, `added`) VALUES
|
||||||
|
(1, 1, 1, 1324211935);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for view `permissions_by_group`
|
||||||
|
--
|
||||||
|
DROP VIEW IF EXISTS `permissions_by_group`;
|
||||||
|
CREATE VIEW `permissions_by_group` AS (
|
||||||
|
SELECT
|
||||||
|
`g`.`id` AS `group`,
|
||||||
|
`p`.*
|
||||||
|
FROM
|
||||||
|
`grouppermission` as `gp`
|
||||||
|
LEFT JOIN `group` AS `g` ON `gp`.`group`=`g`.`id`
|
||||||
|
LEFT JOIN `permission` AS `p` on `gp`.`permission`=`p`.`id`
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for view `permissions_by_user`
|
||||||
|
--
|
||||||
|
DROP VIEW IF EXISTS `permissions_by_user`;
|
||||||
|
CREATE VIEW `permissions_by_user` AS (
|
||||||
|
SELECT
|
||||||
|
`u`.`id` AS `user`,
|
||||||
|
`p`.*
|
||||||
|
FROM
|
||||||
|
`usergroup` as `ug`
|
||||||
|
LEFT JOIN `user` AS `u` ON `ug`.`user`=`u`.`id`
|
||||||
|
LEFT JOIN `permissions_by_group` AS `p` on `ug`.`group`=`p`.`group`
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for dumped tables
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `grouppermission`
|
||||||
|
--
|
||||||
|
ALTER TABLE `grouppermission`
|
||||||
|
ADD CONSTRAINT `grouppermission_ibfk_2` FOREIGN KEY (`permission`) REFERENCES `permission` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT `grouppermission_ibfk_1` FOREIGN KEY (`group`) REFERENCES `group` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `incident`
|
||||||
|
--
|
||||||
|
ALTER TABLE `incident`
|
||||||
|
ADD CONSTRAINT `incident_ibfk_1` FOREIGN KEY (`site`) REFERENCES `site` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `incidentstatus`
|
||||||
|
--
|
||||||
|
ALTER TABLE `incidentstatus`
|
||||||
|
ADD CONSTRAINT `incidentstatus_ibfk_1` FOREIGN KEY (`incident`) REFERENCES `incident` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `site`
|
||||||
|
--
|
||||||
|
ALTER TABLE `site`
|
||||||
|
ADD CONSTRAINT `site_ibfk_1` FOREIGN KEY (`service`) REFERENCES `service` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `usergroup`
|
||||||
|
--
|
||||||
|
ALTER TABLE `usergroup`
|
||||||
|
ADD CONSTRAINT `usergroup_ibfk_2` FOREIGN KEY (`group`) REFERENCES `group` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT `usergroup_ibfk_1` FOREIGN KEY (`user`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|||||||
BIN
public/images/Status_Icons/cross-circle.png
Executable file
BIN
public/images/Status_Icons/cross-circle.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 729 B |
BIN
public/images/Status_Icons/exclamation.png
Executable file
BIN
public/images/Status_Icons/exclamation.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 654 B |
BIN
public/images/Status_Icons/tick-circle.png
Executable file
BIN
public/images/Status_Icons/tick-circle.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 724 B |
BIN
public/images/Status_Icons/traffic-cone.png
Executable file
BIN
public/images/Status_Icons/traffic-cone.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 688 B |
BIN
public/images/favicon.ico
Executable file
BIN
public/images/favicon.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 724 B |
0
public/less/bootstrap.less
vendored
Normal file
0
public/less/bootstrap.less
vendored
Normal file
113
public/scripts/3rdparty/bootstrap-alerts.js
vendored
Normal file
113
public/scripts/3rdparty/bootstrap-alerts.js
vendored
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/* ==========================================================
|
||||||
|
* bootstrap-alerts.js v1.4.0
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#alerts
|
||||||
|
* ==========================================================
|
||||||
|
* Copyright 2011 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ========================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
!function( $ ){
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
/* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
|
||||||
|
* ======================================================= */
|
||||||
|
|
||||||
|
var transitionEnd
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
|
||||||
|
$.support.transition = (function () {
|
||||||
|
var thisBody = document.body || document.documentElement
|
||||||
|
, thisStyle = thisBody.style
|
||||||
|
, support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
|
||||||
|
return support
|
||||||
|
})()
|
||||||
|
|
||||||
|
// set CSS transition event type
|
||||||
|
if ( $.support.transition ) {
|
||||||
|
transitionEnd = "TransitionEnd"
|
||||||
|
if ( $.browser.webkit ) {
|
||||||
|
transitionEnd = "webkitTransitionEnd"
|
||||||
|
} else if ( $.browser.mozilla ) {
|
||||||
|
transitionEnd = "transitionend"
|
||||||
|
} else if ( $.browser.opera ) {
|
||||||
|
transitionEnd = "oTransitionEnd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
/* ALERT CLASS DEFINITION
|
||||||
|
* ====================== */
|
||||||
|
|
||||||
|
var Alert = function ( content, options ) {
|
||||||
|
this.settings = $.extend({}, $.fn.alert.defaults, options)
|
||||||
|
this.$element = $(content)
|
||||||
|
.delegate(this.settings.selector, 'click', this.close)
|
||||||
|
}
|
||||||
|
|
||||||
|
Alert.prototype = {
|
||||||
|
|
||||||
|
close: function (e) {
|
||||||
|
var $element = $(this).parent('.alert-message')
|
||||||
|
|
||||||
|
e && e.preventDefault()
|
||||||
|
$element.removeClass('in')
|
||||||
|
|
||||||
|
function removeElement () {
|
||||||
|
$element.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
$.support.transition && $element.hasClass('fade') ?
|
||||||
|
$element.bind(transitionEnd, removeElement) :
|
||||||
|
removeElement()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ALERT PLUGIN DEFINITION
|
||||||
|
* ======================= */
|
||||||
|
|
||||||
|
$.fn.alert = function ( options ) {
|
||||||
|
|
||||||
|
if ( options === true ) {
|
||||||
|
return this.data('alert')
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
|
||||||
|
if ( typeof options == 'string' ) {
|
||||||
|
return $this.data('alert')[options]()
|
||||||
|
}
|
||||||
|
|
||||||
|
$(this).data('alert', new Alert( this, options ))
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.alert.defaults = {
|
||||||
|
selector: '.close'
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
new Alert($('body'), {
|
||||||
|
selector: '.alert-message[data-alert] .close'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}( window.jQuery || window.ender );
|
||||||
55
public/scripts/3rdparty/bootstrap-dropdown.js
vendored
Normal file
55
public/scripts/3rdparty/bootstrap-dropdown.js
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/* ============================================================
|
||||||
|
* bootstrap-dropdown.js v1.4.0
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#dropdown
|
||||||
|
* ============================================================
|
||||||
|
* Copyright 2011 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
|
||||||
|
!function( $ ){
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
/* DROPDOWN PLUGIN DEFINITION
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
$.fn.dropdown = function ( selector ) {
|
||||||
|
return this.each(function () {
|
||||||
|
$(this).delegate(selector || d, 'click', function (e) {
|
||||||
|
var li = $(this).parent('li')
|
||||||
|
, isActive = li.hasClass('open')
|
||||||
|
|
||||||
|
clearMenus()
|
||||||
|
!isActive && li.toggleClass('open')
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* APPLY TO STANDARD DROPDOWN ELEMENTS
|
||||||
|
* =================================== */
|
||||||
|
|
||||||
|
var d = 'a.menu, .dropdown-toggle'
|
||||||
|
|
||||||
|
function clearMenus() {
|
||||||
|
$(d).parent('li').removeClass('open')
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('html').bind("click", clearMenus)
|
||||||
|
$('body').dropdown( '[data-dropdown] a.menu, [data-dropdown] .dropdown-toggle' )
|
||||||
|
})
|
||||||
|
|
||||||
|
}( window.jQuery || window.ender );
|
||||||
260
public/scripts/3rdparty/bootstrap-modal.js
vendored
Normal file
260
public/scripts/3rdparty/bootstrap-modal.js
vendored
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
/* =========================================================
|
||||||
|
* bootstrap-modal.js v1.4.0
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#modal
|
||||||
|
* =========================================================
|
||||||
|
* Copyright 2011 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ========================================================= */
|
||||||
|
|
||||||
|
|
||||||
|
!function( $ ){
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
/* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
|
||||||
|
* ======================================================= */
|
||||||
|
|
||||||
|
var transitionEnd
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
|
||||||
|
$.support.transition = (function () {
|
||||||
|
var thisBody = document.body || document.documentElement
|
||||||
|
, thisStyle = thisBody.style
|
||||||
|
, support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
|
||||||
|
return support
|
||||||
|
})()
|
||||||
|
|
||||||
|
// set CSS transition event type
|
||||||
|
if ( $.support.transition ) {
|
||||||
|
transitionEnd = "TransitionEnd"
|
||||||
|
if ( $.browser.webkit ) {
|
||||||
|
transitionEnd = "webkitTransitionEnd"
|
||||||
|
} else if ( $.browser.mozilla ) {
|
||||||
|
transitionEnd = "transitionend"
|
||||||
|
} else if ( $.browser.opera ) {
|
||||||
|
transitionEnd = "oTransitionEnd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
/* MODAL PUBLIC CLASS DEFINITION
|
||||||
|
* ============================= */
|
||||||
|
|
||||||
|
var Modal = function ( content, options ) {
|
||||||
|
this.settings = $.extend({}, $.fn.modal.defaults, options)
|
||||||
|
this.$element = $(content)
|
||||||
|
.delegate('.close', 'click.modal', $.proxy(this.hide, this))
|
||||||
|
|
||||||
|
if ( this.settings.show ) {
|
||||||
|
this.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
Modal.prototype = {
|
||||||
|
|
||||||
|
toggle: function () {
|
||||||
|
return this[!this.isShown ? 'show' : 'hide']()
|
||||||
|
}
|
||||||
|
|
||||||
|
, show: function () {
|
||||||
|
var that = this
|
||||||
|
this.isShown = true
|
||||||
|
this.$element.trigger('show')
|
||||||
|
|
||||||
|
escape.call(this)
|
||||||
|
backdrop.call(this, function () {
|
||||||
|
var transition = $.support.transition && that.$element.hasClass('fade')
|
||||||
|
|
||||||
|
that.$element
|
||||||
|
.appendTo(document.body)
|
||||||
|
.show()
|
||||||
|
|
||||||
|
if (transition) {
|
||||||
|
that.$element[0].offsetWidth // force reflow
|
||||||
|
}
|
||||||
|
|
||||||
|
that.$element.addClass('in')
|
||||||
|
|
||||||
|
transition ?
|
||||||
|
that.$element.one(transitionEnd, function () { that.$element.trigger('shown') }) :
|
||||||
|
that.$element.trigger('shown')
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
, hide: function (e) {
|
||||||
|
e && e.preventDefault()
|
||||||
|
|
||||||
|
if ( !this.isShown ) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
var that = this
|
||||||
|
this.isShown = false
|
||||||
|
|
||||||
|
escape.call(this)
|
||||||
|
|
||||||
|
this.$element
|
||||||
|
.trigger('hide')
|
||||||
|
.removeClass('in')
|
||||||
|
|
||||||
|
$.support.transition && this.$element.hasClass('fade') ?
|
||||||
|
hideWithTransition.call(this) :
|
||||||
|
hideModal.call(this)
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* MODAL PRIVATE METHODS
|
||||||
|
* ===================== */
|
||||||
|
|
||||||
|
function hideWithTransition() {
|
||||||
|
// firefox drops transitionEnd events :{o
|
||||||
|
var that = this
|
||||||
|
, timeout = setTimeout(function () {
|
||||||
|
that.$element.unbind(transitionEnd)
|
||||||
|
hideModal.call(that)
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
this.$element.one(transitionEnd, function () {
|
||||||
|
clearTimeout(timeout)
|
||||||
|
hideModal.call(that)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideModal (that) {
|
||||||
|
this.$element
|
||||||
|
.hide()
|
||||||
|
.trigger('hidden')
|
||||||
|
|
||||||
|
backdrop.call(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
function backdrop ( callback ) {
|
||||||
|
var that = this
|
||||||
|
, animate = this.$element.hasClass('fade') ? 'fade' : ''
|
||||||
|
if ( this.isShown && this.settings.backdrop ) {
|
||||||
|
var doAnimate = $.support.transition && animate
|
||||||
|
|
||||||
|
this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
|
||||||
|
.appendTo(document.body)
|
||||||
|
|
||||||
|
if ( this.settings.backdrop != 'static' ) {
|
||||||
|
this.$backdrop.click($.proxy(this.hide, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( doAnimate ) {
|
||||||
|
this.$backdrop[0].offsetWidth // force reflow
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$backdrop.addClass('in')
|
||||||
|
|
||||||
|
doAnimate ?
|
||||||
|
this.$backdrop.one(transitionEnd, callback) :
|
||||||
|
callback()
|
||||||
|
|
||||||
|
} else if ( !this.isShown && this.$backdrop ) {
|
||||||
|
this.$backdrop.removeClass('in')
|
||||||
|
|
||||||
|
$.support.transition && this.$element.hasClass('fade')?
|
||||||
|
this.$backdrop.one(transitionEnd, $.proxy(removeBackdrop, this)) :
|
||||||
|
removeBackdrop.call(this)
|
||||||
|
|
||||||
|
} else if ( callback ) {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeBackdrop() {
|
||||||
|
this.$backdrop.remove()
|
||||||
|
this.$backdrop = null
|
||||||
|
}
|
||||||
|
|
||||||
|
function escape() {
|
||||||
|
var that = this
|
||||||
|
if ( this.isShown && this.settings.keyboard ) {
|
||||||
|
$(document).bind('keyup.modal', function ( e ) {
|
||||||
|
if ( e.which == 27 ) {
|
||||||
|
that.hide()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if ( !this.isShown ) {
|
||||||
|
$(document).unbind('keyup.modal')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* MODAL PLUGIN DEFINITION
|
||||||
|
* ======================= */
|
||||||
|
|
||||||
|
$.fn.modal = function ( options ) {
|
||||||
|
var modal = this.data('modal')
|
||||||
|
|
||||||
|
if (!modal) {
|
||||||
|
|
||||||
|
if (typeof options == 'string') {
|
||||||
|
options = {
|
||||||
|
show: /show|toggle/.test(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.each(function () {
|
||||||
|
$(this).data('modal', new Modal(this, options))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( options === true ) {
|
||||||
|
return modal
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( typeof options == 'string' ) {
|
||||||
|
modal[options]()
|
||||||
|
} else if ( modal ) {
|
||||||
|
modal.toggle()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.modal.Modal = Modal
|
||||||
|
|
||||||
|
$.fn.modal.defaults = {
|
||||||
|
backdrop: false
|
||||||
|
, keyboard: false
|
||||||
|
, show: false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* MODAL DATA- IMPLEMENTATION
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('body').delegate('[data-controls-modal]', 'click', function (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
var $this = $(this).data('show', true)
|
||||||
|
$('#' + $this.attr('data-controls-modal')).modal( $this.data() )
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}( window.jQuery || window.ender );
|
||||||
90
public/scripts/3rdparty/bootstrap-popover.js
vendored
Normal file
90
public/scripts/3rdparty/bootstrap-popover.js
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/* ===========================================================
|
||||||
|
* bootstrap-popover.js v1.4.0
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#popover
|
||||||
|
* ===========================================================
|
||||||
|
* Copyright 2011 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* =========================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
!function( $ ) {
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
var Popover = function ( element, options ) {
|
||||||
|
this.$element = $(element)
|
||||||
|
this.options = options
|
||||||
|
this.enabled = true
|
||||||
|
this.fixTitle()
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: POPOVER EXTENDS BOOTSTRAP-TWIPSY.js
|
||||||
|
========================================= */
|
||||||
|
|
||||||
|
Popover.prototype = $.extend({}, $.fn.twipsy.Twipsy.prototype, {
|
||||||
|
|
||||||
|
setContent: function () {
|
||||||
|
var $tip = this.tip()
|
||||||
|
$tip.find('.title')[this.options.html ? 'html' : 'text'](this.getTitle())
|
||||||
|
$tip.find('.content p')[this.options.html ? 'html' : 'text'](this.getContent())
|
||||||
|
$tip[0].className = 'popover'
|
||||||
|
}
|
||||||
|
|
||||||
|
, hasContent: function () {
|
||||||
|
return this.getTitle() || this.getContent()
|
||||||
|
}
|
||||||
|
|
||||||
|
, getContent: function () {
|
||||||
|
var content
|
||||||
|
, $e = this.$element
|
||||||
|
, o = this.options
|
||||||
|
|
||||||
|
if (typeof this.options.content == 'string') {
|
||||||
|
content = $e.attr(this.options.content)
|
||||||
|
} else if (typeof this.options.content == 'function') {
|
||||||
|
content = this.options.content.call(this.$element[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
|
, tip: function() {
|
||||||
|
if (!this.$tip) {
|
||||||
|
this.$tip = $('<div class="popover" />')
|
||||||
|
.html(this.options.template)
|
||||||
|
}
|
||||||
|
return this.$tip
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
/* POPOVER PLUGIN DEFINITION
|
||||||
|
* ======================= */
|
||||||
|
|
||||||
|
$.fn.popover = function (options) {
|
||||||
|
if (typeof options == 'object') options = $.extend({}, $.fn.popover.defaults, options)
|
||||||
|
$.fn.twipsy.initWith.call(this, options, Popover, 'popover')
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.popover.defaults = $.extend({} , $.fn.twipsy.defaults, {
|
||||||
|
placement: 'right'
|
||||||
|
, content: 'data-content'
|
||||||
|
, template: '<div class="arrow"></div><div class="inner"><h3 class="title"></h3><div class="content"><p></p></div></div>'
|
||||||
|
})
|
||||||
|
|
||||||
|
$.fn.twipsy.rejectAttrOptions.push( 'content' )
|
||||||
|
|
||||||
|
}( window.jQuery || window.ender );
|
||||||
80
public/scripts/3rdparty/bootstrap-tabs.js
vendored
Normal file
80
public/scripts/3rdparty/bootstrap-tabs.js
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/* ========================================================
|
||||||
|
* bootstrap-tabs.js v1.4.0
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#tabs
|
||||||
|
* ========================================================
|
||||||
|
* Copyright 2011 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ======================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
!function( $ ){
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
function activate ( element, container ) {
|
||||||
|
container
|
||||||
|
.find('> .active')
|
||||||
|
.removeClass('active')
|
||||||
|
.find('> .dropdown-menu > .active')
|
||||||
|
.removeClass('active')
|
||||||
|
|
||||||
|
element.addClass('active')
|
||||||
|
|
||||||
|
if ( element.parent('.dropdown-menu') ) {
|
||||||
|
element.closest('li.dropdown').addClass('active')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tab( e ) {
|
||||||
|
var $this = $(this)
|
||||||
|
, $ul = $this.closest('ul:not(.dropdown-menu)')
|
||||||
|
, href = $this.attr('href')
|
||||||
|
, previous
|
||||||
|
, $href
|
||||||
|
|
||||||
|
if ( /^#\w+/.test(href) ) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
if ( $this.parent('li').hasClass('active') ) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = $ul.find('.active a').last()[0]
|
||||||
|
$href = $(href)
|
||||||
|
|
||||||
|
activate($this.parent('li'), $ul)
|
||||||
|
activate($href, $href.parent())
|
||||||
|
|
||||||
|
$this.trigger({
|
||||||
|
type: 'change'
|
||||||
|
, relatedTarget: previous
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TABS/PILLS PLUGIN DEFINITION
|
||||||
|
* ============================ */
|
||||||
|
|
||||||
|
$.fn.tabs = $.fn.pills = function ( selector ) {
|
||||||
|
return this.each(function () {
|
||||||
|
$(this).delegate(selector || '.tabs li > a, .pills > li > a', 'click', tab)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('body').tabs('ul[data-tabs] li > a, ul[data-pills] > li > a')
|
||||||
|
})
|
||||||
|
|
||||||
|
}( window.jQuery || window.ender );
|
||||||
321
public/scripts/3rdparty/bootstrap-twipsy.js
vendored
Normal file
321
public/scripts/3rdparty/bootstrap-twipsy.js
vendored
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
/* ==========================================================
|
||||||
|
* bootstrap-twipsy.js v1.4.0
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#twipsy
|
||||||
|
* Adapted from the original jQuery.tipsy by Jason Frame
|
||||||
|
* ==========================================================
|
||||||
|
* Copyright 2011 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ========================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
!function( $ ) {
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
/* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
|
||||||
|
* ======================================================= */
|
||||||
|
|
||||||
|
var transitionEnd
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
|
||||||
|
$.support.transition = (function () {
|
||||||
|
var thisBody = document.body || document.documentElement
|
||||||
|
, thisStyle = thisBody.style
|
||||||
|
, support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
|
||||||
|
return support
|
||||||
|
})()
|
||||||
|
|
||||||
|
// set CSS transition event type
|
||||||
|
if ( $.support.transition ) {
|
||||||
|
transitionEnd = "TransitionEnd"
|
||||||
|
if ( $.browser.webkit ) {
|
||||||
|
transitionEnd = "webkitTransitionEnd"
|
||||||
|
} else if ( $.browser.mozilla ) {
|
||||||
|
transitionEnd = "transitionend"
|
||||||
|
} else if ( $.browser.opera ) {
|
||||||
|
transitionEnd = "oTransitionEnd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
/* TWIPSY PUBLIC CLASS DEFINITION
|
||||||
|
* ============================== */
|
||||||
|
|
||||||
|
var Twipsy = function ( element, options ) {
|
||||||
|
this.$element = $(element)
|
||||||
|
this.options = options
|
||||||
|
this.enabled = true
|
||||||
|
this.fixTitle()
|
||||||
|
}
|
||||||
|
|
||||||
|
Twipsy.prototype = {
|
||||||
|
|
||||||
|
show: function() {
|
||||||
|
var pos
|
||||||
|
, actualWidth
|
||||||
|
, actualHeight
|
||||||
|
, placement
|
||||||
|
, $tip
|
||||||
|
, tp
|
||||||
|
|
||||||
|
if (this.hasContent() && this.enabled) {
|
||||||
|
$tip = this.tip()
|
||||||
|
this.setContent()
|
||||||
|
|
||||||
|
if (this.options.animate) {
|
||||||
|
$tip.addClass('fade')
|
||||||
|
}
|
||||||
|
|
||||||
|
$tip
|
||||||
|
.remove()
|
||||||
|
.css({ top: 0, left: 0, display: 'block' })
|
||||||
|
.prependTo(document.body)
|
||||||
|
|
||||||
|
pos = $.extend({}, this.$element.offset(), {
|
||||||
|
width: this.$element[0].offsetWidth
|
||||||
|
, height: this.$element[0].offsetHeight
|
||||||
|
})
|
||||||
|
|
||||||
|
actualWidth = $tip[0].offsetWidth
|
||||||
|
actualHeight = $tip[0].offsetHeight
|
||||||
|
|
||||||
|
placement = maybeCall(this.options.placement, this, [ $tip[0], this.$element[0] ])
|
||||||
|
|
||||||
|
switch (placement) {
|
||||||
|
case 'below':
|
||||||
|
tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}
|
||||||
|
break
|
||||||
|
case 'above':
|
||||||
|
tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}
|
||||||
|
break
|
||||||
|
case 'left':
|
||||||
|
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset}
|
||||||
|
break
|
||||||
|
case 'right':
|
||||||
|
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
$tip
|
||||||
|
.css(tp)
|
||||||
|
.addClass(placement)
|
||||||
|
.addClass('in')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
, setContent: function () {
|
||||||
|
var $tip = this.tip()
|
||||||
|
$tip.find('.twipsy-inner')[this.options.html ? 'html' : 'text'](this.getTitle())
|
||||||
|
$tip[0].className = 'twipsy'
|
||||||
|
}
|
||||||
|
|
||||||
|
, hide: function() {
|
||||||
|
var that = this
|
||||||
|
, $tip = this.tip()
|
||||||
|
|
||||||
|
$tip.removeClass('in')
|
||||||
|
|
||||||
|
function removeElement () {
|
||||||
|
$tip.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
$.support.transition && this.$tip.hasClass('fade') ?
|
||||||
|
$tip.bind(transitionEnd, removeElement) :
|
||||||
|
removeElement()
|
||||||
|
}
|
||||||
|
|
||||||
|
, fixTitle: function() {
|
||||||
|
var $e = this.$element
|
||||||
|
if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
|
||||||
|
$e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
, hasContent: function () {
|
||||||
|
return this.getTitle()
|
||||||
|
}
|
||||||
|
|
||||||
|
, getTitle: function() {
|
||||||
|
var title
|
||||||
|
, $e = this.$element
|
||||||
|
, o = this.options
|
||||||
|
|
||||||
|
this.fixTitle()
|
||||||
|
|
||||||
|
if (typeof o.title == 'string') {
|
||||||
|
title = $e.attr(o.title == 'title' ? 'data-original-title' : o.title)
|
||||||
|
} else if (typeof o.title == 'function') {
|
||||||
|
title = o.title.call($e[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
title = ('' + title).replace(/(^\s*|\s*$)/, "")
|
||||||
|
|
||||||
|
return title || o.fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
, tip: function() {
|
||||||
|
return this.$tip = this.$tip || $('<div class="twipsy" />').html(this.options.template)
|
||||||
|
}
|
||||||
|
|
||||||
|
, validate: function() {
|
||||||
|
if (!this.$element[0].parentNode) {
|
||||||
|
this.hide()
|
||||||
|
this.$element = null
|
||||||
|
this.options = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
, enable: function() {
|
||||||
|
this.enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
, disable: function() {
|
||||||
|
this.enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
, toggleEnabled: function() {
|
||||||
|
this.enabled = !this.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
, toggle: function () {
|
||||||
|
this[this.tip().hasClass('in') ? 'hide' : 'show']()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TWIPSY PRIVATE METHODS
|
||||||
|
* ====================== */
|
||||||
|
|
||||||
|
function maybeCall ( thing, ctx, args ) {
|
||||||
|
return typeof thing == 'function' ? thing.apply(ctx, args) : thing
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TWIPSY PLUGIN DEFINITION
|
||||||
|
* ======================== */
|
||||||
|
|
||||||
|
$.fn.twipsy = function (options) {
|
||||||
|
$.fn.twipsy.initWith.call(this, options, Twipsy, 'twipsy')
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.twipsy.initWith = function (options, Constructor, name) {
|
||||||
|
var twipsy
|
||||||
|
, binder
|
||||||
|
, eventIn
|
||||||
|
, eventOut
|
||||||
|
|
||||||
|
if (options === true) {
|
||||||
|
return this.data(name)
|
||||||
|
} else if (typeof options == 'string') {
|
||||||
|
twipsy = this.data(name)
|
||||||
|
if (twipsy) {
|
||||||
|
twipsy[options]()
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
options = $.extend({}, $.fn[name].defaults, options)
|
||||||
|
|
||||||
|
function get(ele) {
|
||||||
|
var twipsy = $.data(ele, name)
|
||||||
|
|
||||||
|
if (!twipsy) {
|
||||||
|
twipsy = new Constructor(ele, $.fn.twipsy.elementOptions(ele, options))
|
||||||
|
$.data(ele, name, twipsy)
|
||||||
|
}
|
||||||
|
|
||||||
|
return twipsy
|
||||||
|
}
|
||||||
|
|
||||||
|
function enter() {
|
||||||
|
var twipsy = get(this)
|
||||||
|
twipsy.hoverState = 'in'
|
||||||
|
|
||||||
|
if (options.delayIn == 0) {
|
||||||
|
twipsy.show()
|
||||||
|
} else {
|
||||||
|
twipsy.fixTitle()
|
||||||
|
setTimeout(function() {
|
||||||
|
if (twipsy.hoverState == 'in') {
|
||||||
|
twipsy.show()
|
||||||
|
}
|
||||||
|
}, options.delayIn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function leave() {
|
||||||
|
var twipsy = get(this)
|
||||||
|
twipsy.hoverState = 'out'
|
||||||
|
if (options.delayOut == 0) {
|
||||||
|
twipsy.hide()
|
||||||
|
} else {
|
||||||
|
setTimeout(function() {
|
||||||
|
if (twipsy.hoverState == 'out') {
|
||||||
|
twipsy.hide()
|
||||||
|
}
|
||||||
|
}, options.delayOut)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.live) {
|
||||||
|
this.each(function() {
|
||||||
|
get(this)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.trigger != 'manual') {
|
||||||
|
binder = options.live ? 'live' : 'bind'
|
||||||
|
eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus'
|
||||||
|
eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur'
|
||||||
|
this[binder](eventIn, enter)[binder](eventOut, leave)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.twipsy.Twipsy = Twipsy
|
||||||
|
|
||||||
|
$.fn.twipsy.defaults = {
|
||||||
|
animate: true
|
||||||
|
, delayIn: 0
|
||||||
|
, delayOut: 0
|
||||||
|
, fallback: ''
|
||||||
|
, placement: 'above'
|
||||||
|
, html: false
|
||||||
|
, live: false
|
||||||
|
, offset: 0
|
||||||
|
, title: 'title'
|
||||||
|
, trigger: 'hover'
|
||||||
|
, template: '<div class="twipsy-arrow"></div><div class="twipsy-inner"></div>'
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.twipsy.rejectAttrOptions = [ 'title' ]
|
||||||
|
|
||||||
|
$.fn.twipsy.elementOptions = function(ele, options) {
|
||||||
|
var data = $(ele).data()
|
||||||
|
, rejects = $.fn.twipsy.rejectAttrOptions
|
||||||
|
, i = rejects.length
|
||||||
|
|
||||||
|
while (i--) {
|
||||||
|
delete data[rejects[i]]
|
||||||
|
}
|
||||||
|
|
||||||
|
return $.extend({}, options, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
}( window.jQuery || window.ender );
|
||||||
73
public/scripts/3rdparty/jquery.chained.js
vendored
Normal file
73
public/scripts/3rdparty/jquery.chained.js
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Chained - jQuery non AJAX(J) chained selects plugin
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2011 Mika Tuupola
|
||||||
|
*
|
||||||
|
* Licensed under the MIT license:
|
||||||
|
* http://www.opensource.org/licenses/mit-license.php
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function($) {
|
||||||
|
|
||||||
|
$.fn.chained = function(parent_selector, options) {
|
||||||
|
|
||||||
|
return this.each(function() {
|
||||||
|
|
||||||
|
/* Save this to self because this changes when scope changes. */
|
||||||
|
var self = this;
|
||||||
|
var backup = $(self).clone();
|
||||||
|
|
||||||
|
/* Handles maximum two parents now. */
|
||||||
|
$(parent_selector).each(function() {
|
||||||
|
|
||||||
|
$(this).bind("change", function() {
|
||||||
|
$(self).html(backup.html());
|
||||||
|
|
||||||
|
/* If multiple parents build classname like foo\bar. */
|
||||||
|
var selected = "";
|
||||||
|
$(parent_selector).each(function() {
|
||||||
|
selected += "\\" + $(":selected", this).val();
|
||||||
|
});
|
||||||
|
selected = selected.substr(1);
|
||||||
|
|
||||||
|
/* Also check for first parent without subclassing. */
|
||||||
|
/* TODO: This should be dynamic and check for each parent */
|
||||||
|
/* without subclassing. */
|
||||||
|
var first = $(parent_selector).first();
|
||||||
|
var selected_first = $(":selected", first).val();
|
||||||
|
|
||||||
|
$("option", self).each(function() {
|
||||||
|
/* Remove unneeded items but save the default value. */
|
||||||
|
if (!$(this).hasClass(selected) &&
|
||||||
|
!$(this).hasClass(selected_first) && $(this).val() !== "") {
|
||||||
|
$(this).remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* If we have only the default value disable select. */
|
||||||
|
if (1 == $("option", self).size() && $(self).val() === "") {
|
||||||
|
$(self).attr("disabled", "disabled");
|
||||||
|
} else {
|
||||||
|
$(self).removeAttr("disabled");
|
||||||
|
}
|
||||||
|
$(self).trigger("change");
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Force IE to see something selected on first page load, */
|
||||||
|
/* unless something is already selected */
|
||||||
|
if ( !$("option:selected", this).length ) {
|
||||||
|
$("option", this).first().attr("selected", "selected");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force updating the children. */
|
||||||
|
$(this).trigger("change");
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Alias for those who like to use more English like syntax. */
|
||||||
|
$.fn.chainedTo = $.fn.chained;
|
||||||
|
|
||||||
|
})(jQuery);
|
||||||
16
public/scripts/3rdparty/less-1.1.5.min.js
vendored
Normal file
16
public/scripts/3rdparty/less-1.1.5.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -2,4 +2,87 @@
|
|||||||
* StatusBoard main script file
|
* StatusBoard main script file
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
var sb = {
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
// Properly format any alert boxes
|
||||||
|
$('.alert-data').alert();
|
||||||
|
|
||||||
|
// Properly format any tab widgets
|
||||||
|
$('.tabs').tabs();
|
||||||
|
|
||||||
|
// Display popovers on all configured items
|
||||||
|
$("a[rel=popover]").popover({
|
||||||
|
offset: 10,
|
||||||
|
html: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
admin: {
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
$('#confirm_delete').modal({
|
||||||
|
backdrop: true,
|
||||||
|
keyboard: true
|
||||||
|
});
|
||||||
|
$('#confirm_delete_cancel').click(function() {
|
||||||
|
$('#confirm_delete').modal('hide');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteItem: function(url) {
|
||||||
|
$('#confirm_delete_do').click(function() {
|
||||||
|
sb.request.post(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#confirm_delete').modal('show');
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
usercp: {
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
$('#usercp_newpassword,#usercp_confirmpassword').bind('keyup', sb.usercp.checkPassword);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
checkPassword: function() {
|
||||||
|
password = $('#usercp_newpassword');
|
||||||
|
confirm = $('#usercp_confirmpassword');
|
||||||
|
|
||||||
|
confirm_container = confirm.parent().parent();
|
||||||
|
|
||||||
|
if (password.val() == confirm.val()) {
|
||||||
|
console.log("passwords match");
|
||||||
|
confirm_container.removeClass('error').addClass('success');
|
||||||
|
$('#usercp_confirmpassword_help').hide();
|
||||||
|
} else {
|
||||||
|
console.log("passwords do not match");
|
||||||
|
confirm_container.addClass('error').removeClass('success');
|
||||||
|
$('#usercp_confirmpassword_help').show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
request: {
|
||||||
|
|
||||||
|
post: function(url, data) {
|
||||||
|
console.log('Posting');
|
||||||
|
var form = $('<form />').attr('method', 'post').attr('action', url);
|
||||||
|
for (var key in data) {
|
||||||
|
form.appendChild($('<input type="hidden">').attr('name', key).val(data[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
$('document').ready(sb.init);
|
||||||
|
|||||||
@@ -2,19 +2,26 @@
|
|||||||
* StatusBoard normal stylesheet
|
* StatusBoard normal stylesheet
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@import url('http://twitter.github.com/bootstrap/1.4.0/bootstrap.min.css');
|
||||||
@CHARSET "UTF-8";
|
@CHARSET "UTF-8";
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0em;
|
margin: 0em;
|
||||||
|
margin-top: 60px;
|
||||||
|
padding-top: 40px;
|
||||||
padding: 0em;
|
padding: 0em;
|
||||||
font-family: verdana, helvetica, sans-serif;
|
font-family: verdana, helvetica, sans-serif;
|
||||||
|
background: #F7F7F7;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: gray;
|
color: gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.span12 a, .span11 a{
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
@@ -89,4 +96,83 @@ label {
|
|||||||
background: lightcyan;
|
background: lightcyan;
|
||||||
color: darkblue;
|
color: darkblue;
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page specific content
|
||||||
|
*/
|
||||||
|
|
||||||
|
div.service {
|
||||||
|
border-top: 1px solid grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.site {
|
||||||
|
margin-left: 5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.incident {
|
||||||
|
margin-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table{
|
||||||
|
background:#fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th, table td {
|
||||||
|
text-align: center;
|
||||||
|
line-height: 20px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
th.service {
|
||||||
|
text-align: left;
|
||||||
|
background-color: #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.odd_row {
|
||||||
|
background-color: #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.page-header{
|
||||||
|
margin:10px -5px 20px;
|
||||||
|
padding:10px 10px 0 10px;
|
||||||
|
-moz-border-radius:5px 5px 0 0;
|
||||||
|
-webkit-border-top-left-radius:5px;
|
||||||
|
-webkit-border-top-right-radius:5px;
|
||||||
|
border-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs, .pills {
|
||||||
|
margin: 0 0 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#my-tab-content{
|
||||||
|
background:#fff;
|
||||||
|
margin:-20px -5px 20px;
|
||||||
|
Padding-top:20px;
|
||||||
|
padding-left:20px;
|
||||||
|
-moz-border-radius:5px 5px 0 0;
|
||||||
|
-webkit-border-radius:5px;
|
||||||
|
border-left: 1px solid #DDD;
|
||||||
|
border-right: 1px solid #DDD;
|
||||||
|
border-bottom: 1px solid #DDD;
|
||||||
|
}
|
||||||
|
.rounded_content{
|
||||||
|
background:#fff;
|
||||||
|
margin:0 -5px 20px;
|
||||||
|
Padding-top:20px;
|
||||||
|
padding-left:20px;
|
||||||
|
-moz-border-radius:5px 5px 0 0;
|
||||||
|
-webkit-border-radius:5px;
|
||||||
|
border: 1px solid #DDD;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.help dt {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.help dd {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|||||||
195
source/lib/StatusBoard/Incident.class.php
Normal file
195
source/lib/StatusBoard/Incident.class.php
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class StatusBoard_Incident extends StatusBoard_DatabaseObject {
|
||||||
|
|
||||||
|
protected static $table = 'incident';
|
||||||
|
|
||||||
|
protected $_db_id;
|
||||||
|
protected $_db_site;
|
||||||
|
protected $_db_reference;
|
||||||
|
protected $_db_description;
|
||||||
|
protected $_db_start_time;
|
||||||
|
protected $_db_estimated_end_time;
|
||||||
|
protected $_db_actual_end_time;
|
||||||
|
|
||||||
|
protected $current_status = null;
|
||||||
|
protected $statuses = null;
|
||||||
|
|
||||||
|
public static function newForSite(StatusBoard_Site $site, $reference, $description, $status, $start_time, $estimated_end_time) {
|
||||||
|
$new_incident = new self();
|
||||||
|
$new_incident->site = $site->id;
|
||||||
|
$new_incident->reference = $reference;
|
||||||
|
$new_incident->description = $description;
|
||||||
|
$new_incident->start_time = $start_time;
|
||||||
|
$new_incident->estimated_end_time = $estimated_end_time;
|
||||||
|
$new_incident->actual_end_time = null;
|
||||||
|
|
||||||
|
$new_incident->create();
|
||||||
|
$new_incident->changeStatus($status, 'Initial Classification', $start_time);
|
||||||
|
|
||||||
|
return $new_incident;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function openForSite(StatusBoard_Site $site) {
|
||||||
|
return static::allFor('site', $site->id, 'incident_open');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function openForSiteDuring(StatusBoard_Site $site, $start, $end) {
|
||||||
|
$params = array(
|
||||||
|
array('name' => 'start', 'value' => $start, 'type' => PDO::PARAM_INT),
|
||||||
|
array('name' => 'end', 'value' => $end, 'type' => PDO::PARAM_INT),
|
||||||
|
);
|
||||||
|
|
||||||
|
return static::allFor('site', $site->id, 'incident_opentimes', '`start_time` < :end AND `ctime` > :start', $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function allNearDeadline() {
|
||||||
|
return static::all('incident_open', "estimated_end_time>=:threshold AND estimated_end_time>=:now", array(
|
||||||
|
array('name' => 'threshold', 'value' => time() - StatusBoard_DateTime::HOUR, 'type' => PDO::PARAM_INT),
|
||||||
|
array('name' => 'now', 'value' => time(), 'type' => PDO::PARAM_INT),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function allPastDeadline() {
|
||||||
|
return static::all('incident_open', "estimated_end_time<=:threshold", array(
|
||||||
|
array('name' => 'threshold', 'value' => time(), 'type' => PDO::PARAM_INT),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function currentStatus($ignore_cache = false) {
|
||||||
|
if ($this->current_status === null || $ignore_cache) {
|
||||||
|
$database = StatusBoard_Main::instance()->database();
|
||||||
|
$row = $database->selectOne('SELECT `status` FROM `incidentstatus_current` WHERE `incident`=:incident', array(
|
||||||
|
array('name' => 'incident', 'value' => $this->id, 'type' => PDO::PARAM_INT),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->current_status = $row['status'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->current_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function statusAt($time) {
|
||||||
|
$database = StatusBoard_Main::instance()->database();
|
||||||
|
$row = $database->selectOne('SELECT `status` FROM `incidentstatus` WHERE `incident`=:incident AND `ctime` < :time ORDER BY `ctime` DESC LIMIT 1', array(
|
||||||
|
array('name' => 'incident', 'value' => $this->id, 'type' => PDO::PARAM_INT),
|
||||||
|
array('name' => 'time', 'value' => $time, 'type' => PDO::PARAM_INT),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $row['status'];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function statusesBetween($start, $end) {
|
||||||
|
$database = StatusBoard_Main::instance()->database();
|
||||||
|
|
||||||
|
$row = $database->selectList('SELECT `status` FROM `incidentstatus` WHERE `incident`=:incident AND `ctime` >= :start AND `ctime` < :end', array(
|
||||||
|
array('name' => 'incident', 'value' => $this->id, 'type' => PDO::PARAM_INT),
|
||||||
|
array('name' => 'start', 'value' => $start, 'type' => PDO::PARAM_INT),
|
||||||
|
array('name' => 'end', 'value' => $end, 'type' => PDO::PARAM_INT),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return array_map(function($a) {
|
||||||
|
return $a['status'];
|
||||||
|
}, $row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status of the most severe incident in the given set
|
||||||
|
*
|
||||||
|
* @param array(StatusBoard_Incident) $incidents
|
||||||
|
*/
|
||||||
|
public static function highestSeverityStatus(array $incidents, $time = null) {
|
||||||
|
// Check for the highest severity incident.
|
||||||
|
$status = StatusBoard_Status::STATUS_Resolved;
|
||||||
|
foreach ($incidents as $incident) {
|
||||||
|
$incident_status = null;
|
||||||
|
if ($time) {
|
||||||
|
$incident_status = $incident->statusAt($time);
|
||||||
|
} else {
|
||||||
|
$incident_status = $incident->currentStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StatusBoard_Status::isMoreSevere($status, $incident_status)) {
|
||||||
|
$status = $incident_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status of the most severe incident in the given set
|
||||||
|
*
|
||||||
|
* @param array(StatusBoard_Incident) $incidents
|
||||||
|
*/
|
||||||
|
public static function highestSeverityStatusBetween(array $incidents, $start, $end) {
|
||||||
|
// Check for the highest severity incident.
|
||||||
|
$most_severe_status = StatusBoard_Status::STATUS_Resolved;
|
||||||
|
foreach ($incidents as $incident) {
|
||||||
|
$most_severe_incident_status = StatusBoard_Status::STATUS_Resolved;
|
||||||
|
|
||||||
|
$statuses_between = $incident->statusesBetween($start, $end);
|
||||||
|
foreach ($statuses_between as $status) {
|
||||||
|
$most_severe_incident_status = StatusBoard_Status::mostSevere($most_severe_incident_status, $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
$incident_status_before = StatusBoard_Status::STATUS_Resolved;
|
||||||
|
try {
|
||||||
|
$incident_status_before = $incident->statusAt($start);
|
||||||
|
} catch (SihnonFramework_Exception_ResultCountMismatch $e) {
|
||||||
|
// Incident was opened after $start, ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
$most_severe_incident_status = StatusBoard_Status::mostSevere($incident_status_before, $most_severe_incident_status);
|
||||||
|
|
||||||
|
$most_severe_status = StatusBoard_Status::mostSevere($most_severe_status, $most_severe_incident_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $most_severe_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function statusChanges($ignore_cache = false) {
|
||||||
|
if ($this->statuses === null || $ignore_cache) {
|
||||||
|
$this->statuses = StatusBoard_IncidentStatus::allFor('incident', $this->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->statuses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function changeStatus($status, $description, $start_time = null) {
|
||||||
|
if ($this->statuses === null) {
|
||||||
|
$this->statuses = StatusBoard_IncidentStatus::allFor('incident', $this->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_status = StatusBoard_IncidentStatus::newForIncident($this, $status, $description, $start_time);
|
||||||
|
$this->statuses[] = $new_status;
|
||||||
|
|
||||||
|
return $new_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function counts() {
|
||||||
|
$database = StatusBoard_Main::instance()->database();
|
||||||
|
$rows = $database->selectList('SELECT `status`, COUNT(*) AS `incident_count` FROM `incidentstatus_current` GROUP BY `status`');
|
||||||
|
|
||||||
|
$counts = array();
|
||||||
|
foreach (StatusBoard_Status::available() as $status) {
|
||||||
|
$counts[$status] = 0;
|
||||||
|
}
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$counts[$row['status']] = $row['incident_count'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function compareEstimatedEndTimes(StatusBoard_Incident $first, StatusBoard_Incident $second) {
|
||||||
|
return $first->estimated_end_time < $second->estimated_end_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
34
source/lib/StatusBoard/IncidentStatus.class.php
Normal file
34
source/lib/StatusBoard/IncidentStatus.class.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class StatusBoard_IncidentStatus extends StatusBoard_DatabaseObject {
|
||||||
|
|
||||||
|
protected static $table = 'incidentstatus';
|
||||||
|
|
||||||
|
protected $_db_id;
|
||||||
|
protected $_db_incident;
|
||||||
|
protected $_db_status;
|
||||||
|
protected $_db_description;
|
||||||
|
protected $_db_ctime;
|
||||||
|
|
||||||
|
public function allForIncident(StatusBoard_Incident $incident) {
|
||||||
|
return static::all_for('incident', $incident->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newForIncident(StatusBoard_Incident $incident, $status, $description, $ctime = null) {
|
||||||
|
if ($ctime === null) {
|
||||||
|
$ctime = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_status = new self();
|
||||||
|
$new_status->incident = $incident->id;
|
||||||
|
$new_status->status = $status;
|
||||||
|
$new_status->description = $description;
|
||||||
|
$new_status->ctime = $ctime;
|
||||||
|
|
||||||
|
$new_status->create();
|
||||||
|
|
||||||
|
return $new_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
@@ -5,6 +5,7 @@ require 'smarty/Smarty.class.php';
|
|||||||
class StatusBoard_Main extends SihnonFramework_Main {
|
class StatusBoard_Main extends SihnonFramework_Main {
|
||||||
|
|
||||||
const TEMPLATE_DIR = '../source/webui/templates/';
|
const TEMPLATE_DIR = '../source/webui/templates/';
|
||||||
|
const CODE_DIR = '../source/webui/pages/';
|
||||||
|
|
||||||
protected static $instance;
|
protected static $instance;
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ class StatusBoard_Main extends SihnonFramework_Main {
|
|||||||
|
|
||||||
$request_string = isset($_GET['l']) ? $_GET['l'] : '';
|
$request_string = isset($_GET['l']) ? $_GET['l'] : '';
|
||||||
|
|
||||||
$this->request = new StatusBoard_RequestParser($request_string, self::TEMPLATE_DIR);
|
$this->request = new StatusBoard_RequestParser($request_string, self::TEMPLATE_DIR, self::CODE_DIR);
|
||||||
|
|
||||||
switch (StatusBoard_File) {
|
switch (StatusBoard_File) {
|
||||||
case 'ajax':
|
case 'ajax':
|
||||||
@@ -31,12 +32,14 @@ class StatusBoard_Main extends SihnonFramework_Main {
|
|||||||
$this->smarty->compile_dir = static::makeAbsolutePath($smarty_tmp . '/templates');
|
$this->smarty->compile_dir = static::makeAbsolutePath($smarty_tmp . '/templates');
|
||||||
$this->smarty->cache_dir = static::makeAbsolutePath($smarty_tmp . '/cache');
|
$this->smarty->cache_dir = static::makeAbsolutePath($smarty_tmp . '/cache');
|
||||||
$this->smarty->config_dir = static::makeAbsolutePath($smarty_tmp . '/config');
|
$this->smarty->config_dir = static::makeAbsolutePath($smarty_tmp . '/config');
|
||||||
$this->smarty->plugins_dir[]= static::makeAbsolutePath('../source/webui/smarty/plugins');
|
$this->smarty->plugins_dir[]= static::makeAbsolutePath('../source/smarty/plugins');
|
||||||
|
|
||||||
$this->smarty->registerPlugin('modifier', 'formatDuration', array('StatusBoard_Main', 'formatDuration'));
|
$this->smarty->registerPlugin('modifier', 'formatDuration', array('StatusBoard_Main', 'formatDuration'));
|
||||||
$this->smarty->registerPlugin('modifier', 'formatFilesize', array('StatusBoard_Main', 'formatFilesize'));
|
$this->smarty->registerPlugin('modifier', 'formatFilesize', array('StatusBoard_Main', 'formatFilesize'));
|
||||||
|
$this->smarty->registerPlugin('modifier', 'fuzzyTime', array('StatusBoard_DateTime', 'fuzzyTime'));
|
||||||
$this->smarty->assign('version', '0.1.0');
|
|
||||||
|
$this->smarty->assign('version', '1.0.0_rc1');
|
||||||
|
$this->smarty->assign('version_codename', 'Acai');
|
||||||
$this->smarty->assign('messages', array());
|
$this->smarty->assign('messages', array());
|
||||||
|
|
||||||
$this->smarty->assign('base_uri', $this->base_uri);
|
$this->smarty->assign('base_uri', $this->base_uri);
|
||||||
|
|||||||
12
source/lib/StatusBoard/Permission.class.php
Normal file
12
source/lib/StatusBoard/Permission.class.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class StatusBoard_Permission {
|
||||||
|
|
||||||
|
const PERM_Administrator = 1;
|
||||||
|
const PERM_UpdateStatusBoards = 2;
|
||||||
|
const PERM_UpdateIncidents = 3;
|
||||||
|
const PERM_ViewStatusBoards = 4;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
44
source/lib/StatusBoard/Service.class.php
Normal file
44
source/lib/StatusBoard/Service.class.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class StatusBoard_Service extends StatusBoard_DatabaseObject {
|
||||||
|
|
||||||
|
protected static $table = 'service';
|
||||||
|
|
||||||
|
protected $_db_id;
|
||||||
|
protected $_db_name;
|
||||||
|
protected $_db_description;
|
||||||
|
|
||||||
|
protected $sites = null;
|
||||||
|
|
||||||
|
public static function newService($name, $description) {
|
||||||
|
$new_service = new self();
|
||||||
|
$new_service->name = $name;
|
||||||
|
$new_service->description = $description;
|
||||||
|
|
||||||
|
$new_service->create();
|
||||||
|
|
||||||
|
return $new_service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newSite($name, $description) {
|
||||||
|
return StatusBoard_Site::newSiteForService($this, $name, $description);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sites($ignore_cache = false) {
|
||||||
|
if ($this->sites === null || $ignore_cache) {
|
||||||
|
$this->sites = StatusBoard_Site::allForService($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->sites;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function count() {
|
||||||
|
$database = StatusBoard_Main::instance()->database();
|
||||||
|
$row = $database->selectOne('SELECT COUNT(*) AS `service_count` FROM `service`');
|
||||||
|
return $row['service_count'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
58
source/lib/StatusBoard/Site.class.php
Normal file
58
source/lib/StatusBoard/Site.class.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class StatusBoard_Site extends StatusBoard_DatabaseObject {
|
||||||
|
|
||||||
|
protected static $table = 'site';
|
||||||
|
|
||||||
|
protected $_db_id;
|
||||||
|
protected $_db_service;
|
||||||
|
protected $_db_name;
|
||||||
|
protected $_db_description;
|
||||||
|
|
||||||
|
protected $incidents = null;
|
||||||
|
protected $incidents_open = null;
|
||||||
|
|
||||||
|
public static function allForService(StatusBoard_Service $service) {
|
||||||
|
return static::allFor('service', $service->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function newSiteForService(StatusBoard_Service $service, $name, $description) {
|
||||||
|
$new_site = new self();
|
||||||
|
$new_site->service = $service->id;
|
||||||
|
$new_site->name = $name;
|
||||||
|
$new_site->description = $description;
|
||||||
|
|
||||||
|
$new_site->create();
|
||||||
|
|
||||||
|
return $new_site;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newIncident($reference, $description, $status, $start_time, $estimated_end_time) {
|
||||||
|
return StatusBoard_Incident::newForSite($this, $reference, $description, $status, $start_time, $estimated_end_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function openIncidents($ignore_cache = false) {
|
||||||
|
if ($this->incidents_open === null || $ignore_cache) {
|
||||||
|
$this->incidents_open = StatusBoard_Incident::openForSite($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->incidents_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function openIncidentsDuring($start, $end) {
|
||||||
|
return StatusBoard_Incident::openForSiteDuring($this, $start, $end);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function status() {
|
||||||
|
return StatusBoard_Incident::highestSeverityStatus($this->openIncidents());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function count() {
|
||||||
|
$database = StatusBoard_Main::instance()->database();
|
||||||
|
$row = $database->selectOne('SELECT COUNT(*) AS `site_count` FROM `site`');
|
||||||
|
return $row['site_count'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
63
source/lib/StatusBoard/Status.class.php
Normal file
63
source/lib/StatusBoard/Status.class.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class StatusBoard_Status {
|
||||||
|
|
||||||
|
const STATUS_Resolved = 0;
|
||||||
|
const STATUS_Maintenance = 1;
|
||||||
|
const STATUS_Minor = 2;
|
||||||
|
const STATUS_Significant = 3;
|
||||||
|
const STATUS_Major = 4;
|
||||||
|
|
||||||
|
protected static $names = array(
|
||||||
|
self::STATUS_Resolved => 'Resolved',
|
||||||
|
self::STATUS_Maintenance => 'Planned Maintenance',
|
||||||
|
self::STATUS_Minor => 'Minor Incident',
|
||||||
|
self::STATUS_Significant => 'Significant Incident',
|
||||||
|
self::STATUS_Major => 'Major Incident',
|
||||||
|
);
|
||||||
|
|
||||||
|
protected static $descriptions = array(
|
||||||
|
self::STATUS_Resolved => 'The service is operating normally.',
|
||||||
|
self::STATUS_Maintenance => 'The service is undergoing scheduled maintenance.',
|
||||||
|
self::STATUS_Minor => 'The service is exeriencing minor issues affecting some customers.',
|
||||||
|
self::STATUS_Significant => 'The service is exeriencing significant issues affecting many customers.',
|
||||||
|
self::STATUS_Major => 'The service is exeriencing a major outage affecting all customers.',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function available() {
|
||||||
|
return array(
|
||||||
|
self::STATUS_Resolved,
|
||||||
|
self::STATUS_Maintenance,
|
||||||
|
self::STATUS_Minor,
|
||||||
|
self::STATUS_Significant,
|
||||||
|
self::STATUS_Major,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function name($status) {
|
||||||
|
if ( ! StatusBoard_Main::isClassConstantValue(get_called_class(), 'STATUS_', $status)) {
|
||||||
|
throw new StatusBoard_Exception_InvalidParameters($status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$names[$status];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function description($status) {
|
||||||
|
if ( ! StatusBoard_Main::isClassConstantValue(get_called_class(), 'STATUS_', $status)) {
|
||||||
|
throw new StatusBoard_Exception_InvalidParameters($status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$descriptions[$status];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isMoreSevere($base, $test) {
|
||||||
|
return ($test > $base);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function mostSevere($first, $second) {
|
||||||
|
return static::isMoreSevere($first, $second) ? $second : $first;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
292
source/smarty/plugins/compiler.switch.php
Normal file
292
source/smarty/plugins/compiler.switch.php
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Switch statement plugin for smarty.
|
||||||
|
* This smarty plugin provides php switch statement functionality in smarty tags.
|
||||||
|
* To install this plugin drop it into your smarty plugins folder. You will also need to manually
|
||||||
|
* load the plugin sot hat all the hooks are registered properly. Add the following line after
|
||||||
|
* you load smarty and create an instance of it in your source code.
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* $this->smartyObj->loadPlugin('smarty_compiler_switch');
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* @author Jeremy Pyne <jeremy.pyne@gmail.com>
|
||||||
|
* - Donations: Accepted via PayPal at the above address.
|
||||||
|
* - Updated: 02/10/2010 - Version 3.2
|
||||||
|
* - File: smarty/plugins/compiler.switch.php
|
||||||
|
* - Licence: CC:BY/NC/SA http://creativecommons.org/licenses/by-nc-sa/3.0/
|
||||||
|
*
|
||||||
|
* - Updates
|
||||||
|
* Version 2:
|
||||||
|
* Changed the break attribute to cause a break to be printed before the next case, instead of before this
|
||||||
|
* case. This way makes more sense and simplifies the code. This change in incompatible with code in
|
||||||
|
* from version one. This is written to support nested switches and will work as expected.
|
||||||
|
* Version 2.1:
|
||||||
|
* Added {/case} tag, this is identical to {break}.
|
||||||
|
* Version 3:
|
||||||
|
* Updated switch statment to support Smarty 3. This update is NOT backwards compatible but the old version is still maintained.
|
||||||
|
* Version 3.1:
|
||||||
|
* Added a prefilter to re-enable the shorthand {switch $myvar} support. To use the shorthand form you will need to add the following line to your code.
|
||||||
|
* $smarty->loadPlugin('smarty_compiler_switch');
|
||||||
|
* Version 3.2:
|
||||||
|
* Fixed a bug when chaining multiple {case} statements without a {break}.
|
||||||
|
* Version 3.5:
|
||||||
|
* Updated to work with Smarty 3.0 release. (Tested and working with 3.0.5, no longer compatible with 3.0rcx releases.)
|
||||||
|
*
|
||||||
|
* - Bugs/Notes:
|
||||||
|
*
|
||||||
|
* @package Smarty
|
||||||
|
* @subpackage plugins
|
||||||
|
*
|
||||||
|
* Sample usage:
|
||||||
|
* <code>
|
||||||
|
* {foreach item=$debugItem from=$debugData}
|
||||||
|
* // Switch on $debugItem.type
|
||||||
|
* {switch $debugItem.type}
|
||||||
|
* {case 1}
|
||||||
|
* {case "invalid_field"}
|
||||||
|
* // Case checks for string and numbers.
|
||||||
|
* {/case}
|
||||||
|
* {case $postError}
|
||||||
|
* {case $getError|cat:"_ajax"|lower}
|
||||||
|
* // Case checks can also use variables and modifiers.
|
||||||
|
* {break}
|
||||||
|
* {default}
|
||||||
|
* // Default case is supported.
|
||||||
|
* {/switch}
|
||||||
|
* {/foreach}
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* Note in the above example that the break statements work exactly as expected. Also the switch and default
|
||||||
|
* tags can take the break attribute. If set they will break automatically before the next case is printed.
|
||||||
|
*
|
||||||
|
* Both blocks produce the same switch logic:
|
||||||
|
* <code>
|
||||||
|
* {case 1 break}
|
||||||
|
* Code 1
|
||||||
|
* {case 2}
|
||||||
|
* Code 2
|
||||||
|
* {default break}
|
||||||
|
* Code 3
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* {case 1}
|
||||||
|
* Code 1
|
||||||
|
* {break}
|
||||||
|
* {case 2}
|
||||||
|
* Code 2
|
||||||
|
* {default}
|
||||||
|
* Code 3
|
||||||
|
* {break}
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* Finally, there is an alternate long hand style for the switch statments that you may need to use in some cases.
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* {switch var=$type}
|
||||||
|
* {case value="box" break}
|
||||||
|
* {case value="line"}
|
||||||
|
* {break}
|
||||||
|
* {default}
|
||||||
|
* {/switch}
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Register the post and pre filters as they are not auto-registered.
|
||||||
|
$this->registerFilter('post', 'smarty_postfilter_switch');
|
||||||
|
|
||||||
|
class Smarty_Compiler_Switch extends Smarty_Internal_CompileBase {
|
||||||
|
public $required_attributes = array('var');
|
||||||
|
public $optional_attributes = array();
|
||||||
|
public $shorttag_order = array('var');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a new switch statement.
|
||||||
|
* A variable must be passed to switch on.
|
||||||
|
* Also, the switch can only directly contain {case} and {default} tags.
|
||||||
|
*
|
||||||
|
* @param string $tag_arg
|
||||||
|
* @param Smarty_Compiler $smarty
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function compile($args, $compiler){
|
||||||
|
$this->compiler = $compiler;
|
||||||
|
$attr = $this->_get_attributes($args);
|
||||||
|
$_output = '';
|
||||||
|
|
||||||
|
$this->_open_tag('switch',array($compiler->tag_nocache));
|
||||||
|
|
||||||
|
if (is_array($attr['var'])) {
|
||||||
|
$_output .= "<?php if (!isset(\$_smarty_tpl->tpl_vars[".$attr['var']['var']."])) \$_smarty_tpl->tpl_vars[".$attr['var']['var']."] = new Smarty_Variable;";
|
||||||
|
$_output .= "switch (\$_smarty_tpl->tpl_vars[".$attr['var']['var']."]->value = ".$attr['var']['value']."){?>";
|
||||||
|
} else {
|
||||||
|
$_output .= '<?php switch (' . $attr['var'] . '){?>';
|
||||||
|
}
|
||||||
|
return $_output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Smarty_Compiler_Case extends Smarty_Internal_CompileBase {
|
||||||
|
public $required_attributes = array('value');
|
||||||
|
public $optional_attributes = array('break');
|
||||||
|
public $shorttag_order = array('value', 'break');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print out a case line for this switch.
|
||||||
|
* A condition must be passed to match on.
|
||||||
|
* This can only go in {switch} tags.
|
||||||
|
* If break is passed, a {break} will be rendered before the next case.
|
||||||
|
*
|
||||||
|
* @param string $tag_arg
|
||||||
|
* @param Smarty_Compiler $smarty
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function compile($args, $compiler){
|
||||||
|
$this->compiler = $compiler;
|
||||||
|
$attr = $this->_get_attributes($args);
|
||||||
|
$_output = '';
|
||||||
|
|
||||||
|
list($last_tag, $last_attr) = $this->compiler->_tag_stack[count($this->compiler->_tag_stack) - 1];
|
||||||
|
|
||||||
|
if($last_tag == 'case')
|
||||||
|
{
|
||||||
|
list($break, $compiler->tag_nocache) = $this->_close_tag(array('case'));
|
||||||
|
if($last_attr[0])
|
||||||
|
$_output .= '<?php break;?>';
|
||||||
|
}
|
||||||
|
$this->_open_tag('case', array(isset($attr['break']) ? $attr['break'] : false, $compiler->tag_nocache));
|
||||||
|
|
||||||
|
if (is_array($attr['value'])) {
|
||||||
|
$_output .= "<?php if (!isset(\$_smarty_tpl->tpl_vars[".$attr['value']['var']."])) \$_smarty_tpl->tpl_vars[".$attr['value']['var']."] = new Smarty_Variable;";
|
||||||
|
$_output .= "case \$_smarty_tpl->tpl_vars[".$attr['value']['var']."]->value = ".$attr['value']['value'].":?>";
|
||||||
|
} else {
|
||||||
|
$_output .= '<?php case ' . $attr['value'] . ':?>';
|
||||||
|
}
|
||||||
|
return $_output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Smarty_Compiler_Default extends Smarty_Internal_CompileBase {
|
||||||
|
public $required_attributes = array();
|
||||||
|
public $optional_attributes = array('break');
|
||||||
|
public $shorttag_order = array('break');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print out a default line for this switch.
|
||||||
|
* This can only go in {switch} tags.
|
||||||
|
* If break is passed, a {break} will be rendered before the next case.
|
||||||
|
*
|
||||||
|
* @param string $tag_arg
|
||||||
|
* @param Smarty_Compiler $smarty
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function compile($args, $compiler){
|
||||||
|
$this->compiler = $compiler;
|
||||||
|
$attr = $this->_get_attributes($args);
|
||||||
|
$_output = '';
|
||||||
|
|
||||||
|
list($last_tag, $last_attr) = $this->compiler->_tag_stack[count($this->compiler->_tag_stack) - 1];
|
||||||
|
if($last_tag == 'case')
|
||||||
|
{
|
||||||
|
list($break, $compiler->tag_nocache) = $this->_close_tag(array('case'));
|
||||||
|
if($last_attr[0])
|
||||||
|
$_output .= '<?php break;?>';
|
||||||
|
}
|
||||||
|
$this->_open_tag('case', array(isset($attr['break']) ? $attr['break'] : false, $compiler->tag_nocache));
|
||||||
|
|
||||||
|
$_output .= '<?php default:?>';
|
||||||
|
|
||||||
|
return $_output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Smarty_Compiler_Break extends Smarty_Internal_CompileBase {
|
||||||
|
public $required_attributes = array();
|
||||||
|
public $optional_attributes = array();
|
||||||
|
public $shorttag_order = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print out a break command for the switch.
|
||||||
|
* This can only go inside of {case} tags.
|
||||||
|
*
|
||||||
|
* @param string $tag_arg
|
||||||
|
* @param Smarty_Compiler $smarty
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function compile($args, $compiler){
|
||||||
|
$this->compiler = $compiler;
|
||||||
|
$attr = $this->_get_attributes($args);
|
||||||
|
|
||||||
|
list($break, $compiler->tag_nocache) = $this->_close_tag(array('case'));
|
||||||
|
|
||||||
|
return '<?php break;?>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Smarty_Compiler_Caseclose extends Smarty_Internal_CompileBase {
|
||||||
|
public $required_attributes = array();
|
||||||
|
public $optional_attributes = array();
|
||||||
|
public $shorttag_order = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print out a break command for the switch.
|
||||||
|
* This can only go inside of {case} tags.
|
||||||
|
*
|
||||||
|
* @param string $tag_arg
|
||||||
|
* @param Smarty_Compiler $smarty
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function compile($args, $compiler){
|
||||||
|
$this->compiler = $compiler;
|
||||||
|
$attr = $this->_get_attributes($args);
|
||||||
|
|
||||||
|
list($break, $compiler->tag_nocache) = $this->_close_tag(array('case'));
|
||||||
|
|
||||||
|
return '<?php break;?>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Smarty_Compiler_Switchclose extends Smarty_Internal_CompileBase {
|
||||||
|
public $required_attributes = array();
|
||||||
|
public $optional_attributes = array();
|
||||||
|
public $shorttag_order = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End a switch statement.
|
||||||
|
*
|
||||||
|
* @param string $tag_arg
|
||||||
|
* @param Smarty_Compiler $smarty
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function compile($args, $compiler){
|
||||||
|
$this->compiler = $compiler;
|
||||||
|
$attr = $this->_get_attributes($args);
|
||||||
|
|
||||||
|
list($last_tag, $last_attr) = $this->compiler->_tag_stack[count($this->compiler->_tag_stack) - 1];
|
||||||
|
if(($last_tag == 'case' || $last_tag == 'default'))
|
||||||
|
list($break, $compiler->tag_nocache) = $this->_close_tag(array('case'));
|
||||||
|
list($compiler->tag_nocache) = $this->_close_tag(array('switch'));
|
||||||
|
|
||||||
|
return '<?php }?>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter the template after it is generated to fix switch bugs.
|
||||||
|
* Remove any spaces after the 'switch () {' code and before the first case. Any tabs or spaces
|
||||||
|
* for layout would cause php errors witch this reged will fix.
|
||||||
|
*
|
||||||
|
* @param string $compiled
|
||||||
|
* @param Smarty_Compiler $smarty
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function smarty_postfilter_switch($compiled, &$smarty) {
|
||||||
|
// Remove the extra spaces after the start of the switch tag and before the first case statement.
|
||||||
|
return preg_replace('/({ ?\?>)\s+(<\?php case)/', "$1\n$2", $compiled);
|
||||||
|
}
|
||||||
|
?>
|
||||||
137
source/webui/pages/admin.php
Normal file
137
source/webui/pages/admin.php
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$auth = $main->auth();
|
||||||
|
$config = $main->config();
|
||||||
|
$request = $main->request();
|
||||||
|
$session = $main->session();
|
||||||
|
|
||||||
|
if ( ! $auth->isAuthenticated() || ! $auth->hasPermission(StatusBoard_Permission::PERM_Administrator)) {
|
||||||
|
throw new StatusBoard_Exception_NotAuthorised();
|
||||||
|
}
|
||||||
|
|
||||||
|
$activity = null;
|
||||||
|
$success = true;
|
||||||
|
|
||||||
|
$destination = $request->get('tab', 'summary');
|
||||||
|
|
||||||
|
if ($request->exists('do')) {
|
||||||
|
$activity = $request->get('do');
|
||||||
|
switch ($activity) {
|
||||||
|
|
||||||
|
case 'add-service': {
|
||||||
|
$name = StatusBoard_Main::issetelse($_POST['name'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$description = StatusBoard_Main::issetelse($_POST['description'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$service = StatusBoard_Service::newService($name, $description);
|
||||||
|
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'success',
|
||||||
|
'content' => 'The service was created succesfully.',
|
||||||
|
);
|
||||||
|
} catch (StatusBoard_Exception_InvalidContent $e) {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The service was not added due to invalid parameters being passed.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'delete-service': {
|
||||||
|
$service_id = $request->get('id', 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$service = StatusBoard_Service::fromId($service_id);
|
||||||
|
$service->delete();
|
||||||
|
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'success',
|
||||||
|
'content' => 'The Service was deleted successfully.',
|
||||||
|
);
|
||||||
|
} catch (Sihnon_Exception_ResultCountMismatch $e) {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The Service was not deleted as the object requested could not be found.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'save-settings': {
|
||||||
|
$supported_settings = array(
|
||||||
|
'site_title' => 'site.title',
|
||||||
|
'debug_display_exceptions' => 'debug.display_exceptions',
|
||||||
|
'cache_base_dir' => 'cache.base_dir',
|
||||||
|
'templates_tmp_path' => 'templates.tmp_path',
|
||||||
|
);
|
||||||
|
|
||||||
|
$dirty = false;
|
||||||
|
foreach ($supported_settings as $param => $setting) {
|
||||||
|
$value = StatusBoard_Main::issetelse($_POST[$param]);
|
||||||
|
if ($value && $value != $config->get($setting)) {
|
||||||
|
$config->set($setting, $value);
|
||||||
|
$dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dirty) {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'success',
|
||||||
|
'content' => 'Settings were saved successfully.',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'warning',
|
||||||
|
'content' => 'Settings were not saved as no changes were necessary.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'warning',
|
||||||
|
'content' => "The activity '{$activity}' is not supported.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$destination = "admin/tab/{$destination}/";
|
||||||
|
|
||||||
|
$session->set('messages', $messages);
|
||||||
|
StatusBoard_Page::redirect($destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->smarty->assign('tab', $destination);
|
||||||
|
if ($destination == 'summary') {
|
||||||
|
$this->smarty->assign('service_count', StatusBoard_Service::count());
|
||||||
|
$this->smarty->assign('site_count', StatusBoard_Site::count());
|
||||||
|
$this->smarty->assign('incident_counts', StatusBoard_Incident::counts());
|
||||||
|
|
||||||
|
$incidents_near_deadline = StatusBoard_Incident::allNearDeadline();
|
||||||
|
usort($incidents_near_deadline, array('StatusBoard_Incident', 'compareEstimatedEndTimes'));
|
||||||
|
|
||||||
|
$incidents_past_deadline = StatusBoard_Incident::allPastDeadline();
|
||||||
|
usort($incidents_past_deadline, array('StatusBoard_Incident', 'compareEstimatedEndTimes'));
|
||||||
|
|
||||||
|
$this->smarty->assign('incidents_near_deadline', $incidents_near_deadline);
|
||||||
|
$this->smarty->assign('incidents_past_deadline', $incidents_past_deadline);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$services = StatusBoard_Service::all();
|
||||||
|
$this->smarty->assign('services', $services);
|
||||||
|
|
||||||
|
$users = $auth->listUsers();
|
||||||
|
$this->smarty->assign('users', $users);
|
||||||
|
|
||||||
|
// Quick Settings
|
||||||
|
$this->smarty->assign('debug_displayexceptions', $config->get('debug.display_exceptions'));
|
||||||
|
$this->smarty->assign('cache_basedir', $config->get('cache.base_dir'));
|
||||||
|
$this->smarty->assign('templates_tmppath', $config->get('templates.tmp_path'));
|
||||||
|
$this->smarty->assign('site_title', $config->get('site.title'));
|
||||||
|
$this->smarty->assign('messages', $messages);
|
||||||
|
|
||||||
|
?>
|
||||||
95
source/webui/pages/admin/add-incident.php
Normal file
95
source/webui/pages/admin/add-incident.php
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$request = $main->request();
|
||||||
|
$auth = $main->auth();
|
||||||
|
$session = $main->session();
|
||||||
|
|
||||||
|
if ( ! $auth->isAuthenticated() || ! $auth->hasPermission(StatusBoard_Permission::PERM_UpdateIncidents)) {
|
||||||
|
throw new StatusBoard_Exception_NotAuthorised();
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages = array();
|
||||||
|
|
||||||
|
if ($request->exists('do')) {
|
||||||
|
|
||||||
|
$service_id = StatusBoard_Main::issetelse($_POST['service'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$site_id = StatusBoard_Main::issetelse($_POST['site'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$reference = StatusBoard_Main::issetelse($_POST['reference'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$description = StatusBoard_Main::issetelse($_POST['description'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$status = StatusBoard_Main::issetelse($_POST['status'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$start_time = StatusBoard_Main::issetelse($_POST['starttime'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$estimated_end_time = StatusBoard_Main::issetelse($_POST['estimatedendtime'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
$incident = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
StatusBoard_Validation_Text::content(array($service_id, $site_id), StatusBoard_Validation_Text::Digit);
|
||||||
|
StatusBoard_Validation_Text::length($reference, 1, 32);
|
||||||
|
StatusBoard_Validation_Enum::validate($status, 'StatusBoard_Status', 'STATUS_');
|
||||||
|
|
||||||
|
$service = StatusBoard_Service::fromId($service_id);
|
||||||
|
$site = StatusBoard_Site::fromId($site_id);
|
||||||
|
|
||||||
|
$start_time = strtotime($start_time);
|
||||||
|
if ($start_time === null) {
|
||||||
|
throw new StatusBoard_Exception_InvalidParameters('starttime');
|
||||||
|
}
|
||||||
|
$estimated_end_time = strtotime($estimated_end_time);
|
||||||
|
if ($estimated_end_time === null) {
|
||||||
|
throw new StatusBoard_Exception_InvalidParameters('estimatedendtime');
|
||||||
|
}
|
||||||
|
|
||||||
|
$incident = $site->newIncident($reference, $description, $status, $start_time, $estimated_end_time);
|
||||||
|
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'success',
|
||||||
|
'content' => 'The incident was created succesfully.',
|
||||||
|
);
|
||||||
|
} catch (StatusBoard_Exception_ResultCountMismatch $e) {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The incident was not created because the Service or Site could not be found.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$session->set('messages', $messages);
|
||||||
|
StatusBoard_Page::redirect("admin/incident/service/{$service->id}/site/{$site->id}/id/{$incident->id}/");
|
||||||
|
}
|
||||||
|
|
||||||
|
$service_id = $request->get('service');
|
||||||
|
$site_id = $request->get('site');
|
||||||
|
|
||||||
|
$service = null;
|
||||||
|
$site = null;
|
||||||
|
|
||||||
|
$services = StatusBoard_Service::all();
|
||||||
|
try {
|
||||||
|
if ($service_id) {
|
||||||
|
$service = StatusBoard_Service::fromId($service_id);
|
||||||
|
}
|
||||||
|
if ($site_id) {
|
||||||
|
$site = StatusBoard_Site::fromId($site_id);
|
||||||
|
}
|
||||||
|
} catch (Sihnon_Exception_ResultCountMismatch $e) {
|
||||||
|
throw new StatusBoard_Exception_FileNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
$all_sites = array();
|
||||||
|
if ($service) {
|
||||||
|
$all_sites[$service->id] = $service->sites();
|
||||||
|
} else {
|
||||||
|
foreach ($services as $all_service) {
|
||||||
|
$all_sites[$all_service->id] = $all_service->sites();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$this->smarty->assign('services', $services);
|
||||||
|
$this->smarty->assign('service', $service);
|
||||||
|
$this->smarty->assign('all_sites', $all_sites);
|
||||||
|
$this->smarty->assign('site', $site);
|
||||||
|
$this->smarty->assign('messages', $messages);
|
||||||
|
|
||||||
|
?>
|
||||||
113
source/webui/pages/admin/incident.php
Normal file
113
source/webui/pages/admin/incident.php
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$request = $main->request();
|
||||||
|
$auth = $main->auth();
|
||||||
|
$session = $main->session();
|
||||||
|
|
||||||
|
if ( ! $auth->isAuthenticated() || ! $auth->hasPermission(StatusBoard_Permission::PERM_UpdateIncidents)) {
|
||||||
|
throw new StatusBoard_Exception_NotAuthorised();
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages = array();
|
||||||
|
|
||||||
|
$service_id = $request->get('service', 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$site_id = $request->get('site', 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$incident_id = $request->get('id', 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
$service = null;
|
||||||
|
$site = null;
|
||||||
|
$incident = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$service = StatusBoard_Service::fromId($service_id);
|
||||||
|
$site = StatusBoard_Site::fromId($site_id);
|
||||||
|
$incident = StatusBoard_Incident::fromId($incident_id);
|
||||||
|
} catch (Sihnon_Exception_ResultCountMismatch $e) {
|
||||||
|
throw new StatusBoard_Exception_FileNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->exists('do')) {
|
||||||
|
$activity = $request->get('do');
|
||||||
|
switch ($activity) {
|
||||||
|
|
||||||
|
case 'edit': {
|
||||||
|
$reference = StatusBoard_Main::issetelse($_POST['reference'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$description = StatusBoard_Main::issetelse($_POST['description'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$estimated_end_time = StatusBoard_Main::issetelse($_POST['estimatedendtime'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
try {
|
||||||
|
StatusBoard_Validation_Text::length($reference, 1, 32);
|
||||||
|
|
||||||
|
$estimated_end_time = strtotime($estimated_end_time);
|
||||||
|
if ($estimated_end_time) {
|
||||||
|
$incident->reference = $reference;
|
||||||
|
$incident->description = $description;
|
||||||
|
$incident->estimated_end_time = $estimated_end_time;
|
||||||
|
$incident->save();
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'success',
|
||||||
|
'content' => 'The incident was updated succesfully.',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The incident was not modified because the value entered for estimated end time was not understood.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (StatusBoard_Exception_InvalidContent $e) {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The incident was not modified due to invalid parameters being passed.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'change-status': {
|
||||||
|
$status = StatusBoard_Main::issetelse($_POST['status'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$description = StatusBoard_Main::issetelse($_POST['description'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
try {
|
||||||
|
StatusBoard_Validation_Enum::validate($status, 'StatusBoard_Status', 'STATUS_');
|
||||||
|
|
||||||
|
$incident->changeStatus($status, $description);
|
||||||
|
|
||||||
|
if ($status == StatusBoard_Status::STATUS_Resolved) {
|
||||||
|
$incident->actual_end_time = time();
|
||||||
|
$incident->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'success',
|
||||||
|
'content' => 'The incident status was changed successfully.',
|
||||||
|
);
|
||||||
|
} catch (StatusBoard_Exception_InvalidContent $e) {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The status was not modified due to invalid parameters being passed.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'warning',
|
||||||
|
'content' => "The activity '{$activity}' is not supported.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$session->set('messages', $messages);
|
||||||
|
StatusBoard_Page::redirect("admin/incident/service/{$service->id}/site/{$site->id}/id/{$incident->id}/");
|
||||||
|
}
|
||||||
|
|
||||||
|
$statuses = $incident->statusChanges();
|
||||||
|
|
||||||
|
$this->smarty->assign('service', $service);
|
||||||
|
$this->smarty->assign('site', $site);
|
||||||
|
$this->smarty->assign('incident', $incident);
|
||||||
|
$this->smarty->assign('statuses', $statuses);
|
||||||
|
$this->smarty->assign('messages', $messages);
|
||||||
|
|
||||||
|
?>
|
||||||
110
source/webui/pages/admin/service.php
Normal file
110
source/webui/pages/admin/service.php
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$request = $main->request();
|
||||||
|
$auth = $main->auth();
|
||||||
|
$session = $main->session();
|
||||||
|
|
||||||
|
if ( ! $auth->isAuthenticated() || ! $auth->hasPermission(StatusBoard_Permission::PERM_UpdateStatusBoards)) {
|
||||||
|
throw new StatusBoard_Exception_NotAuthorised();
|
||||||
|
}
|
||||||
|
|
||||||
|
$activity = null;
|
||||||
|
$messages = array();
|
||||||
|
|
||||||
|
$service_id = $request->get('id', 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$service = null;
|
||||||
|
try {
|
||||||
|
$service = StatusBoard_Service::fromId($service_id);
|
||||||
|
} catch (Sihnon_Exception_ResultCountMismatch $e) {
|
||||||
|
throw new StatusBoard_Exception_FileNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->exists('do')) {
|
||||||
|
$activity = $request->get('do');
|
||||||
|
switch ($activity) {
|
||||||
|
|
||||||
|
case 'edit': {
|
||||||
|
$name = StatusBoard_Main::issetelse($_POST['name'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$description = StatusBoard_Main::issetelse($_POST['description'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
try {
|
||||||
|
StatusBoard_Validation_Text::length($name, 1, 255);
|
||||||
|
|
||||||
|
$service->name = $name;
|
||||||
|
$service->description = $description;
|
||||||
|
$service->save();
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'success',
|
||||||
|
'content' => 'The service was updated succesfully.',
|
||||||
|
);
|
||||||
|
} catch (StatusBoard_Exception_InvalidContent $e) {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The service was not modified due to invalid parameters being passed.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'add-site': {
|
||||||
|
$name = StatusBoard_Main::issetelse($_POST['name'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$description = StatusBoard_Main::issetelse($_POST['description'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
try {
|
||||||
|
StatusBoard_Validation_Text::length($name, 1, 255);
|
||||||
|
|
||||||
|
$site = $service->newSite($name, $description);
|
||||||
|
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'success',
|
||||||
|
'content' => 'The site was created succesfully.',
|
||||||
|
);
|
||||||
|
} catch (StatusBoard_Exception_InvalidContent $e) {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The site was not added due to invalid parameters being passed.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'delete-site': {
|
||||||
|
$site_id = $request->get('site', 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$site = StatusBoard_Site::fromId($site_id);
|
||||||
|
$site->delete();
|
||||||
|
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'success',
|
||||||
|
'content' => 'The Site was deleted successfully.',
|
||||||
|
);
|
||||||
|
} catch (Sihnon_Exception_ResultCountMismatch $e) {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The Site was not deleted as the object requested could not be found.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'warning',
|
||||||
|
'content' => "The activity '{$activity}' is not supported.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$session->set('messages', $messages);
|
||||||
|
StatusBoard_Page::redirect("admin/service/id/{$service->id}/");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$sites = $service->sites();
|
||||||
|
|
||||||
|
$this->smarty->assign('service', $service);
|
||||||
|
$this->smarty->assign('sites', $sites);
|
||||||
|
$this->smarty->assign('messages', $messages);
|
||||||
|
|
||||||
|
?>
|
||||||
76
source/webui/pages/admin/site.php
Normal file
76
source/webui/pages/admin/site.php
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$request = $main->request();
|
||||||
|
$auth = $main->auth();
|
||||||
|
$session = $main->session();
|
||||||
|
|
||||||
|
if ( ! $auth->isAuthenticated() || ! $auth->hasPermission(StatusBoard_Permission::PERM_UpdateStatusBoards)) {
|
||||||
|
throw new StatusBoard_Exception_NotAuthorised();
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages = array();
|
||||||
|
|
||||||
|
$service_id = $request->get('service', 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$site_id = $request->get('id', 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
$service = null;
|
||||||
|
$site = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$service = StatusBoard_Service::fromId($service_id);
|
||||||
|
$site = StatusBoard_Site::fromId($site_id);
|
||||||
|
} catch (Sihnon_Exception_ResultCountMismatch $e) {
|
||||||
|
throw new StatusBoard_Exception_FileNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->exists('do')) {
|
||||||
|
$activity = $request->get('do');
|
||||||
|
switch ($activity) {
|
||||||
|
|
||||||
|
case 'edit': {
|
||||||
|
$name = StatusBoard_Main::issetelse($_POST['name'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$description = StatusBoard_Main::issetelse($_POST['description'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
try {
|
||||||
|
StatusBoard_Validation_Text::length($name, 1, 255);
|
||||||
|
|
||||||
|
$site->name = $name;
|
||||||
|
$site->description = $description;
|
||||||
|
$site->save();
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'success',
|
||||||
|
'content' => 'The site was updated succesfully.',
|
||||||
|
);
|
||||||
|
} catch (StatusBoard_Exception_InvalidContent $e) {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The site was not modified due to invalid parameters being passed.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'warning',
|
||||||
|
'content' => "The activity '{$activity}' is not supported.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$session->set('messages', $messages);
|
||||||
|
StatusBoard_Page::redirect("admin/site/service/{$service->id}/id/{$site->id}/");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$open_incidents = $site->openIncidents();
|
||||||
|
|
||||||
|
$this->smarty->assign('service', $service);
|
||||||
|
$this->smarty->assign('site', $site);
|
||||||
|
$this->smarty->assign('open_incidents', $open_incidents);
|
||||||
|
$this->smarty->assign('messages', $messages);
|
||||||
|
|
||||||
|
?>
|
||||||
9
source/webui/pages/errors/401.php
Normal file
9
source/webui/pages/errors/401.php
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$req = $main->request();
|
||||||
|
|
||||||
|
$this->smarty->assign('requested_page', $req->request_string());
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
||||||
9
source/webui/pages/errors/404.php
Normal file
9
source/webui/pages/errors/404.php
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$req = $main->request();
|
||||||
|
|
||||||
|
$this->smarty->assign('requested_page', $req->request_string());
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
||||||
10
source/webui/pages/errors/unhandled-exception.php
Normal file
10
source/webui/pages/errors/unhandled-exception.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$config = $main->config();
|
||||||
|
|
||||||
|
$this->smarty->assign('display_exceptions', $config->get('debug.display_exceptions'));
|
||||||
|
$this->smarty->assign('exception', $exception);
|
||||||
|
$this->smarty->assign('exception_type', get_class($exception));
|
||||||
|
|
||||||
|
?>
|
||||||
16
source/webui/pages/home.php
Normal file
16
source/webui/pages/home.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$config = $main->config();
|
||||||
|
$auth = $main->auth();
|
||||||
|
|
||||||
|
|
||||||
|
$services = StatusBoard_Service::all();
|
||||||
|
$this->smarty->assign('services', $services);
|
||||||
|
|
||||||
|
$this->smarty->assign('site_title', $config->get('site.title', 'Status Board'));
|
||||||
|
|
||||||
|
$display_admin_links = ($auth->isAuthenticated() && $auth->isAdministrator());
|
||||||
|
$this->smarty->assign('display_admin_links', $display_admin_links);
|
||||||
|
|
||||||
|
?>
|
||||||
39
source/webui/pages/incident.php
Normal file
39
source/webui/pages/incident.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
<?php
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$request = $main->request();
|
||||||
|
$auth = $main->auth();
|
||||||
|
|
||||||
|
$incident_id = $request->get('id', 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$incident = StatusBoard_Incident::fromId($incident_id);
|
||||||
|
$site_id = $incident->site;
|
||||||
|
$site = StatusBoard_Site::fromId($site_id);
|
||||||
|
$service_id = $site->service;
|
||||||
|
$service = StatusBoard_Service::fromId($service_id);
|
||||||
|
}
|
||||||
|
catch (Sihnon_Exception_ResultCountMismatch $e)
|
||||||
|
{
|
||||||
|
throw new StatusBoard_Exception_FileNotFound();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$statuses = $incident->statusChanges();
|
||||||
|
|
||||||
|
|
||||||
|
$this->smarty->assign('service', $service);
|
||||||
|
$this->smarty->assign('site', $site);
|
||||||
|
$this->smarty->assign('incident', $incident);
|
||||||
|
$this->smarty->assign('statuses', $statuses);
|
||||||
|
$this->smarty->assign('messages', $messages);
|
||||||
|
|
||||||
|
$display_admin_links = ($auth->isAuthenticated() && $auth->isAdministrator());
|
||||||
|
$this->smarty->assign('display_admin_links', $display_admin_links);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
||||||
31
source/webui/pages/login.php
Normal file
31
source/webui/pages/login.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$request = $main->request();
|
||||||
|
$auth = $main->auth();
|
||||||
|
$log = $main->log();
|
||||||
|
|
||||||
|
$authenticated = false;
|
||||||
|
$authentication_failed = false;
|
||||||
|
|
||||||
|
if ($request->exists('do')) {
|
||||||
|
$username = StatusBoard_Main::issetelse($_POST['username'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$password = StatusBoard_Main::issetelse($_POST['password'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$auth->authenticate($username, $password);
|
||||||
|
$authenticated = true;
|
||||||
|
|
||||||
|
StatusBoard_Page::redirect('home');
|
||||||
|
|
||||||
|
} catch (Sihnon_Exception_UnknownUser $e) {
|
||||||
|
$authentication_failed = true;
|
||||||
|
} catch (Sihnon_Exception_IncorrectPassword $e) {
|
||||||
|
$authentication_failed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->smarty->assign('authentication', $authenticated);
|
||||||
|
$this->smarty->assign('authentication_failed', $authentication_failed);
|
||||||
|
|
||||||
|
?>
|
||||||
8
source/webui/pages/logout.php
Normal file
8
source/webui/pages/logout.php
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$auth = StatusBoard_Main::instance()->auth();
|
||||||
|
$auth->deauthenticate();
|
||||||
|
|
||||||
|
StatusBoard_Page::redirect('home');
|
||||||
|
|
||||||
|
?>
|
||||||
15
source/webui/pages/navigation.php
Normal file
15
source/webui/pages/navigation.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$authenticated = false;
|
||||||
|
$user = null;
|
||||||
|
|
||||||
|
$auth = StatusBoard_Main::instance()->auth();
|
||||||
|
if ($auth->isAuthenticated()) {
|
||||||
|
$authenticated = true;
|
||||||
|
$user = $auth->authenticatedUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->smarty->assign('authenticated', $authenticated);
|
||||||
|
$this->smarty->assign('auth', $auth);
|
||||||
|
$this->smarty->assign('user', $user);
|
||||||
|
?>
|
||||||
32
source/webui/pages/status.php
Normal file
32
source/webui/pages/status.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$request = $main->request();
|
||||||
|
$auth = $main->auth();
|
||||||
|
|
||||||
|
$service_id = $request->get('service', 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$site_id = $request->get('id', 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
$start = $request->get('start');
|
||||||
|
$end = $request->get('end');
|
||||||
|
|
||||||
|
$service = null;
|
||||||
|
$site = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$service = StatusBoard_Service::fromId($service_id);
|
||||||
|
$site = StatusBoard_Site::fromId($site_id);
|
||||||
|
} catch (Sihnon_Exception_ResultCountMismatch $e) {
|
||||||
|
throw new StatusBoard_Exception_FileNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
$services = StatusBoard_Service::all();
|
||||||
|
|
||||||
|
$this->smarty->assign('service', $service);
|
||||||
|
$this->smarty->assign('site', $site);
|
||||||
|
$this->smarty->assign('start', $start);
|
||||||
|
$this->smarty->assign('end', $end);
|
||||||
|
|
||||||
|
$display_admin_links = ($auth->isAuthenticated() && $auth->isAdministrator());
|
||||||
|
$this->smarty->assign('display_admin_links', $display_admin_links);
|
||||||
|
|
||||||
|
?>
|
||||||
55
source/webui/pages/usercp.php
Normal file
55
source/webui/pages/usercp.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$main = StatusBoard_Main::instance();
|
||||||
|
$request = $main->request();
|
||||||
|
$auth = $main->auth();
|
||||||
|
$session = $main->session();
|
||||||
|
|
||||||
|
$activity = null;
|
||||||
|
|
||||||
|
if ($request->exists('do')) {
|
||||||
|
$activity = $request->get('do');
|
||||||
|
switch ($activity) {
|
||||||
|
|
||||||
|
case 'change-password': {
|
||||||
|
$current_password = StatusBoard_Main::issetelse($_POST['currentpassword'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$new_password = StatusBoard_Main::issetelse($_POST['newpassword'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
$confirm_password = StatusBoard_Main::issetelse($_POST['confirmpassword'], 'Sihnon_Exception_InvalidParameters');
|
||||||
|
|
||||||
|
$user = $auth->authenticatedUser();
|
||||||
|
if ($user->checkPassword($current_password)) {
|
||||||
|
if ($new_password == $confirm_password) {
|
||||||
|
$auth->changePassword($new_password);
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'success',
|
||||||
|
'content' => 'The password has been changed successfully.',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The passwords did not match.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => 'The current password was incorrect.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
$messages[] = array(
|
||||||
|
'severity' => 'error',
|
||||||
|
'content' => "The activity '{$activity}' was not recognised.",
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$session->set('messages', $messages);
|
||||||
|
StatusBoard_Page::redirect("usercp/");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->smarty->assign('activity', $activity);
|
||||||
|
$this->smarty->assign('messages', $messages);
|
||||||
|
?>
|
||||||
@@ -1 +1,232 @@
|
|||||||
TODO
|
<div class="page-header"><!-- page-header (Header containing navigation menu and title) -->
|
||||||
|
<h1>Admin Control Panel</h1>
|
||||||
|
<ul class="tabs" data-tabs="tabs">
|
||||||
|
<li {if $tab == 'summary'}class="active"{/if}><a href="#tab_summary">Summary</a></li>
|
||||||
|
<li {if $tab == 'services'}class="active"{/if}><a href="#tab_services">Services</a></li>
|
||||||
|
<li {if $tab == 'settings'}class="active"{/if}><a href="#tab_settings">Settings</a></li>
|
||||||
|
</ul>
|
||||||
|
</div><!-- /page-header -->
|
||||||
|
|
||||||
|
<div id="my-tab-content" class="tab-content"><!--tab-content(container for all main div content on page -->
|
||||||
|
<div class="tab-pane {if $tab == 'summary'}active{/if}" id="tab_summary"><!--Toggled Div to hide admin content -->
|
||||||
|
<div class="span16"><!--Admin summary content container -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3>Alerts</h3>
|
||||||
|
</div>
|
||||||
|
<div class="span11 column">
|
||||||
|
<p style="padding-top:10px">
|
||||||
|
There {StatusBoard_Formatting::pluralise(count($incidents_near_deadline), 'is', 'are')} {$incidents_near_deadline|count} {StatusBoard_Formatting::pluralise(count($incidents_near_deadline), 'incident', 'incidents')}
|
||||||
|
within 1 hour of the current estimated end time.
|
||||||
|
</p>
|
||||||
|
{if $incidents_near_deadline}
|
||||||
|
<ol>
|
||||||
|
{foreach from=$incidents_near_deadline item=incident}
|
||||||
|
<li>{$incident->reference|escape:html}</li>
|
||||||
|
{/foreach}
|
||||||
|
</ol>
|
||||||
|
{/if}
|
||||||
|
<p>
|
||||||
|
There {StatusBoard_Formatting::pluralise(count($incidents_near_deadline), 'is', 'are')} {$incidents_past_deadline|count} {StatusBoard_Formatting::pluralise(count($incidents_past_deadline), 'incident', 'incidents')}
|
||||||
|
already past the set estimated end time.
|
||||||
|
</p>
|
||||||
|
{if $incidents_past_deadline}
|
||||||
|
<ol>
|
||||||
|
{foreach from=$incidents_past_deadline item=incident}
|
||||||
|
<li>{$incident->reference|escape:html}</li>
|
||||||
|
{/foreach}
|
||||||
|
</ol>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3>Statistics</h3>
|
||||||
|
</div>
|
||||||
|
<div class="span11 column" style="padding-top:10px">
|
||||||
|
<table class="bordered-table condensed-table" >
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Statistic</th>
|
||||||
|
<th>Count</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Services</td>
|
||||||
|
<td>{$service_count}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Sites</td>
|
||||||
|
<td>{$site_count}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Incidents</td>
|
||||||
|
<td>{array_sum(array_values($incident_counts))}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th>Incident Statistics</th>
|
||||||
|
<th>Count</th>
|
||||||
|
</tr>
|
||||||
|
<td>Major</td>
|
||||||
|
<td>{$incident_counts[StatusBoard_Status::STATUS_Major]}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Significant</td>
|
||||||
|
<td>{$incident_counts[StatusBoard_Status::STATUS_Significant]}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Minor</td>
|
||||||
|
<td>{$incident_counts[StatusBoard_Status::STATUS_Minor]}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Planned Maintenance</td>
|
||||||
|
<td>{$incident_counts[StatusBoard_Status::STATUS_Maintenance]}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Resolved</td>
|
||||||
|
<td>{$incident_counts[StatusBoard_Status::STATUS_Resolved]}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/Admin summary content container -->
|
||||||
|
</div><!--/Toggled Div to hide admin content -->
|
||||||
|
|
||||||
|
<div class="tab-pane {if $tab == 'services'}active{/if}" id="tab_services"><!--Toggled Div to hide services content -->
|
||||||
|
<div class="span16"><!--Services content container -->
|
||||||
|
<h1>Services</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3>Current Services</h3>
|
||||||
|
<p>Click on a Service to edit its properties, or access any of the sites defined under it.</p>
|
||||||
|
</div>
|
||||||
|
<div class="span11 column">
|
||||||
|
{if $services}
|
||||||
|
<table class="bordered-table"><!--Services table -->
|
||||||
|
<thead>
|
||||||
|
<th>Service</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{foreach from=$services item=service}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{$base_uri}admin/service/id/{$service->id}/" title="Edit site {$service->name|escape:html}">{$service->name|escape:html}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{$service->description|escape:html}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class='btn small primary' onclick="document.location.href='{$base_uri}admin/service/id/{$service->id}/';return false;">Edit Service</button>
|
||||||
|
<button class='btn small danger' onclick="sb.admin.deleteItem('{$base_uri}admin/tab/services/do/delete-service/id/{$service->id}/');">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table><!--/Services table -->
|
||||||
|
{else}
|
||||||
|
You haven't created any services yet. Create some with the button below.
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div id="confirm_delete" class="modal hide fade">
|
||||||
|
<div class="modal-header">
|
||||||
|
Confirm deletion
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
This action cannot be reversed and all dependent sites and incidents will also be removed.
|
||||||
|
Are you sure you wish to delete this Service?
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn secondary" id="confirm_delete_cancel">Cancel</button>
|
||||||
|
<button class="btn danger" id="confirm_delete_do">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/Row for Existing Service-->
|
||||||
|
<div class="row"><!--Row for New Service-->
|
||||||
|
<div class="span4 column"><!--New Service description-->
|
||||||
|
<h3> New Service</h3>
|
||||||
|
<p>Use this form to define a new service</p>
|
||||||
|
</div><!--/New Service description-->
|
||||||
|
<div class="span11 column"><!--Add New Service -->
|
||||||
|
<form id="admin_addservice" method="post" action="{$base_uri}admin/tab/services/do/add-service/">
|
||||||
|
<fieldset>
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_service_add_name" style="width:85px">Name</label>
|
||||||
|
<div class="text">
|
||||||
|
<input class="xlarge span5" id="admin_service_add_name" name="name" type="text" value="" />
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_service_add_description" style="width:85px">Description</label>
|
||||||
|
<div class="text">
|
||||||
|
<textarea class="xlarge" id="admin_service_add_description" rows="3" name="description"></textarea>
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="input">
|
||||||
|
<input type="submit" class="btn success" name="addservice" value="Add Service" />
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div><!--/Add New Service -->
|
||||||
|
</div><!--/Row for New Service-->
|
||||||
|
</div><!--Toggled Div to hide services content -->
|
||||||
|
</div><!--/Toggled Div to hide services content -->
|
||||||
|
|
||||||
|
<div class="tab-pane {if $tab == 'settings'}active{/if}" id="tab_settings">
|
||||||
|
<div class="span11"><!--Settings content container -->
|
||||||
|
<h1>Settings<h1>
|
||||||
|
|
||||||
|
<form id="admin_quicksettings" method="post" action="{$base_uri}admin/tab/settings/do/save-settings/">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Quick Settings</legend>
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_quicksettings_site_title">Site Title</label>
|
||||||
|
<div class="checkbox">
|
||||||
|
<input class="xlarge span5" id="admin_quicksettings_site_title" name="site_title" type="text" value="{$site_title|escape:html}" />
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_quicksettings_debug_displayexceptions">Display Exceptions?</label>
|
||||||
|
<div class="checkbox">
|
||||||
|
<input class="" id="admin_quicksettings_debug_displayexceptions" name="debug_displayexceptions" type="checkbox" value="1" {if $debug_displayexceptions}checked="checked" {/if}/>
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_quicksettings_cache_basedir">Cache Base Directory</label>
|
||||||
|
<div class="text">
|
||||||
|
<input class="xlarge span5" id="admin_quicksettings_cache_basedir" name="cache_base_dir" type="text" value="{$cache_basedir|escape:html}" />
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_quicksettings_templates_tmppath">Templates Temporary Path</label>
|
||||||
|
<div class="text">
|
||||||
|
<input class="xlarge span5" id="admin_quicksettings_templates_tmppath" name="templates_tmp_path" type="text" value="{$templates_tmppath|escape:html}" />
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="input">
|
||||||
|
<div class="clearfix">
|
||||||
|
<input type="submit" class="btn primary" value="Save"> <button type="reset" class="btn">Cancel</button>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
</div><!-- /input -->
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div><!--/span11 -->
|
||||||
|
</div><!--/tab -->
|
||||||
|
</div><!--/tab-content(container for all main div content on page -->
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
sb.admin.init();
|
||||||
|
</script>
|
||||||
107
source/webui/templates/admin/add-incident.tpl
Normal file
107
source/webui/templates/admin/add-incident.tpl
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<div class="container">
|
||||||
|
<div class="rounded_content">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span5 column">
|
||||||
|
<h3>Add Incident</h3>
|
||||||
|
<p>Use this form to add a new incident</p>
|
||||||
|
</div><!--/New Service description-->
|
||||||
|
<div class="span10 column">
|
||||||
|
|
||||||
|
<form id="admin_addsite" method="post" action="{$base_uri}admin/add-incident/do/">
|
||||||
|
<fieldset>
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_add_service">Service</label>
|
||||||
|
<div class="text">
|
||||||
|
{if $service}
|
||||||
|
<input type="hidden" name="service" value="{$service->id}" />
|
||||||
|
{$service->name|escape:html}
|
||||||
|
{else}
|
||||||
|
<select class="xlarge span5" id="admin_incident_add_service" name="service">
|
||||||
|
{foreach from=$services item=form_service}
|
||||||
|
<option value="{$form_service->id}">{$form_service->name|escape:html}</option>
|
||||||
|
{/foreach}
|
||||||
|
</select>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_add_site">Site</label>
|
||||||
|
<div class="text">
|
||||||
|
{if $service && $site}
|
||||||
|
<input type="hidden" name="site" value="{$site->id}" />
|
||||||
|
{$site->name|escape:html}
|
||||||
|
{else}
|
||||||
|
<select class="xlarge span5" id="admin_incident_add_site" name="site">
|
||||||
|
{if $service}
|
||||||
|
{foreach from=$all_sites[$service->id] item=form_site}
|
||||||
|
<option value="{$form_site->id}">{$form_site->name|escape:html}</option>
|
||||||
|
{/foreach}
|
||||||
|
{else}
|
||||||
|
{foreach from=$services item=all_service}
|
||||||
|
{foreach from=$all_sites[$all_service->id] item=form_site}
|
||||||
|
<option class="{$all_service->id}" value="{$form_site->id}">{$form_site->name|escape:html}</option>
|
||||||
|
{/foreach}
|
||||||
|
{/foreach}
|
||||||
|
{/if}
|
||||||
|
</select>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_add_reference">Reference</label>
|
||||||
|
<div class="text">
|
||||||
|
<input class="xlarge span5" id="admin_incident_add_reference" name="reference" type="text" value="" />
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_add_description">Description</label>
|
||||||
|
<div class="text">
|
||||||
|
<textarea class="xlarge" id="admin_incident_add_description" name="description"></textarea>
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_add_status">Initial Classification</label>
|
||||||
|
<div class="select">
|
||||||
|
<select class="xlarge span5" id="admin_incident_add_status" name="status">
|
||||||
|
{foreach from=StatusBoard_Status::available() item=status}
|
||||||
|
{if $status != StatusBoard_Status::STATUS_Resolved}
|
||||||
|
<option value="{$status}">{StatusBoard_Status::name($status)}</option>
|
||||||
|
{/if}
|
||||||
|
{/foreach}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_add_starttime">Start Time</label>
|
||||||
|
<div class="text">
|
||||||
|
<input class="xlarge span5" id="admin_incident_add_starttime" name="starttime" type="text" value="Now" />
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_add_estimatedendtime">Estimated End Time</label>
|
||||||
|
<div class="text">
|
||||||
|
<input class="xlarge span5" id="admin_incident_add_estimatedendtime" name="estimatedendtime" type="text" value="+4 hours" />
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="input">
|
||||||
|
<input type="submit" class="btn small primary" name="addincident" value="Add Incident" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div><!--/Row for New Service-->
|
||||||
|
</div>
|
||||||
|
</div><!-- /container -->
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$('#admin_incident_add_site').chainedTo('#admin_incident_add_service');
|
||||||
|
</script>
|
||||||
116
source/webui/templates/admin/incident.tpl
Normal file
116
source/webui/templates/admin/incident.tpl
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<ul class="breadcrumb">
|
||||||
|
<li><a href="{$base_uri}admin/">Admin</a> <span class="divider">|</span></li>
|
||||||
|
<li><a href="{$base_uri}admin/service/id/{$service->id}/">Service {$service->name|escape:html}</a></li> <span class="divider">|</span></li>
|
||||||
|
<li><a href="{$base_uri}admin/site/service/{$service->id}/id/{$site->id}/">Site {$site->name|escape:html}</a></li> <span class="divider">|</span></li>
|
||||||
|
<li class="active"><a href="#">Incident {$incident->reference|escape:html}</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span16">
|
||||||
|
<h2>Incident {$incident->reference|escape:html}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="rounded_content">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column"><!--New description-->
|
||||||
|
<h3>Edit Incident</h3>
|
||||||
|
<p>Use this form to update the existing Service</p>
|
||||||
|
</div>
|
||||||
|
<div class="span11 column">
|
||||||
|
<form id="admin_incident_edit" method="post" action="{$base_uri}admin/incident/service/{$service->id}/site/{$site->id}/id/{$incident->id}/do/edit/">
|
||||||
|
<fieldset>
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_edit_name">Reference</label>
|
||||||
|
<div class="text">
|
||||||
|
<input class="xlarge span5" id="admin_incident_edit_name" name="reference" type="text" value="{$incident->reference|escape:html}" />
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_edit_description">Description</label>
|
||||||
|
<div class="text">
|
||||||
|
<textarea class="xlarge" id="admin_incident_edit_description" name="description">{$incident->description|escape:html}</textarea>
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_edit_estimatedendtime">Estimated End Time</label>
|
||||||
|
<div class="text">
|
||||||
|
<input class="xlarge span5" id="admin_incident_edit_estimatedendtime" name="estimatedendtime" type="text" value="{$incident->estimated_end_time|date_format:"r"}" />
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="input">
|
||||||
|
<div class="clearfix">
|
||||||
|
<input type="submit" class="btn primary" value="Edit Incident"> <button type="reset" class="btn">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3>Change Status</h3>
|
||||||
|
<p>Use this form to update the current status of an incident</p>
|
||||||
|
</div><!--/New Service description-->
|
||||||
|
<div class="span11 column">
|
||||||
|
<form id="admin_incident_changestatus" method="post" action="{$base_uri}admin/incident/service/{$service->id}/site/{$site->id}/id/{$incident->id}/do/change-status/">
|
||||||
|
<fieldset>
|
||||||
|
<p>Use this form to update the current status of an incident</p>
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_changestatus_status">New Status</label>
|
||||||
|
<div class="select">
|
||||||
|
<select class="xlarge span5" id="admin_incident_changestatus_status" name="status">
|
||||||
|
{foreach from=StatusBoard_Status::available() item=status}
|
||||||
|
<option value="{$status}">{StatusBoard_Status::name($status)}</option>
|
||||||
|
{/foreach}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_incident_changestatus_description">Description</label>
|
||||||
|
<div class="text">
|
||||||
|
<textarea class="xlarge" id="admin_incident_changestatus_description" name="description"></textarea>
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="input">
|
||||||
|
<div class="clearfix">
|
||||||
|
<input type="submit" class="btn primary" value="Change Status"> <button type="reset" class="btn">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div><!-- /span16 -->
|
||||||
|
</div><!-- /row -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3>Status Changes</h3>
|
||||||
|
<p>The table display an audit log of changes to this incident</p>
|
||||||
|
</div><!--/New Service description-->
|
||||||
|
<div class="span11 column">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<th>Date/Time</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{foreach from=$statuses item=status}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{StatusBoard_DateTime::fuzzyTime($status->ctime)}<br />
|
||||||
|
<em>{$status->ctime|date_format:'y-m-d H:i:s'}</em>
|
||||||
|
</td>
|
||||||
|
<td>{StatusBoard_Status::name($status->status)}</td>
|
||||||
|
<td>{$status->description|escape:html}</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
130
source/webui/templates/admin/service.tpl
Normal file
130
source/webui/templates/admin/service.tpl
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<ul class="breadcrumb">
|
||||||
|
<li><a href="{$base_uri}admin/">Admin</a> <span class="divider">|</span></li>
|
||||||
|
<li class="active"><a href="#">Service {$service->name|escape:html}</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span16"><!--name content container -->
|
||||||
|
<h1>Service {$service->name|escape:html}</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="rounded_content">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column"><!--New description-->
|
||||||
|
<h3>Edit Service</h3>
|
||||||
|
<p>Use this form to update the existing Service</p>
|
||||||
|
</div><!--/New Service description-->
|
||||||
|
<div class="span11 column"><!--Add New Service -->
|
||||||
|
<form id="admin_service_edit" method="post" action="{$base_uri}admin/service/id/{$service->id}/do/edit/">
|
||||||
|
<fieldset>
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_service_edit_name" style="width:87px">Name</label>
|
||||||
|
<div class="text">
|
||||||
|
<input class="xlarge span5" id="admin_service_edit_name" name="name" type="text" value="{$service->name|escape:html}" />
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_service_edit_description" style="width:87px">Description</label>
|
||||||
|
<div class="text">
|
||||||
|
<textarea class="xlarge" id="admin_service_add_description" rows="3" name="description" >{$service->description|escape:html}</textarea>
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="input">
|
||||||
|
<input type="submit" class="btn small primary" value="Save Changes"> <button class="btn small" type="reset" class="btn">Cancel</button>
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div><!--/Add New Service -->
|
||||||
|
</div><!--/Row for New Service-->
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3>Existing Sites</h3>
|
||||||
|
<p>Currently the following sites that are defined for the service {$service->name|escape:html}, Edit the site or delete it from the service here, to add a new one use the form below</p>
|
||||||
|
</div>
|
||||||
|
<div class="span11 column">
|
||||||
|
{if $sites}
|
||||||
|
<table class="bordered-table" name="sites_list_table"><!--Services table -->
|
||||||
|
<thead>
|
||||||
|
<th>Site</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{foreach from=$sites item=site}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{$base_uri}admin/site/service/{$service->id}/id/{$site->id}/" title="Edit site {$site->name|escape:html}">{$site->name|escape:html}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{$site->description|escape:html}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class='btn small primary' onclick="document.location.href='{$base_uri}admin/site/service/{$service->id}/id/{$site->id}/';return false;">Edit Site</button>
|
||||||
|
<button style="margin-left:10px" class='btn small danger' onclick="sb.admin.deleteItem('{$base_uri}admin/service/do/delete-site/id/{$service->id}/site/{$site->id}/');">Delete Site</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table><!--/name table -->
|
||||||
|
{else}
|
||||||
|
You haven't created any sites for this service yet. Create some with the button below.
|
||||||
|
{/if}
|
||||||
|
<div id="confirm_delete" class="modal hide fade">
|
||||||
|
<div class="modal-header">
|
||||||
|
Confirm deletion
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
This action cannot be reversed and all dependent incidents will also be removed.
|
||||||
|
Are you sure you wish to delete this Site?
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn secondary" id="confirm_delete_cancel">Cancel</button>
|
||||||
|
<button class="btn danger" id="confirm_delete_do">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/Row for Existing Service-->
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3>Add Site</h3>
|
||||||
|
<p>Use this form to define a new site to the service {$service->name|escape:html}</p>
|
||||||
|
</div><!--/New Service description-->
|
||||||
|
<div class="span11 column">
|
||||||
|
<form id="admin_addsite" method="post" action="{$base_uri}admin/service/id/{$service->id}/do/add-site/">
|
||||||
|
<fieldset>
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_site_add_name" style="width:85px">Name</label>
|
||||||
|
<div class="text">
|
||||||
|
<input class="xlarge span5" id="admin_site_add_name" name="name" type="text" />
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_site_edit_description" style="width:85px">Description</label>
|
||||||
|
<div class="text">
|
||||||
|
<textarea class="xlarge" id="admin_site_add_description" rows="3" name="description" ></textarea>
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="input">
|
||||||
|
<input type="submit" class="btn success" value="Add Site"> <button type="reset" class="btn">Cancel</button>
|
||||||
|
</div><!-- /text -->
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div><!--/Row for New Service-->
|
||||||
|
</div>
|
||||||
|
</div><!-- /container -->
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
sb.admin.init();
|
||||||
|
</script>
|
||||||
97
source/webui/templates/admin/site.tpl
Normal file
97
source/webui/templates/admin/site.tpl
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
<ul class="breadcrumb">
|
||||||
|
<li><a href="{$base_uri}admin/">Admin</a> <span class="divider">|</span></li>
|
||||||
|
<li><a href="{$base_uri}admin/service/id/{$service->id}/">Service {$service->name|escape:html}</a></li> <span class="divider">|</span></li>
|
||||||
|
<li class="active"><a href="#">Site {$site->name|escape:html}</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span16">
|
||||||
|
<h2>Site: {$site->name|escape:html} - Service: {$service->name|escape:html}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="rounded_content">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column"><!--New description-->
|
||||||
|
<h3>Edit Service</h3>
|
||||||
|
<p>Use this form to update the existing Service</p>
|
||||||
|
</div>
|
||||||
|
<div class="span11 column">
|
||||||
|
<form id="admin_site_edit" method="post" action="{$base_uri}admin/site/service/{$service->id}/id/{$site->id}/do/edit/">
|
||||||
|
<fieldset>
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_site_edit_name">Name</label>
|
||||||
|
<div class="text">
|
||||||
|
<input class="xlarge span5" id="admin_site_edit_name" name="name" type="text" value="{$site->name|escape:html}" />
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="admin_site_edit_description">Description</label>
|
||||||
|
<div class="text">
|
||||||
|
<textarea class="xlarge" id="admin_site_edit_description" name="description">{$site->description|escape:html}</textarea>
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="input">
|
||||||
|
<div class="clearfix">
|
||||||
|
<input type="submit" class="btn small primary" value="Save Changes"> <button type="reset" class="btn small">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3>Open Incidents</h3>
|
||||||
|
</div><!--/New Service description-->
|
||||||
|
<div class="span11 column">
|
||||||
|
{if $open_incidents}
|
||||||
|
<table class="bordered-table" name="sites_list_table"><!--Services table -->
|
||||||
|
<thead>
|
||||||
|
<th>Reference</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{foreach from=$open_incidents item=incident}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{$base_uri}admin/incident/service/{$service->id}/site/{$site->id}/id/{$incident->id}/" title="Edit Incident {$incident->reference|escape:htmll}">{$incident->reference|escape:html}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{$site->description|escape:html}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{StatusBoard_Status::name($incident->currentStatus())}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class='btn small primary' onclick="document.location.href='{$base_uri}admin/incident/service/{$service->id}/site/{$site->id}/id/{$incident->id}/';return false;">Edit</button>
|
||||||
|
<button style="margin-left:10px" class='btn small danger' onclick="sb.admin.deleteItem('{$base_uri}admin/incident/service/{$service->id}/site/{$site->id}/id/{$incident->id}//');">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table><!--/name table -->
|
||||||
|
{else}
|
||||||
|
<p style="padding-top:10px;">There are no open incidents for this site . If you need to open one, use the form below.</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div><!--/Row for Existing Service-->
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3>Add Incident</h3>
|
||||||
|
<p>
|
||||||
|
Click the button to open the Add Incident page.
|
||||||
|
</p>
|
||||||
|
</div><!--/New Service description-->
|
||||||
|
|
||||||
|
<div class="span11 column">
|
||||||
|
<button class="btn small primary" onclick="location.href='{$base_uri}admin/add-incident/service/{$service->id}/site/{$site->id}/'">Add Incident</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!-- /container -->
|
||||||
5
source/webui/templates/errors/401.tpl
Normal file
5
source/webui/templates/errors/401.tpl
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<h2>This page is not accessible.</h2>
|
||||||
|
<p>
|
||||||
|
The page you requested ({$requested_page|escape:html}) could not be opened.
|
||||||
|
Please ensure you are logged in and have permission to access this page.
|
||||||
|
</p>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<h2>The requested page could not be found</h2>
|
<h2>The requested page could not be found</h2>
|
||||||
<p>
|
<p>
|
||||||
The file you requested ({$requested_page}) could not be found.
|
The file you requested ({$requested_page|escape:html}) could not be found.
|
||||||
If you typed in the address manually, check that you have spelled it correctly,
|
If you typed in the address manually, check that you have spelled it correctly,
|
||||||
or if you followed a link, let us know and we'll look into it.
|
or if you followed a link, let us know and we'll look into it.
|
||||||
</p>
|
</p>
|
||||||
@@ -7,40 +7,56 @@
|
|||||||
<p>
|
<p>
|
||||||
An unhandled exception was caught during the page template processing. The full details are shown below:
|
An unhandled exception was caught during the page template processing. The full details are shown below:
|
||||||
</p>
|
</p>
|
||||||
<table class="exception-details">
|
<div class="container">
|
||||||
<colgroup id="header">
|
<div class="row">
|
||||||
<col />
|
<div class="span4 column">
|
||||||
</colgroup>
|
<h2>Exception</h2>
|
||||||
<colgroup>
|
</div>
|
||||||
<col />
|
<div class="span11 column">
|
||||||
</colgroup>
|
{$exception_type|escape:html}
|
||||||
<tbody>
|
</div>
|
||||||
<tr>
|
</div>
|
||||||
<th>Exception</th>
|
|
||||||
<td>{$exception_type}</td>
|
<div class="row">
|
||||||
</tr>
|
<div class="span4 column">
|
||||||
<tr>
|
<h2>File</h2>
|
||||||
<th>File</th>
|
</div>
|
||||||
<td>{$exception->getFile()}</td>
|
<div class="span11 column">
|
||||||
</tr>
|
{$exception->getFile()|escape:html}
|
||||||
<tr>
|
</div>
|
||||||
<th>Line</th>
|
</div>
|
||||||
<td>{$exception->getLine()}</td>
|
|
||||||
</tr>
|
<div class="row">
|
||||||
<tr>
|
<div class="span4 column">
|
||||||
<th>Message</th>
|
<h2>Line</h2>
|
||||||
<td>{$exception->getMessage()}</td>
|
</div>
|
||||||
</tr>
|
<div class="span11 column">
|
||||||
<tr>
|
{$exception->getLine()}
|
||||||
<th>Stack Trace</th>
|
</div>
|
||||||
<td><pre>{$exception->getTrace()|print_r}</pre></td>
|
</div>
|
||||||
</tr>
|
|
||||||
</tbody>
|
<div class="row">
|
||||||
</table>
|
<div class="span4 column">
|
||||||
|
<h2>Message</h2>
|
||||||
|
</div>
|
||||||
|
<div class="span11 column">
|
||||||
|
{$exception->getMessage()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h2>Stack Trace</h2>
|
||||||
|
</div>
|
||||||
|
<div class="span11 column">
|
||||||
|
{$exception->getTrace()|var_dump}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<em>Note:</em> Exception details should not be displayed on production systems.
|
<em>Note:</em> Exception details should not be displayed on production systems.
|
||||||
Disable the <a href="{$base_uri}admin/settings/key/debug.show_exceptions/"><code>debug.show_exceptions</code></a>
|
Disable the <a href="{$base_uri}admin/tab/settings/"><code>Display Exceptions</code></a>
|
||||||
setting to omit the exception details from this page.
|
setting to omit the exception details from this page.
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
12
source/webui/templates/fragments/icon-help.tpl
Normal file
12
source/webui/templates/fragments/icon-help.tpl
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{$statuses=StatusBoard_Status::available()}
|
||||||
|
<dl class="help">
|
||||||
|
{foreach from=$statuses item=status}
|
||||||
|
<dt>
|
||||||
|
{include file="fragments/image-status-icon.tpl"}
|
||||||
|
<strong>{StatusBoard_Status::name($status)}</strong>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
{StatusBoard_Status::description($status)}
|
||||||
|
</dd>
|
||||||
|
{/foreach}
|
||||||
|
</dl>
|
||||||
18
source/webui/templates/fragments/image-status-icon.tpl
Normal file
18
source/webui/templates/fragments/image-status-icon.tpl
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{switch $status}
|
||||||
|
{case StatusBoard_Status::STATUS_Resolved}
|
||||||
|
{assign var=img_src value="{$base_uri}images/Status_Icons/tick-circle.png"}
|
||||||
|
{/case}
|
||||||
|
{case StatusBoard_Status::STATUS_Maintenance}
|
||||||
|
{assign var=img_src value="{$base_uri}images/Status_Icons/traffic-cone.png"}
|
||||||
|
{/case}
|
||||||
|
{case StatusBoard_Status::STATUS_Minor}
|
||||||
|
{assign var=img_src value="{$base_uri}images/Status_Icons/exclamation.png"}
|
||||||
|
{/case}
|
||||||
|
{case StatusBoard_Status::STATUS_Significant}
|
||||||
|
{assign var=img_src value="{$base_uri}images/Status_Icons/exclamation.png"}
|
||||||
|
{/case}
|
||||||
|
{case StatusBoard_Status::STATUS_Major}
|
||||||
|
{assign var=img_src value="{$base_uri}images/Status_Icons/cross-circle.png"}
|
||||||
|
{/case}
|
||||||
|
{/switch}
|
||||||
|
<img src="{$img_src}" alt="{StatusBoard_Status::name($status)}" />
|
||||||
10
source/webui/templates/fragments/site-status-details.tpl
Normal file
10
source/webui/templates/fragments/site-status-details.tpl
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{StatusBoard_Status::description($status)|escape:html}
|
||||||
|
|
||||||
|
{if $incidents}
|
||||||
|
<dl>
|
||||||
|
{foreach from=$incidents item=incident}
|
||||||
|
<dt>{$incident->reference|escape:html} <em>({StatusBoard_Status::name($incident->currentStatus())})</em></dt>
|
||||||
|
<dd>{$incident->description|truncate|escape:html}</dd>
|
||||||
|
{/foreach}
|
||||||
|
</dl>
|
||||||
|
{/if}
|
||||||
3
source/webui/templates/fragments/site-status.tpl
Normal file
3
source/webui/templates/fragments/site-status.tpl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<a href="{$base_uri}status/service/{$service->id}/id/{$site->id}/{if $date}#{$date}{/if}" class="" rel="popover" data-content="{include file="fragments/site-status-details.tpl"}" data-original-title="{StatusBoard_Status::name($status)|escape:html}">
|
||||||
|
{include file="fragments/image-status-icon.tpl"}
|
||||||
|
</a>
|
||||||
@@ -1 +1,66 @@
|
|||||||
TODO
|
<div id="statusboard">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span14">
|
||||||
|
<h2>{$site_title}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="span2">
|
||||||
|
{if $display_admin_links}<a href="{$base_uri}admin/add-incident/" class="btn small">Add Incident</a>{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="bordered-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="200px">Service / Site</th>
|
||||||
|
<th class="status" width="50px">Now</th>
|
||||||
|
{foreach from=array(0,1,2,3,4,5,6) item=day}
|
||||||
|
{if $day == 0}
|
||||||
|
<th class="status" width="50px">Today</th>
|
||||||
|
{else}
|
||||||
|
<th class="status" width="50px">{mktime(0,0,0,date("n"),date("j")-$day)|date_format:"M j"}</th>
|
||||||
|
{/if}
|
||||||
|
{/foreach}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{foreach from=$services item=service}
|
||||||
|
<tr>
|
||||||
|
<th colspan="9" class="service">
|
||||||
|
{if $display_admin_links}
|
||||||
|
<a href="{$base_uri}admin/service/id/{$service->id}/" title="Edit {$service->name}">{$service->name}</a>
|
||||||
|
{else}
|
||||||
|
{$service->name}
|
||||||
|
{/if}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
{foreach from=$service->sites() item=site}
|
||||||
|
{$incidents=$site->openIncidents()}
|
||||||
|
<tr class="site">
|
||||||
|
<td>
|
||||||
|
{if $display_admin_links}
|
||||||
|
<a href="{$base_uri}admin/site/service/{$service->id}/id/{$site->id}/" title="Edit {$site->name|escape:html}">{$site->name|escape:html}</a>
|
||||||
|
{else}
|
||||||
|
{$site->name}
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{$status=$site->status()}
|
||||||
|
{include file="fragments/site-status.tpl" nocache date=null start=null end=null}
|
||||||
|
</td>
|
||||||
|
{foreach from=array(0,1,2,3,4,5,6) item=day}
|
||||||
|
{$start=mktime(0,0,0,date("n"),date("j")-$day)}
|
||||||
|
{$end=mktime(0,0,0,date("n"),date("j")-$day+1)}
|
||||||
|
{$date=mktime(0,0,0,date("n"),date("j")-$day)|date_format:"jM"}
|
||||||
|
{$incidentsDuring=$site->openIncidentsDuring($start, $end)}
|
||||||
|
{$statusDuring=StatusBoard_Incident::highestSeverityStatusBetween($incidentsDuring, $start, $end)}
|
||||||
|
<td>
|
||||||
|
{include file="fragments/site-status.tpl" nocache start=$start end=$end status=$statusDuring incidents=$incidentsDuring}
|
||||||
|
</td>
|
||||||
|
{/foreach}
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
56
source/webui/templates/incident.tpl
Normal file
56
source/webui/templates/incident.tpl
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span16"><!--name content container -->
|
||||||
|
<h1>Incident History: {$incident->reference|escape:html}</h1>
|
||||||
|
<div class="rounded_content">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span13 column">
|
||||||
|
<p>This page details the history of incident: {$incident->reference|escape:html}</p>
|
||||||
|
</div>
|
||||||
|
<div class="span2 column">
|
||||||
|
{if $display_admin_links}<button class='btn small primary' onclick="document.location.href='{$base_uri}admin/incident/service/{$service->id}/site/{$site->id}/id/{$incident->id}/';return false;">Edit Incident</button>{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3>Incident Details</h3>
|
||||||
|
<p></p>
|
||||||
|
</div>
|
||||||
|
<div class="span11 column">
|
||||||
|
<p style="padding-top:10px;"><b>Service:</b> {$service->name|escape:html}</p>
|
||||||
|
<p><b>Site:</b> {$site->name|escape:html}</p>
|
||||||
|
<p><b>Opened:</b> {$incident->start_time|date_format:'H:i d-M-y'}</p>
|
||||||
|
<p><b>Estimated End:</b> {ucwords(StatusBoard_DateTime::fuzzyTime($incident->estimated_end_time))}</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3>Status Changes</h3>
|
||||||
|
<p>The table display an audit log of changes to this incident</p>
|
||||||
|
</div><!--/New Service description-->
|
||||||
|
<div class="span11 column">
|
||||||
|
<table class="bordered-table">
|
||||||
|
<thead>
|
||||||
|
<th>Date/Time</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{foreach from=$statuses item=status}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{ucwords(StatusBoard_DateTime::fuzzyTime($status->ctime))}<br />
|
||||||
|
<em>{$status->ctime|date_format:'H:i d-M-y'}</em>
|
||||||
|
</td>
|
||||||
|
<td>{StatusBoard_Status::name($status->status)}</td>
|
||||||
|
<td>{$status->description|escape:html}</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
<!DOCTYPE HTML>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Status Board</title>
|
<title>Status Board</title>
|
||||||
<script lang="javascript">
|
<script lang="javascript">
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" type="text/css" href="{$base_uri}styles/normal.css" />
|
<link rel="stylesheet" type="text/css" href="{$base_uri}styles/normal.css" />
|
||||||
|
<link rel="shortcut icon" href="{$base_uri}images/favicon.ico" />
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var base_uri = "{$base_uri|escape:'quote'}";
|
var base_uri = "{$base_uri|escape:'quote'}";
|
||||||
@@ -15,46 +16,61 @@
|
|||||||
<link type="text/css" href="{$base_uri}styles/3rdparty/jquery.asmselect.css" rel="Stylesheet" />
|
<link type="text/css" href="{$base_uri}styles/3rdparty/jquery.asmselect.css" rel="Stylesheet" />
|
||||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
|
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
|
||||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script>
|
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script>
|
||||||
|
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/jquery.chained.js"></script>
|
||||||
<script type="text/javascript" src="{$base_uri}scripts/main.js"></script>
|
<script type="text/javascript" src="{$base_uri}scripts/main.js"></script>
|
||||||
|
<link rel="stylesheet/less" href="{$base_uri}less/bootstrap.less" media="all" />
|
||||||
|
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/less-1.1.5.min.js"></script>
|
||||||
|
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-alerts.js"></script>
|
||||||
|
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-twipsy.js"></script>
|
||||||
|
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-popover.js"></script>
|
||||||
|
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-dropdown.js"></script>
|
||||||
|
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-tabs.js"></script>
|
||||||
|
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-modal.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div id="container">
|
<div class="topbar">
|
||||||
|
<div class="topbar-inner">
|
||||||
|
<div class="container-fluid">
|
||||||
|
{$page->include_template('navigation')}
|
||||||
|
</div><!-- /tobar-inner -->
|
||||||
|
</div><!-- /container-fliud -->
|
||||||
|
</div><!-- /topbar -->
|
||||||
|
|
||||||
|
|
||||||
<div id="banner">
|
<div class="container">
|
||||||
<h1>StatusBoard</h1>
|
<div class="content">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="navigation">
|
{if ! $messages}
|
||||||
{include file="navigation.tpl"}
|
{$session = StatusBoard_Main::instance()->session()}
|
||||||
</div>
|
{$messages = $session->get('messages')}
|
||||||
|
{$session->delete('messages')}
|
||||||
|
{/if}
|
||||||
|
{if $messages}
|
||||||
|
<div id="messages">
|
||||||
|
{foreach from=$messages item=message}
|
||||||
|
{if is_array($message)}
|
||||||
|
{$severity=$message['severity']}
|
||||||
|
<div class="alert-message {$severity}">
|
||||||
|
{$message['content']|escape:html}
|
||||||
|
</div>
|
||||||
|
{else}
|
||||||
|
<div class="alert-message info">
|
||||||
|
{$message|escape:html}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/foreach}
|
||||||
|
</div><!-- /messages -->
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div id="page-container">
|
{$page_content}
|
||||||
|
|
||||||
<div id="sidebar">
|
|
||||||
{include file="sidebar.tpl"}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="page">
|
</div><!-- /content -->
|
||||||
|
|
||||||
{if $messages}
|
<footer>
|
||||||
<div id="messages">
|
<p> Powered by <a href="https://github.com/optiz0r/status-board/wiki" title="StatusBoard Wiki">StatusBoard</a> {$version} ({$version_codename}). Written by Ben Roberts and Nathan Booth.</p>
|
||||||
{foreach from=$messages item=message}
|
</footer>
|
||||||
{$message}
|
|
||||||
{/foreach}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{$page_content}
|
</div><!-- /container -->
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="footer">
|
|
||||||
Powered by StatusBoard {$version}. Written by Ben Roberts and Nathan Booth.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
36
source/webui/templates/login.tpl
Normal file
36
source/webui/templates/login.tpl
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{if $authentication_failed}
|
||||||
|
|
||||||
|
<div class="alert-message error">
|
||||||
|
Incorrect username/password combination entered.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span16">
|
||||||
|
<form id="page_login" method="post" action="{$base_uri}login/do/">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Administrator Login</legend>
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="xlInput">Username</label>
|
||||||
|
<div class="input">
|
||||||
|
<input class="xlarge span5" id="page_username" name="username" size="30" type="text"/>
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="page_password">Password</label>
|
||||||
|
<div class="password">
|
||||||
|
<input class="xlarge" id="page_password" name="password" size="30" type="password"/>
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
<div class="input">
|
||||||
|
<div class="clearfix">
|
||||||
|
<input type="submit" class="btn primary" value="Login"> <button type="reset" class="btn">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div><!-- /span16 -->
|
||||||
|
</div><!-- /row -->
|
||||||
|
</div><!-- /container -->
|
||||||
1
source/webui/templates/logout.tpl
Normal file
1
source/webui/templates/logout.tpl
Normal file
@@ -0,0 +1 @@
|
|||||||
|
TODO
|
||||||
@@ -1,4 +1,29 @@
|
|||||||
<ul>
|
<a class="brand" href="{$base_uri}home/">StatusBoard</a>
|
||||||
<li><a href="{$base_uri}home/" title="Home">Home</a></li>
|
|
||||||
<li><a href="{$base_uri}admin/" title="Admin">Admin</a></li>
|
<ul class="nav">
|
||||||
</ul>
|
<li {if $requested_page == home}class="active"{/if}>
|
||||||
|
<a href="{$base_uri}home/" title="Home">Home</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{if $authenticated}
|
||||||
|
{if $auth->isAdministrator()}
|
||||||
|
<li class="dropdown {if $requested_page == admin}active{/if}" data-dropdown="dropdown">
|
||||||
|
<a href="{$base_uri}admin/" class="dropdown-toggle" title="Admin">Admin</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="{$base_uri}admin/tab/summary/" title="Summary">Summary</a></li>
|
||||||
|
<li><a href="{$base_uri}admin/tab/services/" title="Manage Services">Services</a></li>
|
||||||
|
<li><a href="{$base_uri}admin/tab/settings/" title="Manage Settings">Settings</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{/if}
|
||||||
|
<li><a href="{$base_uri}logout/" title="Logout">Logout</a></li>
|
||||||
|
{else}
|
||||||
|
<li><a href="{$base_uri}login/" title="Login">Login</a></li>
|
||||||
|
{/if}
|
||||||
|
{if $requested_page == home}<li><a href='#' data-placement='below' rel='popover' data-content='{include file="fragments/icon-help.tpl"}' data-original-title='What do the status icons mean?'>Help</a></li>{/if}
|
||||||
|
</ul>
|
||||||
|
{if $authenticated}
|
||||||
|
<p class="pull-right" style="color:#BFBFBF;">
|
||||||
|
Logged in as <a href="{$base_uri}usercp/">{$user->username}</a>
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
104
source/webui/templates/status.tpl
Normal file
104
source/webui/templates/status.tpl
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span16"><!--name content container -->
|
||||||
|
<h1>Site Status History: {$service->name|escape:html} - {$site->name|escape:html}</h1>
|
||||||
|
<div class="rounded_content" style="padding-bottom:40px">
|
||||||
|
<p>This page details the incident history for a site:</p>
|
||||||
|
{if $start && $end}
|
||||||
|
{$incidentsDuring=$site->openIncidentsDuring($start, $end)}
|
||||||
|
{$incidentCount=count($incidentsDuring)}
|
||||||
|
<h2>{$start|date_format:'d-M H:i'} to {$end|date_format:'d-M H:i'}</h2>
|
||||||
|
{foreach from=$incidentsDuring item=incident}
|
||||||
|
{$statuses=$incident->statusChanges()}
|
||||||
|
<div class="row">
|
||||||
|
<div class="span4 column">
|
||||||
|
<h3 class="status">
|
||||||
|
{if $display_admin_links && $incident->currentStatus() != StatusBoard_Status::STATUS_Resolved}
|
||||||
|
<a href="{$base_uri}admin/incident/service/{$service->id}/site/{$site->id}/id/{$incident->id}/" title="Edit {$incident->reference|escape:html}">{$incident->reference|escape:html}</a>
|
||||||
|
{else}
|
||||||
|
{$incident->reference|escape:html}
|
||||||
|
{/if}
|
||||||
|
</h3>
|
||||||
|
<p>Opened: {$incident->start_time|date:"r"}<p>
|
||||||
|
{if $incident->estimated_end_time}
|
||||||
|
{$time_difference=time()-$incident->estimated_end_time}
|
||||||
|
<p>Estimated End Time: {$time_difference|fuzzyTime}</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="span11 column">
|
||||||
|
<table class="bordered-table">
|
||||||
|
<thead>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Time</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{foreach from=$statuses item=status}
|
||||||
|
<tr>
|
||||||
|
<td>{$status->status|escape:html}</td>
|
||||||
|
<td>{$status->ctime|date_format:'d-M H:i'}</td>
|
||||||
|
<td>{$status->description|escape:html}</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{foreachelse}
|
||||||
|
<p>There were no recorded incidents during this time period.</p>
|
||||||
|
{/foreach}
|
||||||
|
{else}
|
||||||
|
{foreach from=array(0,1,2,3,4,5,6) item=day}
|
||||||
|
{$start=mktime(0,0,0,date("n"),date("j")-$day)}
|
||||||
|
{$end=mktime(0,0,0,date("n"),date("j")-$day+1)}
|
||||||
|
{$incidentsDuring=$site->openIncidentsDuring($start, $end)}
|
||||||
|
{$incidentCount=count($incidentsDuring)}
|
||||||
|
<div class="row" id="{$start|date_format:"dM"}" style="padding-top:40px">
|
||||||
|
<div class="span3 column"><!--New description-->
|
||||||
|
<h3 class="status">{$start|date_format:"d M Y"}</h3>
|
||||||
|
<p>{$incidentCount} {StatusBoard_Formatting::pluralise($incidentCount,'incident','incidents')}</p>
|
||||||
|
{if $incidentsDuring}<p style="font-size:small"> Note: Click on incident number to see incident audit trail</p>{/if}
|
||||||
|
</div>
|
||||||
|
<div class="span12 column" style="margin-bottom:-40px">
|
||||||
|
{if $incidentsDuring}
|
||||||
|
<table class="bordered-table"><!--Services table -->
|
||||||
|
<thead>
|
||||||
|
<th>Incident</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Time Opened</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Time Closed</th>
|
||||||
|
{if $display_admin_links}<th>Actions</th>{/if}
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{foreach from=$incidentsDuring item=incident}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{$base_uri}incident/id/{$incident->id}/" title="Indident History">{$incident->reference|escape:html}</a>
|
||||||
|
</td>
|
||||||
|
<td>{$incident->description|truncate|escape:html}</td>
|
||||||
|
<td>{date('d-M H:i', $incident->start_time)}</td>
|
||||||
|
<td>{StatusBoard_Status::name($incident->currentStatus())}</td>
|
||||||
|
<td>
|
||||||
|
{if $incident->actual_end_time}
|
||||||
|
{date('d-M H:i', $incident->actual_end_time)}
|
||||||
|
{else}
|
||||||
|
Still Open
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
|
{if $display_admin_links}<td><button class='btn small primary' onclick="document.location.href='{$base_uri}admin/incident/service/{$service->id}/site/{$site->id}/id/{$incident->id}/';return false;">Edit</button>{/if}</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
</table><!--/name table -->
|
||||||
|
{else}
|
||||||
|
<p style="padding-top:10px;">There were no recorded incidents on this day</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/foreach}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
62
source/webui/templates/usercp.tpl
Normal file
62
source/webui/templates/usercp.tpl
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<div class="container">
|
||||||
|
|
||||||
|
{if $activity}
|
||||||
|
{if $successes}
|
||||||
|
{foreach from=$successes item=message}
|
||||||
|
<div class="alert-message success">
|
||||||
|
{$message|escape:html}
|
||||||
|
</div>
|
||||||
|
{/foreach}
|
||||||
|
{/if}
|
||||||
|
{if $errors}
|
||||||
|
{foreach from=$errors item=message}
|
||||||
|
<div class="alert-message error">
|
||||||
|
{$message|escape:html}
|
||||||
|
</div>
|
||||||
|
{/foreach}
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="span16">
|
||||||
|
<form id="usercp_pwchange" method="post" action="{$base_uri}usercp/do/change-password/">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Change Password</legend>
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="usercp_currentpassword">Current Password</label>
|
||||||
|
<div class="password">
|
||||||
|
<input class="xlarge span5" id="usercp_currentpassword" name="currentpassword" type="password"/>
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="usercp_newpassword">New Password</label>
|
||||||
|
<div class="password">
|
||||||
|
<input class="xlarge span5" id="usercp_newpassword" name="newpassword" type="password"/>
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<label for="usercp_confirmpassword">Confirm Password</label>
|
||||||
|
<div class="password">
|
||||||
|
<input class="xlarge span5" id="usercp_confirmpassword" name="confirmpassword" type="password"/>
|
||||||
|
<span class="help-inline" style="display: none" id="usercp_confirmpassword_help">The passwords do not match.</span>
|
||||||
|
</div>
|
||||||
|
</div><!-- /clearfix -->
|
||||||
|
|
||||||
|
<div class="input">
|
||||||
|
<div class="clearfix">
|
||||||
|
<input type="submit" class="btn primary" value="Change Password"> <button type="reset" class="btn">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div><!-- /span16 -->
|
||||||
|
</div><!-- /row -->
|
||||||
|
</div><!-- /container -->
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$('document').ready(sb.usercp.init);
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user