grim/port-authority

f65d1a42d875
flow: Merged '0.0.4' to ('default').
  • +1 -0
    .hgignore
  • +12 -0
    Makefile
  • +17 -3
    css/style.css
  • +37 -19
    html/window.html
  • +49 -8
    js/app.js
  • +1 -1
    manifest.json
  • --- a/.hgignore Mon Jan 19 21:50:01 2015 -0600
    +++ b/.hgignore Sun Jan 25 04:35:39 2015 -0600
    @@ -1,4 +1,5 @@
    syntax: glob
    +*.zip
    .*.swp
    syntax: regexp
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/Makefile Sun Jan 25 04:35:39 2015 -0600
    @@ -0,0 +1,12 @@
    +#!/usr/bin/make -f
    +
    +OUTPUT=port-authority.zip
    +
    +.PHONY: all clean
    +
    +all: .
    + zip -9r $(OUTPUT) . -x .hg* .hg/*
    +
    +clean:
    + rm -f $(OUTPUT)
    +
    --- a/css/style.css Mon Jan 19 21:50:01 2015 -0600
    +++ b/css/style.css Sun Jan 25 04:35:39 2015 -0600
    @@ -18,8 +18,8 @@
    .repo-list {
    padding: 0;
    - margin-top: 1em;
    - height: 90%;
    + margin: 1em 0;
    + height: 100%;
    overflow-y: auto;
    }
    @@ -29,8 +29,22 @@
    .tag-list {
    padding: 1em 5%;
    + height: 100%;
    + overflow-y: auto;
    +}
    +
    +.loading {
    + text-align: center;
    + font-weight: bold;
    + color: #000000;
    +}
    +
    +.full-height {
    + height: 100%;
    +}
    +
    +.height-90 {
    height: 90%;
    - overflow-y: auto;
    }
    [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
    --- a/html/window.html Mon Jan 19 21:50:01 2015 -0600
    +++ b/html/window.html Sun Jan 25 04:35:39 2015 -0600
    @@ -17,38 +17,56 @@
    <div class="col-xs-5">
    <div class="input-group">
    <span class="input-group-addon">Registry</span>
    - <input class="form-control" data-ng-model="registry" placeholder="enter the url of your registry">
    + <input class="form-control" data-ng-model="registry" placeholder="enter the url of your registry" data-ng-disabled="refreshing">
    </div>
    </div>
    <div class="col-xs-5">
    <div class="input-group">
    <span class="input-group-addon">Query</span>
    - <input class="form-control" data-ng-model="query" placeholder="Search Query">
    + <input class="form-control" data-ng-model="query" placeholder="Search Query" ng-disabled="refreshing">
    </div>
    </div>
    <div class="col-xs-2">
    - <button type="button" class="btn btn-primary" data-ng-click="refresh()">Refresh</button>
    + <button type="button" class="btn btn-primary" data-ng-click="refresh()" data-ng-disabled="refreshing">Refresh</button>
    </div>
    </form>
    </div>
    - <div>Clipboard: {{clipboard}}</div>
    - <div class="list-group repo-list col-xs-4">
    - <a class="list-group-item" data-ng-repeat="r in repos" data-ng-click="select_repo(r)" ng-class="(r == repo) ? 'active': ''" href="#">{{r.name}}</a>
    + <div class="row">
    + <div class="col-xs-12">Clipboard: {{clipboard}}</div>
    + </div>
    + <div class="row" data-ng-show="debug">
    + <div class="col-xs-3"><label><input type="checkbox" data-ng-model="refreshing">refreshing</label></div>
    + <div class="col-xs-3"><label><input type="checkbox" data-ng-model="refreshing_repo">refreshing_repo</label></div>
    + </div>
    + <div class="row height-90">
    + <div class="col-xs-4 full-height">
    + <div class="list-group repo-list" data-ng-hide="refreshing">
    + <a class="list-group-item" data-ng-repeat="r in repos" data-ng-click="select_repo(r)" data-ng-class="(r == repo) ? 'active': ''" href>{{r.name}}</a>
    + </div>
    + <div class="loading" data-ng-show="refreshing">
    + <i class="fa fa-spin fa-5x fa-cog"></i><br><span>Loading...</span>
    + </div>
    </div>
    - <div class="repo-info col-xs-8" data-ng-show="repo">
    - <div><h1>{{repo.name}}</h1></div>
    - <div>{{repo.description||""}}</div>
    - <div>
    - <span data-ng-show="repo.is_official" class="label label-primary">Official</span>
    - <span data-ng-show="repo.is_trusted" class="label label-success">Trusted</span>
    - <span data-ng-show="repo.is_automated" class="label label-info">Automated</span>
    - <span class="label label-warning" data-ng-show="repo.star_count > 0">{{repo.star_count}}<span class="fa fa-star"></span></span>
    + <div class="repo-info col-xs-8" data-ng-show="repo">
    + <div><h1>{{repo.name}}</h1></div>
    + <div>{{repo.description||"(no description)"}}</div>
    + <div>
    + <span data-ng-show="repo.is_official" class="label label-primary">Official</span>
    + <span data-ng-show="repo.is_trusted" class="label label-success">Trusted</span>
    + <span data-ng-show="repo.is_automated" class="label label-info">Automated</span>
    + <span class="label label-warning" data-ng-show="repo.star_count > 0">{{repo.star_count}}<span class="fa fa-star"></span></span>
    + </div>
    + <div data-ng-hide="refreshing_repo">
    + <ul class="tag-list">
    + <li data-ng-repeat="(layer, tags) in tags">
    + <span data-ng-repeat="tag in tags"><code>{{tag}}</code><span data-ng-click="copy_tag(tag)" class="fa fa-clipboard"></span>{{$last ? '' : ', '}}</span>
    + </li>
    + </ul>
    + </div>
    + <div class="loading" data-ng-show="refreshing_repo">
    + <i class="fa fa-spin fa-5x fa-cog"></i><br>Loading...
    + </div>
    </div>
    - <ul class="tag-list">
    - <li data-ng-repeat="(layer, tags) in tags">
    - <span data-ng-repeat="tag in tags"><code>{{tag}}</code><span data-ng-click="copy_tag(tag)" class="fa fa-clipboard"></span>{{$last ? '' : ', '}}</span>
    - </li>
    - </ul>
    </div>
    </div>
    </body>
    --- a/js/app.js Mon Jan 19 21:50:01 2015 -0600
    +++ b/js/app.js Sun Jan 25 04:35:39 2015 -0600
    @@ -38,8 +38,11 @@
    });
    function ManifestController($scope, manifestREST) {
    + $scope.debug = false;
    + $scope.refreshing = false;
    + $scope.refreshing_repo = false;
    $scope.registry = "registry.hub.docker.com";
    - $scope.query = "busybox";
    + $scope.query = "node";
    $scope.repos = null;
    $scope.repo = null;
    $scope.error = null;
    @@ -58,6 +61,8 @@
    $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;
    }
    @@ -73,8 +78,15 @@
    $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;
    + $scope.refreshing = false;
    +
    return repo;
    });
    })
    @@ -84,6 +96,8 @@
    $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;
    +
    console.log("Failed to get the registry list: " + status);
    });
    };
    @@ -98,6 +112,8 @@
    $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
    @@ -105,34 +121,59 @@
    * and the private registry returns a dictionary of tag
    * names to images. Like:
    * {"latest", "deadb33f"}
    - * This function will normalize them into an object like
    - * {"deadb33f", ["latest"]}
    + * 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 = {};
    + $scope.tags = [];
    if(data.constructor === Array) { /* registry.hub.docker.com */
    + var dtags = {};
    for(var ntag in data) {
    var tag = data[ntag];
    - $scope.tags[tag.layer] = $scope.tags[tag.layer] || [];
    + dtags[tag.layer] = dtags[tag.layer] || [];
    +
    + dtags[tag.layer].push(tag.name);
    + }
    - $scope.tags[tag.layer].push(tag.name);
    + var tags = [];
    + for(var tag in dtags) {
    + tags.push(dtags[tag].sort());
    }
    +
    + $scope.tags = tags.sort(function(a, b) { return a[0] - b[0]});
    } else if(data !== null && typeof data === 'object') { /* private registries */
    + var dtags = {};
    +
    for(var tag in data) {
    var layer = data[tag];
    - $scope.tags[layer] = $scope.tags[layer] || [];
    - $scope.tags[layer].push(tag);
    + dtags[layer] = dtags[layer] || [];
    + dtags[layer].push(tag);
    }
    +
    + var tags = [];
    + for(var tag in dtags) {
    + tags.push(dtags[tag].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");
    console.log("Failed to get the tag list: " + status);
    +
    + $scope.refreshing_repo = false;
    });
    };
    --- a/manifest.json Mon Jan 19 21:50:01 2015 -0600
    +++ b/manifest.json Sun Jan 25 04:35:39 2015 -0600
    @@ -1,6 +1,6 @@
    {
    "name": "Port Authority",
    - "version": "0.0.3",
    + "version": "0.0.4",
    "manifest_version": 2,
    "description": "Chrome application for interacting with a Docker registry",
    "icons": {