grim/port-authority

lots of hacking and slashing

2016-04-13, Gary Kramlich
53bfb785d971
Parents 0e182c67351b
Children 2bdacaa8e7c1
lots of hacking and slashing
  • +0 -1
    css/pa.css
  • +116 -216
    js/app.js
  • +36 -62
    window.html
  • --- a/css/pa.css Mon Apr 11 17:29:22 2016 -0500
    +++ b/css/pa.css Wed Apr 13 17:35:10 2016 -0500
    @@ -2,4 +2,3 @@
    -webkit-user-select: all;
    overflow-y: auto;
    }
    -
    --- a/js/app.js Mon Apr 11 17:29:22 2016 -0500
    +++ b/js/app.js Wed Apr 13 17:35:10 2016 -0500
    @@ -1,233 +1,133 @@
    -var manifest = angular.module("manifest", [])
    -.config([
    - '$compileProvider',
    - function($compileProvider) {
    - $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension):/);
    - $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension):/);
    - }
    -]);
    +function repository_selected(result, response) {
    + console.log(result);
    + $("#repository-header").text(result.name || "Unknown");
    + $("#repository-description").text(result.description || "(no description)");
    -manifest.factory("manifestREST", function($http) {
    - return {
    - search: function(registry, query) {
    - var url = registry + "/v1/search";
    - if(query) {
    - url += "?q=" + query;
    - }
    - return $http.get(url);
    - },
    - tags: function(registry, repo) {
    - return $http.get(registry + "/v1/repositories/" + repo + "/tags");
    - }
    - };
    -});
    -
    -function ManifestController($scope, manifestREST) {
    - $scope.storage = chrome.storage.sync;
    -
    - var defaults = {
    - debug: false,
    - registry: "registry.hub.docker.com",
    - query: "docker"
    - };
    + $("#repository-official").css("display", result.is_official ? "inline" : "none");
    + $("#repository-trusted").css("display", result.is_trusted ? "inline" : "none");
    + $("#repository-automated").css("display", result.is_automated ? "inline" : "none");
    - $scope.storage.get(defaults, function(items) {
    - $scope.$apply(function() {
    - $scope.debug = items.debug;
    - $scope.registry = items.registry;
    - $scope.query = items.query;
    - });
    - });
    -
    - $scope.refreshing = false;
    - $scope.refreshing_repo = false;
    - $scope.repos = null;
    - $scope.repo = null;
    - $scope.error = null;
    - $scope.tags = null;
    - $scope.clipboard = null;
    + if(result.star_count || result.star_count === 0) {
    + $("#repository-stars").css("display", "inline");
    + $("#repository-stars").html("<i class=\"icon star\"></i>" + result.star_count);
    + } else {
    + $("#repository-stars").css("display", "none");
    + }
    - /* google analytics stuff */
    - $scope.ga_service = analytics.getService("Port Authority Chrome");
    - $scope.ga_tracker = $scope.ga_service.getTracker("UA-47592312-2");
    -
    - $scope.ga_tracker.sendAppView("main");
    + storage.set({"repository": result.name});
    +}
    - $scope.refresh = function() {
    - $scope.error = null;
    - $scope.repos = null;
    - $scope.repo = null;
    - $scope.tags = null;
    - $scope.clipboard = null;
    -
    - $scope.refreshing = true;
    -
    - if($scope.registry.indexOf("http://") !== 0 && $scope.registry.indexOf("https://") !== 0) {
    - $scope.registry = "http://" + $scope.registry;
    +function repository_results(response) {
    + // shove the repositories into a dictionary and clean it up
    + var repos = {};
    + $.each(response.results, function(idx, repo) {
    + var library_prefix = "library/";
    + if(repo.name.indexOf(library_prefix) === 0) {
    + repo.name = repo.name.substring(library_prefix.length, repo.name.length);
    }
    - $scope.storage.set({
    - registry: $scope.registry,
    - query: $scope.query
    - });
    -
    - $scope.ga_tracker.sendEvent("refresh", "search param", "used", $scope.query !== "");
    -
    - var timer_start = window.performance.now();
    - manifestREST.search($scope.registry, $scope.query)
    - .success(function(data, status, headers, config) {
    - var timer_end = window.performance.now();
    -
    - $scope.ga_tracker.sendEvent("refresh", "status", "refresh success");
    - $scope.ga_tracker.sendTiming("refresh", "load time", timer_end - timer_start, "refresh success timing");
    -
    - $scope.repos = data.results.map(function(repo) {
    - var library_prefix = "library/";
    - if(repo.name.indexOf(library_prefix) === 0) {
    - repo.name = repo.name.substring(library_prefix.length, repo.name.length);
    - }
    -
    - repo.expanded = false;
    -
    - return repo;
    - });
    -
    - $scope.refreshing = false;
    - })
    - .error(function(data, status, headers, config) {
    - var timer_end = window.performance.now();
    -
    - $scope.ga_tracker.sendEvent("refresh", "status", "refresh failed");
    - $scope.ga_tracker.sendTiming("refresh", "load time", timer_end - timer_start, "refresh failed timing");
    -
    - $scope.refreshing = false;
    -
    - $scope.error = "Failed to get the registry list";
    - });
    - };
    -
    - $scope.select_repo = function(repo) {
    - $scope.error = null;
    -
    - if(repo === $scope.repo) {
    - return;
    - }
    -
    - $scope.ga_tracker.sendEvent("repo", "selected", "repo-selected");
    -
    - $scope.repo = repo;
    - $scope.tags = null;
    -
    - $scope.refreshing_repo = true;
    -
    - manifestREST.tags($scope.registry, repo.name)
    - .success(function(data, status, headers, config) {
    - /* the docker registry returns a list of objects like
    - * [{"layer", "deadb33f", "name": "latest"}]
    - * and the private registry returns a dictionary of tag
    - * names to images. Like:
    - * {"latest", "deadb33f"}
    - * This function will normalize them into a sorted list like
    - * [
    - * ["foo", "latest"]
    - * ["latest"],
    - * ]
    - * Image IDs are thrown away because we don't care about them.
    - */
    -
    - $scope.ga_tracker.sendEvent("repo", "get tags", "success");
    -
    - $scope.tags = [];
    + repos[repo.name] = repo;
    + })
    - var dtags = {};
    - var dtag = null;
    - var tags = [];
    - var tag = null;
    -
    - if(data.constructor === Array) { /* registry.hub.docker.com */
    - for(var ntag in data) {
    - tag = data[ntag];
    - dtags[tag.layer] = dtags[tag.layer] || [];
    -
    - dtags[tag.layer].push(tag.name);
    - }
    -
    - for(dtag in dtags) {
    - tags.push(dtags[dtag].sort());
    - }
    -
    - $scope.tags = tags.sort(function(a, b) {
    - return a[0] - b[0];
    - });
    - } else if(data !== null && typeof data === 'object') { /* private registries */
    - for(dtag in data) {
    - var layer = data[dtag];
    -
    - dtags[layer] = dtags[layer] || [];
    - dtags[layer].push(dtag);
    - }
    -
    - for(dtag in dtags) {
    - tags.push(dtags[dtag].sort());
    - }
    -
    - $scope.tags = tags.sort(function(a, b) {
    - return a[0] - b[0];
    - });
    - }
    -
    - $scope.refreshing_repo = false;
    - })
    - .error(function(data, status, headers, config) {
    - $scope.ga_tracker.sendEvent("repo", "get tags", "failed");
    -
    - $scope.refreshing_repo = false;
    -
    - $scope.error = "Failed to get the tag list";
    - });
    - };
    -
    - $scope.copy_tag = function(tag) {
    - $scope.ga_tracker.sendEvent("copy", "clicked");
    -
    - var host = $scope.registry;
    -
    - if(host.indexOf("http://") === 0) {
    - host = host.substring(7);
    - } else if(host.indexOf("https://") === 0) {
    - host = host.substring(8);
    - }
    -
    - $scope.clipboard = host + "/" + $scope.repo.name + ":" + tag;
    - };
    -
    - $scope.clear_error = function() {
    - $scope.error = null;
    - };
    -
    - $scope.set_clipboard = function() {
    - var element = document.querySelector(".clipboard");
    - var selection = window.getSelection();
    - var range = document.createRange();
    -
    - range.selectNodeContents(element);
    -
    - selection.removeAllRanges();
    - selection.addRange(range);
    - }
    + repositories = repos;
    }
    -$(document).ready(function() {
    - $(".ui.search")
    +function repository_config() {
    + var url = "http://" + settings.registry;
    +
    + for(registry in settings.registries) {
    + if(registry.hostname === settings.registry) {
    + url = registry.scheme + "://" + registry.hostname;
    + }
    + }
    +
    + $("#repository-search")
    .search({
    apiSettings: {
    - url: "https://registry.hub.docker.com/v1/search?q={query}"
    + url: url + "/v1/search?q={query}"
    },
    fields: {
    results: "results",
    - title: "name",
    - url: "http://google.com"
    + title: "name"
    + },
    + onResults: repository_results,
    + onSelect: repository_selected,
    + minCharacters: 2
    + });
    +}
    +
    +function registry_selected(result, response) {
    + storage.set({"registry": result.hostname});
    + repository_config();
    +}
    +
    +function registry_config() {
    + $("#registry-search")
    + .search({
    + apiSettings: {
    + responseAsync: function(data, callback) {
    + results = []
    +
    + $.each(settings.registries, function(idx, registry) {
    + if(registry.hostname.indexOf(data.urlData.query) > -1)
    + results.push(registry);
    + });
    +
    + callback({
    + success: results.length > 0,
    + results: results
    + });
    + }
    + },
    + fields: {
    + title: "hostname"
    },
    - minCharacters: 2
    + onSelect: registry_selected
    });
    +}
    +
    +function registry_initialize() {
    +}
    +
    +function initialize() {
    + // setup our repository
    + $("#repository").val(settings.repository);
    + repository_config();
    +
    + // setup our registry
    + $("registry").val(settings.registry);
    + registry_config();
    +
    + // add our handler for settings changes
    + chrome.storage.onChanged.addListener(function(changes, namespace) {
    + for(key in changes) {
    + if(key === 'registry') {
    + repository_config();
    + } else if(key === 'repository') {
    + repository_display();
    + }
    + }
    + });
    +}
    +
    +var storage = chrome.storage.sync;
    +storage.clear();
    +
    +var defaults = {
    + "registry": "registry.hub.docker.com",
    + "registries": [{
    + "hostname": "registry.hub.docker.com",
    + "scheme": "https"
    + }, {
    + "hostname": "registry1.docker1.kscyks3.it.corp",
    + "scheme": "http"
    + }],
    + "repository": "docker"
    +};
    +var settings = defaults;
    +
    +storage.get(defaults, function(items) {
    + settings = items;
    +
    + $(document).ready(initialize());
    });
    --- a/window.html Mon Apr 11 17:29:22 2016 -0500
    +++ b/window.html Wed Apr 13 17:35:10 2016 -0500
    @@ -1,63 +1,54 @@
    <!DOCTYPE html>
    -<html lang="en" data-ng-app="manifest" data-ng-csp>
    +<html lang="en">
    <head>
    <title>Port Authority</title>
    - <script src="/js/angular.min.js"></script>
    <script src="/js/jquery.min.js"></script>
    <script src="/js/semantic.min.js"></script>
    - <script src="/js/google-analytics-bundle.js"></script>
    <script src="/js/app.js"></script>
    <link rel="stylesheet" href="/css/semantic.min.css">
    <link rel="stylesheet" href="/css/pa.css">
    </head>
    - <body data-ng-controller="ManifestController">
    - <div class="ui page grid">
    - <div class="row">
    - <div class="column eight wide">
    - <div class="ui icon input fluid">
    - <input data-ng-model="registry" placeholder="Registry" data-ng-disabled="refreshing" ng-keyup="$event.keyCode == 13 && refresh()">
    - <i class="icon cloud"></i>
    + <body>
    + <div class="ui borderless menu blue inverted">
    + <div class="item"><img src="marketing/logo-128.png" alt="Port Authority"></div>
    + <div class="item">
    + <div id="repository-search" class="ui search">
    + <div class="ui left icon input">
    + <input id="repository" class="prompt" placeholder="Repository">
    + <i class="icon code"></i>
    </div>
    </div>
    - <div class="column eight wide">
    - <div class="ui icon input fluid">
    - <input data-ng-model="query" placeholder="Search query..." data-ng-disabled="refreshing" ng-keyup="$event.keyCode == 13 && refresh()">
    - <i class="icon search"></i>
    + </div>
    + <div class="item right fluid">
    + <div id="registry-search" class="ui search">
    + <div class="ui left icon input">
    + <input id="registry" class="prompt" placeholder="Registry">
    + <i class="icon cloud"></i>
    </div>
    </div>
    </div>
    - <div class="row">
    - <div class="column eight wide">
    - <div class="ui search">
    - <div class="ui left icon input">
    - <input class="prompt" placeholder="Repository">
    - <i class="code icon"></i>
    - </div>
    - </div>
    + </div>
    + <div class="ui segment basic">
    + <div id="repository-header" class="ui huge header"></div>
    + <div id="repository-description" class="description"></div>
    +
    + <div class="ui segment basic">
    + <div id="repository-official" class="ui label green" style="display:none;">
    + <i class="icon checkmark"></i>Official
    + </div>
    + <div id="repository-trusted" class="ui label blue" style="display:none;">
    + <i class="icon lock"></i>Trusted
    + </div>
    + <div id="repository-automated" class="ui label" style="display:none;">
    + <i class="icon wizard"></i>Automated
    + </div>
    + <div id="repository-stars" class="ui label yellow" style="display:none;">
    + <i class="icon star"></i>0
    </div>
    </div>
    - <div class="row" data-ng-if="error">
    - <div class="column">
    - <div class="ui negative message">
    - <i class="icon close" data-ng-click="clear_error()"></i>
    - <div class="content">
    - {{error}}
    - </div>
    - </div>
    - </div>
    - </div>
    - <div class="row" data-ng-if="debug">
    - <div class="column">
    - <div class="ui icon message">
    - <i class="icon bug"></i>
    - <div class="content">
    - <label><input type="checkbox" data-ng-model="refreshing">refreshing</label>
    - <label><input type="checkbox" data-ng-model="refreshing_repo">refreshing_repo</label>
    - <button type="button" class="btn btn-primary" data-ng-click="refresh()" data-ng-disabled="refreshing">Refresh</button>
    - </div>
    - </div>
    - </div>
    - </div>
    + </div>
    +
    + <div class="ui page grid">
    <div class="row">
    <div class="column">
    <div class="ui icon message yellow">
    @@ -69,25 +60,8 @@
    </div>
    </div>
    <div class="row">
    - <div class="column six wide" data-ng-if="repos">
    - <div class="ui segment" data-ng-class="refreshing ? 'loading' : ''">
    - <div class="ui vertical menu fluid">
    - <a class="item" data-ng-repeat="r in repos | orderBy : 'name'" data-ng-click="select_repo(r)" data-ng-class="r == repo ? 'active' : ''">{{r.name}}</a>
    - </div>
    - </div>
    - </div>
    - <div class="column ten wide" data-ng-if="repo">
    + <div class="column sixteen wide" data-ng-if="repo">
    <div class="ui segment" data-ng-class="refreshing_repo ? 'loading': ''">
    - <h1 class="ui header">
    - {{repo.name}}
    - <div class="sub header">{{repo.description||"(no description)"}}</div>
    - </h1>
    - <div>
    - <span data-ng-if="repo.is_official" class="ui tag label green">Official</span>
    - <span data-ng-if="repo.is_trusted" class="ui tag label blue">Trusted</span>
    - <span data-ng-if="repo.is_automated" class="ui tag label">Automated</span>
    - <span data-ng-if="repo.star_count > 0" class="ui tag label"><i class="icon star"></i> {{repo.star_count}}</span>
    - </div>
    <div class="ui divided list">
    <div class="item" data-ng-repeat="(layer, tags) in tags">
    <span data-ng-repeat="tag in tags"><a data-ng-click="copy_tag(tag)">{{tag}}</a>{{$last ? '' : ', '}}</span>