Tweak drawing.js to have a better default margin that never truncates image ids on the left in small widths. Tweak the screenshot generator to use the smallest possible width. Remove tabs from several files. Add the browser-chrome plugin to wrap phantomjs screenshots with browser chrome. Add some repository descriptions to the dataset generator. Switch to using our own screenshots vs those hosted on blogger.

This commit is contained in:
yackob03 2013-10-11 21:28:02 -04:00
parent 04b8a009da
commit 4040bb37c6
15 changed files with 391 additions and 155 deletions

2
.gitignore vendored
View file

@ -2,4 +2,4 @@
venv venv
.elasticbeanstalk/ .elasticbeanstalk/
static/snapshots/ static/snapshots/
screenshots/*.png screenshots/screenshots/

View file

@ -52,12 +52,16 @@ def create_subtree(repo, structure, parent):
create_subtree(repo, subtree, new_image) create_subtree(repo, subtree, new_image)
def __generate_repository(user, name, is_public, permissions, structure): def __generate_repository(user, name, description, is_public, permissions, structure):
repo = model.create_repository(user.username, name, user) repo = model.create_repository(user.username, name, user)
if is_public: if is_public:
model.set_repository_visibility(repo, 'public') model.set_repository_visibility(repo, 'public')
if description:
repo.description = description
repo.save()
for delegate, role in permissions: for delegate, role in permissions:
model.set_user_repo_permission(delegate.username, user.username, name, model.set_user_repo_permission(delegate.username, user.username, name,
role) role)
@ -81,16 +85,18 @@ if __name__ == '__main__':
new_user_2.verified = True new_user_2.verified = True
new_user_2.save() new_user_2.save()
__generate_repository(new_user_1, 'simple', False, [], (4, [], __generate_repository(new_user_1, 'simple', 'Simple repository.', False,
['latest', 'prod'])) [], (4, [], ['latest', 'prod']))
__generate_repository(new_user_1, 'complex', False, [], __generate_repository(new_user_1, 'complex',
'Complex repository with many branches and tags.',
False, [(new_user_2, 'read')],
(2, [(3, [], 'v2.0'), (2, [(3, [], 'v2.0'),
(1, [(1, [(1, [], ['latest', 'prod'])], (1, [(1, [(1, [], ['latest', 'prod'])],
'staging'), 'staging'),
(1, [], None)], None)], None)) (1, [], None)], None)], None))
__generate_repository(new_user_1, 'horrific', False, [], __generate_repository(new_user_1, 'horrific', None, False, [],
(2, [(3, [], 'v2.0'), (2, [(3, [], 'v2.0'),
(1, [(1, [(1, [], ['latest', 'prod'])], (1, [(1, [(1, [], ['latest', 'prod'])],
'staging'), 'staging'),
@ -100,8 +106,10 @@ if __name__ == '__main__':
(1, [(1, [], 'v5.0'), (1, [], 'v6.0')], None)], (1, [(1, [], 'v5.0'), (1, [], 'v6.0')], None)],
None)) None))
__generate_repository(new_user_2, 'publicrepo', True, [], __generate_repository(new_user_2, 'publicrepo',
(10, [], 'latest')) 'Public repository pullable by the world.', True,
[], (10, [], 'latest'))
__generate_repository(new_user_1, 'shared', False, __generate_repository(new_user_1, 'shared',
'Shared repository, another user can write.', False,
[(new_user_2, 'write')], (5, [], 'latest')) [(new_user_2, 'write')], (5, [], 'latest'))

View file

@ -1,6 +1,6 @@
var casper = require('casper').create({ var casper = require('casper').create({
viewportSize: { viewportSize: {
width: 1280, width: 1070,
height: 768 height: 768
}, },
verbose: true, verbose: true,
@ -11,7 +11,9 @@ var options = casper.cli.options;
var isDebug = !!options['d']; var isDebug = !!options['d'];
var rootUrl = isDebug ? 'http://localhost:5001/' : 'https://quay.io/'; var rootUrl = isDebug ? 'http://localhost:5001/' : 'https://quay.io/';
var repo = isDebug ? 'simple' : 'r0'; var repo = isDebug ? 'complex' : 'r0';
var outputDir = "screenshots/";
casper.start(rootUrl); casper.start(rootUrl);
@ -24,7 +26,7 @@ casper.on("page.error", function(msg, trace) {
}); });
casper.then(function() { casper.then(function() {
this.capture('landing.png'); this.capture(outputDir + 'landing.png');
}); });
casper.thenOpen(rootUrl + 'signin', function () { casper.thenOpen(rootUrl + 'signin', function () {
@ -39,7 +41,7 @@ casper.then(function() {
}); });
casper.then(function() { casper.then(function() {
this.capture('user-home.png'); this.capture(outputDir + 'user-home.png');
}); });
casper.thenOpen(rootUrl + 'repository/devtable/' + repo, function() { casper.thenOpen(rootUrl + 'repository/devtable/' + repo, function() {
@ -51,7 +53,7 @@ casper.thenOpen(rootUrl + 'repository/devtable/' + repo, function() {
}); });
casper.then(function() { casper.then(function() {
this.capture('repo-view.png'); this.capture(outputDir + 'repo-view.png');
}); });
casper.thenOpen(rootUrl + 'repository/devtable/' + repo + '/admin', function() { casper.thenOpen(rootUrl + 'repository/devtable/' + repo + '/admin', function() {
@ -59,7 +61,7 @@ casper.thenOpen(rootUrl + 'repository/devtable/' + repo + '/admin', function() {
}); });
casper.then(function() { casper.then(function() {
this.capture('repo-admin.png'); this.capture(outputDir + 'repo-admin.png');
}); });
casper.run(); casper.run();

View file

@ -1,3 +1,6 @@
* {
font-family: 'Droid Sans', sans-serif;
}
.plans .callout { .plans .callout {
font-size: 2em; font-size: 2em;
@ -719,6 +722,7 @@ p.editable:hover i {
#image-history-container { #image-history-container {
overflow: hidden; overflow: hidden;
min-height: 400px;
} }
#image-history-container .node circle { #image-history-container .node circle {

BIN
static/img/repo-admin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
static/img/repo-view.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
static/img/user-home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

View file

@ -199,6 +199,8 @@ function LandingCtrl($scope, $timeout, Restangular, UserService, KeyService) {
}; };
$scope.status = 'ready'; $scope.status = 'ready';
browserchrome.update();
} }
function RepoCtrl($scope, Restangular, $routeParams, $rootScope) { function RepoCtrl($scope, Restangular, $routeParams, $rootScope) {

View file

@ -65,12 +65,7 @@ ImageHistoryTree.prototype.draw = function(container) {
var boundingBox = document.getElementById(container).getBoundingClientRect(); var boundingBox = document.getElementById(container).getBoundingClientRect();
document.getElementById(container).style.maxHeight = (viewportHeight - boundingBox.top) + 'px'; document.getElementById(container).style.maxHeight = (viewportHeight - boundingBox.top) + 'px';
var leftMargin = 20; var margin = { top: 40, right: 20, bottom: 20, left: 40 };
if (width > document.getElementById(container).clientWidth) {
leftMargin = 120;
}
var margin = { top: 40, right: 20, bottom: 20, left: leftMargin };
var m = [margin.top, margin.right, margin.bottom, margin.left]; var m = [margin.top, margin.right, margin.bottom, margin.left];
var w = width - m[1] - m[3]; var w = width - m[1] - m[3];
var h = height - m[0] - m[2]; var h = height - m[0] - m[2];
@ -98,13 +93,13 @@ ImageHistoryTree.prototype.draw = function(container) {
.direction('e') .direction('e')
.html(function(d) { .html(function(d) {
var html = ''; var html = '';
if (d.collapsed) { if (d.collapsed) {
for (var i = 1; i < d.encountered.length; ++i) { for (var i = 1; i < d.encountered.length; ++i) {
html += '<span>' + d.encountered[i].image.id.substr(0, 12) + '</span>'; html += '<span>' + d.encountered[i].image.id.substr(0, 12) + '</span>';
html += '<span class="created">' + formatTime(d.encountered[i].image.created) + '</span>'; html += '<span class="created">' + formatTime(d.encountered[i].image.created) + '</span>';
} }
return html; return html;
} }
if (d.image.comment) { if (d.image.comment) {
html += '<span class="comment">' + formatComment(d.image.comment) + '</span>'; html += '<span class="comment">' + formatComment(d.image.comment) + '</span>';
@ -228,9 +223,9 @@ ImageHistoryTree.prototype.buildRoot_ = function() {
var immediateParent = ancestors[ancestors.length - 1] * 1; var immediateParent = ancestors[ancestors.length - 1] * 1;
var parent = imageByDBID[immediateParent]; var parent = imageByDBID[immediateParent];
if (parent) { if (parent) {
// Add a reference to the parent. This makes walking the tree later easier. // Add a reference to the parent. This makes walking the tree later easier.
imageNode.parent = parent; imageNode.parent = parent;
parent.children.push(imageNode); parent.children.push(imageNode);
} else { } else {
formatted = imageNode; formatted = imageNode;
} }
@ -240,16 +235,16 @@ ImageHistoryTree.prototype.buildRoot_ = function() {
// the width of the tree properly. // the width of the tree properly.
var maxChildCount = 0; var maxChildCount = 0;
for (var i = 0; i < this.images_.length; ++i) { for (var i = 0; i < this.images_.length; ++i) {
var image = this.images_[i]; var image = this.images_[i];
var imageNode = imageByDBID[image.dbid]; var imageNode = imageByDBID[image.dbid];
maxChildCount = Math.max(maxChildCount, this.determineMaximumChildCount_(imageNode)); maxChildCount = Math.max(maxChildCount, this.determineMaximumChildCount_(imageNode));
} }
// Compact the graph so that any single chain of three (or more) images becomes a collapsed // Compact the graph so that any single chain of three (or more) images becomes a collapsed
// section. We only do this if the max width is > 1 (since for a single width tree, no long // section. We only do this if the max width is > 1 (since for a single width tree, no long
// chain will hide a branch). // chain will hide a branch).
if (maxChildCount > 1) { if (maxChildCount > 1) {
this.collapseNodes_(formatted); this.collapseNodes_(formatted);
} }
// Determine the maximum height of the tree. // Determine the maximum height of the tree.
@ -259,8 +254,8 @@ ImageHistoryTree.prototype.buildRoot_ = function() {
this.root_ = formatted; this.root_ = formatted;
return { return {
'maxWidth': maxChildCount + 1, 'maxWidth': maxChildCount + 1,
'maxHeight': maxHeight 'maxHeight': maxHeight
}; };
}; };
@ -284,35 +279,35 @@ ImageHistoryTree.prototype.determineMaximumHeight_ = function(node) {
*/ */
ImageHistoryTree.prototype.collapseNodes_ = function(node) { ImageHistoryTree.prototype.collapseNodes_ = function(node) {
if (node.children.length == 1) { if (node.children.length == 1) {
// Keep searching downward until we find a node with more than a single child. // Keep searching downward until we find a node with more than a single child.
var current = node; var current = node;
var previous = node; var previous = node;
var encountered = []; var encountered = [];
while (current.children.length == 1) { while (current.children.length == 1) {
encountered.push(current); encountered.push(current);
previous = current; previous = current;
current = current.children[0]; current = current.children[0];
} }
if (encountered.length >= 3) { if (encountered.length >= 3) {
// Collapse the node. // Collapse the node.
var collapsed = { var collapsed = {
"name": '(' + encountered.length + ' images)', "name": '(' + encountered.length + ' images)',
"children": [current], "children": [current],
"collapsed": true, "collapsed": true,
"encountered": encountered "encountered": encountered
}; };
node.children = [collapsed]; node.children = [collapsed];
// Update the parent relationships. // Update the parent relationships.
collapsed.parent = node; collapsed.parent = node;
current.parent = collapsed; current.parent = collapsed;
return; return;
} }
} }
for (var i = 0; i < node.children.length; ++i) { for (var i = 0; i < node.children.length; ++i) {
this.collapseNodes_(node.children[i]); this.collapseNodes_(node.children[i]);
} }
}; };
@ -326,7 +321,7 @@ ImageHistoryTree.prototype.determineMaximumChildCount_ = function(node) {
var nestedCount = 0; var nestedCount = 0;
for (var i = 0; i < children.length; ++i) { for (var i = 0; i < children.length; ++i) {
nestedCount += children[i].children.length; nestedCount += children[i].children.length;
} }
return Math.max(myLevelCount, nestedCount); return Math.max(myLevelCount, nestedCount);
@ -339,10 +334,10 @@ ImageHistoryTree.prototype.determineMaximumChildCount_ = function(node) {
*/ */
ImageHistoryTree.prototype.findImage_ = function(checker) { ImageHistoryTree.prototype.findImage_ = function(checker) {
for (var i = 0; i < this.images_.length; ++i) { for (var i = 0; i < this.images_.length; ++i) {
var image = this.images_[i]; var image = this.images_[i];
if (checker(image)) { if (checker(image)) {
return image; return image;
} }
} }
return null; return null;
@ -356,8 +351,8 @@ ImageHistoryTree.prototype.markPath_ = function(startingNode, isHighlighted) {
var currentNode = startingNode; var currentNode = startingNode;
currentNode.current = isHighlighted; currentNode.current = isHighlighted;
while (currentNode != null) { while (currentNode != null) {
currentNode.highlighted = isHighlighted; currentNode.highlighted = isHighlighted;
currentNode = currentNode.parent; currentNode = currentNode.parent;
} }
}; };
@ -384,25 +379,25 @@ ImageHistoryTree.prototype.setTag_ = function(tagName) {
// Ensure that the children are in the correct order. // Ensure that the children are in the correct order.
for (var i = 0; i < this.images_.length; ++i) { for (var i = 0; i < this.images_.length; ++i) {
var image = this.images_[i]; var image = this.images_[i];
var imageNode = this.imageByDBID_[image.dbid]; var imageNode = this.imageByDBID_[image.dbid];
var ancestors = this.getAncestors_(image); var ancestors = this.getAncestors_(image);
var immediateParent = ancestors[ancestors.length - 1] * 1; var immediateParent = ancestors[ancestors.length - 1] * 1;
var parent = imageByDBID[immediateParent]; var parent = imageByDBID[immediateParent];
if (parent && imageNode.highlighted) { if (parent && imageNode.highlighted) {
var arr = parent.children; var arr = parent.children;
if (parent._children) { if (parent._children) {
arr = parent._children; arr = parent._children;
} }
if (arr[0] != imageNode) { if (arr[0] != imageNode) {
var index = arr.indexOf(imageNode); var index = arr.indexOf(imageNode);
if (index > 0) { if (index > 0) {
arr.splice(index, 1); arr.splice(index, 1);
arr.splice(0, 0, imageNode); arr.splice(0, 0, imageNode);
} }
} }
} }
} }
// Update the tree. // Update the tree.
@ -416,11 +411,11 @@ ImageHistoryTree.prototype.setTag_ = function(tagName) {
ImageHistoryTree.prototype.setImage_ = function(imageId) { ImageHistoryTree.prototype.setImage_ = function(imageId) {
// Find the new current image. // Find the new current image.
var newImage = this.findImage_(function(image) { var newImage = this.findImage_(function(image) {
return image.id == imageId; return image.id == imageId;
}); });
if (newImage == this.currentImage_) { if (newImage == this.currentImage_) {
return; return;
} }
this.currentImage_ = newImage; this.currentImage_ = newImage;
@ -510,7 +505,7 @@ ImageHistoryTree.prototype.update_ = function(source) {
nodeUpdate.select("circle") nodeUpdate.select("circle")
.attr("r", 4.5) .attr("r", 4.5)
.attr("class", function(d) { .attr("class", function(d) {
return (d._children ? "closed " : "open ") + (d.current ? "current " : "") + (d.highlighted ? "highlighted " : ""); return (d._children ? "closed " : "open ") + (d.current ? "current " : "") + (d.highlighted ? "highlighted " : "");
}) })
.style("fill", function(d) { .style("fill", function(d) {
if (d.current) { if (d.current) {
@ -522,10 +517,10 @@ ImageHistoryTree.prototype.update_ = function(source) {
// Update the repo text. // Update the repo text.
nodeUpdate.select("text") nodeUpdate.select("text")
.attr("class", function(d) { .attr("class", function(d) {
if (d.collapsed) { if (d.collapsed) {
return 'collapsed'; return 'collapsed';
} }
return d.image.id == that.currentImage_.id ? 'current' : ''; return d.image.id == that.currentImage_.id ? 'current' : '';
}); });
// Ensure that the node is visible. // Ensure that the node is visible.
@ -535,9 +530,9 @@ ImageHistoryTree.prototype.update_ = function(source) {
// Update the tags. // Update the tags.
node.select(".tags") node.select(".tags")
.html(function(d) { .html(function(d) {
if (!d.tags) { if (!d.tags) {
return ''; return '';
} }
var html = ''; var html = '';
for (var i = 0; i < d.tags.length; ++i) { for (var i = 0; i < d.tags.length; ++i) {
@ -554,10 +549,10 @@ ImageHistoryTree.prototype.update_ = function(source) {
// Listen for click events on the labels. // Listen for click events on the labels.
node.selectAll(".tag") node.selectAll(".tag")
.on("click", function(d, e) { .on("click", function(d, e) {
var tag = this.getAttribute('data-tag'); var tag = this.getAttribute('data-tag');
if (tag) { if (tag) {
that.changeTag_(tag); that.changeTag_(tag);
} }
}); });
// Ensure the tags are visible. // Ensure the tags are visible.
@ -568,7 +563,7 @@ ImageHistoryTree.prototype.update_ = function(source) {
// we force a redraw by adjusting the height of the object ever so slightly. // we force a redraw by adjusting the height of the object ever so slightly.
nodeUpdate.select(".fo") nodeUpdate.select(".fo")
.attr('height', function(d) { .attr('height', function(d) {
return DEPTH_HEIGHT - 20 + Math.random() / 10; return DEPTH_HEIGHT - 20 + Math.random() / 10;
}); });
// Transition exiting nodes to the parent's new position. // Transition exiting nodes to the parent's new position.

View file

@ -0,0 +1,183 @@
.browser-chrome-container * {
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
.browser-chrome-container {
border: 2px solid #363532;
display: inline-block;
border-radius: 2px;
max-width: 100%;
height: auto;
}
.browser-chrome-header {
height: 40px;
padding: 2px;
overflow: hidden;
background-color: rgb(54,53,50);
background-image: linear-gradient(bottom, rgb(54,53,50) 0%, rgb(86,85,81) 100%);
background-image: -o-linear-gradient(bottom, rgb(54,53,50) 0%, rgb(86,85,81) 100%);
background-image: -moz-linear-gradient(bottom, rgb(54,53,50) 0%, rgb(86,85,81) 100%);
background-image: -webkit-linear-gradient(bottom, rgb(54,53,50) 0%, rgb(86,85,81) 100%);
background-image: -ms-linear-gradient(bottom, rgb(54,53,50) 0%, rgb(86,85,81) 100%);
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, rgb(54,53,50)),
color-stop(1, rgb(86,85,81))
);
}
.browser-chrome-header .user-icon-container {
float: right;
margin-right: 5px;
margin-top: 10px;
}
.browser-chrome-header .user-icon-container i {
color: #78bcf3;
}
.browser-chrome-header i {
color: white;
}
.browser-chrome-tab {
display: inline-block;
position: relative;
width: 200px;
height: 25px;
bottom: -13px;
left: 10px;
background-color: #f2f1f0;
vertical-align: middle;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.browser-chrome-tab-wrapper:before,
.browser-chrome-tab-wrapper:after {
content: "";
position: absolute;
background-color: #f2f1f0;
width: 10px;
height: 10px;
bottom: 0px;
}
.browser-chrome-tab-wrapper:before {
left: -10px;
}
.browser-chrome-tab-wrapper:after {
right: -10px;
}
.browser-chrome-tab:before,
.browser-chrome-tab:after {
content: "";
position: absolute;
width: 20px;
height: 20px;
border-radius: 10px;
bottom: 0px;
background-color: rgb(54,53,50);
background-image: linear-gradient(bottom, rgb(54,53,50) 0%, rgb(70,69,65) 100%);
background-image: -o-linear-gradient(bottom, rgb(54,53,50) 0%, rgb(70,69,65) 100%);
background-image: -moz-linear-gradient(bottom, rgb(54,53,50) 0%, rgb(70,69,65) 100%);
background-image: -webkit-linear-gradient(bottom, rgb(54,53,50) 0%, rgb(70,69,65) 100%);
background-image: -ms-linear-gradient(bottom, rgb(54,53,50) 0%, rgb(70,69,65) 100%);
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, rgb(54,53,50)),
color-stop(1, rgb(70,69,65))
);
z-index: 1;
}
.browser-chrome-tab:before {
left: -20px;
}
.browser-chrome-tab:after {
right: -20px;
}
.browser-chrome-tab-content {
overflow: hidden;
text-overflow: ellipsis;
font-size: 14px;
padding: 4px;
white-space: nowrap;
}
.browser-chrome-tab-content i {
color: #363532;
}
.browser-chrome-url-bar {
height: 35px;
background-color: #f2f1f0;
padding: 5px;
}
.browser-chrome-url-bar i {
color: #363532;
margin-right: 5px;
}
.browser-chrome-url-bar .left-controls {
width: 78px;
float: left;
padding-top: 2px;
}
.browser-chrome-url-bar .right-controls {
width: 26px;
float: right;
padding-top: 2px;
}
.browser-chrome-url-bar .right-controls i {
margin-left: 5px;
margin-right: 0;
}
.browser-chrome-url {
color: black;
background-color: white;
border-radius: 2px;
border: 1px solid #ada9a5;
padding: 2px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.browser-chrome-url .protocol-https {
color: #079500;
}
.browser-chrome-url .protocol-https i {
color: #079500;
}
.browser-chrome-url i {
margin-right: 5px;
margin-left: 5px;
}

View file

@ -0,0 +1,39 @@
(function(browserchrome, $) {
var htmlTemplate = '<div class="browser-chrome-container"><div class="browser-chrome-header"><i class="icon-remove-sign"></i> <i class="icon-minus-sign"></i> <i class="icon-plus-sign"></i><div class="browser-chrome-tab"><div class="browser-chrome-tab-wrapper"><div class="browser-chrome-tab-content"><i class="icon-file-alt icon-large"></i> <span class="tab-title">Tab Title</span></div></div></div><div class="user-icon-container"><i class="icon-user icon-2x"></i></div></div><div class="browser-chrome-url-bar"><div class="left-controls"><i class="icon-arrow-left icon-large"></i> <i class="icon-arrow-right icon-large"></i> <i class="icon-rotate-right icon-large"></i> </div><div class="right-controls"> <i class="icon-reorder icon-large"></i></div><div class="browser-chrome-url"><span class="protocol-https" style="display: none"><i class="icon-lock"></i>https</span><span class="protocol-http"><i class="icon-file-alt"></i>http</span><span class="url-text">://google.com/</span></div></div></div>'
browserchrome.update = function() {
$('[data-screenshot-url]').each(function(index, element) {
var elem = $(element);
if (!elem.data('has-chrome')) {
// Create chrome
var createdHtml = $(htmlTemplate);
// Add the new chrome to the page where the image was
elem.replaceWith(createdHtml);
// Add the image to the new browser chrome html
createdHtml.append(elem);
// Set the tab title
var tabTitle = elem.attr('title') || elem.data('tab-title');
createdHtml.find('.tab-title').text(tabTitle);
// Pick the protocol and set the url
var url = elem.data('screenshot-url');
if (url.substring(0, 6) === 'https:') {
createdHtml.find('.protocol-http').hide();
createdHtml.find('.protocol-https').show();
url = url.substring(5);
} else {
createdHtml.find('.protocol-http').hide();
createdHtml.find('.protocol-https').show();
url = url.substring(4);
}
console.log('setting url to: ' + url);
createdHtml.find('.url-text').text(url);
elem.data('has-chrome', 'true');
}
});
};
}(window.browserchrome = window.browserchrome || {}, window.jQuery));

View file

@ -102,7 +102,7 @@
</div> </div>
<div class="tour-section row"> <div class="tour-section row">
<div class="col-md-7"><img src="//1.bp.blogspot.com/-HieEyF9wvVQ/Uk3epFZc6QI/AAAAAAAAADU/-Ov_3v2JkHQ/s640/Screenshot+from+2013-10-03+17%253A12%253A21.png" class="img-responsive"></div> <div class="col-md-7"><img src="/static/img/user-home.png" title="User Home - Quay" data-screenshot-url="https://quay.io/" class="img-responsive"></div>
<div class="col-md-5"> <div class="col-md-5">
<div class="tour-section-title">Customized for you</div> <div class="tour-section-title">Customized for you</div>
<div class="tour-section-description"> <div class="tour-section-description">
@ -113,7 +113,7 @@
</div> </div>
<div class="tour-section row"> <div class="tour-section row">
<div class="col-md-7 col-md-push-5"><img src="//4.bp.blogspot.com/-0uJZWmoTuaU/Uk3eo8BHAjI/AAAAAAAAADM/PhY-ZNNj0tw/s640/Screenshot+from+2013-10-03+17%253A12%253A41.png" class="img-responsive"></div> <div class="col-md-7 col-md-push-5"><img src="/static/img/repo-view.png" title="Repository View - Quay" data-screenshot-url="https://quay.io/repository/devtable/complex" class="img-responsive"></div>
<div class="col-md-5 col-md-pull-7"> <div class="col-md-5 col-md-pull-7">
<div class="tour-section-title">Useful views of respositories</div> <div class="tour-section-title">Useful views of respositories</div>
<div class="tour-section-description"> <div class="tour-section-description">
@ -123,7 +123,7 @@
</div> </div>
<div class="tour-section row"> <div class="tour-section row">
<div class="col-md-7"><img src="//4.bp.blogspot.com/-aF-RMMxhKmw/Uk3eoys3wsI/AAAAAAAAADc/1uxE8BJ-QHY/s640/Screenshot+from+2013-10-03+17%253A13%253A07.png" class="img-responsive"></div> <div class="col-md-7"><img src="/static/img/repo-admin.png" title="Repository Admin - Quay" data-screenshot-url="https://quay.io/repository/devtable/complex/admin" class="img-responsive"></div>
<div class="col-md-5"> <div class="col-md-5">
<div class="tour-section-title">Share at your control</div> <div class="tour-section-title">Share at your control</div>
<div class="tour-section-description"> <div class="tour-section-description">

View file

@ -62,64 +62,64 @@
</div> </div>
<div class="row"> <div class="row">
<!-- Tree View container --> <!-- Tree View container -->
<div class="col-md-8"> <div class="col-md-7">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<!-- Tag dropdown --> <!-- Tag dropdown -->
<span class="tag-dropdown dropdown" title="Tags"> <span class="tag-dropdown dropdown" title="Tags">
<i class="icon-tag"><span class="tag-count">{{getTagCount(repo)}}</span></i> <i class="icon-tag"><span class="tag-count">{{getTagCount(repo)}}</span></i>
<a href="javascript:void(0)" class="dropdown-toggle" data-toggle="dropdown">{{currentTag.name}} <b class="caret"></b></a> <a href="javascript:void(0)" class="dropdown-toggle" data-toggle="dropdown">{{currentTag.name}} <b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-repeat="tag in repo.tags"> <li ng-repeat="tag in repo.tags">
<a href="javascript:void(0)" ng-click="setTag(tag.name)">{{tag.name}}</a> <a href="javascript:void(0)" ng-click="setTag(tag.name)">{{tag.name}}</a>
</li> </li>
</ul> </ul>
</span> </span>
<span class="right-title">Tags</span> <span class="right-title">Tags</span>
</div> </div>
<!-- Tree View itself --> <!-- Tree View itself -->
<div id="image-history-container"></div> <div id="image-history-container"></div>
</div> </div>
</div> </div>
<!-- Side Panel --> <!-- Side Panel -->
<div class="col-md-4"> <div class="col-md-5">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<!-- Image dropdown --> <!-- Image dropdown -->
<span class="tag-dropdown dropdown" title="Images"> <span class="tag-dropdown dropdown" title="Images">
<i class="icon-archive"><span class="tag-count">{{imageHistory.length}}</span></i> <i class="icon-archive"><span class="tag-count">{{imageHistory.length}}</span></i>
<a href="javascript:void(0)" class="dropdown-toggle" data-toggle="dropdown">{{currentImage.id.substr(0, 12)}} <b class="caret"></b></a> <a href="javascript:void(0)" class="dropdown-toggle" data-toggle="dropdown">{{currentImage.id.substr(0, 12)}} <b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-repeat="image in imageHistory"> <li ng-repeat="image in imageHistory">
<a href="javascript:void(0)" ng-click="setImage(image)">{{image.id.substr(0, 12)}}</a> <a href="javascript:void(0)" ng-click="setImage(image)">{{image.id.substr(0, 12)}}</a>
</li> </li>
</ul> </ul>
</span> </span>
<span class="right-title">Selected Image</span> <span class="right-title">Selected Image</span>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div id="current-image"> <div id="current-image">
<dl class="dl-horizontal"> <dl class="dl-horizontal">
<dt>Created</dt> <dt>Created</dt>
<dd am-time-ago="parseDate(currentTag.image.created)"></dd> <dd am-time-ago="parseDate(currentTag.image.created)"></dd>
</dl> </dl>
<div ng-show="currentTag.image.comment"> <div ng-show="currentTag.image.comment">
<strong>Description:</strong> <strong>Description:</strong>
<blockquote style="margin-top: 10px;" ng-bind-html-unsafe="getMarkedDown(currentTag.image.comment)"> <blockquote style="margin-top: 10px;" ng-bind-html-unsafe="getMarkedDown(currentTag.image.comment)">
</blockquote> </blockquote>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -12,6 +12,8 @@
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.min.css"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.min.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.no-icons.min.css"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.no-icons.min.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css">
<link href='http://fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="/static/lib/browser-chrome.css">
<link rel="stylesheet" href="/static/css/quay.css"> <link rel="stylesheet" href="/static/css/quay.css">
@ -39,6 +41,7 @@
<script src="static/lib/typeahead.min.js"></script> <script src="static/lib/typeahead.min.js"></script>
<script src="static/lib/d3-tip.js" charset="utf-8"></script> <script src="static/lib/d3-tip.js" charset="utf-8"></script>
<script src="static/lib/browser-chrome.js"></script>
<script src="static/js/app.js"></script> <script src="static/js/app.js"></script>
<script src="static/js/controllers.js"></script> <script src="static/js/controllers.js"></script>

BIN
test.db

Binary file not shown.