merged current upstream/master

This commit is contained in:
Marc Aschmann 2014-12-07 17:50:19 +01:00
commit 2df2ca5cb5
395 changed files with 54027 additions and 1464 deletions

View file

@ -14,7 +14,7 @@ use b8\Exception\HttpException;
use b8\Http\Response;
use b8\Http\Response\RedirectResponse;
use b8\View;
use Symfony\Component\Yaml\Parser;
use PHPCI\Model\Build;
/**
* PHPCI Front Controller
@ -30,15 +30,15 @@ class Application extends b8\Application
// Inlined as a closure to fix "using $this when not in object context" on 5.3
$validateSession = function () {
if (!empty($_SESSION['user_id'])) {
$user = b8\Store\Factory::getStore('User')->getByPrimaryKey($_SESSION['user_id']);
if (!empty($_SESSION['phpci_user_id'])) {
$user = b8\Store\Factory::getStore('User')->getByPrimaryKey($_SESSION['phpci_user_id']);
if ($user) {
$_SESSION['user'] = $user;
$_SESSION['phpci_user'] = $user;
return true;
}
unset($_SESSION['user_id']);
unset($_SESSION['phpci_user_id']);
}
return false;
@ -46,7 +46,7 @@ class Application extends b8\Application
// load settings to check if there's a configured default user and auth disabled
$skipAuth = function () {
$parser = new Parser();
/** $parser = new Parser();
$yaml = file_get_contents(APPLICATION_PATH . 'PHPCI/config.yml');
$settings = $parser->parse($yaml);
if ((!empty($settings['phpci']['authentication_settings']['state'])
@ -61,7 +61,7 @@ class Application extends b8\Application
return true;
}
}
*/
return false;
};
@ -74,7 +74,7 @@ class Application extends b8\Application
$response->setResponseCode(401);
$response->setContent('');
} else {
$_SESSION['login_redirect'] = substr($request->getPath(), 1);
$_SESSION['phpci_login_redirect'] = substr($request->getPath(), 1);
$response = new RedirectResponse($response);
$response->setHeader('Location', PHPCI_URL.'session/login');
}
@ -113,18 +113,30 @@ class Application extends b8\Application
$this->response->setContent($view->render());
}
if (View::exists('layout') && $this->response->hasLayout()) {
$view = new View('layout');
$pageTitle = $this->config->get('page_title', null);
if ($this->response->hasLayout()) {
$this->setLayoutVariables($this->controller->layout);
if (!is_null($pageTitle)) {
$view->title = $pageTitle;
}
$view->content = $this->response->getContent();
$this->response->setContent($view->render());
$this->controller->layout->content = $this->response->getContent();
$this->response->setContent($this->controller->layout->render());
}
return $this->response;
}
protected function loadController($class)
{
$controller = parent::loadController($class);
$controller->layout = new View('layout');
$controller->layout->title = 'PHPCI';
$controller->layout->breadcrumb = array();
return $controller;
}
protected function setLayoutVariables(View &$layout)
{
/** @var \PHPCI\Store\ProjectStore $projectStore */
$projectStore = b8\Store\Factory::getStore('Project');
$layout->projects = $projectStore->getAll();
}
}

View file

@ -36,11 +36,6 @@ class Builder implements LoggerAwareInterface
*/
public $ignore = array();
/**
* @var string
*/
protected $ciDir;
/**
* @var string
*/
@ -287,10 +282,7 @@ class Builder implements LoggerAwareInterface
*/
protected function setupBuild()
{
$buildId = 'project' . $this->build->getProject()->getId()
. '-build' . $this->build->getId();
$this->ciDir = dirname(dirname(__FILE__) . '/../') . '/';
$this->buildPath = $this->ciDir . 'build/' . $buildId . '/';
$this->buildPath = PHPCI_DIR . 'PHPCI/build/' . $this->build->getId() . '/';
$this->build->currentBuildPath = $this->buildPath;
$this->interpolator->setupInterpolationVars(

View file

@ -75,7 +75,8 @@ class DaemoniseCommand extends Command
$this->run = true;
$this->sleep = 0;
$runner = new RunCommand($this->logger);
$runner->setBaxBuilds(1);
$runner->setMaxBuilds(1);
$runner->setIsDaemon(true);
$emptyInput = new ArgvInput(array());

View file

@ -23,7 +23,6 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Helper\DialogHelper;
use PHPCI\Service\UserService;
/**
* Install console command - Installs PHPCI.
* @author Dan Cryer <dan@block8.co.uk>
@ -32,10 +31,23 @@ use PHPCI\Service\UserService;
*/
class InstallCommand extends Command
{
protected $configFilePath;
protected function configure()
{
$defaultPath = PHPCI_DIR . 'PHPCI/config.yml';
$this
->setName('phpci:install')
->addOption('url', null, InputOption::VALUE_OPTIONAL, 'PHPCI Installation URL')
->addOption('db-host', null, InputOption::VALUE_OPTIONAL, 'Database hostname')
->addOption('db-name', null, InputOption::VALUE_OPTIONAL, 'Database name')
->addOption('db-user', null, InputOption::VALUE_OPTIONAL, 'Database username')
->addOption('db-pass', null, InputOption::VALUE_OPTIONAL, 'Database password')
->addOption('admin-name', null, InputOption::VALUE_OPTIONAL, 'Admin username')
->addOption('admin-pass', null, InputOption::VALUE_OPTIONAL, 'Admin password')
->addOption('admin-mail', null, InputOption::VALUE_OPTIONAL, 'Admin e-mail')
->addOption('config-path', null, InputOption::VALUE_OPTIONAL, 'Config file path', $defaultPath)
->setDescription('Install PHPCI.');
}
@ -44,6 +56,8 @@ class InstallCommand extends Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->configFilePath = $input->getOption('config-path');
$this->verifyNotInstalled($output);
$output->writeln('');
@ -58,60 +72,39 @@ class InstallCommand extends Command
$output->writeln('-------------------------------------');
$output->writeln('');
/**
* @var \Symfony\Component\Console\Helper\DialogHelper
*/
$dialog = $this->getHelperSet()->get('dialog');
// ----
// Get MySQL connection information and verify that it works:
// ----
$connectionVerified = false;
while (!$connectionVerified) {
$db = array();
$db['servers']['read'] = $dialog->ask($output, 'Please enter your MySQL host [localhost]: ', 'localhost');
$db['servers']['write'] = $db['servers']['read'];
$db['name'] = $dialog->ask($output, 'Please enter your database name [phpci]: ', 'phpci');
$db['username'] = $dialog->ask($output, 'Please enter your database username [phpci]: ', 'phpci');
$db['password'] = $dialog->askHiddenResponse($output, 'Please enter your database password: ');
$db = $this->getDatabaseInformation($input, $output);
$connectionVerified = $this->verifyDatabaseDetails($db, $output);
}
$output->writeln('');
$conf = array();
$conf['b8']['database'] = $db;
// ----
// Get basic installation details (URL, etc)
// ----
$conf = array();
$conf['b8']['database'] = $db;
$conf['phpci']['url'] = $dialog->askAndValidate(
$output,
'Your PHPCI URL ("http://phpci.local" for example): ',
function ($answer) {
if (!filter_var($answer, FILTER_VALIDATE_URL)) {
throw new Exception('Must be a valid URL');
}
return rtrim($answer, '/');
},
false
);
$conf['phpci'] = $this->getPhpciConfigInformation($input, $output);
$this->writeConfigFile($conf);
$this->setupDatabase($output);
$this->createAdminUser($output, $dialog);
$admin = $this->getAdminInforamtion($input, $output);
$this->createAdminUser($admin, $output);
}
/**
* Check PHP version, required modules and for disabled functions.
*
* @param OutputInterface $output
* @throws \Exception
*/
protected function checkRequirements(OutputInterface $output)
{
$output->write('Checking requirements...');
@ -160,6 +153,127 @@ class InstallCommand extends Command
$output->writeln('');
}
/**
* Load information for admin user form CLI options or ask info to user.
*
* @param InputInterface $input
* @param OutputInterface $output
* @return array
*/
protected function getAdminInforamtion(InputInterface $input, OutputInterface $output)
{
$admin = array();
/**
* @var \Symfony\Component\Console\Helper\DialogHelper
*/
$dialog = $this->getHelperSet()->get('dialog');
// Function to validate mail address.
$mailValidator =function ($answer) {
if (!filter_var($answer, FILTER_VALIDATE_EMAIL)) {
throw new Exception('Must be a valid email address.');
}
return $answer;
};
if ($adminEmail = $input->getOption('admin-mail')) {
$adminEmail = $mailValidator($adminEmail);
} else {
$adminEmail = $dialog->askAndValidate($output, 'Your email address: ', $mailValidator, false);
}
if (!$adminName = $input->getOption('admin-name')) {
$adminName = $dialog->ask($output, 'Enter your name: ');
}
if (!$adminPass = $input->getOption('admin-pass')) {
$adminPass = $dialog->askHiddenResponse($output, 'Enter your desired admin password: ');
}
$admin['mail'] = $adminEmail;
$admin['name'] = $adminName;
$admin['pass'] = $adminPass;
return $admin;
}
/**
* Load configuration for PHPCI form CLI options or ask info to user.
*
* @param InputInterface $input
* @param OutputInterface $output
* @return array
*/
protected function getPhpciConfigInformation(InputInterface $input, OutputInterface $output)
{
$phpci = array();
/**
* @var \Symfony\Component\Console\Helper\DialogHelper
*/
$dialog = $this->getHelperSet()->get('dialog');
// FUnction do validate URL.
$urlValidator = function ($answer) {
if (!filter_var($answer, FILTER_VALIDATE_URL)) {
throw new Exception('Must be a valid URL');
}
return rtrim($answer, '/');
};
if ($url = $input->getOption('url')) {
$url = $urlValidator($url);
} else {
$url = $dialog->askAndValidate($output, 'Your PHPCI URL ("http://phpci.local" for example): ', $urlValidator, false);
}
$phpci['url'] = $url;
return $phpci;
}
/**
* Load configuration for DB form CLI options or ask info to user.
*
* @param InputInterface $input
* @param OutputInterface $output
* @return array
*/
protected function getDatabaseInformation(InputInterface $input, OutputInterface $output)
{
$db = array();
/**
* @var \Symfony\Component\Console\Helper\DialogHelper
*/
$dialog = $this->getHelperSet()->get('dialog');
if (!$dbHost = $input->getOption('db-host')) {
$dbHost = $dialog->ask($output, 'Please enter your MySQL host [localhost]: ', 'localhost');
}
if (!$dbName = $input->getOption('db-name')) {
$dbName = $dialog->ask($output, 'Please enter your database name [phpci]: ', 'phpci');
}
if (!$dbUser = $input->getOption('db-user')) {
$dbUser = $dialog->ask($output, 'Please enter your database username [phpci]: ', 'phpci');
}
if (!$dbPass = $input->getOption('db-pass')) {
$dbPass = $dialog->askHiddenResponse($output, 'Please enter your database password: ');
}
$db['servers']['read'] = $dbHost;
$db['servers']['write'] = $dbHost;
$db['name'] = $dbName;
$db['username'] = $dbUser;
$db['password'] = $dbPass;
return $db;
}
/**
* Try and connect to MySQL using the details provided.
* @param array $db
@ -198,9 +312,9 @@ class InstallCommand extends Command
protected function writeConfigFile(array $config)
{
$dumper = new \Symfony\Component\Yaml\Dumper();
$yaml = $dumper->dump($config, 2);
$yaml = $dumper->dump($config, 4);
file_put_contents(PHPCI_DIR . 'PHPCI/config.yml', $yaml);
file_put_contents($this->configFilePath, $yaml);
}
protected function setupDatabase(OutputInterface $output)
@ -213,34 +327,19 @@ class InstallCommand extends Command
}
/**
* Create admin user using information loaded before.
*
* @param array $admin
* @param OutputInterface $output
* @param DialogHelper $dialog
*/
protected function createAdminUser(OutputInterface $output, DialogHelper $dialog)
protected function createAdminUser($admin, $output)
{
// Try to create a user account:
$adminEmail = $dialog->askAndValidate(
$output,
'Your email address: ',
function ($answer) {
if (!filter_var($answer, FILTER_VALIDATE_EMAIL)) {
throw new Exception('Must be a valid email address.');
}
return $answer;
},
false
);
$adminPass = $dialog->askHiddenResponse($output, 'Enter your desired admin password: ');
$adminName = $dialog->ask($output, 'Enter your name: ');
try {
$this->reloadConfig();
$userStore = Factory::getStore('User');
$userService = new UserService($userStore);
$userService->createUser($adminName, $adminEmail, $adminPass, 1);
$userService->createUser($admin['name'], $admin['mail'], $admin['pass'], 1);
$output->writeln('<info>User account created!</info>');
} catch (\Exception $ex) {
@ -252,11 +351,10 @@ class InstallCommand extends Command
protected function reloadConfig()
{
$configFile = PHPCI_DIR . 'PHPCI/config.yml';
$config = Config::getInstance();
$config = Config::getInstance();
if (file_exists($configFile)) {
$config->loadYaml($configFile);
if (file_exists($this->configFilePath)) {
$config->loadYaml($this->configFilePath);
}
}
@ -265,11 +363,11 @@ class InstallCommand extends Command
*/
protected function verifyNotInstalled(OutputInterface $output)
{
if (file_exists(PHPCI_DIR . 'PHPCI/config.yml')) {
$content = file_get_contents(PHPCI_DIR . 'PHPCI/config.yml');
if (file_exists($this->configFilePath)) {
$content = file_get_contents($this->configFilePath);
if (!empty($content)) {
$output->writeln('<error>PHPCI/config.yml exists and is not empty.</error>');
$output->writeln('<error>The PHPCI config file exists and is not empty.</error>');
$output->writeln('<error>If you were trying to update PHPCI, please use phpci:update instead.</error>');
die;
}

View file

@ -75,6 +75,7 @@ class PollCommand extends Command
$last_commit = $commits['body'][0]['sha'];
$last_committer = $commits['body'][0]['commit']['committer']['email'];
$message = $commits['body'][0]['commit']['message'];
$this->logger->info("Last commit to github for " . $project->getTitle() . " is " . $last_commit);
@ -89,6 +90,7 @@ class PollCommand extends Command
$build->setStatus(Build::STATUS_NEW);
$build->setBranch($project->getBranch());
$build->setCreated(new \DateTime());
$build->setCommitMessage($message);
if (!empty($last_committer)) {
$build->setCommitterEmail($last_committer);
}

View file

@ -9,6 +9,7 @@
namespace PHPCI\Command;
use b8\Config;
use Monolog\Logger;
use PHPCI\Logging\BuildDBLogHandler;
use PHPCI\Logging\LoggedBuildContextTidier;
@ -47,6 +48,11 @@ class RunCommand extends Command
*/
protected $maxBuilds = null;
/**
* @var bool
*/
protected $isFromDaemon = false;
/**
* @param \Monolog\Logger $logger
* @param string $name
@ -73,14 +79,15 @@ class RunCommand extends Command
// For verbose mode we want to output all informational and above
// messages to the symphony output interface.
if ($input->hasOption('verbose')) {
if ($input->hasOption('verbose') && $input->getOption('verbose')) {
$this->logger->pushHandler(
new OutputLogHandler($this->output, Logger::INFO)
);
}
$this->logger->pushProcessor(new LoggedBuildContextTidier());
$running = $this->validateRunningBuilds();
$this->logger->pushProcessor(new LoggedBuildContextTidier());
$this->logger->addInfo("Finding builds to process");
$store = Factory::getStore('Build');
$result = $store->getByStatus(0, $this->maxBuilds);
@ -88,11 +95,22 @@ class RunCommand extends Command
$builds = 0;
foreach ($result['items'] as $build) {
$builds++;
while (count($result['items'])) {
$build = array_shift($result['items']);
$build = BuildFactory::getBuild($build);
// Skip build (for now) if there's already a build running in that project:
if (!$this->isFromDaemon && in_array($build->getProjectId(), $running)) {
$this->logger->addInfo('Skipping Build #'.$build->getId() . ' - Project build already in progress.');
$result['items'][] = $build;
// Re-run build validator:
$running = $this->validateRunningBuilds();
continue;
}
$builds++;
try {
// Logging relevant to this build should be stored
// against the build itself.
@ -107,6 +125,7 @@ class RunCommand extends Command
$this->logger->popHandler($buildDbLog);
} catch (\Exception $ex) {
$build->setStatus(Build::STATUS_FAILED);
$build->setFinished(new \DateTime());
$build->setLog($build->getLog() . PHP_EOL . PHP_EOL . $ex->getMessage());
$store->save($build);
}
@ -118,8 +137,59 @@ class RunCommand extends Command
return $builds;
}
public function setBaxBuilds($numBuilds)
public function setMaxBuilds($numBuilds)
{
$this->maxBuilds = (int)$numBuilds;
}
public function setIsDaemon($fromDaemon)
{
$this->isFromDaemon = (bool)$fromDaemon;
}
protected function validateRunningBuilds()
{
/** @var \PHPCI\Store\BuildStore $store */
$store = Factory::getStore('Build');
$running = $store->getByStatus(1);
$rtn = array();
$timeout = Config::getInstance()->get('phpci.build.failed_after', 1800);
foreach ($running['items'] as $build) {
/** @var \PHPCI\Model\Build $build */
$build = BuildFactory::getBuild($build);
$now = time();
$start = $build->getStarted()->getTimestamp();
if (($now - $start) > $timeout) {
$this->logger->addInfo('Build #'.$build->getId().' marked as failed due to timeout.');
$build->setStatus(Build::STATUS_FAILED);
$build->setFinished(new \DateTime());
$store->save($build);
$this->removeBuildDirectory($build);
continue;
}
$rtn[$build->getProjectId()] = true;
}
return $rtn;
}
protected function removeBuildDirectory($build)
{
$buildPath = PHPCI_DIR . 'PHPCI/build/' . $build->getId() . '/';
if (is_dir($buildPath)) {
$cmd = 'rm -Rf "%s"';
if (IS_WIN) {
$cmd = 'rmdir /S /Q "%s"';
}
shell_exec($cmd);
}
}
}

View file

@ -72,10 +72,23 @@ class Controller extends \b8\Controller
return $this->response;
}
/**
* Require that the currently logged in user is an administrator.
* @throws ForbiddenException
*/
protected function requireAdmin()
{
if (!$_SESSION['user']->getIsAdmin()) {
if (!$this->currentUserIsAdmin()) {
throw new ForbiddenException('You do not have permission to do that.');
}
}
/**
* Check if the currently logged in user is an administrator.
* @return bool
*/
protected function currentUserIsAdmin()
{
return $_SESSION['phpci_user']->getIsAdmin();
}
}

View file

@ -13,6 +13,7 @@ use b8;
use b8\Exception\HttpException\NotFoundException;
use PHPCI\BuildFactory;
use PHPCI\Model\Build;
use PHPCI\Model\Project;
use PHPCI\Service\BuildService;
/**
@ -58,8 +59,22 @@ class BuildController extends \PHPCI\Controller
$this->view->build = $build;
$this->view->data = $this->getBuildData($build);
$title = 'Build #' . $build->getId() . ' - ' . $build->getProjectTitle();
$this->config->set('page_title', $title);
$this->layout->title = 'Build #' . $build->getId();
$this->layout->subtitle = $build->getProjectTitle();
$nav = array(
'title' => 'Build '.$build->getId(),
'icon' => 'cog',
'links' => array(
'build/rebuild/' . $build->getId() => 'Rebuild Now',
),
);
if ($this->currentUserIsAdmin()) {
$nav['links']['build/delete/' . $build->getId()] = 'Delete Build';
}
$this->layout->nav = $nav;
}
protected function getUiPlugins()
@ -141,9 +156,7 @@ class BuildController extends \PHPCI\Controller
*/
public function delete($buildId)
{
if (empty($_SESSION['user']) || !$_SESSION['user']->getIsAdmin()) {
throw new \Exception('You do not have permission to do that.');
}
$this->requireAdmin();
$build = BuildFactory::getBuildById($buildId);
@ -168,4 +181,36 @@ class BuildController extends \PHPCI\Controller
return $log;
}
public function latest()
{
$rtn = array(
'pending' => $this->formatBuilds($this->buildStore->getByStatus(Build::STATUS_NEW)),
'running' => $this->formatBuilds($this->buildStore->getByStatus(Build::STATUS_RUNNING)),
);
if ($this->request->isAjax()) {
die(json_encode($rtn));
}
}
protected function formatBuilds($builds)
{
Project::$sleepable = array('id', 'title', 'reference', 'type');
$rtn = array('count' => $builds['count'], 'items' => array());
foreach ($builds['items'] as $build) {
$item = $build->toArray(1);
$header = new b8\View('Build/header-row');
$header->build = $build;
$item['header_row'] = $header->render();
$rtn['items'][$item['id']] = $item;
}
ksort($rtn['items']);
return $rtn;
}
}

View file

@ -68,23 +68,15 @@ class BuildStatusController extends \PHPCI\Controller
}
/**
* Returns the appropriate build status image for a given project.
* Returns the appropriate build status image in SVG format for a given project.
*/
public function image($projectId)
{
$status = $this->getStatus($projectId);
header('Content-Type: image/png');
die(file_get_contents(APPLICATION_PATH . 'public/assets/img/build-' . $status . '.png'));
}
/**
* Returns the appropriate build status image in SVG format for a given project.
*/
public function svg($projectId)
{
$status = $this->getStatus($projectId);
$color = ($status == 'passing') ? 'green' : 'red';
header('Content-Type: image/svg+xml');
die(file_get_contents(APPLICATION_PATH . 'public/assets/img/build-' . $status . '.svg'));
die(file_get_contents('http://img.shields.io/badge/build-' . $status . '-' . $color . '.svg'));
}
public function view($projectId)

View file

@ -11,6 +11,7 @@ namespace PHPCI\Controller;
use b8;
use PHPCI\BuildFactory;
use PHPCI\Model\Build;
/**
* Home Controller - Displays the PHPCI Dashboard.
@ -41,14 +42,20 @@ class HomeController extends \PHPCI\Controller
*/
public function index()
{
$this->layout->title = 'Dashboard';
$projects = $this->projectStore->getWhere(array(), 50, 0, array(), array('title' => 'ASC'));
$this->view->builds = $this->getLatestBuildsHtml();
$builds = $this->buildStore->getLatestBuilds(null, 10);
foreach ($builds as &$build) {
$build = BuildFactory::getBuild($build);
}
$this->view->builds = $builds;
$this->view->projects = $projects['items'];
$this->view->summary = $this->getSummaryHtml($projects);
$this->config->set('page_title', 'Dashboard');
return $this->view->render();
}
@ -69,13 +76,24 @@ class HomeController extends \PHPCI\Controller
protected function getSummaryHtml($projects)
{
$summaryBuilds = array();
$successes = array();
$failures = array();
foreach ($projects['items'] as $project) {
$summaryBuilds[$project->getId()] = $this->buildStore->getLatestBuilds($project->getId());
$success = $this->buildStore->getLastBuildByStatus($project->getId(), Build::STATUS_SUCCESS);
$failure = $this->buildStore->getLastBuildByStatus($project->getId(), Build::STATUS_FAILED);
$successes[$project->getId()] = $success;
$failures[$project->getId()] = $failure;
}
$summaryView = new b8\View('SummaryTable');
$summaryView->projects = $projects['items'];
$summaryView->builds = $summaryBuilds;
$summaryView->successful = $successes;
$summaryView->failed = $failures;
return $summaryView->render();
}

View file

@ -24,6 +24,10 @@ use PHPCI\Plugin\Util\PluginInformationCollection;
class PluginController extends \PHPCI\Controller
{
protected $required = array(
'php',
'ext-mcrypt',
'ext-pdo',
'ext-pdo_mysql',
'block8/b8framework',
'ircmaxell/password-compat',
'swiftmailer/swiftmailer',
@ -31,7 +35,8 @@ class PluginController extends \PHPCI\Controller
'symfony/console',
'psr/log',
'monolog/monolog',
'pimple/pimple'
'pimple/pimple',
'robmorgan/phinx',
);
protected $canInstall;
@ -39,9 +44,7 @@ class PluginController extends \PHPCI\Controller
public function index()
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new \Exception('You do not have permission to do that.');
}
$this->requireAdmin();
$this->view->canWrite = is_writable(APPLICATION_PATH . 'composer.json');
$this->view->required = $this->required;
@ -60,16 +63,14 @@ class PluginController extends \PHPCI\Controller
$this->view->plugins = $pluginInfo->getInstalledPlugins();
$this->config->set('page_title', 'Plugins');
$this->layout->title = 'Plugins';
return $this->view->render();
}
public function remove()
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new \Exception('You do not have permission to do that.');
}
$this->requireAdmin();
$package = $this->getParam('package', null);
$json = $this->getComposerJson();
@ -88,9 +89,7 @@ class PluginController extends \PHPCI\Controller
public function install()
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new \Exception('You do not have permission to do that.');
}
$this->requireAdmin();
$package = $this->getParam('package', null);
$version = $this->getParam('version', '*');
@ -109,9 +108,19 @@ class PluginController extends \PHPCI\Controller
return json_decode($json, true);
}
/**
* Convert array to json and save composer.json
*
* @param $array
*/
protected function setComposerJson($array)
{
$json = json_encode($array);
if (defined('JSON_PRETTY_PRINT')) {
$json = json_encode($array, JSON_PRETTY_PRINT);
} else {
$json = json_encode($array);
}
file_put_contents(APPLICATION_PATH . 'composer.json', $json);
}

View file

@ -64,6 +64,7 @@ class ProjectController extends \PHPCI\Controller
*/
public function view($projectId)
{
$branch = $this->getParam('branch', '');
$project = $this->projectStore->getById($projectId);
if (empty($project)) {
@ -72,20 +73,23 @@ class ProjectController extends \PHPCI\Controller
$per_page = 10;
$page = $this->getParam('p', 1);
$builds = $this->getLatestBuildsHtml($projectId, (($page - 1) * $per_page));
$builds = $this->getLatestBuildsHtml($projectId, urldecode($branch), (($page - 1) * $per_page));
$pages = $builds[1] == 0 ? 1 : ceil($builds[1] / $per_page);
if ($page > $pages) {
throw new NotFoundException('Page with number: ' . $page . ' not found');
}
$this->view->builds = $builds[0];
$this->view->total = $builds[1];
$this->view->project = $project;
$this->view->page = $page;
$this->view->pages = $pages;
$this->view->builds = $builds[0];
$this->view->total = $builds[1];
$this->view->project = $project;
$this->view->branch = urldecode($branch);
$this->view->branches = $this->projectStore->getKnownBranches($projectId);
$this->view->page = $page;
$this->view->pages = $pages;
$this->config->set('page_title', $project->getTitle());
$this->layout->title = $project->getTitle();
$this->layout->subtitle = $this->view->branch;
return $this->view->render();
}
@ -93,16 +97,21 @@ class ProjectController extends \PHPCI\Controller
/**
* Create a new pending build for a project.
*/
public function build($projectId)
public function build($projectId, $branch = '')
{
/* @var \PHPCI\Model\Project $project */
$project = $this->projectStore->getById($projectId);
if (empty($branch)) {
$branch = $project->getBranch();
}
if (empty($project)) {
throw new NotFoundException('Project with id: ' . $projectId . ' not found');
}
$build = $this->buildService->createBuild($project, null, null, $_SESSION['user']->getEmail());
$email = $_SESSION['phpci_user']->getEmail();
$build = $this->buildService->createBuild($project, null, urldecode($branch), $email);
header('Location: '.PHPCI_URL.'build/view/' . $build->getId());
exit;
@ -113,9 +122,7 @@ class ProjectController extends \PHPCI\Controller
*/
public function delete($projectId)
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new ForbiddenException('You do not have permission to do that.');
}
$this->requireAdmin();
$project = $this->projectStore->getById($projectId);
$this->projectService->deleteProject($project);
@ -129,16 +136,26 @@ class ProjectController extends \PHPCI\Controller
*/
public function builds($projectId)
{
$builds = $this->getLatestBuildsHtml($projectId);
$branch = $this->getParam('branch', '');
$builds = $this->getLatestBuildsHtml($projectId, urldecode($branch));
die($builds[0]);
}
/**
* Render latest builds for project as HTML table.
*/
protected function getLatestBuildsHtml($projectId, $start = 0)
* Render latest builds for project as HTML table.
*
* @param $projectId
* @param string $branch A urldecoded branch name.
* @param int $start
* @return array
*/
protected function getLatestBuildsHtml($projectId, $branch = '', $start = 0)
{
$criteria = array('project_id' => $projectId);
if (!empty($branch)) {
$criteria['branch'] = $branch;
}
$order = array('id' => 'DESC');
$builds = $this->buildStore->getWhere($criteria, 10, $start, array(), $order);
$view = new b8\View('BuildsTable');
@ -157,7 +174,7 @@ class ProjectController extends \PHPCI\Controller
*/
public function add()
{
$this->config->set('page_title', 'Add Project');
$this->layout->title = 'Add Project';
$this->requireAdmin();
$method = $this->request->getMethod();
@ -208,9 +225,7 @@ class ProjectController extends \PHPCI\Controller
*/
public function edit($projectId)
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new ForbiddenException('You do not have permission to do that.');
}
$this->requireAdmin();
$method = $this->request->getMethod();
$project = $this->projectStore->getById($projectId);
@ -322,7 +337,6 @@ class ProjectController extends \PHPCI\Controller
$form->addField($field);
$field = Form\Element\Text::create('branch', 'Default branch name', true);
$field->setValidator($this->getReferenceValidator($values));
$field->setClass('form-control')->setContainerClass('form-group')->setValue('master');
$form->addField($field);

View file

@ -40,9 +40,9 @@ class SessionController extends \PHPCI\Controller
if ($this->request->getMethod() == 'POST') {
$user = $this->userStore->getByEmail($this->getParam('email'));
if ($user && password_verify($this->getParam('password', ''), $user->getHash())) {
$_SESSION['user_id'] = $user->getId();
$_SESSION['phpci_user_id'] = $user->getId();
header('Location: ' . $this->getLoginRedirect());
die;
} else {
@ -84,7 +84,9 @@ class SessionController extends \PHPCI\Controller
*/
public function logout()
{
$_SESSION = array();
unset($_SESSION['phpci_user']);
unset($_SESSION['phpci_user_id']);
session_destroy();
header('Location: ' . PHPCI_URL);
die;
@ -147,8 +149,8 @@ MSG;
$hash = password_hash($this->getParam('password'), PASSWORD_DEFAULT);
$user->setHash($hash);
$_SESSION['user'] = $this->userStore->save($user);
$_SESSION['user_id'] = $user->getId();
$_SESSION['phpci_user'] = $this->userStore->save($user);
$_SESSION['phpci_user_id'] = $user->getId();
header('Location: ' . PHPCI_URL);
die;
@ -164,9 +166,9 @@ MSG;
{
$rtn = PHPCI_URL;
if (!empty($_SESSION['login_redirect'])) {
$rtn .= $_SESSION['login_redirect'];
$_SESSION['login_redirect'] = null;
if (!empty($_SESSION['phpci_login_redirect'])) {
$rtn .= $_SESSION['phpci_login_redirect'];
$_SESSION['phpci_login_redirect'] = null;
}
return $rtn;

View file

@ -41,19 +41,18 @@ class SettingsController extends Controller
$this->view->settings = $this->settings;
$emailSettings = array();
$authenticationSettings = array();
if (isset($this->settings['phpci']['email_settings'])) {
$emailSettings = $this->settings['phpci']['email_settings'];
}
if (isset($this->settings['phpci']['authentication_settings'])) {
$authenticationSettings = $this->settings['phpci']['authentication_settings'];
$buildSettings = array();
if (isset($this->settings['phpci']['build'])) {
$buildSettings = $this->settings['phpci']['build'];
}
$this->view->github = $this->getGithubForm();
$this->view->emailSettings = $this->getEmailForm($emailSettings);
$this->view->authenticationSettings = $this->getAuthenticationForm($authenticationSettings);
$this->view->buildSettings = $this->getBuildForm($buildSettings);
$this->view->isWriteable = $this->canWriteConfig();
if (!empty($this->settings['phpci']['github']['token'])) {
@ -65,6 +64,8 @@ class SettingsController extends Controller
public function github()
{
$this->requireAdmin();
$this->settings['phpci']['github']['id'] = $this->getParam('githubid', '');
$this->settings['phpci']['github']['secret'] = $this->getParam('githubsecret', '');
$error = $this->storeSettings();
@ -80,6 +81,8 @@ class SettingsController extends Controller
public function email()
{
$this->requireAdmin();
$this->settings['phpci']['email_settings'] = $this->getParams();
$this->settings['phpci']['email_settings']['smtp_encryption'] = $this->getParam('smtp_encryption', 0);
@ -94,10 +97,11 @@ class SettingsController extends Controller
die;
}
public function authentication()
public function build()
{
$this->settings['phpci']['authentication_settings']['state'] = $this->getParam('disable_authentication', 0);
$this->settings['phpci']['authentication_settings']['user_id'] = $_SESSION['user_id'];
$this->requireAdmin();
$this->settings['phpci']['build'] = $this->getParams();
$error = $this->storeSettings();
@ -110,7 +114,6 @@ class SettingsController extends Controller
die;
}
/**
* Github redirects users back to this URL when t
*/
@ -141,11 +144,16 @@ class SettingsController extends Controller
die;
}
/**
* Convert config to yaml and store to file.
* @return mixed
*/
protected function storeSettings()
{
$dumper = new Dumper();
$yaml = $dumper->dump($this->settings);
$yaml = $dumper->dump($this->settings, 4);
file_put_contents(APPLICATION_PATH . 'PHPCI/config.yml', $yaml);
if (error_get_last()) {
$error_get_last = error_get_last();
return $error_get_last['message'];
@ -243,8 +251,8 @@ class SettingsController extends Controller
$field->setContainerClass('form-group');
$form->addField($field);
$field = new Form\Element\Checkbox('smtp_encryption');
$field->setCheckedValue(1);
$field = new Form\Element\Select('smtp_encryption');
$field->setOptions(['' => 'None', 'tls' => 'TLS', 'ssl' => 'SSL']);
$field->setRequired(false);
$field->setLabel('Use SMTP encryption?');
$field->setContainerClass('form-group');
@ -261,6 +269,51 @@ class SettingsController extends Controller
return $form;
}
protected function getGithubUser($token)
{
$http = new HttpClient('https://api.github.com');
$user = $http->get('/user', array('access_token' => $token));
return $user['body'];
}
protected function canWriteConfig()
{
return is_writeable(APPLICATION_PATH . 'PHPCI/config.yml');
}
protected function getBuildForm($values = array())
{
$form = new Form();
$form->setMethod('POST');
$form->setAction(PHPCI_URL . 'settings/build');
$field = new Form\Element\Select('failed_after');
$field->setRequired(false);
$field->setLabel('Consider a build failed after');
$field->setClass('form-control');
$field->setContainerClass('form-group');
$field->setOptions([
300 => '5 Minutes',
900 => '15 Minutes',
1800 => '30 Minutes',
3600 => '1 Hour',
10800 => '3 Hours',
]);
$field->setValue(1800);
$form->addField($field);
$field = new Form\Element\Submit();
$field->setValue('Save &raquo;');
$field->setClass('btn btn-success pull-right');
$form->addField($field);
$form->setValues($values);
return $form;
}
protected function getAuthenticationForm($values = array())
{
$form = new Form();
@ -290,17 +343,4 @@ class SettingsController extends Controller
return $form;
}
protected function getGithubUser($token)
{
$http = new HttpClient('https://api.github.com');
$user = $http->get('/user', array('access_token' => $token));
return $user['body'];
}
protected function canWriteConfig()
{
return is_writeable(APPLICATION_PATH . 'PHPCI/config.yml');
}
}

View file

@ -49,24 +49,30 @@ class UserController extends Controller
$users = $this->userStore->getWhere(array(), 1000, 0, array(), array('email' => 'ASC'));
$this->view->users = $users;
$this->config->set('page_title', 'Users');
$this->layout->title = 'Users';
return $this->view->render();
}
public function profile()
{
$user = $_SESSION['user'];
$values = $user->getDataArray();
$user = $_SESSION['phpci_user'];
$this->layout->title = 'Edit Profile';
if ($this->request->getMethod() == 'POST') {
$name = $this->getParam('name', null);
$email = $this->getParam('email', null);
$password = $this->getParam('password', null);
$_SESSION['user'] = $this->userService->updateUser($name, $email, $password);
$_SESSION['phpci_user'] = $this->userService->updateUser($user, $name, $email, $password);
$user = $_SESSION['phpci_user'];
$this->view->updated = 1;
}
$values = $user->getDataArray();
$form = new Form();
$form->setAction(PHPCI_URL.'user/profile');
$form->setMethod('POST');
@ -109,11 +115,9 @@ class UserController extends Controller
*/
public function add()
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new ForbiddenException('You do not have permission to do that.');
}
$this->requireAdmin();
$this->config->set('page_title', 'Add User');
$this->layout->title = 'Add User';
$method = $this->request->getMethod();
@ -151,9 +155,7 @@ class UserController extends Controller
*/
public function edit($userId)
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new ForbiddenException('You do not have permission to do that.');
}
$this->requireAdmin();
$method = $this->request->getMethod();
$user = $this->userStore->getById($userId);
@ -162,6 +164,9 @@ class UserController extends Controller
throw new NotFoundException('User with ID: ' . $userId . ' does not exist.');
}
$this->layout->title = $user->getName();
$this->layout->subtitle = 'Edit User';
$values = array_merge($user->getDataArray(), $this->getParams());
$form = $this->userForm($values, 'edit/' . $userId);
@ -244,10 +249,8 @@ class UserController extends Controller
*/
public function delete($userId)
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new ForbiddenException('You do not have permission to do that.');
}
$this->requireAdmin();
$user = $this->userStore->getById($userId);
if (empty($user)) {

View file

@ -56,7 +56,6 @@ class WebhookController extends \PHPCI\Controller
foreach ($payload['commits'] as $commit) {
try {
$email = $commit['raw_author'];
$email = substr($email, 0, strpos($email, '>'));
$email = substr($email, strpos($email, '<') + 1);
@ -73,7 +72,7 @@ class WebhookController extends \PHPCI\Controller
}
/**
* Called by POSTing to /git/webhook/<project_id>?branch=<branch>&commit=<commit>
* Called by POSTing to /webhook/git/<project_id>?branch=<branch>&commit=<commit>
*
* @param string $project
*/
@ -81,6 +80,8 @@ class WebhookController extends \PHPCI\Controller
{
$branch = $this->getParam('branch');
$commit = $this->getParam('commit');
$commitMessage = $this->getParam('message');
$committer = $this->getParam('committer');
try {
if (empty($branch)) {
@ -91,8 +92,15 @@ class WebhookController extends \PHPCI\Controller
$commit = null;
}
$this->createBuild($project, $commit, $branch, null, null);
if (empty($commitMessage)) {
$commitMessage = null;
}
if (empty($committer)) {
$committer = null;
}
$this->createBuild($project, $commit, $branch, $committer, $commitMessage);
} catch (\Exception $ex) {
header('HTTP/1.1 400 Bad Request');
header('Ex: ' . $ex->getMessage());
@ -107,7 +115,19 @@ class WebhookController extends \PHPCI\Controller
*/
public function github($project)
{
$payload = json_decode($this->getParam('payload'), true);
switch ($_SERVER['CONTENT_TYPE']) {
case 'application/json':
$payload = json_decode(file_get_contents('php://input'), true);
break;
case 'application/x-www-form-urlencoded':
$payload = json_decode($this->getParam('payload'), true);
break;
default:
header('HTTP/1.1 400 Bad Request');
die('Request content type not supported');
}
// Handle Pull Request web hooks:
if (array_key_exists('pull_request', $payload)) {

View file

@ -32,6 +32,7 @@ class BuildInterpolator
$this->interpolation_vars = array();
$this->interpolation_vars['%PHPCI%'] = 1;
$this->interpolation_vars['%COMMIT%'] = $build->getCommitId();
$this->interpolation_vars['%BRANCH%'] = $build->getBranch();
$this->interpolation_vars['%PROJECT%'] = $build->getProjectId();
$this->interpolation_vars['%BUILD%'] = $build->getId();
$this->interpolation_vars['%PROJECT_TITLE%'] = $build->getProjectTitle();

View file

@ -28,11 +28,19 @@ class MailerFactory
*/
public function getSwiftMailerFromConfig()
{
$encryptionType = $this->getMailConfig('smtp_encryption');
// Workaround issue where smtp_encryption could == 1 in the past by
// checking it is a valid transport
if ($encryptionType && !in_array($encryptionType, stream_get_transports())) {
$encryptionType = null;
}
/** @var \Swift_SmtpTransport $transport */
$transport = \Swift_SmtpTransport::newInstance(
$this->getMailConfig('smtp_address'),
$this->getMailConfig('smtp_port'),
$this->getMailConfig('smtp_encryption')
$encryptionType
);
$transport->setUsername($this->getMailConfig('smtp_username'));
$transport->setPassword($this->getMailConfig('smtp_password'));

View file

@ -19,7 +19,7 @@ class User
{
public function __call($method, $params = array())
{
$user = $_SESSION['user'];
$user = $_SESSION['phpci_user'];
if (!is_object($user)) {
return null;

View file

@ -9,6 +9,13 @@ class FixDatabaseColumns extends AbstractMigration
*/
public function up()
{
$dbAdapter = $this->getAdapter();
if ($dbAdapter instanceof \Phinx\Db\Adapter\PdoAdapter) {
$pdo = $dbAdapter->getConnection();
$pdo->exec('SET foreign_key_checks = 0');
}
$build = $this->table('build');
$build->changeColumn('project_id', 'integer', array('null' => false));
$build->changeColumn('commit_id', 'string', array('limit' => 50, 'null' => false));
@ -45,5 +52,10 @@ class FixDatabaseColumns extends AbstractMigration
$user->changeColumn('hash', 'string', array('limit' => 250, 'null' => false));
$user->changeColumn('is_admin', 'integer', array('null' => false, 'default' => 0));
$user->changeColumn('name', 'string', array('limit' => 250, 'null' => false));
if ($dbAdapter instanceof \Phinx\Db\Adapter\PdoAdapter) {
$pdo = $dbAdapter->getConnection();
$pdo->exec('SET foreign_key_checks = 1');
}
}
}

View file

@ -110,16 +110,15 @@ class BuildBase extends Model
'commit_id' => array(
'type' => 'varchar',
'length' => 50,
'nullable' => true,
'default' => null,
),
'status' => array(
'type' => 'tinyint',
'length' => 4,
'type' => 'int',
'length' => 11,
'default' => null,
),
'log' => array(
'type' => 'longtext',
'type' => 'text',
'nullable' => true,
'default' => null,
),
@ -155,7 +154,7 @@ class BuildBase extends Model
'default' => null,
),
'extra' => array(
'type' => 'longtext',
'type' => 'text',
'nullable' => true,
'default' => null,
),
@ -382,10 +381,12 @@ class BuildBase extends Model
/**
* Set the value of CommitId / commit_id.
*
* Must not be null.
* @param $value string
*/
public function setCommitId($value)
{
$this->_validateNotNull('CommitId', $value);
$this->_validateString('CommitId', $value);
if ($this->data['commit_id'] === $value) {

View file

@ -91,17 +91,15 @@ class BuildMetaBase extends Model
'build_id' => array(
'type' => 'int',
'length' => 11,
'nullable' => true,
'default' => null,
),
'meta_key' => array(
'type' => 'varchar',
'length' => 255,
'length' => 250,
'default' => null,
),
'meta_value' => array(
'type' => 'longtext',
'nullable' => true,
'type' => 'text',
'default' => null,
),
);
@ -238,10 +236,12 @@ class BuildMetaBase extends Model
/**
* Set the value of BuildId / build_id.
*
* Must not be null.
* @param $value int
*/
public function setBuildId($value)
{
$this->_validateNotNull('BuildId', $value);
$this->_validateInt('BuildId', $value);
if ($this->data['build_id'] === $value) {
@ -276,10 +276,12 @@ class BuildMetaBase extends Model
/**
* Set the value of MetaValue / meta_value.
*
* Must not be null.
* @param $value string
*/
public function setMetaValue($value)
{
$this->_validateNotNull('MetaValue', $value);
$this->_validateString('MetaValue', $value);
if ($this->data['meta_value'] === $value) {

View file

@ -38,11 +38,11 @@ class ProjectBase extends Model
'reference' => null,
'branch' => null,
'ssh_private_key' => null,
'ssh_public_key' => null,
'type' => null,
'access_information' => null,
'last_commit' => null,
'build_config' => null,
'ssh_public_key' => null,
'allow_public_status' => null,
);
@ -56,11 +56,11 @@ class ProjectBase extends Model
'reference' => 'getReference',
'branch' => 'getBranch',
'ssh_private_key' => 'getSshPrivateKey',
'ssh_public_key' => 'getSshPublicKey',
'type' => 'getType',
'access_information' => 'getAccessInformation',
'last_commit' => 'getLastCommit',
'build_config' => 'getBuildConfig',
'ssh_public_key' => 'getSshPublicKey',
'allow_public_status' => 'getAllowPublicStatus',
// Foreign key getters:
@ -76,11 +76,11 @@ class ProjectBase extends Model
'reference' => 'setReference',
'branch' => 'setBranch',
'ssh_private_key' => 'setSshPrivateKey',
'ssh_public_key' => 'setSshPublicKey',
'type' => 'setType',
'access_information' => 'setAccessInformation',
'last_commit' => 'setLastCommit',
'build_config' => 'setBuildConfig',
'ssh_public_key' => 'setSshPublicKey',
'allow_public_status' => 'setAllowPublicStatus',
// Foreign key setters:
@ -109,23 +109,18 @@ class ProjectBase extends Model
),
'branch' => array(
'type' => 'varchar',
'length' => 250,
'default' => null,
'length' => 50,
'default' => 'master',
),
'ssh_private_key' => array(
'type' => 'text',
'nullable' => true,
'default' => null,
),
'ssh_public_key' => array(
'type' => 'text',
'nullable' => true,
'default' => null,
),
'type' => array(
'type' => 'varchar',
'length' => 50,
'default' => 1,
'default' => null,
),
'access_information' => array(
'type' => 'varchar',
@ -144,9 +139,14 @@ class ProjectBase extends Model
'nullable' => true,
'default' => null,
),
'ssh_public_key' => array(
'type' => 'text',
'nullable' => true,
'default' => null,
),
'allow_public_status' => array(
'type' => 'tinyint',
'length' => 4,
'type' => 'int',
'length' => 11,
),
);
@ -224,18 +224,6 @@ class ProjectBase extends Model
return $rtn;
}
/**
* Get the value of SshPublicKey / ssh_public_key.
*
* @return string
*/
public function getSshPublicKey()
{
$rtn = $this->data['ssh_public_key'];
return $rtn;
}
/**
* Get the value of Type / type.
*
@ -284,6 +272,18 @@ class ProjectBase extends Model
return $rtn;
}
/**
* Get the value of SshPublicKey / ssh_public_key.
*
* @return string
*/
public function getSshPublicKey()
{
$rtn = $this->data['ssh_public_key'];
return $rtn;
}
/**
* Get the value of AllowPublicStatus / allow_public_status.
*
@ -394,24 +394,6 @@ class ProjectBase extends Model
$this->_setModified('ssh_private_key');
}
/**
* Set the value of SshPublicKey / ssh_public_key.
*
* @param $value string
*/
public function setSshPublicKey($value)
{
$this->_validateString('SshPublicKey', $value);
if ($this->data['ssh_public_key'] === $value) {
return;
}
$this->data['ssh_public_key'] = $value;
$this->_setModified('ssh_public_key');
}
/**
* Set the value of Type / type.
*
@ -486,6 +468,24 @@ class ProjectBase extends Model
$this->_setModified('build_config');
}
/**
* Set the value of SshPublicKey / ssh_public_key.
*
* @param $value string
*/
public function setSshPublicKey($value)
{
$this->_validateString('SshPublicKey', $value);
if ($this->data['ssh_public_key'] === $value) {
return;
}
$this->data['ssh_public_key'] = $value;
$this->_setModified('ssh_public_key');
}
/**
* Set the value of AllowPublicStatus / allow_public_status.
*

View file

@ -90,14 +90,12 @@ class UserBase extends Model
'default' => null,
),
'is_admin' => array(
'type' => 'tinyint',
'length' => 1,
'default' => null,
'type' => 'int',
'length' => 11,
),
'name' => array(
'type' => 'varchar',
'length' => 250,
'nullable' => true,
'default' => null,
),
);
@ -259,10 +257,12 @@ class UserBase extends Model
/**
* Set the value of Name / name.
*
* Must not be null.
* @param $value string
*/
public function setName($value)
{
$this->_validateNotNull('Name', $value);
$this->_validateString('Name', $value);
if ($this->data['name'] === $value) {

View file

@ -88,4 +88,28 @@ class Project extends ProjectBase
return $this->data['branch'];
}
}
public function getIcon()
{
switch ($this->getType()) {
case 'github':
$icon = 'github';
break;
case 'bitbucket':
$icon = 'bitbucket';
break;
case 'git':
case 'gitlab':
$icon = 'git';
break;
default:
$icon = 'cog';
break;
}
return $icon;
}
}

85
PHPCI/Plugin/Gulp.php Normal file
View file

@ -0,0 +1,85 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/**
* Gulp Plugin - Provides access to gulp functionality.
* @author Dirk Heilig <dirk@heilig-online.com>
* @package PHPCI
* @subpackage Plugins
*/
class Gulp implements \PHPCI\Plugin
{
protected $directory;
protected $task;
protected $preferDist;
protected $phpci;
protected $build;
protected $gulp;
protected $gulpfile;
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$path = $phpci->buildPath;
$this->build = $build;
$this->phpci = $phpci;
$this->directory = $path;
$this->task = null;
$this->gulp = $this->phpci->findBinary('gulp');
$this->gulpfile = 'gulpfile.js';
// Handle options:
if (isset($options['directory'])) {
$this->directory = $path . '/' . $options['directory'];
}
if (isset($options['task'])) {
$this->task = $options['task'];
}
if (isset($options['gulp'])) {
$this->gulp = $options['gulp'];
}
if (isset($options['gulpfile'])) {
$this->gulpfile = $options['gulpfile'];
}
}
/**
* Executes gulp and runs a specified command (e.g. install / update)
*/
public function execute()
{
// if npm does not work, we cannot use gulp, so we return false
$cmd = 'cd %s && npm install';
if (IS_WIN) {
$cmd = 'cd /d %s && npm install';
}
if (!$this->phpci->executeCommand($cmd, $this->directory)) {
return false;
}
// build the gulp command
$cmd = 'cd %s && ' . $this->gulp;
if (IS_WIN) {
$cmd = 'cd /d %s && ' . $this->gulp;
}
$cmd .= ' --no-color';
$cmd .= ' --gulpfile %s';
$cmd .= ' %s'; // the task that will be executed
// and execute it
return $this->phpci->executeCommand($cmd, $this->directory, $this->gulpfile, $this->task);
}
}

View file

@ -62,6 +62,7 @@ class Irc implements \PHPCI\Plugin
$sock = fsockopen($this->server, $this->port);
fputs($sock, 'USER ' . $this->nick . ' phptesting.org ' . $this->nick . ' :' . $this->nick . "\r\n");
fputs($sock, 'NICK ' . $this->nick . "\r\n");
fputs($sock, 'JOIN ' . $this->room . "\r\n");
fputs($sock, 'PRIVMSG ' . $this->room . ' :' . $msg . "\r\n");
while (fgets($sock)) {

240
PHPCI/Plugin/Phar.php Normal file
View file

@ -0,0 +1,240 @@
<?php
namespace PHPCI\Plugin;
use Exception;
use PHPCI\Builder;
use PHPCI\Model\Build;
use Phar as PHPPhar;
/**
* Phar Plugin
*/
class Phar implements \PHPCI\Plugin
{
/**
* PHPCI
* @var Builder
*/
protected $phpci;
/**
* Build
* @var Build
*/
protected $build;
/**
* Output Directory
* @var string
*/
protected $directory;
/**
* Phar Filename
* @var string
*/
protected $filename;
/**
* Regular Expression Filename Capture
* @var string
*/
protected $regexp;
/**
* Stub Filename
* @var string
*/
protected $stub;
/**
* Standard Constructor
*
* $options['directory'] Output Directory. Default: %BUILDPATH%
* $options['filename'] Phar Filename. Default: build.phar
* $options['regexp'] Regular Expression Filename Capture. Default: /\.php$/
* $options['stub'] Stub Content. No Default Value
*
* @param Builder $phpci
* @param Build $build
* @param array $options
*/
public function __construct(Builder $phpci, Build $build, array $options = array())
{
// Basic
$this->phpci = $phpci;
$this->build = $build;
// Directory?
if (isset($options['directory'])) {
$this->setDirectory($options['directory']);
}
// Filename?
if (isset($options['filename'])) {
$this->setFilename($options['filename']);
}
// RegExp?
if (isset($options['regexp'])) {
$this->setRegExp($options['regexp']);
}
// Stub?
if (isset($options['stub'])) {
$this->setStub($options['stub']);
}
}
/**
* Returns PHPCI
*
* @return PHPCI
*/
public function getPHPCI()
{
return $this->phpci;
}
/**
* Returns Build
*
* @return Build
*/
public function getBuild()
{
return $this->build;
}
/**
* Directory Setter
*
* @param string $directory Configuration Value
* @return Phar Fluent Interface
*/
public function setDirectory($directory)
{
$this->directory = $directory;
return $this;
}
/**
* Directory Getter
*
* @return string Configurated or Default Value
*/
public function getDirectory()
{
if (!isset($this->directory)) {
$this->setDirectory($this->getPHPCI()->buildPath);
}
return $this->directory;
}
/**
* Filename Setter
*
* @param string $filename Configuration Value
* @return Phar Fluent Interface
*/
public function setFilename($filename)
{
$this->filename = $filename;
return $this;
}
/**
* Filename Getter
*
* @return string Configurated or Default Value
*/
public function getFilename()
{
if (!isset($this->filename)) {
$this->setFilename('build.phar');
}
return $this->filename;
}
/**
* Regular Expression Setter
*
* @param string $regexp Configuration Value
* @return Phar Fluent Interface
*/
public function setRegExp($regexp)
{
$this->regexp = $regexp;
return $this;
}
/**
* Regular Expression Getter
*
* @return string Configurated or Default Value
*/
public function getRegExp()
{
if (!isset($this->regexp)) {
$this->setRegExp('/\.php$/');
}
return $this->regexp;
}
/**
* Stub Filename Setter
*
* @param string $stub Configuration Value
* @return Phar Fluent Interface
*/
public function setStub($stub)
{
$this->stub = $stub;
return $this;
}
/**
* Stub Filename Getter
*
* @return string Configurated Value
*/
public function getStub()
{
return $this->stub;
}
public function getStubContent()
{
$content = '';
$filename = $this->getStub();
if ($filename) {
$content = file_get_contents($this->getPHPCI()->buildPath . '/' . $this->getStub());
}
return $content;
}
// Execution
public function execute()
{
$success = false;
try {
$phar = new PHPPhar($this->getDirectory() . '/' . $this->getFilename(), 0, $this->getFilename());
$phar->buildFromDirectory($this->getPHPCI()->buildPath, $this->getRegExp());
$stub = $this->getStubContent();
if ($stub) {
$phar->setStub($stub);
}
$success = true;
} catch (Exception $e) {
$this->getPHPCI()->log('Phar Plugin Internal Error');
$this->getPHPCI()->log($e->getMessage());
}
return $success;
}
}

View file

@ -90,7 +90,7 @@ class PhpCpd implements \PHPCI\Plugin
$tmpfilename = tempnam('/tmp', 'phpcpd');
$cmd = $phpcpd . ' --log-pmd="%s" %s "%s"';
$cmd = $phpcpd . ' --log-pmd "%s" %s "%s"';
$success = $this->phpci->executeCommand($cmd, $tmpfilename, $ignore, $this->path);
print $this->phpci->getLastOutput();

View file

@ -48,7 +48,7 @@ class PhpParallelLint implements \PHPCI\Plugin
$this->ignore = $this->phpci->ignore;
if (isset($options['directory'])) {
$this->directory = $options['directory'];
$this->directory = $phpci->buildPath.$options['directory'];
}
if (isset($options['ignore'])) {

View file

@ -58,10 +58,91 @@ class PhpSpec implements PHPCI\Plugin
return false;
}
$success = $this->phpci->executeCommand($phpspec . ' --format=pretty --no-code-generation run');
$success = $this->phpci->executeCommand($phpspec . ' --format=junit --no-code-generation run');
$output = $this->phpci->getLastOutput();
chdir($curdir);
/*
* process xml output
*
* <testsuites time=FLOAT tests=INT failures=INT errors=INT>
* <testsuite name=STRING time=FLOAT tests=INT failures=INT errors=INT skipped=INT>
* <testcase name=STRING time=FLOAT classname=STRING status=STRING/>
* </testsuite>
* </testsuites
*/
$xml = new \SimpleXMLElement($output);
$attr = $xml->attributes();
$data = array(
'time' => (float)$attr['time'],
'tests' => (int)$attr['tests'],
'failures' => (int)$attr['failures'],
'errors' => (int)$attr['errors'],
// now all the tests
'suites' => array()
);
/**
* @var \SimpleXMLElement $group
*/
foreach ($xml->xpath('testsuite') as $group) {
$attr = $group->attributes();
$suite = array(
'name' => (String)$attr['name'],
'time' => (float)$attr['time'],
'tests' => (int)$attr['tests'],
'failures' => (int)$attr['failures'],
'errors' => (int)$attr['errors'],
'skipped' => (int)$attr['skipped'],
// now the cases
'cases' => array()
);
/**
* @var \SimpleXMLElement $child
*/
foreach ($group->xpath('testcase') as $child) {
$attr = $child->attributes();
$case = array(
'name' => (String)$attr['name'],
'classname' => (String)$attr['classname'],
'time' => (float)$attr['time'],
'status' => (String)$attr['status'],
);
if ($case['status']=='failed') {
$error = array();
/*
* ok, sad, we had an error
*
* there should be one - foreach makes this easier
*/
foreach ($child->xpath('failure') as $failure) {
$attr = $failure->attributes();
$error['type'] = (String)$attr['type'];
$error['message'] = (String)$attr['message'];
}
foreach ($child->xpath('system-err') as $system_err) {
$error['raw'] = (String)$system_err;
}
$case['error'] = $error;
}
$suite['cases'][] = $case;
}
$data['suites'][] = $suite;
}
$this->build->storeMeta('phpspec', $data);
return $success;
}
}

View file

@ -129,7 +129,7 @@ class PhpUnit implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
// Run any dirs next. Again this can be either a single value or an array.
if ($this->directory !== null) {
$success &= $this->runDir();
$success &= $this->runDir($this->directory);
}
$tapString = $this->phpci->getLastOutput();
@ -182,10 +182,10 @@ class PhpUnit implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
}
}
protected function runDir()
protected function runDir($directory)
{
if (is_array($this->directory)) {
return $this->recurseArg($this->directory, array($this, "runDir"));
if (is_array($directory)) {
return $this->recurseArg($directory, array($this, "runDir"));
} else {
$curdir = getcwd();
chdir($this->phpci->buildPath);
@ -198,7 +198,7 @@ class PhpUnit implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
}
$cmd = $phpunit . ' --tap %s "%s"';
$success = $this->phpci->executeCommand($cmd, $this->args, $this->phpci->buildPath . $this->directory);
$success = $this->phpci->executeCommand($cmd, $this->args, $this->phpci->buildPath . $directory);
chdir($curdir);
return $success;
}

View file

@ -67,7 +67,7 @@ class FilesPluginInformation implements InstalledPluginInformation
$this->pluginInfo = array();
foreach ($this->files as $fileInfo) {
if ($fileInfo instanceof \SplFileInfo) {
if ($fileInfo->isFile()) {
if ($fileInfo->isFile() && $fileInfo->getExtension()=='php') {
$this->addPluginFromFile($fileInfo);
}
}
@ -76,13 +76,17 @@ class FilesPluginInformation implements InstalledPluginInformation
protected function addPluginFromFile(\SplFileInfo $fileInfo)
{
$newPlugin = new \stdClass();
$newPlugin->class = $this->getFullClassFromFile($fileInfo);
$newPlugin->source = "core";
$parts = explode('\\', $newPlugin->class);
$newPlugin->name = end($parts);
$class = $this->getFullClassFromFile($fileInfo);
$this->pluginInfo[] = $newPlugin;
if (!is_null($class)) {
$newPlugin = new \stdClass();
$newPlugin->class = $class;
$newPlugin->source = "core";
$parts = explode('\\', $newPlugin->class);
$newPlugin->name = end($parts);
$this->pluginInfo[] = $newPlugin;
}
}
protected function getFullClassFromFile(\SplFileInfo $fileInfo)
@ -90,15 +94,20 @@ class FilesPluginInformation implements InstalledPluginInformation
//TODO: Something less horrible than a regular expression
// on the contents of a file
$contents = file_get_contents($fileInfo->getRealPath());
$matches = array();
preg_match('#class +([A-Za-z]+) +implements#i', $contents, $matches);
$className = $matches[1];
$matches = array();
preg_match('#namespace +([A-Za-z\\\\]+);#i', $contents, $matches);
$namespace = $matches[1];
return $namespace . '\\' . $className;
if (isset($matches[1])) {
$className = $matches[1];
$matches = array();
preg_match('#namespace +([A-Za-z\\\\]+);#i', $contents, $matches);
$namespace = $matches[1];
return $namespace . '\\' . $className;
} else {
return null;
}
}
}

View file

@ -8,6 +8,7 @@ class TapParser
const TEST_LINE_PATTERN = '/(ok|not ok)\s+[0-9]+\s+\-\s+([^\n]+)::([^\n]+)/';
const TEST_MESSAGE_PATTERN = '/message\:\s+\'([^\']+)\'/';
const TEST_COVERAGE_PATTERN = '/Generating code coverage report/';
const TEST_SKIP_PATTERN = '/ok\s+[0-9]+\s+\-\s+#\s+SKIP/';
/**
* @var string
@ -43,7 +44,7 @@ class TapParser
throw new \Exception('TapParser only supports TAP version 13');
}
if (preg_match(self::TEST_COVERAGE_PATTERN, $lines[count($lines) - 1])) {
if (isset($lines[count($lines) - 1]) && preg_match(self::TEST_COVERAGE_PATTERN, $lines[count($lines) - 1])) {
array_pop($lines);
if ($lines[count($lines) - 1] == "") {
array_pop($lines);
@ -57,7 +58,8 @@ class TapParser
$totalTests = (int) $matches[2];
}
if (preg_match(self::TEST_COUNTS_PATTERN, $lines[count($lines) - 1], $matches)) {
if (isset($lines[count($lines) - 1]) &&
preg_match(self::TEST_COUNTS_PATTERN, $lines[count($lines) - 1], $matches)) {
array_pop($lines);
$totalTests = (int) $matches[2];
}
@ -92,6 +94,8 @@ class TapParser
);
$rtn[] = $item;
} elseif (preg_match(self::TEST_SKIP_PATTERN, $line, $matches)) {
$rtn[] = array('message' => 'SKIP');
} elseif (preg_match(self::TEST_MESSAGE_PATTERN, $line, $matches)) {
$rtn[count($rtn) - 1]['message'] = $matches[1];
}

View file

@ -56,7 +56,6 @@ class BuildMetaStoreBase extends Store
$add .= ' LIMIT ' . $limit;
}
$count = null;
$query = 'SELECT * FROM `build_meta` WHERE `project_id` = :project_id' . $add;
$stmt = Database::getConnection($useConnection)->prepare($query);
@ -70,6 +69,9 @@ class BuildMetaStoreBase extends Store
};
$rtn = array_map($map, $res);
$count = count($rtn);
return array('items' => $rtn, 'count' => $count);
} else {
return array('items' => array(), 'count' => 0);
@ -88,7 +90,6 @@ class BuildMetaStoreBase extends Store
$add .= ' LIMIT ' . $limit;
}
$count = null;
$query = 'SELECT * FROM `build_meta` WHERE `build_id` = :build_id' . $add;
$stmt = Database::getConnection($useConnection)->prepare($query);
@ -102,6 +103,9 @@ class BuildMetaStoreBase extends Store
};
$rtn = array_map($map, $res);
$count = count($rtn);
return array('items' => $rtn, 'count' => $count);
} else {
return array('items' => array(), 'count' => 0);

View file

@ -56,7 +56,6 @@ class BuildStoreBase extends Store
$add .= ' LIMIT ' . $limit;
}
$count = null;
$query = 'SELECT * FROM `build` WHERE `project_id` = :project_id' . $add;
$stmt = Database::getConnection($useConnection)->prepare($query);
@ -70,6 +69,9 @@ class BuildStoreBase extends Store
};
$rtn = array_map($map, $res);
$count = count($rtn);
return array('items' => $rtn, 'count' => $count);
} else {
return array('items' => array(), 'count' => 0);
@ -88,7 +90,6 @@ class BuildStoreBase extends Store
$add .= ' LIMIT ' . $limit;
}
$count = null;
$query = 'SELECT * FROM `build` WHERE `status` = :status' . $add;
$stmt = Database::getConnection($useConnection)->prepare($query);
@ -102,6 +103,9 @@ class BuildStoreBase extends Store
};
$rtn = array_map($map, $res);
$count = count($rtn);
return array('items' => $rtn, 'count' => $count);
} else {
return array('items' => array(), 'count' => 0);

View file

@ -56,7 +56,6 @@ class ProjectStoreBase extends Store
$add .= ' LIMIT ' . $limit;
}
$count = null;
$query = 'SELECT * FROM `project` WHERE `title` = :title' . $add;
$stmt = Database::getConnection($useConnection)->prepare($query);
@ -70,6 +69,9 @@ class ProjectStoreBase extends Store
};
$rtn = array_map($map, $res);
$count = count($rtn);
return array('items' => $rtn, 'count' => $count);
} else {
return array('items' => array(), 'count' => 0);

View file

@ -10,6 +10,7 @@
namespace PHPCI\Store;
use b8\Database;
use PHPCI\BuildFactory;
use PHPCI\Model\Build;
use PHPCI\Store\Base\BuildStoreBase;
@ -21,11 +22,22 @@ use PHPCI\Store\Base\BuildStoreBase;
*/
class BuildStore extends BuildStoreBase
{
public function getLatestBuilds($projectId)
public function getLatestBuilds($projectId = null, $limit = 5)
{
$query = 'SELECT * FROM build WHERE project_id = :pid ORDER BY id DESC LIMIT 5';
$where = '';
if (!is_null($projectId)) {
$where = ' WHERE `project_id` = :pid ';
}
$query = 'SELECT * FROM build '.$where.' ORDER BY id DESC LIMIT :limit';
$stmt = Database::getConnection('read')->prepare($query);
$stmt->bindValue(':pid', $projectId);
if (!is_null($projectId)) {
$stmt->bindValue(':pid', $projectId);
}
$stmt->bindValue(':limit', $limit, \PDO::PARAM_INT);
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
@ -41,6 +53,22 @@ class BuildStore extends BuildStoreBase
}
}
public function getLastBuildByStatus($projectId = null, $status = Build::STATUS_SUCCESS)
{
$query = 'SELECT * FROM build WHERE project_id = :pid AND status = :status ORDER BY id DESC LIMIT 1';
$stmt = Database::getConnection('read')->prepare($query);
$stmt->bindValue(':pid', $projectId);
$stmt->bindValue(':status', $status);
if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
return new Build($data);
}
} else {
return array();
}
}
public function getByProjectAndCommit($projectId, $commitId)
{
$query = 'SELECT * FROM `build` WHERE `project_id` = :project_id AND `commit_id` = :commit_id';

View file

@ -9,6 +9,8 @@
namespace PHPCI\Store;
use b8\Database;
use PHPCI\Model\Project;
use PHPCI\Store\Base\ProjectStoreBase;
/**
@ -19,5 +21,45 @@ use PHPCI\Store\Base\ProjectStoreBase;
*/
class ProjectStore extends ProjectStoreBase
{
// This class has been left blank so that you can modify it - changes in this file will not be overwritten.
public function getKnownBranches($projectId)
{
$query = 'SELECT DISTINCT branch from build WHERE project_id = :pid';
$stmt = Database::getConnection('read')->prepare($query);
$stmt->bindValue(':pid', $projectId);
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) {
return $item['branch'];
};
$rtn = array_map($map, $res);
return $rtn;
} else {
return array();
}
}
public function getAll()
{
$query = 'SELECT * FROM `project` ORDER BY `title` ASC';
$stmt = Database::getConnection('read')->prepare($query);
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) {
return new Project($item);
};
$rtn = array_map($map, $res);
$count = count($rtn);
return array('items' => $rtn, 'count' => $count);
} else {
return array('items' => array(), 'count' => 0);
}
}
}

View file

@ -0,0 +1,20 @@
<li>
<a href="<?php print PHPCI_URL; ?>build/view/<?php print $build->getId(); ?>">
<?php if ($build->getCommitterEmail()): ?>
<div class="pull-left">
<img src="https://www.gravatar.com/avatar/<?php print md5($build->getCommitterEmail()); ?>?d=mm&s=40" class="img-circle" alt="">
</div>
<?php endif; ?>
<h4>
<?php print $build->getProject()->getTitle(); ?>
<?php if ($build->getStatus() == \PHPCI\Model\Build::STATUS_NEW): ?>
<small class="pull-right">Created <?php print $build->getCreated()->format('g:ia'); ?></small>
<?php elseif ($build->getStatus() == \PHPCI\Model\Build::STATUS_RUNNING): ?>
<small class="pull-right">Started <?php print $build->getStarted()->format('g:ia'); ?></small>
<?php endif; ?>
</h4>
<p>Branch: <?php print $build->getBranch(); ?></p>
</a>
</li>

View file

@ -1,17 +1,15 @@
<div class="build-info-panel panel panel-default">
<img class="pull-left" src="//www.gravatar.com/avatar/<?php print md5($build->getCommitterEmail()); ?>?d=mm">
<div class="panel-heading">
<h1 class="panel-title">
<a href="<?php print PHPCI_URL; ?>project/view/<?php print $build->getProjectId(); ?>">
<?php print $build->getProject()->getTitle(); ?></a>
<span>#<?php print $build->getId(); ?></span>
<div class="build-info-panel box box-solid">
<div class="box-header">
<h1 class="box-title">
Committed by <?php print $build->getCommitterEmail(); ?>
<label class="pull-right label"></label>
</h1>
</div>
<div class="panel-body">
<div class="box-body">
<img class="pull-left" src="//www.gravatar.com/avatar/<?php print md5($build->getCommitterEmail()); ?>?d=mm">
<div id="build-info">
<?php if ($build->getCommitMessage()): ?>
<div class="commit-message">
@ -19,8 +17,7 @@
</div>
<?php endif; ?>
<strong>Branch: </strong> <?php print $build->getBranch(); ?><br>
<strong>Committer: </strong> <?php print $build->getCommitterEmail(); ?>
<strong>Branch: </strong> <?php print $build->getBranch(); ?>
<?php if ($build->getCommitId() != 'Manual'): ?>
<br><strong>Commit ID: </strong> <?php print $build->getCommitId(); ?><br>
@ -30,35 +27,19 @@
</div>
<div class="row">
<div class="col-lg-3">
<div class="panel panel-default affix">
<div class="panel-heading">
<h4 class="panel-title">Options</h4>
</div>
<ul class="list-group">
<a class="list-group-item" href="<?php echo PHPCI_URL ?>build/rebuild/<?php print $build->getId(); ?>"><i class="icon-cog"></i> Rebuild</a>
<?php if($this->User()->getIsAdmin()): ?>
<a class="list-group-item" href="<?php echo PHPCI_URL ?>build/delete/<?php print $build->getId(); ?>" id="delete-build"><i class="icon-trash"></i> Delete Build</a>
<?php endif; ?>
</ul>
<div class="panel-heading">
<h4 class="panel-title">Quick links</h4>
</div>
<ul class="list-group" id="anchorPlugins"></ul>
</div>
</div>
<div class="col-lg-9">
<div class="col-lg-12">
<div id="status"></div>
<div id="plugins" class="row"></div>
</div>
</div>
<script src="<?php print PHPCI_URL; ?>assets/js/build.js"></script>
<script>
var PHPCI = new PHPCIObject(<?php print $build->getId() ?>);
PHPCI.buildData = <?php print $data; ?>;
PHPCI.fileLinkTemplate = <?php print json_encode($build->getFileLinkTemplate()); ?>;
var ActiveBuild = new Build(<?php print $build->getId() ?>);
ActiveBuild.buildData = <?php print $data; ?>;
ActiveBuild.fileLinkTemplate = <?php print json_encode($build->getFileLinkTemplate()); ?>;
</script>
<?php
@ -69,7 +50,7 @@ foreach ($plugins as $plugin) {
<script>
$(document).ready(function() {
PHPCI.renderPlugins();
ActiveBuild.renderPlugins();
$('#delete-build').on('click', function (e) {
e.preventDefault();
@ -86,41 +67,38 @@ foreach ($plugins as $plugin) {
});
function updateBuildStatus(status) {
var statusClass = null;
var statusText = null;
switch (status) {
case 0:
statusClass = 'info';
statusText = 'Pending';
$('.build-info-panel')
.removeClass('bg-yellow')
.removeClass('bg-green')
.removeClass('bg-red')
.addClass('bg-blue');
break;
case 1:
statusClass = 'warning';
statusText = 'Running';
$('.build-info-panel')
.removeClass('bg-green')
.removeClass('bg-red')
.removeClass('bg-blue')
.addClass('bg-yellow');
break;
case 2:
statusClass = 'success';
statusText = 'Success';
$('.build-info-panel')
.removeClass('bg-yellow')
.removeClass('bg-red')
.removeClass('bg-blue')
.addClass('bg-green');
break;
case 3:
statusClass = 'danger';
statusText = 'Failed';
$('.build-info-panel')
.removeClass('bg-yellow')
.removeClass('bg-green')
.removeClass('bg-blue')
.addClass('bg-red');
break;
}
$('.build-info-panel')
.removeClass('panel-info')
.removeClass('panel-warning')
.removeClass('panel-success')
.removeClass('panel-danger')
.addClass('panel-' + statusClass);
$('.build-info-panel .label')
.removeClass('label-info')
.removeClass('label-warning')
.removeClass('label-success')
.removeClass('label-danger')
.addClass('label-' + statusClass)
.text(statusText);
}
</script>

View file

@ -66,8 +66,8 @@
<div class="build-info-panel panel panel-<?php print $statusClass; ?>">
<img class="pull-left" src="//www.gravatar.com/avatar/<?php print md5($latest->getCommitterEmail()); ?>?d=mm">
<div class="panel-heading">
<h1 class="panel-title">
<div class="box-header">
<h1 class="box-title">
<a href="/project/view/<?php print $latest->getProjectId(); ?>">
<?php print $latest->getProject()->getTitle(); ?></a>
<span>#<?php print $latest->getId(); ?></span>
@ -76,7 +76,7 @@
</h1>
</div>
<div class="panel-body">
<div class="box-body">
<div id="build-info">
<?php if ($latest->getCommitMessage()): ?>
<div class="commit-message">
@ -97,8 +97,8 @@
<!-- Recent builds: -->
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">Builds</h3></div>
<div class="box box-primary">
<div class="box-header"><h3 class="box-title">Builds</h3></div>
<table class="table table-striped table-bordered">
<thead>
<tr>

View file

@ -47,19 +47,22 @@ switch($build->getStatus())
}
?></a></td>
<td>
<td class="hidden-md hidden-sm hidden-xs">
<?php
if ($build->getCommitId() !== 'Manual') {
print '<a href="' . $build->getCommitLink() . '">';
}
print $build->getCommitId();
if ($build->getCommitId() !== 'Manual') {
print '</a>';
print sprintf(
'<a href="%s" target="_blank">%s (%s)</a>',
$build->getCommitLink(),
substr($build->getCommitId(), 0, 7),
$build->getCommitterEmail()
);
} else {
print 'Manual Build';
}
?>
</td>
<td><a href="<?php print $build->getBranchLink(); ?>"><?php print $build->getBranch(); ?></a></td>
<td><a href="<?php print $build->getBranchLink(); ?>" target="_blank"><?php print $build->getBranch(); ?></a></td>
<td>
<span class='label label-<?php echo $subcls ?>'><?php echo $status ?></span>
</td>

View file

@ -1,93 +1,102 @@
<div id="title">
<h1><i class="glyphicon glyphicon-home"></i> Dashboard</h1>
</div>
<div class="row">
<div class="col-lg-3">
<?php if (count($projects)): ?>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">Projects</h4>
</div>
<div class="list-group">
<?php foreach($projects as $project): ?>
<a class="list-group-item" href="<?php echo PHPCI_URL ?>project/view/<?php print $project->getId(); ?>"><?php print htmlspecialchars($project->getTitle()); ?></a>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<div class="col-sm-5">
<?php print $summary; ?>
</div>
<div class="col-lg-9">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">Project Overview</h3></div>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Health</th>
<th>Project</th>
<th>Last Success</th>
<th>Last Failure</th>
<th>Success/Failures</th>
<th style="width: 100px"></th>
</tr>
</thead>
<tbody id="project-overview">
<?php print $summary; ?>
</tbody>
</table>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Last 5 Builds</h3>
<div class="col-sm-7 pull-left">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Latest Builds</h3>
</div>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Project</th>
<th>Commit</th>
<th>Branch</th>
<th>Status</th>
<th style="width: 100px"></th>
</tr>
</thead>
<tbody id="latest-builds">
<?php print $builds; ?>
</tbody>
</table>
<div class="box-body">
<ul class="timeline">
<?php $last = new \DateTime('-1 Year'); ?>
<?php
foreach ($builds as $build):
switch ($build->getStatus()) {
case \PHPCI\Model\Build::STATUS_NEW:
$updated = $build->getCreated();
$label = 'Created';
$color = 'blue';
break;
case \PHPCI\Model\Build::STATUS_RUNNING:
$updated = $build->getStarted();
$label = 'Started';
$color = 'yellow';
break;
case \PHPCI\Model\Build::STATUS_SUCCESS:
$updated = $build->getFinished();
$label = 'Successful';
$color = 'green';
break;
case \PHPCI\Model\Build::STATUS_FAILED:
$updated = $build->getFinished();
$label = 'Failed';
$color = 'red';
break;
}
if ($updated->format('Y-m-d') != $last->format('Y-m-d')): $last = $updated;
?>
<li class="time-label">
<span class="bg-gray">
<?php print $last->format('M j Y'); ?>
</span>
</li>
<?php endif; ?>
<!-- /.timeline-label -->
<!-- timeline item -->
<li>
<i class="fa fa-<?php print $build->getProject()->getIcon(); ?> bg-<?php print $color; ?>"></i>
<div class="timeline-item">
<span class="time"><i class="fa fa-clock-o"></i> <?php print $updated->format('g:ia'); ?></span>
<h3 class="timeline-header">
<a href="<?php print PHPCI_URL; ?>project/view/<?php print $build->getProjectId(); ?>">
<?php print $build->getProject()->getTitle(); ?>
</a>
-
<a href="<?php print PHPCI_URL; ?>build/view/<?php print $build->getId(); ?>">
Build #<?php print $build->getId(); ?>
</a>
-
<?php print $label; ?>
</h3>
<div class="timeline-body">
<?php
if ($build->getCommitId() !== 'Manual') {
print sprintf(
'<a href="%s" target="_blank">%s (%s)</a>',
$build->getCommitLink(),
substr($build->getCommitId(), 0, 7),
$build->getCommitterEmail()
);
} else {
print 'Manual Build';
}
?>
- <?php print $build->getCommitMessage(); ?>
</div>
</div>
</li>
<!-- END timeline item -->
<?php endforeach; ?>
<li>
<i class="fa fa-clock-o"></i>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<script>
var refreshProjectData = function()
{
$.ajax({
url: '<?php echo PHPCI_URL ?>home/latest',
success: function (data) {
$('#latest-builds').html(data);
$('#latest-builds').trigger('latest-builds:reload');
},
error: handleFailedAjax
});
$.ajax({
url: '<?php echo PHPCI_URL ?>home/summary',
success: function (data) {
$('#project-overview').html(data);
$('#project-overview').trigger('project-overview:reload');
},
error: handleFailedAjax
});
};
setInterval(refreshProjectData, 10000);
</script>

View file

@ -1,5 +1,3 @@
<h1 id="title">Packages and Provided Plugins</h1>
<?php if (!$canWrite): ?>
<p class="alert alert-danger">PHPCI cannot update composer.json for you as it is not writable.</p>
<?php endif; ?>
@ -12,10 +10,12 @@
<p class="alert alert-success"><strong><?php echo $_GET['w']; ?></strong> has been added to composer.json for you and will be installed next time you run composer update.</p>
<?php endif; ?>
<div class="box">
<h3 class="title">Available Plugins</h3>
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Enabled Plugins</h3>
</div>
<table class="table-striped table-bordered table">
<table class="table">
<thead>
<tr>
<th>Name</th>
@ -35,85 +35,104 @@
</table>
</div>
<div class="box">
<h3 class="title">Installed Packages</h3>
<table class="table-striped table-bordered table">
<thead>
<tr>
<th>Title</th>
<th>Version</th>
<th width="1"></th>
</tr>
</thead>
<tbody>
<?php foreach ($installedPackages as $package => $version): ?>
<tr>
<td><?php echo $package; ?></td>
<td><?php echo $version; ?></td>
<td>
<?php if (!in_array($package, $required) && $canWrite): ?>
<a class="btn btn-danger btn-small" href="<?php echo PHPCI_URL ?>plugin/remove?package=<?php echo $package; ?>">Remove &raquo;</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="row">
<div class="col-lg-6">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Installed Packages</h3>
</div>
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Version</th>
<th width="1"></th>
</tr>
</thead>
<tbody>
<?php foreach ($installedPackages as $package => $version): ?>
<tr>
<td><?php echo $package; ?></td>
<td><?php echo $version; ?></td>
<td>
<?php if (!in_array($package, $required) && $canWrite): ?>
<a class="btn btn-danger btn-small" href="<?php echo PHPCI_URL ?>plugin/remove?package=<?php echo $package; ?>">Remove &raquo;</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<div class="col-lg-6">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Suggested Packages</h3>
</div>
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th width="1"></th>
</tr>
</thead>
<tbody>
<?php foreach ($suggestedPackages as $package => $version): ?>
<?php if (in_array($package, array_keys($installedPackages))) { continue; } ?>
<tr>
<td><?php echo $package; ?></td>
<td><?php echo $version; ?></td>
<td>
<?php if ($canWrite): ?>
<button data-name="<?php echo $package; ?>" class="install-package btn btn-success btn-small">Install &raquo;</button>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<div class="box">
<h3 class="title">Suggested Packages</h3>
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Search Packagist for More Packages</h3>
</div>
<table class="table-striped table-bordered table">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th width="1"></th>
</tr>
</thead>
<tbody>
<?php foreach ($suggestedPackages as $package => $version): ?>
<?php if (in_array($package, array_keys($installedPackages))) { continue; } ?>
<tr>
<td><?php echo $package; ?></td>
<td><?php echo $version; ?></td>
<td>
<?php if ($canWrite): ?>
<button data-name="<?php echo $package; ?>" class="install-package btn btn-success btn-small">Install &raquo;</button>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="box">
<h3 class="title">Search Packagist for More Packages</h3>
<div class="input-group">
<input id="search-query" type="text" class="form-control">
<div class="box-body">
<div class="input-group">
<input id="search-query" type="text" class="form-control">
<span class="input-group-btn">
<button id="search-button" class="btn btn-success" type="button">Search</button>
</span>
</div>
<div id="results" style="margin-top: 15px; display: none;">
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th width="1"></th>
</tr>
</thead>
<tbody id="search-results">
</tbody>
</table>
</div>
</div>
<div id="results" style="margin-top: 15px; display: none;">
<table class="table-striped table-bordered table">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th width="1"></th>
</tr>
</thead>
<tbody id="search-results">
</tbody>
</table>
</div>
</div>
<script>

View file

@ -1,73 +1,47 @@
<h1><i class="glyphicon glyphicon-th-list"></i> <?php print htmlspecialchars($project->getTitle()); ?></h1>
<script>
var PHPCI_PROJECT_ID = <?php print $project->getId(); ?>;
var PHPCI_PROJECT_BRANCH = '<?php print $branch; ?>';
</script>
<div class="clearfix" style="margin-bottom: 20px;">
<div class="pull-right btn-group">
<a class="btn btn-success" href="<?php print PHPCI_URL . 'project/build/' . $project->getId(); ?>">Build Now</a>
<div class="btn-group branch-btn pull-right">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
Branch<?php print !empty($branch) ? ': ' . $branch : ''; ?>&nbsp;&nbsp;<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<?php foreach ($branches as $curbranch) : ?>
<li <?php echo ($curbranch == $branch) ? 'class="active"' : ''?>>
<a href="<?php echo PHPCI_URL ?>project/view/<?php print $project->getId(); ?>?branch=<?php echo urlencode($curbranch) ?>">
<?php echo $curbranch ?>
</a>
</li>
<?php endforeach; ?>
<li class="divider"></li>
<li><a href="<?php echo PHPCI_URL ?>project/view/<?php print $project->getId(); ?>">All</a></li>
</ul>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-3">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Options</h3>
<div class="col-lg-9 col-md-8 col-sm-8">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Builds</h3>
</div>
<div class="list-group">
<a class="list-group-item" href="<?php echo PHPCI_URL ?>project/build/<?php print $project->getId(); ?>"><i class="glyphicon glyphicon-cog"></i> Build Now</a>
<?php if($this->User()->getIsAdmin()): ?>
<a class="list-group-item" href="<?php echo PHPCI_URL ?>project/edit/<?php print $project->getId(); ?>"><i class="glyphicon glyphicon-edit"></i> Edit Project</a>
<a class="list-group-item" href="#" id="delete-project"><i class="glyphicon glyphicon-trash"></i> Delete Project</a>
<?php endif; ?>
</div>
</div>
<?php if (in_array($project->getType(), array('github', 'gitlab', 'bitbucket'))): ?>
<div class="panel panel-info">
<div class="panel-heading">
<h4 class="panel-title">Webhooks</h4>
</div>
<div class="panel-body">
To automatically build this project when new commits are pushed, add the URL below
<?php
switch($project->getType())
{
case 'github':
$url = PHPCI_URL . 'webhook/github/' . $project->getId();
print ' as a "WebHook URL" in the <a href="https://github.com/' . $project->getReference() . '/settings/hooks">Service Hooks</a> section of your Github repository.<br><br><strong style="word-wrap: break-word;">' . $url . '</strong>';
break;
case 'gitlab':
$url = PHPCI_URL. 'webhook/gitlab/' . $project->getId();
print ' as a "WebHook URL" in the Web Hooks section of your Gitlab repository.<br><br><strong style="word-wrap: break-word;">' . $url . '</strong>';
break;
case 'bitbucket':
$url = PHPCI_URL . 'webhook/bitbucket/' . $project->getId();
print ' as a "POST" service in the <a href="https://bitbucket.org/' . $project->getReference() . '/admin/services">Services</a> section of your Bitbucket repository.<br><br><strong style="word-wrap: break-word;">' . $url . '</strong>';
break;
}
?>
</div>
</div>
<?php endif; ?>
<?php if ($project->getSshPublicKey()): ?>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title"><a data-toggle="collapse" data-parent="#accordion" href="#publicCollapse">Public Key</a></h3></div>
<div id="publicCollapse" class="panel-collapse collapse out">
<div class="panel-body word-wrap"><?php print $project->getSshPublicKey(); ?></div>
</div>
</div>
<?php endif; ?>
</div>
<div class="col-lg-9">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">Builds</h3></div>
<table class="table table-striped table-bordered">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Project</th>
<th>Commit</th>
<th class="hidden-md hidden-sm hidden-xs">Commit</th>
<th>Branch</th>
<th>Status</th>
<th style="width: 100px"></th>
@ -78,61 +52,103 @@
</tbody>
</table>
</div>
<?php
print '<div><ul class="pagination">';
if ($page > 1) {
print '<li><a href="' . PHPCI_URL . 'project/view/'.$project->getId().'?p='.($page == 1 ? '1' : $page - 1).'">&laquo; Prev</a></li>';
}
if ($pages > 1) {
for($i = 1; $i <= $pages; $i++)
{
if ($i == $page) {
print '<li><span>' . $i . '</span></li>';
} else {
print '<li><a href="' . PHPCI_URL . 'project/view/' . $project->getId() . '?p=' . $i . '">' . $i . '</a></li>';
}
}
}
if ($page < $pages) {
print '<li><a href="' . PHPCI_URL . 'project/view/'.$project->getId().'?p='.($page == $pages ? $pages : $page + 1).'">Next &raquo;</a></li>';
}
print '</ul></div>';
?>
</div>
<div class="col-lg-3 col-md-4 col-sm-4">
<?php if (in_array($project->getType(), array('github', 'gitlab', 'bitbucket'))): ?>
<div class="box box-info">
<div class="box-header">
<h4 class="box-title">Webhooks</h4>
</div>
<div class="box-body">
To automatically build this project when new commits are pushed, add the URL below
<?php
switch($project->getType())
{
case 'github':
$url = PHPCI_URL . 'webhook/github/' . $project->getId();
print ' as a new "Webhook" in the <a href="https://github.com/' . $project->getReference() . '/settings/hooks">Webhooks and Services</a> section of your Github repository.<br><br><strong style="word-wrap: break-word;">' . $url . '</strong>';
break;
case 'gitlab':
$url = PHPCI_URL. 'webhook/gitlab/' . $project->getId();
print ' as a "WebHook URL" in the Web Hooks section of your Gitlab repository.<br><br><strong style="word-wrap: break-word;">' . $url . '</strong>';
break;
case 'bitbucket':
$url = PHPCI_URL . 'webhook/bitbucket/' . $project->getId();
print ' as a "POST" service in the <a href="https://bitbucket.org/' . $project->getReference() . '/admin/services">Services</a> section of your Bitbucket repository.<br><br><strong style="word-wrap: break-word;">' . $url . '</strong>';
break;
}
?>
</div>
</div>
<?php endif; ?>
<?php if ($project->getSshPublicKey()): ?>
<div class="box box-info">
<div class="box-header"><h3 class="box-title"><a data-toggle="collapse" data-parent="#accordion" href="#publicCollapse">Public Key</a></h3></div>
<div class="box-body" style="word-break: break-word;"><?php print $project->getSshPublicKey(); ?></div>
</div>
<?php endif; ?>
</div>
</div>
<?php if($page == 1): ?>
<script>
setInterval(function()
<?php
print '<div><ul class="pagination">';
$project_url = PHPCI_URL . 'project/view/' . $project->getId() . ((!empty($branch)) ? '/' . urlencode($branch) : '');
if ($page > 1) {
print '<li><a href="' . $project_url . '?p='.($page == 1 ? '1' : $page - 1).'">&laquo; Prev</a></li>';
}
if ($pages > 1) {
$start = $page - 3;
if ($start <= 0) {
$start = 1;
}
$end = $page + 3;
if ($end > $pages) {
$end = $pages;
}
if ($start > 1) {
print '<li><a href="' . $project_url . '">1...</a></li>';
}
for($i = $start; $i <= $end; $i++)
{
$.ajax({
url: '<?php echo PHPCI_URL ?>project/builds/<?php print $project->getId(); ?>',
if ($pages > $end && $i == $pages) continue;
success: function (data) {
$('#latest-builds').html(data);
$('#latest-builds').trigger('latest-builds:reload');
},
if ($i == $page) {
print '<li class="bg-blue"><span>' . $i . '</span></li>';
} else {
print '<li><a href="' . $project_url . '?p=' . $i . '">' . $i . '</a></li>';
}
}
error: handleFailedAjax
});
}, 10000);
if ($pages > $end) {
print '<li><a href="' . $project_url . '?p='.$pages.'">...'.$pages.'</a></li>';
}
}
$(function() {
$('#delete-project').on('click', function (e) {
e.preventDefault();
confirmDelete(
"<?php echo PHPCI_URL ?>project/delete/<?php print $project->getId(); ?>", "Project"
).onCloseConfirmed = function () {window.location = '/'};
});
})
</script>
<?php endif; ?>
if ($page < $pages - 1) {
print '<li><a href="' . $project_url . '?p='.($page == $pages ? $pages : $page + 1).'">Next &raquo;</a></li>';
}
print '</ul></div>';
?>

View file

@ -1,34 +1,29 @@
<div id="title">
<h1><?php print $type == 'add' ? 'Add Project' : 'Edit Project' ?></h1>
</div>
<div class="row">
<div class="col-lg-4">
<div class="panel panel-info">
<div class="panel-body">
<?php if(!is_null($key)): ?>
<p>To make it easier to get started, we've generated a public / private key pair for you to use for this project. To use it, just add the following public key to the "deploy keys" section of your repository settings on Github / Bitbucket.</p>
<textarea style="width: 90%; height: 150px;"><?php print $key ?></textarea>
<?php elseif($type == 'add'): ?>
<p style="margin-bottom:0;">Fill in the form to the right to add your new project.</p>
<?php else: ?>
<p style="margin-bottom:0;">Edit your project details using the form to the right.</p>
<?php endif; ?>
</div>
</div>
</div>
<div class="col-lg-8">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Project Details</h3>
<div class="col-sm-8">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Project Details</h3>
</div>
<div class="panel-body">
<div class="box-body">
<?php print $form; ?>
</div>
</div>
</div>
<?php if(!is_null($key)): ?>
<div class="col-sm-4">
<div class="box box-info">
<div class="box-body">
<p>To make it easier to get started, we've generated a public / private key pair for you to use for this project. To use it, just add the following public key to the "deploy keys" section of your repository settings on Github / Bitbucket.</p>
<textarea style="width: 90%; height: 150px;"><?php print $key ?></textarea>
</div>
</div>
</div>
<?php endif; ?>
</div>
<script>

View file

@ -5,17 +5,17 @@
<?php else: ?>
<?php if (empty($error)): ?>
<div class="panel panel-success" style="margin-bottom: 0">
<div class="panel-heading">
<div class="box-header">
<strong>Don't worry!</strong><br>Just enter your email address below and we'll email you a link to reset your password.
</div>
<?php else: ?>
<div class="panel panel-danger" style="margin-bottom: 0">
<div class="panel-heading">
<div class="box-header">
<?php print $error; ?>
</div>
<?php endif; ?>
<div class="panel-body">
<div class="box-body">
<form class="form" action="<?php print PHPCI_URL; ?>session/forgot-password" method="POST">
<div class="form-group">
<label for="email">Enter your email address:</label>

View file

@ -1,11 +1,11 @@
<?php if (empty($error)): ?>
<div class="panel panel-success" style="margin-bottom: 0">
<div class="panel-heading">
<div class="box-header">
Please enter a new password
</div>
<div class="panel-body">
<div class="box-body">
<form class="form" action="<?php print PHPCI_URL; ?>session/reset-password/<?php print $id; ?>/<?php print $key; ?>" method="POST">
<div class="form-group">
<label for="password">New password:</label>

View file

@ -28,77 +28,81 @@
</p>
<?php endif; ?>
<div class="box">
<div class="row">
<div class="col-lg-12">
<h3 class="title">Github Application</h3>
<?php
$id = null;
if (isset($settings['phpci']['github']['id'])) {
$id = $settings['phpci']['github']['id'];
}
$returnTo = PHPCI_URL . 'settings/github-callback';
$githubUri = 'https://github.com/login/oauth/authorize?client_id='.$id.'&scope=repo&redirect_uri=' . $returnTo;
?>
<?php if (!empty($id) && empty($settings['phpci']['github']['token'])): ?>
<p class="alert alert-warning clearfix">
Before you can start using Github, you need to <a href="<?php echo $githubUri; ?>">sign in</a> and grant PHPCI access to your account.
</p>
<?php endif; ?>
<?php if (!empty($id) && !empty($settings['phpci']['github']['token'])): ?>
<p class="alert alert-success">
PHPCI is successfully linked to Github account
<strong>
<a href="<?php echo $githubUser['html_url']; ?>"><?php echo $githubUser['name']; ?></a>
</strong>
</p>
<?php endif; ?>
</div>
<div class="col-lg-8">
<?php print $github; ?>
</div>
<div class="col-lg-4">
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">Where to find these...</h3>
</div>
<div class="panel-body">
<p>If you own the application you would like to use, you can find this information within your
<a href="https://github.com/settings/applications">applications</a> settings area.</p>
</div>
</div>
</div>
<div class="box box-primary">
<div class="box-header"><h3 class="box-title">Build Settings</h3></div>
<div class="box-body clearfix">
<?php print $buildSettings; ?>
</div>
</div>
<div class="box">
<div class="row">
<div class="col-lg-12">
<h3 class="title">Email Settings</h3>
<div class="box box-primary">
<div class="box-header"><h3 class="box-title">Github Application</h3></div>
<div class="box-body clearfix">
<div class="row">
<div class="col-lg-12">
<?php
$id = null;
<?php if (!isset($settings['phpci']['email_settings'])): ?>
<p class="alert alert-warning clearfix">
Before PHPCI can send build status emails, you need to configure your SMTP settings below.
</p>
<?php endif; ?>
if (isset($settings['phpci']['github']['id'])) {
$id = $settings['phpci']['github']['id'];
}
$returnTo = PHPCI_URL . 'settings/github-callback';
$githubUri = 'https://github.com/login/oauth/authorize?client_id='.$id.'&scope=repo&redirect_uri=' . $returnTo;
?>
<?php if (!empty($id) && empty($settings['phpci']['github']['token'])): ?>
<p class="alert alert-warning clearfix">
Before you can start using Github, you need to <a href="<?php echo $githubUri; ?>">sign in</a> and grant PHPCI access to your account.
</p>
<?php endif; ?>
<?php if (!empty($id) && !empty($settings['phpci']['github']['token'])): ?>
<p class="alert alert-success">
PHPCI is successfully linked to Github account
<strong>
<a href="<?php echo $githubUser['html_url']; ?>"><?php echo $githubUser['name']; ?></a>
</strong>
</p>
<?php endif; ?>
</div>
<div class="col-lg-8">
<?php print $github; ?>
</div>
<div class="col-lg-4">
<div class="box box-info">
<div class="box-header">
<h3 class="box-title">Where to find these...</h3>
</div>
<div class="box-body">
<p>If you own the application you would like to use, you can find this information within your
<a href="https://github.com/settings/applications">applications</a> settings area.</p>
</div>
</div>
</div>
</div>
<div class="col-lg-8">
<?php print $emailSettings; ?>
</div>
</div>
</div>
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Email Settings</h3>
</div>
<div class="box-body clearfix">
<?php if (!isset($settings['phpci']['email_settings'])): ?>
<p class="alert alert-warning clearfix">
Before PHPCI can send build status emails, you need to configure your SMTP settings below.
</p>
<?php endif; ?>
<?php print $emailSettings; ?>
<div class="col-lg-4">
<!-- nothing -->
</div>
</div>
</div>

View file

@ -53,12 +53,12 @@ foreach($projects as $project):
case 2:
$successes++;
$statuses[] = 'ok';
$success = is_null($success) && !is_null($build->getFinished()) ? $build->getFinished()->format('Y-m-d H:i:s') : $success;
$success = is_null($success) && !is_null($build->getFinished()) ? $build->getFinished()->format('M j Y g:ia') : $success;
break;
case 3:
$failures++;
$statuses[] = 'failed';
$failure = is_null($failure) && !is_null($build->getFinished()) ? $build->getFinished()->format('Y-m-d H:i:s') : $failure;
$failure = is_null($failure) && !is_null($build->getFinished()) ? $build->getFinished()->format('M j Y g:ia') : $failure;
break;
}
}
@ -66,32 +66,83 @@ foreach($projects as $project):
if ($failures == 0) {
$health = 'Good';
$subcls = 'success';
} elseif ($failures > $successes) {
$subcls = 'green';
} elseif ($successes == 0) {
$health = 'Bad';
$subcls = 'danger';
$subcls = 'red';
} else {
$health = 'Warning';
$subcls = 'warning';
$subcls = 'yellow';
}
$buildCount = count($builds[$project->getId()]);
$lastSuccess = $successful[$project->getId()];
$lastFailure = $failed[$project->getId()];
$message = 'No builds yet!';
$shortMessage = 'No builds yet!';
if ($buildCount > 0) {
if ($failures > 0) {
$shortMessage = $failures . ' / ' . $buildCount . ' failed.';
$message = $failures . ' out of the last ' . $buildCount . ' builds failed.';
if (!is_null($lastSuccess) && !is_null($lastSuccess->getFinished())) {
$message .= ' The last successful build was ' . $lastSuccess->getFinished()->format('M j Y') . '.';
} else {
$message .= ' This project has never built successfully.';
}
} else {
$shortMessage = $buildCount . ' / ' . $buildCount . ' passed.';
$message = 'All of the last ' . $buildCount . ' builds passed.';
if (!is_null($lastFailure) && !is_null($lastFailure->getFinished())) {
$message .= ' The last failed build was ' . $lastFailure->getFinished()->format('M j Y') . '.';
} else {
$message .= ' This project has never failed to build.';
}
}
}
?>
<tr class="<?php print $cls; ?>">
<td>
<span class='label label-<?php echo $subcls ?>'>
<?php echo $health ?>
</span>
</td>
<td><a href='<?php echo PHPCI_URL ?>project/view/<?php echo $project->getId() ?>'><?php echo htmlspecialchars($project->getTitle()) ?></a></td>
<td><?php print is_null($success) ? 'Never' : $success; ?></td>
<td><?php print is_null($failure) ? 'Never' : $failure; ?></td>
<td>
<?php
foreach ($statuses as $status) {
print '<img alt="'.$status.'" src="' . PHPCI_URL . 'assets/img/icon-build-' . $status . '.png">';
}
?>
</td>
<td><a class="btn btn-default btn-sm" href='<?php echo PHPCI_URL ?>project/build/<?php echo $project->getId(); ?>'>build now &raquo;</a></td>
</tr>
<?php if (count($projects) > 10): ?>
<div class="small-box bg-<?php print $subcls; ?>">
<div class="inner">
<h4>
<strong>
<a href="<?php print PHPCI_URL; ?>project/view/<?php print $project->getId(); ?>">
<?php print $project->getTitle(); ?>
</a>
</strong> -
<?php print $shortMessage; ?>
</h4>
</div>
</div>
<?php else: ?>
<div class="small-box bg-<?php print $subcls; ?>">
<div class="inner">
<h3>
<a href="<?php print PHPCI_URL; ?>project/view/<?php print $project->getId(); ?>">
<?php print $project->getTitle(); ?>
</a>
</h3>
<p>
<?php print $message; ?>
</p>
</div>
<div class="icon">
<i class="fa fa-<?php print $project->getIcon(); ?>"></i>
</div>
<a href="<?php print PHPCI_URL; ?>project/view/<?php print $project->getId(); ?>" class="small-box-footer">
View Project <i class="fa fa-arrow-circle-right"></i>
</a>
</div>
<?php endif; ?>
<?php endforeach; ?>

View file

@ -1,67 +1,60 @@
<div id="title">
<h1>Users</h1>
<div class="clearfix" style="margin-bottom: 20px;">
<div class="pull-right btn-group">
<a class="btn btn-primary" href="<?php print PHPCI_URL; ?>user/add">Add User</a>
</div>
</div>
<div class="row">
<div class="col-lg-3">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">Options</h4>
</div>
<div class="col-xs-12">
<div class="box box-primary">
<div class="list-group">
<?php if($this->User()->getIsAdmin()): ?>
<a class="list-group-item" href="<?php echo PHPCI_URL ?>user/add"><i class="icon-plus-sign"></i> Add User</a>
<?php endif; ?>
</div>
</div>
</div>
<div class="col-lg-9">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Email Address</th>
<th>Name</th>
<th>Administrator</th>
<th style="width: 100px"></th>
</tr>
</thead>
<tbody id="users">
<?php foreach($users['items'] as $user): ?>
<?php
switch($user->getIsAdmin())
{
case 0:
$cls = '';
$status = 'No';
break;
<table class="table">
<thead>
<tr>
<th>Email Address</th>
<th>Name</th>
<th>Administrator</th>
<th style="width: 100px"></th>
</tr>
</thead>
<tbody id="users">
<?php foreach($users['items'] as $user): ?>
<?php
switch($user->getIsAdmin())
{
case 0:
$cls = '';
$status = 'No';
break;
case 1:
$cls = 'warning';
$status = 'Yes';
break;
}
?>
<tr class="<?php print $cls; ?>">
<td><a href="<?php echo PHPCI_URL ?>user/edit/<?php print $user->getId(); ?>"><?php print $user->getEmail(); ?></a></td>
<td><?php print htmlspecialchars($user->getName()); ?></td>
<td><?php print $status; ?></td>
<td>
<?php if($this->User()->getIsAdmin()): ?>
<div class="btn-group">
<a class="btn btn-default btn-small" href="<?php echo PHPCI_URL ?>user/edit/<?php print $user->getId(); ?>">Edit</a>
<button class="btn btn-default btn-small dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="<?php echo PHPCI_URL ?>user/delete/<?php print $user->getId(); ?>" class="phpci-app-delete-user">Delete User</a></li>
</ul>
</div>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
case 1:
$cls = 'warning';
$status = 'Yes';
break;
}
?>
<tr class="<?php print $cls; ?>">
<td><a href="<?php echo PHPCI_URL ?>user/edit/<?php print $user->getId(); ?>"><?php print $user->getEmail(); ?></a></td>
<td><?php print htmlspecialchars($user->getName()); ?></td>
<td><?php print $status; ?></td>
<td>
<?php if($this->User()->getIsAdmin()): ?>
<div class="btn-group">
<a class="btn btn-default btn-small" href="<?php echo PHPCI_URL ?>user/edit/<?php print $user->getId(); ?>">Edit</a>
<button class="btn btn-default btn-small dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="<?php echo PHPCI_URL ?>user/delete/<?php print $user->getId(); ?>" class="phpci-app-delete-user">Delete User</a></li>
</ul>
</div>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>

View file

@ -1,14 +1,12 @@
<h1><?php print $this->User()->getName(); ?></h1>
<?php if (isset($updated)): ?>
<p class="alert alert-success">Your details have been updated.</p>
<?php endif; ?>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Update your details</h3>
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Update your details</h3>
</div>
<div class="panel-body">
<div class="box-body">
<?php print $form; ?>
</div>
</div>

View file

@ -1,20 +1,9 @@
<div id="title">
<h1><?php print $type == 'add' ? 'Add User' : 'Edit ' . htmlspecialchars($user->getName()) ?></h1>
</div>
<div class="row">
<div class="col-lg-4">
<div class="well" style="">
<?php if($type == 'add'): ?>
<p style="margin-bottom:0;">Fill in the form to the right to add a new user.</p>
<?php else: ?>
<p style="margin-bottom:0;">Edit user details using the form to the right.</p>
<?php endif; ?>
</div>
</div>
<div class="col-lg-8">
<div class="box">
<?php print $form; ?>
<div class="col-sm-12">
<div class="box box-primary">
<div class="box-body">
<?php print $form; ?>
</div>
</div>
</div>
</div>

View file

@ -1,9 +1,9 @@
<div class="panel panel-danger">
<div class="panel-heading">
<h2 class="panel-title">Sorry, there was a problem</h2>
<div class="box-header">
<h2 class="box-title">Sorry, there was a problem</h2>
</div>
<div class="panel-body">
<div class="box-body">
<?php print $exception->getMessage(); ?>
</div>
</div>

View file

@ -1,86 +1,312 @@
<!DOCTYPE html>
<html>
<head>
<title><?php if (!empty($title)) { print $title . ' - '; } ?>PHPCI</title>
<head>
<meta charset="UTF-8">
<title><?php print $title; ?><?php print !empty($subtitle) ? ' - ' . $subtitle : ''; ?></title>
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<link href="//cdnjs.cloudflare.com/ajax/libs/ionicons/1.5.2/css/ionicons.min.css" rel="stylesheet" type="text/css" />
<link href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css" rel="stylesheet" type="text/css" />
<link href='//fonts.googleapis.com/css?family=Roboto:300,500&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="<?php echo PHPCI_URL ?>assets/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="<?php echo PHPCI_URL ?>assets/css/phpci.css">
<link href="<?php print PHPCI_URL; ?>assets/css/datepicker/datepicker3.css" rel="stylesheet" type="text/css" />
<link href="<?php print PHPCI_URL; ?>assets/css/daterangepicker/daterangepicker-bs3.css" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" type="image/x-icon" href="<?php echo PHPCI_URL ?>favicon.ico">
<link rel="shortcut icon" type="image/png" href="<?php echo PHPCI_URL ?>assets/img/favicon.png">
<!-- Theme style -->
<link href="<?php print PHPCI_URL; ?>assets/css/AdminLTE.css" rel="stylesheet" type="text/css" />
<script>window.PHPCI_URL = <?php print json_encode(PHPCI_URL) ?></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/class.js"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/phpci.js" type="text/javascript"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script src="<?php echo PHPCI_URL ?>assets/js/bootstrap.min.js"></script>
<script src="<?php echo PHPCI_URL ?>assets/js/jqueryui.js"></script>
<script src="<?php echo PHPCI_URL ?>assets/js/class.js"></script>
<script src="<?php echo PHPCI_URL ?>assets/js/phpci.js"></script>
<script src="<?php echo PHPCI_URL ?>assets/js/init.js"></script>
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="container">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-responsive-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<script>var PHPCI_URL = '<?php print PHPCI_URL; ?>';</script>
<a class="navbar-brand" href="<?php echo PHPCI_URL ?>"><img src="<?php echo PHPCI_URL ?>/assets/img/logo.png"></a>
<style>
.skin-blue .logo, .skin-blue .logo:hover {
background-image: url('/assets/img/logo-large.png');
background-repeat: no-repeat;
background-size: 40%;
background-position: 65px;
text-indent: -5000px;
}
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
.build-info-panel {
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<img class="pull-left" style="margin-right: 7px; margin-top: -5px; border-radius: 50%" src="//www.gravatar.com/avatar/<?php print md5($this->User()->getEmail()); ?>?d=mm&amp;s=30">
}
<strong><?php print htmlspecialchars($this->User()->getName()); ?></strong> <b class="caret"></b>
.build-info-panel .box-header h1.box-title {
border: 0;
font-size: 1.5em;
font-weight: bold;
margin-left: 110px;
}
.build-info-panel h1.box-title span {
font-weight: normal;
}
.build-info-panel img {
border: 2px solid #fff;
border-radius: 50%;
margin-top: -40px;
}
.build-info-panel #build-info {
margin-left: 110px;
min-height: 50px;
}
.build-info-panel .commit-message {
margin-bottom: 20px;
}
.small-box h3 a, .small-box h4 a {
color: #fff;
}
.pagination>li>span {
font-weight: bold;
background: #337ab7;
color: #fff;
}
</style>
</head>
<body class="skin-blue">
<!-- header logo: style can be found in header.less -->
<header class="header">
<a href="<?php print PHPCI_URL; ?>" class="logo">PHPCI</a>
<!-- Header Navbar: style can be found in header.less -->
<nav class="navbar navbar-static-top" role="navigation">
<!-- Sidebar toggle button-->
<a href="#" class="navbar-btn sidebar-toggle" data-toggle="offcanvas" role="button">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="navbar-right">
<ul class="nav navbar-nav">
<li class="dropdown messages-menu phpci-pending">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-clock-o"></i>
<span class="label label-info phpci-pending-count"></span>
</a>
<ul class="dropdown-menu">
<li class="header"><span class="phpci-pending-count"></span> builds pending</li>
<li>
<ul class="menu phpci-pending-list">
</ul>
</li>
</ul>
</li>
<li class="dropdown messages-menu phpci-running">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-cogs"></i>
<span class="label label-warning phpci-running-count"></span>
</a>
<ul class="dropdown-menu">
<li class="header"><span class="phpci-running-count"></span> builds running</li>
<li>
<ul class="menu phpci-running-list">
</ul>
</li>
</ul>
</li>
<!-- User Account: style can be found in dropdown.less -->
<li class="dropdown user user-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="glyphicon glyphicon-user"></i>
<span><?php print $this->User()->getName(); ?> <i class="caret"></i></span>
</a>
<ul class="dropdown-menu">
<!-- User image -->
<li class="user-header bg-light-blue">
<img src="https://www.gravatar.com/avatar/<?php print md5($this->User()->getEmail()); ?>?d=mm" class="img-circle" alt="<?php print $this->User()->getName(); ?>" />
<p>
<?php print $this->User()->getName(); ?>
</p>
</li>
<!-- Menu Footer-->
<li class="user-footer">
<div class="pull-left">
<a href="<?php print PHPCI_URL ?>user/profile" class="btn btn-default btn-flat">Edit Profile</a>
</div>
<div class="pull-right">
<a href="<?php print PHPCI_URL ?>session/logout" class="btn btn-default btn-flat">Sign out</a>
</div>
</li>
</ul>
</li>
</ul>
</div>
</nav>
</header>
<div class="wrapper row-offcanvas row-offcanvas-left">
<!-- Left side column. contains the logo and sidebar -->
<aside class="left-side sidebar-offcanvas">
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
<!-- Sidebar user panel -->
<div class="user-panel">
<div class="pull-left image">
<img src="https://www.gravatar.com/avatar/<?php print md5($this->User()->getEmail()); ?>?d=mm" class="img-circle" alt="<?php print $this->User()->getName(); ?>" />
</div>
<div class="pull-left info">
<p>Hello, <?php print $this->User()->getName(); ?></p>
<a href="#"><i class="fa fa-circle text-success"></i> Online</a>
</div>
</div>
<!-- sidebar menu: : style can be found in sidebar.less -->
<ul class="sidebar-menu">
<li class="active">
<a href="<?php print PHPCI_URL; ?>">
<i class="fa fa-dashboard"></i> <span>Dashboard</span>
</a>
</li>
<?php if ($this->User()->getIsAdmin()): ?>
<li class="treeview">
<a href="#">
<i class="fa fa-edit"></i>
<span>Admin Options</span>
<i class="fa fa-angle-left pull-right"></i>
</a>
<ul class="treeview-menu">
<li>
<a href="<?php print PHPCI_URL; ?>project/add">
<i class="fa fa-angle-double-right"></i> Add Project
</a>
</li>
<li>
<a href="<?php print PHPCI_URL; ?>settings">
<i class="fa fa-angle-double-right"></i> Settings
</a>
</li>
<li>
<a href="<?php print PHPCI_URL; ?>user">
<i class="fa fa-angle-double-right"></i> Manage Users
</a>
</li>
<li>
<a href="<?php print PHPCI_URL; ?>plugin">
<i class="fa fa-angle-double-right"></i> Plugins
</a>
</li>
</ul>
</li>
<?php endif; ?>
<?php foreach ($projects['items'] as $project): ?>
<li class="treeview">
<a href="#">
<i class="fa fa-<?php print $project->getIcon(); ?>"></i>
<span><?php print $project->getTitle(); ?></span>
<i class="fa fa-angle-left pull-right"></i>
</a>
<ul class="treeview-menu">
<li>
<a href="<?php print PHPCI_URL; ?>project/view/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> View
</a>
</li>
<li>
<a href="<?php print PHPCI_URL; ?>project/build/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> Build Now
</a>
<ul class="dropdown-menu" role="menu">
<li><a href="<?php print PHPCI_URL ?>user/profile">Edit Profile</a></li>
<li class="divider"></li>
<li><a href="<?php print PHPCI_URL ?>session/logout">Log out</a></li>
</ul>
</li>
<?php if ($this->User()->getIsAdmin()): ?>
<li>
<div class="btn-group">
<a class="btn btn-success navbar-btn" href="<?php echo PHPCI_URL ?>project/add">Add Project</a>
</div>
<a href="<?php print PHPCI_URL; ?>project/edit/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> Edit Project
</a>
</li>
<div class="btn-group">
<button type="button" class="btn navbar-btn btn-default dropdown-toggle" data-toggle="dropdown">
Admin <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="<?php echo PHPCI_URL ?>settings">Settings</a></li>
<li><a href="<?php echo PHPCI_URL ?>plugin">Manage Plugins</a></li>
<li><a href="<?php echo PHPCI_URL ?>user">Manage Users</a></li>
</ul>
</div>
<li>
<a href="<?php print PHPCI_URL; ?>project/delete/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> Delete Project
</a>
</li>
<?php endif; ?>
</ul>
</div>
</li>
<?php endforeach; ?>
<?php if (isset($nav)): ?>
<li class="treeview">
<a href="#">
<i class="fa fa-<?php print $nav['icon']; ?>"></i>
<span><?php print $nav['title']; ?></span>
<i class="fa fa-angle-left pull-right"></i>
</a>
<ul class="treeview-menu">
<?php foreach ($nav['links'] as $link => $linkTitle): ?>
<li>
<a href="<?php print PHPCI_URL . $link; ?>">
<i class="fa fa-angle-double-right"></i> <?php print $linkTitle; ?>
</a>
</li>
<?php endforeach; ?>
</ul>
</li>
<?php endif; ?>
</ul>
</section>
<!-- /.sidebar -->
</aside>
<!-- Right side column. Contains the navbar and content of the page -->
<aside class="right-side">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
<?php print !empty($title) ? $title : 'PHPCI'; ?>
<?php if (!empty($subtitle)): ?>
<small><?php print $subtitle; ?></small>
<?php endif; ?>
</h1>
</section>
<!-- Main content -->
<section class="content">
<?php print $content; ?>
</section><!-- /.content -->
</aside><!-- /.right-side -->
</div><!-- ./wrapper -->
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js" type="text/javascript"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/js/bootstrap.min.js" type="text/javascript"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js" type="text/javascript"></script>
</div>
</div>
<script src="<?php print PHPCI_URL; ?>assets/js/plugins/daterangepicker/daterangepicker.js" type="text/javascript"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/plugins/datepicker/bootstrap-datepicker.js" type="text/javascript"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/AdminLTE/app.js" type="text/javascript"></script>
<div id="content" class="container">
<?php print $content; ?>
</div>
<div id="loading">Loading...</div>
</body>
</html>
</body>
</html>

View file

@ -7,6 +7,10 @@ PHPCI is a free and open source (BSD License) continuous integration tool specif
[![Build Status](http://phpci.block8.net/build-status/image/2?branch=master)](http://phpci.block8.net/build-status/view/2?branch=master)
**Chat Room**
We have a chat room for discussing PHPCI, you can access it here: [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/Block8/PHPCI?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge)
##What it does:
* Clones your project from Github, Bitbucket or a local path
* Allows you to set up and tear down test databases.

View file

@ -0,0 +1,237 @@
<?php
namespace PHPCI\Plugin\Tests\Command;
use Symfony\Component\Console\Application;
use PHPCI\Command\InstallCommand;
use Prophecy\PhpUnit\ProphecyTestCase;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Console\Helper\HelperSet;
class InstallCommandTest extends ProphecyTestCase
{
protected $config;
protected $admin;
protected $command;
protected $dialog;
protected $application;
public function setup()
{
parent::setup();
// Current command, we need to mock all method that interact with
// Database & File system.
$this->command = $this->getMockBuilder('PHPCI\\Command\\InstallCommand')
->setMethods(array(
'reloadConfig',
'verifyNotInstalled',
'verifyDatabaseDetails',
'setupDatabase',
'createAdminUser',
'writeConfigFile',
))
->getMock();
$this->command->expects($this->once())->method('verifyDatabaseDetails')->willReturn(true);
$this->command->expects($this->once())->method('setupDatabase')->willReturn(true);
$this->command->expects($this->once())->method('createAdminUser')->will(
$this->returnCallback(function ($adm) {// use (&$admin) {
$this->admin = $adm;
})
);
$this->command->expects($this->once())->method('writeConfigFile')->will(
$this->returnCallback(function ($cfg) { //use (&$config) {
$this->config = $cfg;
})
);
// We check that there's no interaction with user.
$this->dialog = $this->getMockBuilder('Symfony\\Component\\Console\\Helper\\DialogHelper')
->setMethods(array(
'ask',
'askConfirmation',
'askAndValidate',
'askHiddenResponse',
'askHiddenResponseAndValidate',
))
->getMock();
$this->application = new Application();
$this->application->setHelperSet(new HelperSet());
}
protected function getCommandTester()
{
$this->application->getHelperSet()->set($this->dialog, 'dialog');
$this->application->add($this->command);
$command = $this->application->find('phpci:install');
$commandTester = new CommandTester($command);
return $commandTester;
}
protected function getConfig($exclude = null)
{
$config = array(
'--db-host' => 'localhost',
'--db-name' => 'phpci1',
'--db-user' => 'phpci2',
'--db-pass' => 'phpci3',
'--admin-mail' => 'phpci@phpci.test',
'--admin-name' => 'phpci4',
'--admin-pass' => 'phpci5',
'--url' => 'http://test.phpci.org',
);
if (!is_null($exclude)) {
unset($config[$exclude]);
}
return $config;
}
protected function executeWithoutParam($param = null)
{
// Clean result variables.
$this->admin = array();
$this->config = array();
// Get tester and execute with extracted parameters.
$commandTester = $this->getCommandTester();
$parameters = $this->getConfig($param);
$commandTester->execute($parameters);
}
public function testAutomticInstallation()
{
$this->dialog->expects($this->never())->method('ask');
$this->dialog->expects($this->never())->method('askConfirmation');
$this->dialog->expects($this->never())->method('askAndValidate');
$this->dialog->expects($this->never())->method('askHiddenResponse');
$this->dialog->expects($this->never())->method('askHiddenResponseAndValidate');
$this->executeWithoutParam();
}
public function testDatabaseHostnameConfig()
{
// We specified an input value for hostname.
$this->dialog->expects($this->once())->method('ask')->willReturn('testedvalue');
$this->dialog->expects($this->never())->method('askConfirmation');
$this->dialog->expects($this->never())->method('askAndValidate');
$this->dialog->expects($this->never())->method('askHiddenResponse');
$this->dialog->expects($this->never())->method('askHiddenResponseAndValidate');
$this->executeWithoutParam('--db-host');
// Check that specified arguments are correctly loaded.
$this->assertEquals('testedvalue', $this->config['b8']['database']['servers']['read']);
$this->assertEquals('testedvalue', $this->config['b8']['database']['servers']['write']);
}
public function testDatabaseNameConfig()
{
// We specified an input value for hostname.
$this->dialog->expects($this->once())->method('ask')->willReturn('testedvalue');
$this->dialog->expects($this->never())->method('askConfirmation');
$this->dialog->expects($this->never())->method('askAndValidate');
$this->dialog->expects($this->never())->method('askHiddenResponse');
$this->dialog->expects($this->never())->method('askHiddenResponseAndValidate');
$this->executeWithoutParam('--db-name');
// Check that specified arguments are correctly loaded.
$this->assertEquals('testedvalue', $this->config['b8']['database']['name']);
}
public function testDatabaseUserameConfig()
{
// We specified an input value for hostname.
$this->dialog->expects($this->once())->method('ask')->willReturn('testedvalue');
$this->dialog->expects($this->never())->method('askConfirmation');
$this->dialog->expects($this->never())->method('askAndValidate');
$this->dialog->expects($this->never())->method('askHiddenResponse');
$this->dialog->expects($this->never())->method('askHiddenResponseAndValidate');
$this->executeWithoutParam('--db-user');
// Check that specified arguments are correctly loaded.
$this->assertEquals('testedvalue', $this->config['b8']['database']['username']);
}
public function testDatabasePasswordConfig()
{
// We specified an input value for hostname.
$this->dialog->expects($this->never())->method('ask');
$this->dialog->expects($this->never())->method('askConfirmation');
$this->dialog->expects($this->never())->method('askAndValidate');
$this->dialog->expects($this->once())->method('askHiddenResponse')->willReturn('testedvalue');
$this->dialog->expects($this->never())->method('askHiddenResponseAndValidate');
$this->executeWithoutParam('--db-pass');
// Check that specified arguments are correctly loaded.
$this->assertEquals('testedvalue', $this->config['b8']['database']['password']);
}
public function testPhpciUrlConfig()
{
// We specified an input value for hostname.
$this->dialog->expects($this->never())->method('ask');
$this->dialog->expects($this->never())->method('askConfirmation');
$this->dialog->expects($this->once())->method('askAndValidate')->willReturn('http://testedvalue.com');
$this->dialog->expects($this->never())->method('askHiddenResponse');
$this->dialog->expects($this->never())->method('askHiddenResponseAndValidate');
$this->executeWithoutParam('--url');
// Check that specified arguments are correctly loaded.
$this->assertEquals('http://testedvalue.com', $this->config['phpci']['url']);
}
public function testAdminEmailConfig()
{
// We specified an input value for hostname.
$this->dialog->expects($this->never())->method('ask');
$this->dialog->expects($this->never())->method('askConfirmation');
$this->dialog->expects($this->once())->method('askAndValidate')->willReturn('test@phpci.com');
$this->dialog->expects($this->never())->method('askHiddenResponse');
$this->dialog->expects($this->never())->method('askHiddenResponseAndValidate');
$this->executeWithoutParam('--admin-mail');
// Check that specified arguments are correctly loaded.
$this->assertEquals('test@phpci.com', $this->admin['mail']);
}
public function testAdminUserameConfig()
{
// Define expectation for dialog.
$this->dialog->expects($this->once())->method('ask')->willReturn('testedvalue');
$this->dialog->expects($this->never())->method('askConfirmation');
$this->dialog->expects($this->never())->method('askAndValidate');
$this->dialog->expects($this->never())->method('askHiddenResponse');
$this->dialog->expects($this->never())->method('askHiddenResponseAndValidate');
$this->executeWithoutParam('--admin-name');
// Check that specified arguments are correctly loaded.
$this->assertEquals('testedvalue', $this->admin['name']);
}
public function testAdminPasswordConfig()
{
// We specified an input value for hostname.
$this->dialog->expects($this->never())->method('ask');
$this->dialog->expects($this->never())->method('askConfirmation');
$this->dialog->expects($this->never())->method('askAndValidate');
$this->dialog->expects($this->once())->method('askHiddenResponse')->willReturn('testedvalue');
$this->dialog->expects($this->never())->method('askHiddenResponseAndValidate');
$this->executeWithoutParam('--admin-pass');
// Check that specified arguments are correctly loaded.
$this->assertEquals('testedvalue', $this->admin['pass']);
}
}

View file

@ -0,0 +1,201 @@
<?php
namespace PHPCI\Plugin\Tests;
use PHPCI\Plugin\Phar as PharPlugin;
use Phar as PHPPhar;
use RuntimeException;
class PharTest extends \PHPUnit_Framework_TestCase
{
protected $directory;
protected function tearDown()
{
$this->cleanSource();
}
protected function getPlugin(array $options = array())
{
$build = $this
->getMockBuilder('PHPCI\Model\Build')
->disableOriginalConstructor()
->getMock();
$phpci = $this
->getMockBuilder('PHPCI\Builder')
->disableOriginalConstructor()
->getMock();
return new PharPlugin($phpci, $build, $options);
}
protected function buildTemp()
{
$directory = tempnam(APPLICATION_PATH . '/Tests/temp', 'source');
unlink($directory);
return $directory;
}
protected function buildSource()
{
$directory = $this->buildTemp();
mkdir($directory);
file_put_contents($directory . '/one.php', '<?php echo "one";');
file_put_contents($directory . '/two.php', '<?php echo "two";');
mkdir($directory . '/config');
file_put_contents($directory . '/config/config.ini', '[config]');
mkdir($directory . '/views');
file_put_contents($directory . '/views/index.phtml', '<?php echo "hello";');
$this->directory = $directory;
return $directory;
}
protected function cleanSource()
{
if ($this->directory) {
$filenames = array(
'/build.phar',
'/stub.php',
'/views/index.phtml',
'/views',
'/config/config.ini',
'/config',
'/two.php',
'/one.php',
);
foreach ($filenames as $filename) {
if (is_dir($this->directory . $filename)) {
rmdir($this->directory . $filename);
} else if (is_file($this->directory . $filename)) {
unlink($this->directory . $filename);
}
}
rmdir($this->directory);
$this->directory = null;
}
}
protected function checkReadonly()
{
if (ini_get('phar.readonly')) {
$this->markTestSkipped();
throw new RuntimeException('Readonly Phar');
}
}
public function testPlugin()
{
$plugin = $this->getPlugin();
$this->assertInstanceOf('PHPCI\Plugin', $plugin);
$this->assertInstanceOf('PHPCI\Model\Build', $plugin->getBuild());
$this->assertInstanceOf('PHPCI\Builder', $plugin->getPHPCI());
}
public function testDirectory()
{
$plugin = $this->getPlugin();
$plugin->getPHPCI()->buildPath = 'foo';
$this->assertEquals('foo', $plugin->getDirectory());
$plugin = $this->getPlugin(array('directory' => 'dirname'));
$this->assertEquals('dirname', $plugin->getDirectory());
}
public function testFilename()
{
$plugin = $this->getPlugin();
$this->assertEquals('build.phar', $plugin->getFilename());
$plugin = $this->getPlugin(array('filename' => 'another.phar'));
$this->assertEquals('another.phar', $plugin->getFilename());
}
public function testRegExp()
{
$plugin = $this->getPlugin();
$this->assertEquals('/\.php$/', $plugin->getRegExp());
$plugin = $this->getPlugin(array('regexp' => '/\.(php|phtml)$/'));
$this->assertEquals('/\.(php|phtml)$/', $plugin->getRegExp());
}
public function testStub()
{
$plugin = $this->getPlugin();
$this->assertNull($plugin->getStub());
$plugin = $this->getPlugin(array('stub' => 'stub.php'));
$this->assertEquals('stub.php', $plugin->getStub());
}
public function testExecute()
{
$this->checkReadonly();
$plugin = $this->getPlugin();
$path = $this->buildSource();
$plugin->getPHPCI()->buildPath = $path;
$this->assertTrue($plugin->execute());
$this->assertFileExists($path . '/build.phar');
PHPPhar::loadPhar($path . '/build.phar');
$this->assertFileEquals($path . '/one.php', 'phar://build.phar/one.php');
$this->assertFileEquals($path . '/two.php', 'phar://build.phar/two.php');
$this->assertFileNotExists('phar://build.phar/config/config.ini');
$this->assertFileNotExists('phar://build.phar/views/index.phtml');
}
public function testExecuteRegExp()
{
$this->checkReadonly();
$plugin = $this->getPlugin(array('regexp' => '/\.(php|phtml)$/'));
$path = $this->buildSource();
$plugin->getPHPCI()->buildPath = $path;
$this->assertTrue($plugin->execute());
$this->assertFileExists($path . '/build.phar');
PHPPhar::loadPhar($path . '/build.phar');
$this->assertFileEquals($path . '/one.php', 'phar://build.phar/one.php');
$this->assertFileEquals($path . '/two.php', 'phar://build.phar/two.php');
$this->assertFileNotExists('phar://build.phar/config/config.ini');
$this->assertFileEquals($path . '/views/index.phtml', 'phar://build.phar/views/index.phtml');
}
public function testExecuteStub()
{
$this->checkReadonly();
$content = <<<STUB
<?php
Phar::mapPhar();
__HALT_COMPILER(); ?>
STUB;
$path = $this->buildSource();
file_put_contents($path . '/stub.php', $content);
$plugin = $this->getPlugin(array('stub' => 'stub.php'));
$plugin->getPHPCI()->buildPath = $path;
$this->assertTrue($plugin->execute());
$this->assertFileExists($path . '/build.phar');
$phar = new PHPPhar($path . '/build.phar');
$this->assertEquals($content, trim($phar->getStub())); // + trim because PHP adds newline char
}
public function testExecuteUnknownDirectory()
{
$this->checkReadonly();
$directory = $this->buildTemp();
$plugin = $this->getPlugin(array('directory' => $directory));
$plugin->getPHPCI()->buildPath = $this->buildSource();
$this->assertFalse($plugin->execute());
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace PHPCI\Plugin\Tests\Util;
use PHPCI\Plugin\Util\TapParser;
class TapParserTest extends \PHPUnit_Framework_TestCase
{
public function testSkipped()
{
$content = <<<TAP
TAP version 13
ok 1 - SomeTest::testAnother
ok 2 - # SKIP
1..2
TAP;
$parser = new TapParser($content);
$result = $parser->parse();
$this->assertEquals(array(
array('pass' => true, 'suite' => 'SomeTest', 'test' => 'testAnother'),
array('message' => 'SKIP'),
), $result);
$this->assertEquals(0, $parser->getTotalFailures());
}
}

View file

@ -10,23 +10,6 @@
// Let PHP take a guess as to the default timezone, if the user hasn't set one:
date_default_timezone_set(@date_default_timezone_get());
// Set up a basic autoloader for PHPCI:
$autoload = function ($class) {
$file = str_replace(array('\\', '_'), '/', $class);
$file .= '.php';
if (substr($file, 0, 1) == '/') {
$file = substr($file, 1);
}
if (is_file(dirname(__DIR__) . '/' . $file)) {
include(dirname(__DIR__) . '/' . $file);
return;
}
};
spl_autoload_register($autoload, true, true);
// Load Composer autoloader:
require_once(dirname(__DIR__) . '/vendor/autoload.php');

2
Tests/temp/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

View file

@ -16,23 +16,6 @@ if (empty($timezone)) {
date_default_timezone_set('UTC');
}
// Set up a basic autoloader for PHPCI:
$autoload = function ($class) {
$file = str_replace(array('\\', '_'), '/', $class);
$file .= '.php';
if (substr($file, 0, 1) == '/') {
$file = substr($file, 1);
}
if (is_file(dirname(__FILE__) . '/' . $file)) {
include(dirname(__FILE__) . '/' . $file);
return;
}
};
spl_autoload_register($autoload, true, true);
// If the PHPCI config file is not where we expect it, try looking in
// env for an alternative config path.
$configFile = dirname(__FILE__) . '/PHPCI/config.yml';
@ -47,12 +30,18 @@ if (!file_exists($configFile)) {
// If we don't have a config file at all, fail at this point and tell the user to install:
if (!file_exists($configFile) && (!defined('PHPCI_IS_CONSOLE') || !PHPCI_IS_CONSOLE)) {
die('PHPCI has not yet been installed - Please use the command ./console phpci:install to install it.');
$message = 'PHPCI has not yet been installed - Please use the command "./console phpci:install" ';
$message .= '(or "php ./console phpci:install" for Windows) to install it.';
die($message);
}
// If composer has not been run, fail at this point and tell the user to install:
if (!file_exists(dirname(__FILE__) . '/vendor/autoload.php') && defined('PHPCI_IS_CONSOLE') && PHPCI_IS_CONSOLE) {
file_put_contents('php://stderr', 'Please install PHPCI with "composer install" before using console');
$message = 'Please install PHPCI with "composer install" (or "php composer.phar install"';
$message .= ' for Windows) before using console';
file_put_contents('php://stderr', $message);
exit(1);
}

View file

@ -22,12 +22,18 @@
"source": "https://github.com/Block8/PHPCI"
},
"autoload": {
"psr-4": {
"PHPCI\\": "PHPCI"
}
},
"require": {
"php": ">=5.3.8",
"ext-mcrypt": "*",
"ext-pdo": "*",
"ext-pdo_mysql": "*",
"block8/b8framework": "~1.1",
"block8/b8framework": "~1.0",
"ircmaxell/password-compat": "~1.0",
"swiftmailer/swiftmailer": "~5.0",
"symfony/yaml": "~2.1",

970
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,9 @@
bootstrap="./Tests/bootstrap.php"
>
<testsuites>
<testsuite name="PHPCI Command Test Suite">
<directory suffix="Test.php">./Tests/PHPCI/Command</directory>
</testsuite>
<testsuite name="PHPCI Helper Test Suite">
<directory suffix="Test.php">./Tests/PHPCI/Helper</directory>
</testsuite>

7
public/.htaccess.dist Normal file
View file

@ -0,0 +1,7 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

3539
public/assets/css/AdminLTE.css Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,169 @@
/*!
* Slider for Bootstrap
*
* Copyright 2012 Stefan Petre
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
.slider {
display: block;
vertical-align: middle;
position: relative;
}
.slider.slider-horizontal {
width: 100%;
height: 20px;
margin-bottom: 20px;
}
.slider.slider-horizontal:last-of-type {
margin-bottom: 0;
}
.slider.slider-horizontal .slider-track {
height: 10px;
width: 100%;
margin-top: -5px;
top: 50%;
left: 0;
}
.slider.slider-horizontal .slider-selection {
height: 100%;
top: 0;
bottom: 0;
}
.slider.slider-horizontal .slider-handle {
margin-left: -10px;
margin-top: -5px;
}
.slider.slider-horizontal .slider-handle.triangle {
border-width: 0 10px 10px 10px;
width: 0;
height: 0;
border-bottom-color: #0480be;
margin-top: 0;
}
.slider.slider-vertical {
height: 230px;
width: 20px;
margin-right: 20px;
display: inline-block;
}
.slider.slider-vertical:last-of-type {
margin-right: 0;
}
.slider.slider-vertical .slider-track {
width: 10px;
height: 100%;
margin-left: -5px;
left: 50%;
top: 0;
}
.slider.slider-vertical .slider-selection {
width: 100%;
left: 0;
top: 0;
bottom: 0;
}
.slider.slider-vertical .slider-handle {
margin-left: -5px;
margin-top: -10px;
}
.slider.slider-vertical .slider-handle.triangle {
border-width: 10px 0 10px 10px;
width: 1px;
height: 1px;
border-left-color: #0480be;
margin-left: 0;
}
.slider input {
display: none;
}
.slider .tooltip-inner {
white-space: nowrap;
}
.slider-track {
position: absolute;
cursor: pointer;
background-color: #f7f7f7;
background-image: -moz-linear-gradient(top, #f0f0f0, #f9f9f9);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f0f0f0), to(#f9f9f9));
background-image: -webkit-linear-gradient(top, #f0f0f0, #f9f9f9);
background-image: -o-linear-gradient(top, #f0f0f0, #f9f9f9);
background-image: linear-gradient(to bottom, #f0f0f0, #f9f9f9);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0f0f0', endColorstr='#fff9f9f9', GradientType=0);
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.slider-selection {
position: absolute;
background-color: #f7f7f7;
background-image: -moz-linear-gradient(top, #f9f9f9, #f5f5f5);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f9f9f9), to(#f5f5f5));
background-image: -webkit-linear-gradient(top, #f9f9f9, #f5f5f5);
background-image: -o-linear-gradient(top, #f9f9f9, #f5f5f5);
background-image: linear-gradient(to bottom, #f9f9f9, #f5f5f5);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0);
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.slider-handle {
position: absolute;
width: 20px;
height: 20px;
background-color: #444;
-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
opacity: 1;
border: 0px solid transparent;
}
.slider-handle.round {
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
border-radius: 20px;
}
.slider-handle.triangle {
background: transparent none;
}
.slider-disabled .slider-selection {
opacity: 0.5;
}
#red .slider-selection {
background: #f56954;
}
#blue .slider-selection {
background: #3c8dbc;
}
#green .slider-selection {
background: #00a65a;
}
#yellow .slider-selection {
background: #f39c12;
}
#aqua .slider-selection {
background: #00c0ef;
}
#purple .slider-selection {
background: #932ab6;
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,102 @@
ul.wysihtml5-toolbar {
margin: 0;
padding: 0;
display: block;
}
ul.wysihtml5-toolbar::after {
clear: both;
display: table;
content: "";
}
ul.wysihtml5-toolbar > li {
float: left;
display: list-item;
list-style: none;
margin: 0 5px 10px 0;
}
ul.wysihtml5-toolbar a[data-wysihtml5-command=bold] {
font-weight: bold;
}
ul.wysihtml5-toolbar a[data-wysihtml5-command=italic] {
font-style: italic;
}
ul.wysihtml5-toolbar a[data-wysihtml5-command=underline] {
text-decoration: underline;
}
ul.wysihtml5-toolbar a.btn.wysihtml5-command-active {
background-image: none;
-webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
-moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
background-color: #E6E6E6;
background-color: #D9D9D9;
outline: 0;
}
ul.wysihtml5-commands-disabled .dropdown-menu {
display: none !important;
}
ul.wysihtml5-toolbar div.wysihtml5-colors {
display:block;
width: 50px;
height: 20px;
margin-top: 2px;
margin-left: 5px;
position: absolute;
pointer-events: none;
}
ul.wysihtml5-toolbar a.wysihtml5-colors-title {
padding-left: 70px;
}
ul.wysihtml5-toolbar div[data-wysihtml5-command-value="black"] {
background: black !important;
}
ul.wysihtml5-toolbar div[data-wysihtml5-command-value="silver"] {
background: silver !important;
}
ul.wysihtml5-toolbar div[data-wysihtml5-command-value="gray"] {
background: gray !important;
}
ul.wysihtml5-toolbar div[data-wysihtml5-command-value="maroon"] {
background: maroon !important;
}
ul.wysihtml5-toolbar div[data-wysihtml5-command-value="red"] {
background: red !important;
}
ul.wysihtml5-toolbar div[data-wysihtml5-command-value="purple"] {
background: purple !important;
}
ul.wysihtml5-toolbar div[data-wysihtml5-command-value="green"] {
background: green !important;
}
ul.wysihtml5-toolbar div[data-wysihtml5-command-value="olive"] {
background: olive !important;
}
ul.wysihtml5-toolbar div[data-wysihtml5-command-value="navy"] {
background: navy !important;
}
ul.wysihtml5-toolbar div[data-wysihtml5-command-value="blue"] {
background: blue !important;
}
ul.wysihtml5-toolbar div[data-wysihtml5-command-value="orange"] {
background: orange !important;
}

View file

@ -0,0 +1,3 @@
/*! bootstrap3-wysihtml5-bower 2013-11-22 */
ul.wysihtml5-toolbar{margin:0;padding:0;display:block}ul.wysihtml5-toolbar::after{clear:both;display:table;content:""}ul.wysihtml5-toolbar>li{float:left;display:list-item;list-style:none;margin:0 5px 10px 0}ul.wysihtml5-toolbar a[data-wysihtml5-command=bold]{font-weight:700}ul.wysihtml5-toolbar a[data-wysihtml5-command=italic]{font-style:italic}ul.wysihtml5-toolbar a[data-wysihtml5-command=underline]{text-decoration:underline}ul.wysihtml5-toolbar a.btn.wysihtml5-command-active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);background-color:#E6E6E6;background-color:#D9D9D9;outline:0}ul.wysihtml5-commands-disabled .dropdown-menu{display:none!important}ul.wysihtml5-toolbar div.wysihtml5-colors{display:block;width:50px;height:20px;margin-top:2px;margin-left:5px;position:absolute;pointer-events:none}ul.wysihtml5-toolbar a.wysihtml5-colors-title{padding-left:70px}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=black]{background:#000!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=silver]{background:silver!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=gray]{background:gray!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=maroon]{background:maroon!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=red]{background:red!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=purple]{background:purple!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=green]{background:green!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=olive]{background:olive!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=navy]{background:navy!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=blue]{background:#00f!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=orange]{background:orange!important}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,214 @@
/*!
* Bootstrap Colorpicker
* http://mjolnic.github.io/bootstrap-colorpicker/
*
* Originally written by (c) 2012 Stefan Petre
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
*/
.colorpicker-saturation {
float: left;
width: 100px;
height: 100px;
cursor: crosshair;
background-image: url("../../img/bootstrap-colorpicker/saturation.png");
}
.colorpicker-saturation i {
position: absolute;
top: 0;
left: 0;
display: block;
width: 5px;
height: 5px;
margin: -4px 0 0 -4px;
border: 1px solid #000;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
.colorpicker-saturation i b {
display: block;
width: 5px;
height: 5px;
border: 1px solid #fff;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
.colorpicker-hue,
.colorpicker-alpha {
float: left;
width: 15px;
height: 100px;
margin-bottom: 4px;
margin-left: 4px;
cursor: row-resize;
}
.colorpicker-hue i,
.colorpicker-alpha i {
position: absolute;
top: 0;
left: 0;
display: block;
width: 100%;
height: 1px;
margin-top: -1px;
background: #000;
border-top: 1px solid #fff;
}
.colorpicker-hue {
background-image: url("../../img/bootstrap-colorpicker/hue.png");
}
.colorpicker-alpha {
display: none;
background-image: url("../../img/bootstrap-colorpicker/alpha.png");
}
.colorpicker {
top: 0;
left: 0;
z-index: 2500;
min-width: 130px;
padding: 4px;
margin-top: 1px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
*zoom: 1;
}
.colorpicker:before,
.colorpicker:after {
display: table;
line-height: 0;
content: "";
}
.colorpicker:after {
clear: both;
}
.colorpicker:before {
position: absolute;
top: -7px;
left: 6px;
display: inline-block;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-left: 7px solid transparent;
border-bottom-color: rgba(0, 0, 0, 0.2);
content: '';
}
.colorpicker:after {
position: absolute;
top: -6px;
left: 7px;
display: inline-block;
border-right: 6px solid transparent;
border-bottom: 6px solid #ffffff;
border-left: 6px solid transparent;
content: '';
}
.colorpicker div {
position: relative;
}
.colorpicker.colorpicker-with-alpha {
min-width: 140px;
}
.colorpicker.colorpicker-with-alpha .colorpicker-alpha {
display: block;
}
.colorpicker-color {
height: 10px;
margin-top: 5px;
clear: both;
background-image: url("../../img/bootstrap-colorpicker/alpha.png");
background-position: 0 100%;
}
.colorpicker-color div {
height: 10px;
}
.colorpicker-element .input-group-addon i {
display: block;
width: 16px;
height: 16px;
cursor: pointer;
}
.colorpicker.colorpicker-inline {
position: relative;
display: inline-block;
float: none;
}
.colorpicker.colorpicker-horizontal {
width: 110px;
height: auto;
min-width: 110px;
}
.colorpicker.colorpicker-horizontal .colorpicker-saturation {
margin-bottom: 4px;
}
.colorpicker.colorpicker-horizontal .colorpicker-color {
width: 100px;
}
.colorpicker.colorpicker-horizontal .colorpicker-hue,
.colorpicker.colorpicker-horizontal .colorpicker-alpha {
float: left;
width: 100px;
height: 15px;
margin-bottom: 4px;
margin-left: 0;
cursor: col-resize;
}
.colorpicker.colorpicker-horizontal .colorpicker-hue i,
.colorpicker.colorpicker-horizontal .colorpicker-alpha i {
position: absolute;
top: 0;
left: 0;
display: block;
width: 1px;
height: 15px;
margin-top: 0;
background: #ffffff;
border: none;
}
.colorpicker.colorpicker-horizontal .colorpicker-hue {
background-image: url("../../img/bootstrap-colorpicker/hue-horizontal.png");
}
.colorpicker.colorpicker-horizontal .colorpicker-alpha {
background-image: url("../../img/bootstrap-colorpicker/alpha-horizontal.png");
}
.colorpicker.colorpicker-hidden {
display: none;
}
.colorpicker.colorpicker-visible {
display: block;
}
.colorpicker-inline.colorpicker-visible {
display: inline-block;
}

View file

@ -0,0 +1,9 @@
/*!
* Bootstrap Colorpicker
* http://mjolnic.github.io/bootstrap-colorpicker/
*
* Originally written by (c) 2012 Stefan Petre
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
*/.colorpicker-saturation{float:left;width:100px;height:100px;cursor:crosshair;background-image:url("../../img/bootstrap-colorpicker/saturation.png")}.colorpicker-saturation i{position:absolute;top:0;left:0;display:block;width:5px;height:5px;margin:-4px 0 0 -4px;border:1px solid #000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.colorpicker-saturation i b{display:block;width:5px;height:5px;border:1px solid #fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.colorpicker-hue,.colorpicker-alpha{float:left;width:15px;height:100px;margin-bottom:4px;margin-left:4px;cursor:row-resize}.colorpicker-hue i,.colorpicker-alpha i{position:absolute;top:0;left:0;display:block;width:100%;height:1px;margin-top:-1px;background:#000;border-top:1px solid #fff}.colorpicker-hue{background-image:url("../../img/bootstrap-colorpicker/hue.png")}.colorpicker-alpha{display:none;background-image:url("../../img/bootstrap-colorpicker/alpha.png")}.colorpicker{top:0;left:0;z-index:2500;min-width:130px;padding:4px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1}.colorpicker:before,.colorpicker:after{display:table;line-height:0;content:""}.colorpicker:after{clear:both}.colorpicker:before{position:absolute;top:-7px;left:6px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.colorpicker:after{position:absolute;top:-6px;left:7px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.colorpicker div{position:relative}.colorpicker.colorpicker-with-alpha{min-width:140px}.colorpicker.colorpicker-with-alpha .colorpicker-alpha{display:block}.colorpicker-color{height:10px;margin-top:5px;clear:both;background-image:url("../../img/bootstrap-colorpicker/alpha.png");background-position:0 100%}.colorpicker-color div{height:10px}.colorpicker-element .input-group-addon i{display:block;width:16px;height:16px;cursor:pointer}.colorpicker.colorpicker-inline{position:relative;display:inline-block;float:none}.colorpicker.colorpicker-horizontal{width:110px;height:auto;min-width:110px}.colorpicker.colorpicker-horizontal .colorpicker-saturation{margin-bottom:4px}.colorpicker.colorpicker-horizontal .colorpicker-color{width:100px}.colorpicker.colorpicker-horizontal .colorpicker-hue,.colorpicker.colorpicker-horizontal .colorpicker-alpha{float:left;width:100px;height:15px;margin-bottom:4px;margin-left:0;cursor:col-resize}.colorpicker.colorpicker-horizontal .colorpicker-hue i,.colorpicker.colorpicker-horizontal .colorpicker-alpha i{position:absolute;top:0;left:0;display:block;width:1px;height:15px;margin-top:0;background:#fff;border:0}.colorpicker.colorpicker-horizontal .colorpicker-hue{background-image:url("../../img/bootstrap-colorpicker/hue-horizontal.png")}.colorpicker.colorpicker-horizontal .colorpicker-alpha{background-image:url("../../img/bootstrap-colorpicker/alpha-horizontal.png")}.colorpicker.colorpicker-hidden{display:none}.colorpicker.colorpicker-visible{display:block}.colorpicker-inline.colorpicker-visible{display:inline-block}

View file

@ -0,0 +1,223 @@
div.dataTables_length label {
font-weight: normal;
float: left;
text-align: left;
}
div.dataTables_length select {
width: 75px;
}
div.dataTables_filter label {
font-weight: normal;
float: right;
}
div.dataTables_filter input {
width: 16em;
}
div.dataTables_info {
padding-top: 8px;
}
div.dataTables_paginate {
float: right;
margin: 0;
}
div.dataTables_paginate ul.pagination {
margin: 2px 0;
white-space: nowrap;
}
table.dataTable,
table.dataTable td,
table.dataTable th {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
table.dataTable {
clear: both;
margin-top: 6px !important;
margin-bottom: 6px !important;
max-width: none !important;
}
table.dataTable thead .sorting,
table.dataTable thead .sorting_asc,
table.dataTable thead .sorting_desc,
table.dataTable thead .sorting_asc_disabled,
table.dataTable thead .sorting_desc_disabled {
cursor: pointer;
}
table.dataTable thead .sorting { background: url('images/sort_both.png') no-repeat center right; }
table.dataTable thead .sorting_asc { background: url('images/sort_asc.png') no-repeat center right; }
table.dataTable thead .sorting_desc { background: url('images/sort_desc.png') no-repeat center right; }
table.dataTable thead .sorting_asc_disabled { background: url('images/sort_asc_disabled.png') no-repeat center right; }
table.dataTable thead .sorting_desc_disabled { background: url('images/sort_desc_disabled.png') no-repeat center right; }
table.dataTable th:active {
outline: none;
}
/* Scrolling */
div.dataTables_scrollHead table {
margin-bottom: 0 !important;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
div.dataTables_scrollHead table thead tr:last-child th:first-child,
div.dataTables_scrollHead table thead tr:last-child td:first-child {
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
div.dataTables_scrollBody table {
border-top: none;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
div.dataTables_scrollBody tbody tr:first-child th,
div.dataTables_scrollBody tbody tr:first-child td {
border-top: none;
}
div.dataTables_scrollFoot table {
margin-top: 0 !important;
border-top: none;
}
/*
* TableTools styles
*/
.table tbody tr.active td,
.table tbody tr.active th {
background-color: #08C;
color: white;
}
.table tbody tr.active:hover td,
.table tbody tr.active:hover th {
background-color: #0075b0 !important;
}
.table tbody tr.active a {
color: white;
}
.table-striped tbody tr.active:nth-child(odd) td,
.table-striped tbody tr.active:nth-child(odd) th {
background-color: #017ebc;
}
table.DTTT_selectable tbody tr {
cursor: pointer;
}
div.DTTT .btn {
color: #333 !important;
font-size: 12px;
}
div.DTTT .btn:hover {
text-decoration: none !important;
}
ul.DTTT_dropdown.dropdown-menu {
z-index: 2003;
}
ul.DTTT_dropdown.dropdown-menu a {
color: #333 !important; /* needed only when demo_page.css is included */
}
ul.DTTT_dropdown.dropdown-menu li {
position: relative;
}
ul.DTTT_dropdown.dropdown-menu li:hover a {
background-color: #0088cc;
color: white !important;
}
div.DTTT_collection_background {
z-index: 2002;
}
/* TableTools information display */
div.DTTT_print_info.modal {
height: 150px;
margin-top: -75px;
text-align: center;
}
div.DTTT_print_info h6 {
font-weight: normal;
font-size: 28px;
line-height: 28px;
margin: 1em;
}
div.DTTT_print_info p {
font-size: 14px;
line-height: 20px;
}
/*
* FixedColumns styles
*/
div.DTFC_LeftHeadWrapper table,
div.DTFC_LeftFootWrapper table,
div.DTFC_RightHeadWrapper table,
div.DTFC_RightFootWrapper table,
table.DTFC_Cloned tr.even {
background-color: white;
}
div.DTFC_RightHeadWrapper table ,
div.DTFC_LeftHeadWrapper table {
margin-bottom: 0 !important;
border-top-right-radius: 0 !important;
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child,
div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child,
div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child,
div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child {
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
div.DTFC_RightBodyWrapper table,
div.DTFC_LeftBodyWrapper table {
border-top: none;
margin-bottom: 0 !important;
}
div.DTFC_RightBodyWrapper tbody tr:first-child th,
div.DTFC_RightBodyWrapper tbody tr:first-child td,
div.DTFC_LeftBodyWrapper tbody tr:first-child th,
div.DTFC_LeftBodyWrapper tbody tr:first-child td {
border-top: none;
}
div.DTFC_RightFootWrapper table,
div.DTFC_LeftFootWrapper table {
border-top: none;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,790 @@
/*!
* Datepicker for Bootstrap
*
* Copyright 2012 Stefan Petre
* Improvements by Andrew Rowls
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
.datepicker {
padding: 4px;
border-radius: 4px;
direction: ltr;
/*.dow {
border-top: 1px solid #ddd !important;
}*/
}
.datepicker-inline {
width: 100%;
}
.datepicker.datepicker-rtl {
direction: rtl;
}
.datepicker.datepicker-rtl table tr td span {
float: right;
}
.datepicker-dropdown {
top: 0;
left: 0;
}
.datepicker-dropdown:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-top: 0;
border-bottom-color: rgba(0, 0, 0, 0.2);
position: absolute;
}
.datepicker-dropdown:after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-top: 0;
position: absolute;
}
.datepicker-dropdown.datepicker-orient-left:before {
left: 6px;
}
.datepicker-dropdown.datepicker-orient-left:after {
left: 7px;
}
.datepicker-dropdown.datepicker-orient-right:before {
right: 6px;
}
.datepicker-dropdown.datepicker-orient-right:after {
right: 7px;
}
.datepicker-dropdown.datepicker-orient-top:before {
top: -7px;
}
.datepicker-dropdown.datepicker-orient-top:after {
top: -6px;
}
.datepicker-dropdown.datepicker-orient-bottom:before {
bottom: -7px;
border-bottom: 0;
border-top: 7px solid #999;
}
.datepicker-dropdown.datepicker-orient-bottom:after {
bottom: -6px;
border-bottom: 0;
border-top: 6px solid #fff;
}
.datepicker > div {
display: none;
}
.datepicker.days div.datepicker-days {
display: block;
}
.datepicker.months div.datepicker-months {
display: block;
}
.datepicker.years div.datepicker-years {
display: block;
}
.datepicker table {
margin: 0;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.datepicker table tr td,
.datepicker table tr th {
text-align: center;
width: 30px;
height: 30px;
border-radius: 4px;
border: none;
}
.table-striped .datepicker table tr td,
.table-striped .datepicker table tr th {
background-color: transparent;
}
.datepicker table tr td.day:hover,
.datepicker table tr td.day.focused {
background: rgba(0,0,0,0.2);
cursor: pointer;
}
.datepicker table tr td.old,
.datepicker table tr td.new {
color: #777;
}
.datepicker table tr td.disabled,
.datepicker table tr td.disabled:hover {
background: none;
color: #444;
cursor: default;
}
.datepicker table tr td.today,
.datepicker table tr td.today:hover,
.datepicker table tr td.today.disabled,
.datepicker table tr td.today.disabled:hover {
color: #000000;
background: rgba(0,0,0,0.2);
border-color: #ffb733;
}
.datepicker table tr td.today:hover,
.datepicker table tr td.today:hover:hover,
.datepicker table tr td.today.disabled:hover,
.datepicker table tr td.today.disabled:hover:hover,
.datepicker table tr td.today:focus,
.datepicker table tr td.today:hover:focus,
.datepicker table tr td.today.disabled:focus,
.datepicker table tr td.today.disabled:hover:focus,
.datepicker table tr td.today:active,
.datepicker table tr td.today:hover:active,
.datepicker table tr td.today.disabled:active,
.datepicker table tr td.today.disabled:hover:active,
.datepicker table tr td.today.active,
.datepicker table tr td.today:hover.active,
.datepicker table tr td.today.disabled.active,
.datepicker table tr td.today.disabled:hover.active,
.open .dropdown-toggle.datepicker table tr td.today,
.open .dropdown-toggle.datepicker table tr td.today:hover,
.open .dropdown-toggle.datepicker table tr td.today.disabled,
.open .dropdown-toggle.datepicker table tr td.today.disabled:hover {
color: #000000;
background: rgba(0,0,0,0.2);
border-color: #f59e00;
}
.datepicker table tr td.today:active,
.datepicker table tr td.today:hover:active,
.datepicker table tr td.today.disabled:active,
.datepicker table tr td.today.disabled:hover:active,
.datepicker table tr td.today.active,
.datepicker table tr td.today:hover.active,
.datepicker table tr td.today.disabled.active,
.datepicker table tr td.today.disabled:hover.active,
.open .dropdown-toggle.datepicker table tr td.today,
.open .dropdown-toggle.datepicker table tr td.today:hover,
.open .dropdown-toggle.datepicker table tr td.today.disabled,
.open .dropdown-toggle.datepicker table tr td.today.disabled:hover {
background-image: none;
}
.datepicker table tr td.today.disabled,
.datepicker table tr td.today:hover.disabled,
.datepicker table tr td.today.disabled.disabled,
.datepicker table tr td.today.disabled:hover.disabled,
.datepicker table tr td.today[disabled],
.datepicker table tr td.today:hover[disabled],
.datepicker table tr td.today.disabled[disabled],
.datepicker table tr td.today.disabled:hover[disabled],
fieldset[disabled] .datepicker table tr td.today,
fieldset[disabled] .datepicker table tr td.today:hover,
fieldset[disabled] .datepicker table tr td.today.disabled,
fieldset[disabled] .datepicker table tr td.today.disabled:hover,
.datepicker table tr td.today.disabled:hover,
.datepicker table tr td.today:hover.disabled:hover,
.datepicker table tr td.today.disabled.disabled:hover,
.datepicker table tr td.today.disabled:hover.disabled:hover,
.datepicker table tr td.today[disabled]:hover,
.datepicker table tr td.today:hover[disabled]:hover,
.datepicker table tr td.today.disabled[disabled]:hover,
.datepicker table tr td.today.disabled:hover[disabled]:hover,
fieldset[disabled] .datepicker table tr td.today:hover,
fieldset[disabled] .datepicker table tr td.today:hover:hover,
fieldset[disabled] .datepicker table tr td.today.disabled:hover,
fieldset[disabled] .datepicker table tr td.today.disabled:hover:hover,
.datepicker table tr td.today.disabled:focus,
.datepicker table tr td.today:hover.disabled:focus,
.datepicker table tr td.today.disabled.disabled:focus,
.datepicker table tr td.today.disabled:hover.disabled:focus,
.datepicker table tr td.today[disabled]:focus,
.datepicker table tr td.today:hover[disabled]:focus,
.datepicker table tr td.today.disabled[disabled]:focus,
.datepicker table tr td.today.disabled:hover[disabled]:focus,
fieldset[disabled] .datepicker table tr td.today:focus,
fieldset[disabled] .datepicker table tr td.today:hover:focus,
fieldset[disabled] .datepicker table tr td.today.disabled:focus,
fieldset[disabled] .datepicker table tr td.today.disabled:hover:focus,
.datepicker table tr td.today.disabled:active,
.datepicker table tr td.today:hover.disabled:active,
.datepicker table tr td.today.disabled.disabled:active,
.datepicker table tr td.today.disabled:hover.disabled:active,
.datepicker table tr td.today[disabled]:active,
.datepicker table tr td.today:hover[disabled]:active,
.datepicker table tr td.today.disabled[disabled]:active,
.datepicker table tr td.today.disabled:hover[disabled]:active,
fieldset[disabled] .datepicker table tr td.today:active,
fieldset[disabled] .datepicker table tr td.today:hover:active,
fieldset[disabled] .datepicker table tr td.today.disabled:active,
fieldset[disabled] .datepicker table tr td.today.disabled:hover:active,
.datepicker table tr td.today.disabled.active,
.datepicker table tr td.today:hover.disabled.active,
.datepicker table tr td.today.disabled.disabled.active,
.datepicker table tr td.today.disabled:hover.disabled.active,
.datepicker table tr td.today[disabled].active,
.datepicker table tr td.today:hover[disabled].active,
.datepicker table tr td.today.disabled[disabled].active,
.datepicker table tr td.today.disabled:hover[disabled].active,
fieldset[disabled] .datepicker table tr td.today.active,
fieldset[disabled] .datepicker table tr td.today:hover.active,
fieldset[disabled] .datepicker table tr td.today.disabled.active,
fieldset[disabled] .datepicker table tr td.today.disabled:hover.active {
background: rgba(0,0,0,0.2);
border-color: #ffb733;
}
.datepicker table tr td.today:hover:hover {
color: #000;
}
.datepicker table tr td.today.active:hover {
color: #fff;
}
.datepicker table tr td.range,
.datepicker table tr td.range:hover,
.datepicker table tr td.range.disabled,
.datepicker table tr td.range.disabled:hover {
background: rgba(0,0,0,0.2);
border-radius: 0;
}
.datepicker table tr td.range.today,
.datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today.disabled:hover {
color: #000000;
background: rgba(0,0,0,0.2);
border-color: #f1a417;
border-radius: 0;
}
.datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today:hover:hover,
.datepicker table tr td.range.today.disabled:hover,
.datepicker table tr td.range.today.disabled:hover:hover,
.datepicker table tr td.range.today:focus,
.datepicker table tr td.range.today:hover:focus,
.datepicker table tr td.range.today.disabled:focus,
.datepicker table tr td.range.today.disabled:hover:focus,
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today:hover:active,
.datepicker table tr td.range.today.disabled:active,
.datepicker table tr td.range.today.disabled:hover:active,
.datepicker table tr td.range.today.active,
.datepicker table tr td.range.today:hover.active,
.datepicker table tr td.range.today.disabled.active,
.datepicker table tr td.range.today.disabled:hover.active,
.open .dropdown-toggle.datepicker table tr td.range.today,
.open .dropdown-toggle.datepicker table tr td.range.today:hover,
.open .dropdown-toggle.datepicker table tr td.range.today.disabled,
.open .dropdown-toggle.datepicker table tr td.range.today.disabled:hover {
color: #000000;
background: rgba(0,0,0,0.2);
border-color: #bf800c;
}
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today:hover:active,
.datepicker table tr td.range.today.disabled:active,
.datepicker table tr td.range.today.disabled:hover:active,
.datepicker table tr td.range.today.active,
.datepicker table tr td.range.today:hover.active,
.datepicker table tr td.range.today.disabled.active,
.datepicker table tr td.range.today.disabled:hover.active,
.open .dropdown-toggle.datepicker table tr td.range.today,
.open .dropdown-toggle.datepicker table tr td.range.today:hover,
.open .dropdown-toggle.datepicker table tr td.range.today.disabled,
.open .dropdown-toggle.datepicker table tr td.range.today.disabled:hover {
background-image: none;
}
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today:hover.disabled,
.datepicker table tr td.range.today.disabled.disabled,
.datepicker table tr td.range.today.disabled:hover.disabled,
.datepicker table tr td.range.today[disabled],
.datepicker table tr td.range.today:hover[disabled],
.datepicker table tr td.range.today.disabled[disabled],
.datepicker table tr td.range.today.disabled:hover[disabled],
fieldset[disabled] .datepicker table tr td.range.today,
fieldset[disabled] .datepicker table tr td.range.today:hover,
fieldset[disabled] .datepicker table tr td.range.today.disabled,
fieldset[disabled] .datepicker table tr td.range.today.disabled:hover,
.datepicker table tr td.range.today.disabled:hover,
.datepicker table tr td.range.today:hover.disabled:hover,
.datepicker table tr td.range.today.disabled.disabled:hover,
.datepicker table tr td.range.today.disabled:hover.disabled:hover,
.datepicker table tr td.range.today[disabled]:hover,
.datepicker table tr td.range.today:hover[disabled]:hover,
.datepicker table tr td.range.today.disabled[disabled]:hover,
.datepicker table tr td.range.today.disabled:hover[disabled]:hover,
fieldset[disabled] .datepicker table tr td.range.today:hover,
fieldset[disabled] .datepicker table tr td.range.today:hover:hover,
fieldset[disabled] .datepicker table tr td.range.today.disabled:hover,
fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:hover,
.datepicker table tr td.range.today.disabled:focus,
.datepicker table tr td.range.today:hover.disabled:focus,
.datepicker table tr td.range.today.disabled.disabled:focus,
.datepicker table tr td.range.today.disabled:hover.disabled:focus,
.datepicker table tr td.range.today[disabled]:focus,
.datepicker table tr td.range.today:hover[disabled]:focus,
.datepicker table tr td.range.today.disabled[disabled]:focus,
.datepicker table tr td.range.today.disabled:hover[disabled]:focus,
fieldset[disabled] .datepicker table tr td.range.today:focus,
fieldset[disabled] .datepicker table tr td.range.today:hover:focus,
fieldset[disabled] .datepicker table tr td.range.today.disabled:focus,
fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:focus,
.datepicker table tr td.range.today.disabled:active,
.datepicker table tr td.range.today:hover.disabled:active,
.datepicker table tr td.range.today.disabled.disabled:active,
.datepicker table tr td.range.today.disabled:hover.disabled:active,
.datepicker table tr td.range.today[disabled]:active,
.datepicker table tr td.range.today:hover[disabled]:active,
.datepicker table tr td.range.today.disabled[disabled]:active,
.datepicker table tr td.range.today.disabled:hover[disabled]:active,
fieldset[disabled] .datepicker table tr td.range.today:active,
fieldset[disabled] .datepicker table tr td.range.today:hover:active,
fieldset[disabled] .datepicker table tr td.range.today.disabled:active,
fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:active,
.datepicker table tr td.range.today.disabled.active,
.datepicker table tr td.range.today:hover.disabled.active,
.datepicker table tr td.range.today.disabled.disabled.active,
.datepicker table tr td.range.today.disabled:hover.disabled.active,
.datepicker table tr td.range.today[disabled].active,
.datepicker table tr td.range.today:hover[disabled].active,
.datepicker table tr td.range.today.disabled[disabled].active,
.datepicker table tr td.range.today.disabled:hover[disabled].active,
fieldset[disabled] .datepicker table tr td.range.today.active,
fieldset[disabled] .datepicker table tr td.range.today:hover.active,
fieldset[disabled] .datepicker table tr td.range.today.disabled.active,
fieldset[disabled] .datepicker table tr td.range.today.disabled:hover.active {
background: rgba(0,0,0,0.2);
border-color: #f1a417;
}
.datepicker table tr td.selected,
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected.disabled,
.datepicker table tr td.selected.disabled:hover {
color: #ffffff;
background: rgba(0,0,0,0.2);
border-color: #555555;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected:hover:hover,
.datepicker table tr td.selected.disabled:hover,
.datepicker table tr td.selected.disabled:hover:hover,
.datepicker table tr td.selected:focus,
.datepicker table tr td.selected:hover:focus,
.datepicker table tr td.selected.disabled:focus,
.datepicker table tr td.selected.disabled:hover:focus,
.datepicker table tr td.selected:active,
.datepicker table tr td.selected:hover:active,
.datepicker table tr td.selected.disabled:active,
.datepicker table tr td.selected.disabled:hover:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected:hover.active,
.datepicker table tr td.selected.disabled.active,
.datepicker table tr td.selected.disabled:hover.active,
.open .dropdown-toggle.datepicker table tr td.selected,
.open .dropdown-toggle.datepicker table tr td.selected:hover,
.open .dropdown-toggle.datepicker table tr td.selected.disabled,
.open .dropdown-toggle.datepicker table tr td.selected.disabled:hover {
color: #ffffff;
background: rgba(0,0,0,0.2);
border-color: #373737;
}
.datepicker table tr td.selected:active,
.datepicker table tr td.selected:hover:active,
.datepicker table tr td.selected.disabled:active,
.datepicker table tr td.selected.disabled:hover:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected:hover.active,
.datepicker table tr td.selected.disabled.active,
.datepicker table tr td.selected.disabled:hover.active,
.open .dropdown-toggle.datepicker table tr td.selected,
.open .dropdown-toggle.datepicker table tr td.selected:hover,
.open .dropdown-toggle.datepicker table tr td.selected.disabled,
.open .dropdown-toggle.datepicker table tr td.selected.disabled:hover {
background-image: none;
}
.datepicker table tr td.selected.disabled,
.datepicker table tr td.selected:hover.disabled,
.datepicker table tr td.selected.disabled.disabled,
.datepicker table tr td.selected.disabled:hover.disabled,
.datepicker table tr td.selected[disabled],
.datepicker table tr td.selected:hover[disabled],
.datepicker table tr td.selected.disabled[disabled],
.datepicker table tr td.selected.disabled:hover[disabled],
fieldset[disabled] .datepicker table tr td.selected,
fieldset[disabled] .datepicker table tr td.selected:hover,
fieldset[disabled] .datepicker table tr td.selected.disabled,
fieldset[disabled] .datepicker table tr td.selected.disabled:hover,
.datepicker table tr td.selected.disabled:hover,
.datepicker table tr td.selected:hover.disabled:hover,
.datepicker table tr td.selected.disabled.disabled:hover,
.datepicker table tr td.selected.disabled:hover.disabled:hover,
.datepicker table tr td.selected[disabled]:hover,
.datepicker table tr td.selected:hover[disabled]:hover,
.datepicker table tr td.selected.disabled[disabled]:hover,
.datepicker table tr td.selected.disabled:hover[disabled]:hover,
fieldset[disabled] .datepicker table tr td.selected:hover,
fieldset[disabled] .datepicker table tr td.selected:hover:hover,
fieldset[disabled] .datepicker table tr td.selected.disabled:hover,
fieldset[disabled] .datepicker table tr td.selected.disabled:hover:hover,
.datepicker table tr td.selected.disabled:focus,
.datepicker table tr td.selected:hover.disabled:focus,
.datepicker table tr td.selected.disabled.disabled:focus,
.datepicker table tr td.selected.disabled:hover.disabled:focus,
.datepicker table tr td.selected[disabled]:focus,
.datepicker table tr td.selected:hover[disabled]:focus,
.datepicker table tr td.selected.disabled[disabled]:focus,
.datepicker table tr td.selected.disabled:hover[disabled]:focus,
fieldset[disabled] .datepicker table tr td.selected:focus,
fieldset[disabled] .datepicker table tr td.selected:hover:focus,
fieldset[disabled] .datepicker table tr td.selected.disabled:focus,
fieldset[disabled] .datepicker table tr td.selected.disabled:hover:focus,
.datepicker table tr td.selected.disabled:active,
.datepicker table tr td.selected:hover.disabled:active,
.datepicker table tr td.selected.disabled.disabled:active,
.datepicker table tr td.selected.disabled:hover.disabled:active,
.datepicker table tr td.selected[disabled]:active,
.datepicker table tr td.selected:hover[disabled]:active,
.datepicker table tr td.selected.disabled[disabled]:active,
.datepicker table tr td.selected.disabled:hover[disabled]:active,
fieldset[disabled] .datepicker table tr td.selected:active,
fieldset[disabled] .datepicker table tr td.selected:hover:active,
fieldset[disabled] .datepicker table tr td.selected.disabled:active,
fieldset[disabled] .datepicker table tr td.selected.disabled:hover:active,
.datepicker table tr td.selected.disabled.active,
.datepicker table tr td.selected:hover.disabled.active,
.datepicker table tr td.selected.disabled.disabled.active,
.datepicker table tr td.selected.disabled:hover.disabled.active,
.datepicker table tr td.selected[disabled].active,
.datepicker table tr td.selected:hover[disabled].active,
.datepicker table tr td.selected.disabled[disabled].active,
.datepicker table tr td.selected.disabled:hover[disabled].active,
fieldset[disabled] .datepicker table tr td.selected.active,
fieldset[disabled] .datepicker table tr td.selected:hover.active,
fieldset[disabled] .datepicker table tr td.selected.disabled.active,
fieldset[disabled] .datepicker table tr td.selected.disabled:hover.active {
background: rgba(0,0,0,0.2);
border-color: #555555;
}
.datepicker table tr td.active,
.datepicker table tr td.active:hover,
.datepicker table tr td.active.disabled,
.datepicker table tr td.active.disabled:hover {
color: #ffffff;
background: rgba(0,0,0,0.2);
border-color: #357ebd;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.active:hover,
.datepicker table tr td.active:hover:hover,
.datepicker table tr td.active.disabled:hover,
.datepicker table tr td.active.disabled:hover:hover,
.datepicker table tr td.active:focus,
.datepicker table tr td.active:hover:focus,
.datepicker table tr td.active.disabled:focus,
.datepicker table tr td.active.disabled:hover:focus,
.datepicker table tr td.active:active,
.datepicker table tr td.active:hover:active,
.datepicker table tr td.active.disabled:active,
.datepicker table tr td.active.disabled:hover:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active:hover.active,
.datepicker table tr td.active.disabled.active,
.datepicker table tr td.active.disabled:hover.active,
.open .dropdown-toggle.datepicker table tr td.active,
.open .dropdown-toggle.datepicker table tr td.active:hover,
.open .dropdown-toggle.datepicker table tr td.active.disabled,
.open .dropdown-toggle.datepicker table tr td.active.disabled:hover {
color: #ffffff;
background: rgba(0,0,0,0.5);
border-color: #285e8e;
}
.datepicker table tr td.active:active,
.datepicker table tr td.active:hover:active,
.datepicker table tr td.active.disabled:active,
.datepicker table tr td.active.disabled:hover:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active:hover.active,
.datepicker table tr td.active.disabled.active,
.datepicker table tr td.active.disabled:hover.active,
.open .dropdown-toggle.datepicker table tr td.active,
.open .dropdown-toggle.datepicker table tr td.active:hover,
.open .dropdown-toggle.datepicker table tr td.active.disabled,
.open .dropdown-toggle.datepicker table tr td.active.disabled:hover {
background-image: none;
}
.datepicker table tr td.active.disabled,
.datepicker table tr td.active:hover.disabled,
.datepicker table tr td.active.disabled.disabled,
.datepicker table tr td.active.disabled:hover.disabled,
.datepicker table tr td.active[disabled],
.datepicker table tr td.active:hover[disabled],
.datepicker table tr td.active.disabled[disabled],
.datepicker table tr td.active.disabled:hover[disabled],
fieldset[disabled] .datepicker table tr td.active,
fieldset[disabled] .datepicker table tr td.active:hover,
fieldset[disabled] .datepicker table tr td.active.disabled,
fieldset[disabled] .datepicker table tr td.active.disabled:hover,
.datepicker table tr td.active.disabled:hover,
.datepicker table tr td.active:hover.disabled:hover,
.datepicker table tr td.active.disabled.disabled:hover,
.datepicker table tr td.active.disabled:hover.disabled:hover,
.datepicker table tr td.active[disabled]:hover,
.datepicker table tr td.active:hover[disabled]:hover,
.datepicker table tr td.active.disabled[disabled]:hover,
.datepicker table tr td.active.disabled:hover[disabled]:hover,
fieldset[disabled] .datepicker table tr td.active:hover,
fieldset[disabled] .datepicker table tr td.active:hover:hover,
fieldset[disabled] .datepicker table tr td.active.disabled:hover,
fieldset[disabled] .datepicker table tr td.active.disabled:hover:hover,
.datepicker table tr td.active.disabled:focus,
.datepicker table tr td.active:hover.disabled:focus,
.datepicker table tr td.active.disabled.disabled:focus,
.datepicker table tr td.active.disabled:hover.disabled:focus,
.datepicker table tr td.active[disabled]:focus,
.datepicker table tr td.active:hover[disabled]:focus,
.datepicker table tr td.active.disabled[disabled]:focus,
.datepicker table tr td.active.disabled:hover[disabled]:focus,
fieldset[disabled] .datepicker table tr td.active:focus,
fieldset[disabled] .datepicker table tr td.active:hover:focus,
fieldset[disabled] .datepicker table tr td.active.disabled:focus,
fieldset[disabled] .datepicker table tr td.active.disabled:hover:focus,
.datepicker table tr td.active.disabled:active,
.datepicker table tr td.active:hover.disabled:active,
.datepicker table tr td.active.disabled.disabled:active,
.datepicker table tr td.active.disabled:hover.disabled:active,
.datepicker table tr td.active[disabled]:active,
.datepicker table tr td.active:hover[disabled]:active,
.datepicker table tr td.active.disabled[disabled]:active,
.datepicker table tr td.active.disabled:hover[disabled]:active,
fieldset[disabled] .datepicker table tr td.active:active,
fieldset[disabled] .datepicker table tr td.active:hover:active,
fieldset[disabled] .datepicker table tr td.active.disabled:active,
fieldset[disabled] .datepicker table tr td.active.disabled:hover:active,
.datepicker table tr td.active.disabled.active,
.datepicker table tr td.active:hover.disabled.active,
.datepicker table tr td.active.disabled.disabled.active,
.datepicker table tr td.active.disabled:hover.disabled.active,
.datepicker table tr td.active[disabled].active,
.datepicker table tr td.active:hover[disabled].active,
.datepicker table tr td.active.disabled[disabled].active,
.datepicker table tr td.active.disabled:hover[disabled].active,
fieldset[disabled] .datepicker table tr td.active.active,
fieldset[disabled] .datepicker table tr td.active:hover.active,
fieldset[disabled] .datepicker table tr td.active.disabled.active,
fieldset[disabled] .datepicker table tr td.active.disabled:hover.active {
background-color: #428bca;
border-color: #357ebd;
}
.datepicker table tr td span {
display: block;
width: 23%;
height: 54px;
line-height: 54px;
float: left;
margin: 1%;
cursor: pointer;
border-radius: 4px;
}
.datepicker table tr td span:hover {
background: rgba(0,0,0,0.2);
}
.datepicker table tr td span.disabled,
.datepicker table tr td span.disabled:hover {
background: none;
color: #444;
cursor: default;
}
.datepicker table tr td span.active,
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active.disabled:hover {
color: #ffffff;
background-color: #428bca;
border-color: #357ebd;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active:hover:hover,
.datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active.disabled:hover:hover,
.datepicker table tr td span.active:focus,
.datepicker table tr td span.active:hover:focus,
.datepicker table tr td span.active.disabled:focus,
.datepicker table tr td span.active.disabled:hover:focus,
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active,
.open .dropdown-toggle.datepicker table tr td span.active,
.open .dropdown-toggle.datepicker table tr td span.active:hover,
.open .dropdown-toggle.datepicker table tr td span.active.disabled,
.open .dropdown-toggle.datepicker table tr td span.active.disabled:hover {
color: #ffffff;
background-color: #3276b1;
border-color: #285e8e;
}
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active,
.open .dropdown-toggle.datepicker table tr td span.active,
.open .dropdown-toggle.datepicker table tr td span.active:hover,
.open .dropdown-toggle.datepicker table tr td span.active.disabled,
.open .dropdown-toggle.datepicker table tr td span.active.disabled:hover {
background-image: none;
}
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active:hover.disabled,
.datepicker table tr td span.active.disabled.disabled,
.datepicker table tr td span.active.disabled:hover.disabled,
.datepicker table tr td span.active[disabled],
.datepicker table tr td span.active:hover[disabled],
.datepicker table tr td span.active.disabled[disabled],
.datepicker table tr td span.active.disabled:hover[disabled],
fieldset[disabled] .datepicker table tr td span.active,
fieldset[disabled] .datepicker table tr td span.active:hover,
fieldset[disabled] .datepicker table tr td span.active.disabled,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active:hover.disabled:hover,
.datepicker table tr td span.active.disabled.disabled:hover,
.datepicker table tr td span.active.disabled:hover.disabled:hover,
.datepicker table tr td span.active[disabled]:hover,
.datepicker table tr td span.active:hover[disabled]:hover,
.datepicker table tr td span.active.disabled[disabled]:hover,
.datepicker table tr td span.active.disabled:hover[disabled]:hover,
fieldset[disabled] .datepicker table tr td span.active:hover,
fieldset[disabled] .datepicker table tr td span.active:hover:hover,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover:hover,
.datepicker table tr td span.active.disabled:focus,
.datepicker table tr td span.active:hover.disabled:focus,
.datepicker table tr td span.active.disabled.disabled:focus,
.datepicker table tr td span.active.disabled:hover.disabled:focus,
.datepicker table tr td span.active[disabled]:focus,
.datepicker table tr td span.active:hover[disabled]:focus,
.datepicker table tr td span.active.disabled[disabled]:focus,
.datepicker table tr td span.active.disabled:hover[disabled]:focus,
fieldset[disabled] .datepicker table tr td span.active:focus,
fieldset[disabled] .datepicker table tr td span.active:hover:focus,
fieldset[disabled] .datepicker table tr td span.active.disabled:focus,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover:focus,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active:hover.disabled:active,
.datepicker table tr td span.active.disabled.disabled:active,
.datepicker table tr td span.active.disabled:hover.disabled:active,
.datepicker table tr td span.active[disabled]:active,
.datepicker table tr td span.active:hover[disabled]:active,
.datepicker table tr td span.active.disabled[disabled]:active,
.datepicker table tr td span.active.disabled:hover[disabled]:active,
fieldset[disabled] .datepicker table tr td span.active:active,
fieldset[disabled] .datepicker table tr td span.active:hover:active,
fieldset[disabled] .datepicker table tr td span.active.disabled:active,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active:hover.disabled.active,
.datepicker table tr td span.active.disabled.disabled.active,
.datepicker table tr td span.active.disabled:hover.disabled.active,
.datepicker table tr td span.active[disabled].active,
.datepicker table tr td span.active:hover[disabled].active,
.datepicker table tr td span.active.disabled[disabled].active,
.datepicker table tr td span.active.disabled:hover[disabled].active,
fieldset[disabled] .datepicker table tr td span.active.active,
fieldset[disabled] .datepicker table tr td span.active:hover.active,
fieldset[disabled] .datepicker table tr td span.active.disabled.active,
fieldset[disabled] .datepicker table tr td span.active.disabled:hover.active {
background-color: #428bca;
border-color: #357ebd;
}
.datepicker table tr td span.old,
.datepicker table tr td span.new {
color: #444;
}
.datepicker th.datepicker-switch {
width: 145px;
}
.datepicker thead tr:first-child th,
.datepicker tfoot tr th {
cursor: pointer;
}
.datepicker thead tr:first-child th:hover,
.datepicker tfoot tr th:hover {
background: rgba(0,0,0,0.2);
}
.datepicker .cw {
font-size: 10px;
width: 12px;
padding: 0 2px 0 5px;
vertical-align: middle;
}
.datepicker thead tr:first-child th.cw {
cursor: default;
background-color: transparent;
}
.input-group.date .input-group-addon i {
cursor: pointer;
width: 16px;
height: 16px;
}
.input-daterange input {
text-align: center;
}
.input-daterange input:first-child {
border-radius: 3px 0 0 3px;
}
.input-daterange input:last-child {
border-radius: 0 3px 3px 0;
}
.input-daterange .input-group-addon {
width: auto;
min-width: 16px;
padding: 4px 5px;
font-weight: normal;
line-height: 1.428571429;
text-align: center;
text-shadow: 0 1px 0 #fff;
vertical-align: middle;
background-color: #eeeeee;
border: solid #cccccc;
border-width: 1px 0;
margin-left: -5px;
margin-right: -5px;
}
.datepicker.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
z-index: 1000;
float: left;
display: none;
min-width: 160px;
list-style: none;
background-color: #ffffff;
border: 1px solid #ccc;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 5px;
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-webkit-background-clip: padding-box;
-moz-background-clip: padding;
background-clip: padding-box;
*border-right-width: 2px;
*border-bottom-width: 2px;
color: #333333;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
line-height: 1.428571429;
}
.datepicker.dropdown-menu th,
.datepicker.dropdown-menu td {
padding: 4px 5px;
}

View file

@ -0,0 +1,245 @@
/*!
* Stylesheet for the Date Range Picker, for use with Bootstrap 3.x
*
* Copyright 2013 Dan Grossman ( http://www.dangrossman.info )
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Built for http://www.improvely.com
*/
.daterangepicker.dropdown-menu {
max-width: none;
z-index: 3000;
}
.daterangepicker.opensleft .ranges, .daterangepicker.opensleft .calendar {
float: left;
margin: 4px;
}
.daterangepicker.opensright .ranges, .daterangepicker.opensright .calendar {
float: right;
margin: 4px;
}
.daterangepicker .ranges {
width: 160px;
text-align: left;
}
.daterangepicker .ranges .range_inputs>div {
float: left;
}
.daterangepicker .ranges .range_inputs>div:nth-child(2) {
padding-left: 11px;
}
.daterangepicker .calendar {
display: none;
max-width: 270px;
}
.daterangepicker .calendar th, .daterangepicker .calendar td {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
white-space: nowrap;
text-align: center;
min-width: 32px;
}
.daterangepicker .ranges label {
color: #333;
display: block;
font-size: 11px;
font-weight: normal;
height: 20px;
line-height: 20px;
margin-bottom: 2px;
text-shadow: #fff 1px 1px 0px;
text-transform: uppercase;
width: 74px;
}
.daterangepicker .ranges input {
font-size: 11px;
}
.daterangepicker .ranges .input-mini {
background-color: #eee;
border: 1px solid #ccc;
border-radius: 4px;
color: #555;
display: block;
font-size: 11px;
height: 30px;
line-height: 30px;
vertical-align: middle;
margin: 0 0 10px 0;
padding: 0 6px;
width: 74px;
}
.daterangepicker .ranges ul {
list-style: none;
margin: 0;
padding: 0;
}
.daterangepicker .ranges li {
font-size: 13px;
background: #f5f5f5;
border: 1px solid #f5f5f5;
color: #08c;
padding: 3px 12px;
margin-bottom: 8px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
cursor: pointer;
}
.daterangepicker .ranges li.active, .daterangepicker .ranges li:hover {
background: #08c;
border: 1px solid #08c;
color: #fff;
}
.daterangepicker .calendar-date {
border: 1px solid #ddd;
padding: 4px;
border-radius: 4px;
background: #fff;
}
.daterangepicker .calendar-time {
text-align: center;
margin: 8px auto 0 auto;
line-height: 30px;
}
.daterangepicker {
position: absolute;
background: #fff;
top: 100px;
left: 20px;
padding: 4px;
margin-top: 1px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.daterangepicker.opensleft:before {
position: absolute;
top: -7px;
right: 9px;
display: inline-block;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-left: 7px solid transparent;
border-bottom-color: rgba(0, 0, 0, 0.2);
content: '';
}
.daterangepicker.opensleft:after {
position: absolute;
top: -6px;
right: 10px;
display: inline-block;
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-left: 6px solid transparent;
content: '';
}
.daterangepicker.opensright:before {
position: absolute;
top: -7px;
left: 9px;
display: inline-block;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-left: 7px solid transparent;
border-bottom-color: rgba(0, 0, 0, 0.2);
content: '';
}
.daterangepicker.opensright:after {
position: absolute;
top: -6px;
left: 10px;
display: inline-block;
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-left: 6px solid transparent;
content: '';
}
.daterangepicker table {
width: 100%;
margin: 0;
}
.daterangepicker td, .daterangepicker th {
text-align: center;
width: 20px;
height: 20px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
cursor: pointer;
white-space: nowrap;
}
.daterangepicker td.off {
color: #999;
}
.daterangepicker td.disabled {
color: #999;
}
.daterangepicker td.available:hover, .daterangepicker th.available:hover {
background: #eee;
}
.daterangepicker td.in-range {
background: #ebf4f8;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.daterangepicker td.active, .daterangepicker td.active:hover {
background-color: #357ebd;
border-color: #3071a9;
color: #fff;
}
.daterangepicker td.week, .daterangepicker th.week {
font-size: 80%;
color: #ccc;
}
.daterangepicker select.monthselect, .daterangepicker select.yearselect {
font-size: 12px;
padding: 1px;
height: auto;
margin: 0;
cursor: default;
}
.daterangepicker select.monthselect {
margin-right: 2%;
width: 56%;
}
.daterangepicker select.yearselect {
width: 40%;
}
.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.ampmselect {
width: 50px;
margin-bottom: 0;
}

View file

@ -0,0 +1,61 @@
/* iCheck plugin skins
----------------------------------- */
@import url("minimal/_all.css");
/*
@import url("minimal/minimal.css");
@import url("minimal/red.css");
@import url("minimal/green.css");
@import url("minimal/blue.css");
@import url("minimal/aero.css");
@import url("minimal/grey.css");
@import url("minimal/orange.css");
@import url("minimal/yellow.css");
@import url("minimal/pink.css");
@import url("minimal/purple.css");
*/
@import url("square/_all.css");
/*
@import url("square/square.css");
@import url("square/red.css");
@import url("square/green.css");
@import url("square/blue.css");
@import url("square/aero.css");
@import url("square/grey.css");
@import url("square/orange.css");
@import url("square/yellow.css");
@import url("square/pink.css");
@import url("square/purple.css");
*/
@import url("flat/_all.css");
/*
@import url("flat/flat.css");
@import url("flat/red.css");
@import url("flat/green.css");
@import url("flat/blue.css");
@import url("flat/aero.css");
@import url("flat/grey.css");
@import url("flat/orange.css");
@import url("flat/yellow.css");
@import url("flat/pink.css");
@import url("flat/purple.css");
*/
@import url("line/_all.css");
/*
@import url("line/line.css");
@import url("line/red.css");
@import url("line/green.css");
@import url("line/blue.css");
@import url("line/aero.css");
@import url("line/grey.css");
@import url("line/orange.css");
@import url("line/yellow.css");
@import url("line/pink.css");
@import url("line/purple.css");
*/
@import url("polaris/polaris.css");
@import url("futurico/futurico.css");

View file

@ -0,0 +1,560 @@
/* iCheck plugin Flat skin
----------------------------------- */
.icheckbox_flat,
.iradio_flat {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(flat.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat {
background-position: 0 0;
}
.icheckbox_flat.checked {
background-position: -22px 0;
}
.icheckbox_flat.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat.checked.disabled {
background-position: -66px 0;
}
.iradio_flat {
background-position: -88px 0;
}
.iradio_flat.checked {
background-position: -110px 0;
}
.iradio_flat.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat,
.iradio_flat {
background-image: url(flat@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}
/* red */
.icheckbox_flat-red,
.iradio_flat-red {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(red.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-red {
background-position: 0 0;
}
.icheckbox_flat-red.checked {
background-position: -22px 0;
}
.icheckbox_flat-red.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-red.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-red {
background-position: -88px 0;
}
.iradio_flat-red.checked {
background-position: -110px 0;
}
.iradio_flat-red.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-red.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-red,
.iradio_flat-red {
background-image: url(red@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}
/* green */
.icheckbox_flat-green,
.iradio_flat-green {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(green.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-green {
background-position: 0 0;
}
.icheckbox_flat-green.checked {
background-position: -22px 0;
}
.icheckbox_flat-green.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-green.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-green {
background-position: -88px 0;
}
.iradio_flat-green.checked {
background-position: -110px 0;
}
.iradio_flat-green.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-green.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-green,
.iradio_flat-green {
background-image: url(green@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}
/* blue */
.icheckbox_flat-blue,
.iradio_flat-blue {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(blue.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-blue {
background-position: 0 0;
}
.icheckbox_flat-blue.checked {
background-position: -22px 0;
}
.icheckbox_flat-blue.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-blue.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-blue {
background-position: -88px 0;
}
.iradio_flat-blue.checked {
background-position: -110px 0;
}
.iradio_flat-blue.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-blue.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-blue,
.iradio_flat-blue {
background-image: url(blue@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}
/* aero */
.icheckbox_flat-aero,
.iradio_flat-aero {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(aero.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-aero {
background-position: 0 0;
}
.icheckbox_flat-aero.checked {
background-position: -22px 0;
}
.icheckbox_flat-aero.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-aero.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-aero {
background-position: -88px 0;
}
.iradio_flat-aero.checked {
background-position: -110px 0;
}
.iradio_flat-aero.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-aero.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-aero,
.iradio_flat-aero {
background-image: url(aero@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}
/* grey */
.icheckbox_flat-grey,
.iradio_flat-grey {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(grey.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-grey {
background-position: 0 0;
}
.icheckbox_flat-grey.checked {
background-position: -22px 0;
}
.icheckbox_flat-grey.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-grey.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-grey {
background-position: -88px 0;
}
.iradio_flat-grey.checked {
background-position: -110px 0;
}
.iradio_flat-grey.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-grey.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-grey,
.iradio_flat-grey {
background-image: url(grey@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}
/* orange */
.icheckbox_flat-orange,
.iradio_flat-orange {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(orange.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-orange {
background-position: 0 0;
}
.icheckbox_flat-orange.checked {
background-position: -22px 0;
}
.icheckbox_flat-orange.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-orange.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-orange {
background-position: -88px 0;
}
.iradio_flat-orange.checked {
background-position: -110px 0;
}
.iradio_flat-orange.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-orange.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-orange,
.iradio_flat-orange {
background-image: url(orange@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}
/* yellow */
.icheckbox_flat-yellow,
.iradio_flat-yellow {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(yellow.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-yellow {
background-position: 0 0;
}
.icheckbox_flat-yellow.checked {
background-position: -22px 0;
}
.icheckbox_flat-yellow.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-yellow.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-yellow {
background-position: -88px 0;
}
.iradio_flat-yellow.checked {
background-position: -110px 0;
}
.iradio_flat-yellow.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-yellow.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-yellow,
.iradio_flat-yellow {
background-image: url(yellow@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}
/* pink */
.icheckbox_flat-pink,
.iradio_flat-pink {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(pink.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-pink {
background-position: 0 0;
}
.icheckbox_flat-pink.checked {
background-position: -22px 0;
}
.icheckbox_flat-pink.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-pink.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-pink {
background-position: -88px 0;
}
.iradio_flat-pink.checked {
background-position: -110px 0;
}
.iradio_flat-pink.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-pink.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-pink,
.iradio_flat-pink {
background-image: url(pink@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}
/* purple */
.icheckbox_flat-purple,
.iradio_flat-purple {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(purple.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-purple {
background-position: 0 0;
}
.icheckbox_flat-purple.checked {
background-position: -22px 0;
}
.icheckbox_flat-purple.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-purple.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-purple {
background-position: -88px 0;
}
.iradio_flat-purple.checked {
background-position: -110px 0;
}
.iradio_flat-purple.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-purple.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-purple,
.iradio_flat-purple {
background-image: url(purple@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}

View file

@ -0,0 +1,56 @@
/* iCheck plugin Flat skin, aero
----------------------------------- */
.icheckbox_flat-aero,
.iradio_flat-aero {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(aero.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-aero {
background-position: 0 0;
}
.icheckbox_flat-aero.checked {
background-position: -22px 0;
}
.icheckbox_flat-aero.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-aero.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-aero {
background-position: -88px 0;
}
.iradio_flat-aero.checked {
background-position: -110px 0;
}
.iradio_flat-aero.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-aero.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-aero,
.iradio_flat-aero {
background-image: url(aero@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -0,0 +1,56 @@
/* iCheck plugin Flat skin, blue
----------------------------------- */
.icheckbox_flat-blue,
.iradio_flat-blue {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(blue.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-blue {
background-position: 0 0;
}
.icheckbox_flat-blue.checked {
background-position: -22px 0;
}
.icheckbox_flat-blue.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-blue.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-blue {
background-position: -88px 0;
}
.iradio_flat-blue.checked {
background-position: -110px 0;
}
.iradio_flat-blue.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-blue.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-blue,
.iradio_flat-blue {
background-image: url(blue@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -0,0 +1,56 @@
/* iCheck plugin flat skin, black
----------------------------------- */
.icheckbox_flat,
.iradio_flat {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(flat.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat {
background-position: 0 0;
}
.icheckbox_flat.checked {
background-position: -22px 0;
}
.icheckbox_flat.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat.checked.disabled {
background-position: -66px 0;
}
.iradio_flat {
background-position: -88px 0;
}
.iradio_flat.checked {
background-position: -110px 0;
}
.iradio_flat.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat,
.iradio_flat {
background-image: url(flat@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -0,0 +1,56 @@
/* iCheck plugin Flat skin, green
----------------------------------- */
.icheckbox_flat-green,
.iradio_flat-green {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(green.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-green {
background-position: 0 0;
}
.icheckbox_flat-green.checked {
background-position: -22px 0;
}
.icheckbox_flat-green.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-green.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-green {
background-position: -88px 0;
}
.iradio_flat-green.checked {
background-position: -110px 0;
}
.iradio_flat-green.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-green.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-green,
.iradio_flat-green {
background-image: url(green@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -0,0 +1,56 @@
/* iCheck plugin Flat skin, grey
----------------------------------- */
.icheckbox_flat-grey,
.iradio_flat-grey {
display: inline-block;
*display: inline;
vertical-align: middle;
margin: 0;
padding: 0;
width: 20px;
height: 20px;
background: url(grey.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_flat-grey {
background-position: 0 0;
}
.icheckbox_flat-grey.checked {
background-position: -22px 0;
}
.icheckbox_flat-grey.disabled {
background-position: -44px 0;
cursor: default;
}
.icheckbox_flat-grey.checked.disabled {
background-position: -66px 0;
}
.iradio_flat-grey {
background-position: -88px 0;
}
.iradio_flat-grey.checked {
background-position: -110px 0;
}
.iradio_flat-grey.disabled {
background-position: -132px 0;
cursor: default;
}
.iradio_flat-grey.checked.disabled {
background-position: -154px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_flat-grey,
.iradio_flat-grey {
background-image: url(grey@2x.png);
-webkit-background-size: 176px 22px;
background-size: 176px 22px;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Some files were not shown because too many files have changed in this diff Show more